| From ccbbd6a2ae27c6712a168ea48ce320aa2c4249da Mon Sep 17 00:00:00 2001 |
| From: Yong Wu <yong.wu@mediatek.com> |
| Date: Sat, 10 Apr 2021 17:11:15 +0800 |
| Subject: [PATCH] FROMLIST: iommu/mediatek: Add device_link between the |
| consumer and the larb devices |
| |
| MediaTek IOMMU-SMI diagram is like below. all the consumer connect with |
| smi-larb, then connect with smi-common. |
| |
| M4U |
| | |
| smi-common |
| | |
| ------------- |
| | | ... |
| | | |
| larb1 larb2 |
| | | |
| vdec venc |
| |
| When the consumer works, it should enable the smi-larb's power which |
| also need enable the smi-common's power firstly. |
| |
| Thus, First of all, use the device link connect the consumer and the |
| smi-larbs. then add device link between the smi-larb and smi-common. |
| |
| This patch adds device_link between the consumer and the larbs. |
| |
| When device_link_add, I add the flag DL_FLAG_STATELESS to avoid calling |
| pm_runtime_xx to keep the original status of clocks. It can avoid two |
| issues: |
| 1) Display HW show fastlogo abnormally reported in [1]. At the beggining, |
| all the clocks are enabled before entering kernel, but the clocks for |
| display HW(always in larb0) will be gated after clk_enable and clk_disable |
| called from device_link_add(->pm_runtime_resume) and rpm_idle. The clock |
| operation happened before display driver probe. At that time, the display |
| HW will be abnormal. |
| |
| 2) A deadlock issue reported in [2]. Use DL_FLAG_STATELESS to skip |
| pm_runtime_xx to avoid the deadlock. |
| |
| Corresponding, DL_FLAG_AUTOREMOVE_CONSUMER can't be added, then |
| device_link_removed should be added explicitly. |
| |
| [1] https://lore.kernel.org/linux-mediatek/1564213888.22908.4.camel@mhfsdcap03/ |
| [2] https://lore.kernel.org/patchwork/patch/1086569/ |
| |
| Suggested-by: Tomasz Figa <tfiga@chromium.org> |
| Signed-off-by: Yong Wu <yong.wu@mediatek.com> |
| |
| (am from https://patchwork.kernel.org/project/linux-mediatek/patch/20210410091128.31823-4-yong.wu@mediatek.com/) |
| |
| BUG=b:126008328 |
| TEST=boot krane |
| |
| Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org> |
| Change-Id: Ie97b4775516f468f011da08d8e3a143ca9f52ac7 |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2866750 |
| Reviewed-by: Sean Paul <seanpaul@chromium.org> |
| Reviewed-by: Nicolas Boichat <drinkcat@chromium.org> |
| --- |
| drivers/iommu/mtk_iommu.c | 22 ++++++++++++++++++++++ |
| drivers/iommu/mtk_iommu_v1.c | 20 +++++++++++++++++++- |
| 2 files changed, 41 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c |
| index c8b82a3cdf3f..e89bb5cc8d61 100644 |
| --- a/drivers/iommu/mtk_iommu.c |
| +++ b/drivers/iommu/mtk_iommu.c |
| @@ -572,22 +572,44 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev) |
| { |
| struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); |
| struct mtk_iommu_data *data; |
| + struct device_link *link; |
| + struct device *larbdev; |
| + unsigned int larbid; |
| |
| if (!fwspec || fwspec->ops != &mtk_iommu_ops) |
| return ERR_PTR(-ENODEV); /* Not a iommu client device */ |
| |
| data = dev_iommu_priv_get(dev); |
| |
| + /* |
| + * Link the consumer device with the smi-larb device(supplier) |
| + * The device in each a larb is a independent HW. thus only link |
| + * one larb here. |
| + */ |
| + larbid = MTK_M4U_TO_LARB(fwspec->ids[0]); |
| + larbdev = data->larb_imu[larbid].dev; |
| + link = device_link_add(dev, larbdev, |
| + DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); |
| + if (!link) |
| + dev_err(dev, "Unable to link %s\n", dev_name(larbdev)); |
| return &data->iommu; |
| } |
| |
| static void mtk_iommu_release_device(struct device *dev) |
| { |
| struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); |
| + struct mtk_iommu_data *data; |
| + struct device *larbdev; |
| + unsigned int larbid; |
| |
| if (!fwspec || fwspec->ops != &mtk_iommu_ops) |
| return; |
| |
| + data = dev_iommu_priv_get(dev); |
| + larbid = MTK_M4U_TO_LARB(fwspec->ids[0]); |
| + larbdev = data->larb_imu[larbid].dev; |
| + device_link_remove(dev, larbdev); |
| + |
| iommu_fwspec_free(dev); |
| } |
| |
| diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c |
| index 278908716a13..7bbcd456e136 100644 |
| --- a/drivers/iommu/mtk_iommu_v1.c |
| +++ b/drivers/iommu/mtk_iommu_v1.c |
| @@ -425,7 +425,9 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev) |
| struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); |
| struct of_phandle_args iommu_spec; |
| struct mtk_iommu_data *data; |
| - int err, idx = 0; |
| + struct device_link *link; |
| + struct device *larbdev; |
| + int err, larbid, idx = 0; |
| |
| while (!of_parse_phandle_with_args(dev->of_node, "iommus", |
| "#iommu-cells", |
| @@ -446,6 +448,14 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev) |
| |
| data = dev_iommu_priv_get(dev); |
| |
| + /* Link the consumer device with the smi-larb device(supplier) */ |
| + larbid = mt2701_m4u_to_larb(fwspec->ids[0]); |
| + larbdev = data->larb_imu[larbid].dev; |
| + link = device_link_add(dev, larbdev, |
| + DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); |
| + if (!link) |
| + dev_err(dev, "Unable to link %s\n", dev_name(larbdev)); |
| + |
| return &data->iommu; |
| } |
| |
| @@ -466,10 +476,18 @@ static void mtk_iommu_probe_finalize(struct device *dev) |
| static void mtk_iommu_release_device(struct device *dev) |
| { |
| struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); |
| + struct mtk_iommu_data *data; |
| + struct device *larbdev; |
| + unsigned int larbid; |
| |
| if (!fwspec || fwspec->ops != &mtk_iommu_ops) |
| return; |
| |
| + data = dev_iommu_priv_get(dev); |
| + larbid = mt2701_m4u_to_larb(fwspec->ids[0]); |
| + larbdev = data->larb_imu[larbid].dev; |
| + device_link_remove(dev, larbdev); |
| + |
| iommu_fwspec_free(dev); |
| } |
| |
| -- |
| 2.31.1.607.g51e8a6a459-goog |
| |