Message ID | 20211007080934.108804-16-chanho61.park@samsung.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [v4,01/16] scsi: ufs: add quirk to handle broken UIC command | expand |
> > This patch introduces virtual host driver of exynosauto v9 ufs mHCI. > VH(Virtual Host) only supports data transfer functions. So, most of physical > features are broken. So, we need to set below quirks. > - UFSHCD_QUIRK_BROKEN_UIC_CMD > - UFSHCD_QUIRK_SKIP_PH_CONFIGURATION Oh - you set it here. Maybe just add a comment in your commit log of patches 1 & 2 that you are doing it later. > Before initialization, the VH is necessary to wait until PH is ready. > It's implemented as polling at the moment. > > Cc: Alim Akhtar <alim.akhtar@samsung.com> > Cc: Kiwoong Kim <kwmad.kim@samsung.com> > Cc: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> > Signed-off-by: Chanho Park <chanho61.park@samsung.com> > --- > drivers/scsi/ufs/ufs-exynos.c | 84 +++++++++++++++++++++++++++++++++++ > 1 file changed, 84 insertions(+) > > diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c index > 32f73c906018..c2b654027b0f 100644 > --- a/drivers/scsi/ufs/ufs-exynos.c > +++ b/drivers/scsi/ufs/ufs-exynos.c > @@ -121,6 +121,8 @@ > #define HCI_MH_ALLOWABLE_TRAN_OF_VH 0x30C > #define HCI_MH_IID_IN_TASK_TAG 0X308 > > +#define PH_READY_TIMEOUT_MS (5 * MSEC_PER_SEC) > + > enum { > UNIPRO_L1_5 = 0,/* PHY Adapter */ > UNIPRO_L2, /* Data Link */ > @@ -1403,6 +1405,68 @@ static int exynos_ufs_resume(struct ufs_hba *hba, > enum ufs_pm_op pm_op) > return 0; > } > > +static int exynosauto_ufs_vh_link_startup_notify(struct ufs_hba *hba, > + enum > +ufs_notify_change_status status) { > + if (status == POST_CHANGE) { > + ufshcd_set_link_active(hba); > + ufshcd_set_ufs_dev_active(hba); > + hba->wlun_dev_clr_ua = true; wlun_dev_clr_ua no longer exists - needs rebase > + } > + > + return 0; > +} > + > +static int exynosauto_ufs_vh_wait_ph_ready(struct ufs_hba *hba) { > + u32 mbox; > + ktime_t start, stop; > + > + start = ktime_get(); > + stop = ktime_add(start, ms_to_ktime(PH_READY_TIMEOUT_MS)); > + > + do { > + mbox = ufshcd_readl(hba, PH2VH_MBOX); > + if ((mbox & MH_MSG_MASK) == MH_MSG_PH_READY) > + return 0; Maybe add a comment here that the mbox protocol will be defined later. Thanks, Avri > + > + usleep_range(40, 50); > + } while (ktime_before(ktime_get(), stop)); > + > + return -ETIME; > +} > + > +static int exynosauto_ufs_vh_init(struct ufs_hba *hba) { > + struct device *dev = hba->dev; > + struct platform_device *pdev = to_platform_device(dev); > + struct exynos_ufs *ufs; > + int ret; > + > + ufs = devm_kzalloc(dev, sizeof(*ufs), GFP_KERNEL); > + if (!ufs) > + return -ENOMEM; > + > + /* exynos-specific hci */ > + ufs->reg_hci = devm_platform_ioremap_resource_byname(pdev, > "vs_hci"); > + if (IS_ERR(ufs->reg_hci)) { > + dev_err(dev, "cannot ioremap for hci vendor register\n"); > + return PTR_ERR(ufs->reg_hci); > + } > + > + ret = exynosauto_ufs_vh_wait_ph_ready(hba); > + if (ret) > + return ret; > + > + ufs->drv_data = device_get_match_data(dev); > + if (!ufs->drv_data) > + return -ENODEV; > + > + exynos_ufs_priv_init(hba, ufs); > + > + return 0; > +} > + > static struct ufs_hba_variant_ops ufs_hba_exynos_ops = { > .name = "exynos_ufs", > .init = exynos_ufs_init, > @@ -1417,6 +1481,12 @@ static struct ufs_hba_variant_ops > ufs_hba_exynos_ops = { > .resume = exynos_ufs_resume, > }; > > +static struct ufs_hba_variant_ops ufs_hba_exynosauto_vh_ops = { > + .name = "exynosauto_ufs_vh", > + .init = exynosauto_ufs_vh_init, > + .link_startup_notify = exynosauto_ufs_vh_link_startup_notify, > +}; > + > static int exynos_ufs_probe(struct platform_device *pdev) { > int err; > @@ -1485,6 +1555,18 @@ static struct exynos_ufs_drv_data > exynosauto_ufs_drvs = { > .post_pwr_change = exynosauto_ufs_post_pwr_change, > }; > > +static struct exynos_ufs_drv_data exynosauto_ufs_vh_drvs = { > + .vops = &ufs_hba_exynosauto_vh_ops, > + .quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN | > + UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR | > + UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR | > + UFSHCI_QUIRK_BROKEN_HCE | > + UFSHCD_QUIRK_BROKEN_UIC_CMD | > + UFSHCD_QUIRK_SKIP_PH_CONFIGURATION | > + UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING, > + .opts = EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX, > +}; > + > static struct exynos_ufs_drv_data exynos_ufs_drvs = { > .uic_attr = &exynos7_uic_attr, > .quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN | > @@ -1512,6 +1594,8 @@ static const struct of_device_id > exynos_ufs_of_match[] = { > .data = &exynos_ufs_drvs }, > { .compatible = "samsung,exynosautov9-ufs", > .data = &exynosauto_ufs_drvs }, > + { .compatible = "samsung,exynosautov9-ufs-vh", > + .data = &exynosauto_ufs_vh_drvs }, > {}, > }; > > -- > 2.33.0
> > +static int exynosauto_ufs_vh_link_startup_notify(struct ufs_hba *hba, > > + enum > > +ufs_notify_change_status status) { > > + if (status == POST_CHANGE) { > > + ufshcd_set_link_active(hba); > > + ufshcd_set_ufs_dev_active(hba); > > + hba->wlun_dev_clr_ua = true; > wlun_dev_clr_ua no longer exists - needs rebase I found the commit. I'll remove this next patch. > > > + } > > + > > + return 0; > > +} > > + > > +static int exynosauto_ufs_vh_wait_ph_ready(struct ufs_hba *hba) { > > + u32 mbox; > > + ktime_t start, stop; > > + > > + start = ktime_get(); > > + stop = ktime_add(start, ms_to_ktime(PH_READY_TIMEOUT_MS)); > > + > > + do { > > + mbox = ufshcd_readl(hba, PH2VH_MBOX); > > + if ((mbox & MH_MSG_MASK) == MH_MSG_PH_READY) > > + return 0; > Maybe add a comment here that the mbox protocol will be defined later. Put some comments with TODO: tag. Best Regards, Chanho Park
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c index 32f73c906018..c2b654027b0f 100644 --- a/drivers/scsi/ufs/ufs-exynos.c +++ b/drivers/scsi/ufs/ufs-exynos.c @@ -121,6 +121,8 @@ #define HCI_MH_ALLOWABLE_TRAN_OF_VH 0x30C #define HCI_MH_IID_IN_TASK_TAG 0X308 +#define PH_READY_TIMEOUT_MS (5 * MSEC_PER_SEC) + enum { UNIPRO_L1_5 = 0,/* PHY Adapter */ UNIPRO_L2, /* Data Link */ @@ -1403,6 +1405,68 @@ static int exynos_ufs_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) return 0; } +static int exynosauto_ufs_vh_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + if (status == POST_CHANGE) { + ufshcd_set_link_active(hba); + ufshcd_set_ufs_dev_active(hba); + hba->wlun_dev_clr_ua = true; + } + + return 0; +} + +static int exynosauto_ufs_vh_wait_ph_ready(struct ufs_hba *hba) +{ + u32 mbox; + ktime_t start, stop; + + start = ktime_get(); + stop = ktime_add(start, ms_to_ktime(PH_READY_TIMEOUT_MS)); + + do { + mbox = ufshcd_readl(hba, PH2VH_MBOX); + if ((mbox & MH_MSG_MASK) == MH_MSG_PH_READY) + return 0; + + usleep_range(40, 50); + } while (ktime_before(ktime_get(), stop)); + + return -ETIME; +} + +static int exynosauto_ufs_vh_init(struct ufs_hba *hba) +{ + struct device *dev = hba->dev; + struct platform_device *pdev = to_platform_device(dev); + struct exynos_ufs *ufs; + int ret; + + ufs = devm_kzalloc(dev, sizeof(*ufs), GFP_KERNEL); + if (!ufs) + return -ENOMEM; + + /* exynos-specific hci */ + ufs->reg_hci = devm_platform_ioremap_resource_byname(pdev, "vs_hci"); + if (IS_ERR(ufs->reg_hci)) { + dev_err(dev, "cannot ioremap for hci vendor register\n"); + return PTR_ERR(ufs->reg_hci); + } + + ret = exynosauto_ufs_vh_wait_ph_ready(hba); + if (ret) + return ret; + + ufs->drv_data = device_get_match_data(dev); + if (!ufs->drv_data) + return -ENODEV; + + exynos_ufs_priv_init(hba, ufs); + + return 0; +} + static struct ufs_hba_variant_ops ufs_hba_exynos_ops = { .name = "exynos_ufs", .init = exynos_ufs_init, @@ -1417,6 +1481,12 @@ static struct ufs_hba_variant_ops ufs_hba_exynos_ops = { .resume = exynos_ufs_resume, }; +static struct ufs_hba_variant_ops ufs_hba_exynosauto_vh_ops = { + .name = "exynosauto_ufs_vh", + .init = exynosauto_ufs_vh_init, + .link_startup_notify = exynosauto_ufs_vh_link_startup_notify, +}; + static int exynos_ufs_probe(struct platform_device *pdev) { int err; @@ -1485,6 +1555,18 @@ static struct exynos_ufs_drv_data exynosauto_ufs_drvs = { .post_pwr_change = exynosauto_ufs_post_pwr_change, }; +static struct exynos_ufs_drv_data exynosauto_ufs_vh_drvs = { + .vops = &ufs_hba_exynosauto_vh_ops, + .quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN | + UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR | + UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR | + UFSHCI_QUIRK_BROKEN_HCE | + UFSHCD_QUIRK_BROKEN_UIC_CMD | + UFSHCD_QUIRK_SKIP_PH_CONFIGURATION | + UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING, + .opts = EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX, +}; + static struct exynos_ufs_drv_data exynos_ufs_drvs = { .uic_attr = &exynos7_uic_attr, .quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN | @@ -1512,6 +1594,8 @@ static const struct of_device_id exynos_ufs_of_match[] = { .data = &exynos_ufs_drvs }, { .compatible = "samsung,exynosautov9-ufs", .data = &exynosauto_ufs_drvs }, + { .compatible = "samsung,exynosautov9-ufs-vh", + .data = &exynosauto_ufs_vh_drvs }, {}, };
This patch introduces virtual host driver of exynosauto v9 ufs mHCI. VH(Virtual Host) only supports data transfer functions. So, most of physical features are broken. So, we need to set below quirks. - UFSHCD_QUIRK_BROKEN_UIC_CMD - UFSHCD_QUIRK_SKIP_PH_CONFIGURATION Before initialization, the VH is necessary to wait until PH is ready. It's implemented as polling at the moment. Cc: Alim Akhtar <alim.akhtar@samsung.com> Cc: Kiwoong Kim <kwmad.kim@samsung.com> Cc: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> Signed-off-by: Chanho Park <chanho61.park@samsung.com> --- drivers/scsi/ufs/ufs-exynos.c | 84 +++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)