21. 9. 17. 오후 3:54에 Chanho Park 이(가) 쓴 글: > UFS controller of ExynosAuto v9 SoC supports multi-host interface for I/O > virtualization. In general, we're using para-virtualized driver to > support a block device by several virtual machines. However, it should > be relayed by backend driver. Multi-host functionality extends the host > controller by providing register interfaces that can be used by each > VM's ufs drivers respectively. By this, we can provide direct access to > the UFS device for multiple VMs. It's similar with SR-IOV of PCIe. > > We divide this M-HCI as PH(Physical Host) and VHs(Virtual Host). The PH > supports all UFSHCI functions(all SAPs) same as conventional UFSHCI but > the VH only supports data transfer function. Thus, except UTP_CMD_SAP and > UTP_TMPSAP, the PH should handle all the physical features. > > This patch provides an initial implementation of PH part. M-HCI can > support up to four interfaces but this patch initially supports only 1 > PH and 1 VH. For this, we uses TASK_TAG[7:5] field so TASK_TAG[4:0] for > 32 doorbel will be supported. After the PH is initiated, this will send > a ready message to VHs through a mailbox register. The message handler > is not fully implemented yet such as supporting reset / abort cases. > > Cc: Alim Akhtar <alim.akhtar@xxxxxxxxxxx> > Cc: Kiwoong Kim <kwmad.kim@xxxxxxxxxxx> > Cc: Krzysztof Kozlowski <krzysztof.kozlowski@xxxxxxxxxxxxx> > Signed-off-by: Chanho Park <chanho61.park@xxxxxxxxxxx> > --- > drivers/scsi/ufs/ufs-exynos.c | 45 +++++++++++++++++++++++++++++++++++ > 1 file changed, 45 insertions(+) > > diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c > index 28f027d45917..0ca21cd8e76e 100644 > --- a/drivers/scsi/ufs/ufs-exynos.c > +++ b/drivers/scsi/ufs/ufs-exynos.c > @@ -83,6 +83,21 @@ > #define UFS_SHARABLE (UFS_WR_SHARABLE | UFS_RD_SHARABLE) > #define UFS_SHAREABILITY_OFFSET 0x710 > > +/* Multi-host registers */ > +#define MHCTRL 0xC4 > +#define MHCTRL_EN_VH_MASK (0xE) > +#define MHCTRL_EN_VH(vh) (vh << 1) > +#define PH2VH_MBOX 0xD8 > + > +#define MH_MSG_MASK (0xFF) > + > +#define MH_MSG(id, msg) ((id << 8) | (msg & 0xFF)) > +#define MH_MSG_PH_READY 0x1 > +#define MH_MSG_VH_READY 0x2 > + > +#define HCI_MH_ALLOWABLE_TRAN_OF_VH 0x30C > +#define HCI_MH_IID_IN_TASK_TAG 0X308 > + > enum { > UNIPRO_L1_5 = 0,/* PHY Adapter */ > UNIPRO_L2, /* Data Link */ > @@ -173,6 +188,20 @@ static int exynosauto_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs) > return 0; > } > > +static int exynosauto_ufs_post_hce_enable(struct exynos_ufs *ufs) > +{ > + struct ufs_hba *hba = ufs->hba; > + > + /* Enable Virtual Host #1 */ > + ufshcd_rmwl(hba, MHCTRL_EN_VH_MASK, MHCTRL_EN_VH(1), MHCTRL); > + /* Default VH Transfer permissions */ > + hci_writel(ufs, 0x03FFE1FE, HCI_MH_ALLOWABLE_TRAN_OF_VH); How about using a defined macro instead of constant value, 0x03FFE1FE for code readability? And maybe 0x03FFE1FE to 0x3FFE1FE. Thanks, Inki Dae > + /* IID information is replaced in TASKTAG[7:5] instead of IID in UCD */ > + hci_writel(ufs, 0x1, HCI_MH_IID_IN_TASK_TAG); > + > + return 0; > +} > + > static int exynosauto_ufs_pre_link(struct exynos_ufs *ufs) > { > struct ufs_hba *hba = ufs->hba; > @@ -231,6 +260,20 @@ static int exynosauto_ufs_pre_pwr_change(struct exynos_ufs *ufs, > return 0; > } > > +static int exynosauto_ufs_post_pwr_change(struct exynos_ufs *ufs, > + struct ufs_pa_layer_attr *pwr) > +{ > + struct ufs_hba *hba = ufs->hba; > + u32 enabled_vh; > + > + enabled_vh = ufshcd_readl(hba, MHCTRL) & MHCTRL_EN_VH_MASK; > + > + /* Send physical host ready message to virtual hosts */ > + ufshcd_writel(hba, MH_MSG(enabled_vh, MH_MSG_PH_READY), PH2VH_MBOX); > + > + return 0; > +} > + > static int exynos7_ufs_pre_link(struct exynos_ufs *ufs) > { > struct ufs_hba *hba = ufs->hba; > @@ -1395,8 +1438,10 @@ static struct exynos_ufs_drv_data exynosauto_ufs_drvs = { > EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR | > EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX, > .drv_init = exynosauto_ufs_drv_init, > + .post_hce_enable = exynosauto_ufs_post_hce_enable, > .pre_link = exynosauto_ufs_pre_link, > .pre_pwr_change = exynosauto_ufs_pre_pwr_change, > + .post_pwr_change = exynosauto_ufs_post_pwr_change, > }; > > static struct exynos_ufs_drv_data exynos_ufs_drvs = { >