Commit d2e9a110 authored by Yong Wu's avatar Yong Wu Committed by Joerg Roedel
Browse files

iommu/mediatek: Contain MM IOMMU flow with the MM TYPE



Prepare for supporting INFRA_IOMMU, and APU_IOMMU later.

For Infra IOMMU/APU IOMMU, it doesn't have the "larb""port". thus, Use
the MM flag contain the MM_IOMMU special flow, Also, it moves a big
chunk code about parsing the mediatek,larbs into a function, this is
only needed for MM IOMMU. and all the current SoC are MM_IOMMU.

The device link between iommu consumer device and smi-larb device only
is needed in MM iommu case.

Signed-off-by: default avatarYong Wu <yong.wu@mediatek.com>
Reviewed-by: default avatarAngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: default avatarMatthias Brugger <matthias.bgg@gmail.com>
Link: https://lore.kernel.org/r/20220503071427.2285-18-yong.wu@mediatek.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent 8cd1e619
Loading
Loading
Loading
Loading
+122 −91
Original line number Diff line number Diff line
@@ -138,6 +138,8 @@
#define MTK_IOMMU_IS_TYPE(pdata, _x)	MTK_IOMMU_HAS_FLAG_MASK(pdata, _x,\
							MTK_IOMMU_TYPE_MASK)

#define MTK_INVALID_LARBID		MTK_LARB_NR_MAX

struct mtk_iommu_domain {
	struct io_pgtable_cfg		cfg;
	struct io_pgtable_ops		*iop;
@@ -274,7 +276,7 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
{
	struct mtk_iommu_data *data = dev_id;
	struct mtk_iommu_domain *dom = data->m4u_dom;
	unsigned int fault_larb, fault_port, sub_comm = 0;
	unsigned int fault_larb = MTK_INVALID_LARBID, fault_port = 0, sub_comm = 0;
	u32 int_state, regval, va34_32, pa34_32;
	u64 fault_iova, fault_pa;
	bool layer, write;
@@ -300,6 +302,7 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
	pa34_32 = FIELD_GET(F_MMU_INVAL_PA_34_32_MASK, fault_iova);
	fault_pa |= (u64)pa34_32 << 32;

	if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
		fault_port = F_MMU_INT_ID_PORT_ID(regval);
		if (MTK_IOMMU_HAS_FLAG(data->plat_data, HAS_SUB_COMM_2BITS)) {
			fault_larb = F_MMU_INT_ID_COMM_ID(regval);
@@ -311,6 +314,7 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
			fault_larb = F_MMU_INT_ID_LARB_ID(regval);
		}
		fault_larb = data->plat_data->larbid_remap[fault_larb][sub_comm];
	}

	if (report_iommu_fault(&dom->domain, data->dev, fault_iova,
			       write ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ)) {
@@ -374,6 +378,7 @@ static void mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev,
		larbid = MTK_M4U_TO_LARB(fwspec->ids[i]);
		portid = MTK_M4U_TO_PORT(fwspec->ids[i]);

		if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
			larb_mmu = &data->larb_imu[larbid];

			region = data->plat_data->iova_region + domid;
@@ -389,6 +394,7 @@ static void mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev,
				larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
		}
	}
}

static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom,
				     struct mtk_iommu_data *data,
@@ -593,6 +599,9 @@ static struct iommu_device *mtk_iommu_probe_device(struct device *dev)

	data = dev_iommu_priv_get(dev);

	if (!MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM))
		return &data->iommu;

	/*
	 * Link the consumer device with the smi-larb device(supplier).
	 * The device that connects with each a larb is a independent HW.
@@ -626,9 +635,11 @@ static void mtk_iommu_release_device(struct device *dev)
		return;

	data = dev_iommu_priv_get(dev);
	if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
		larbid = MTK_M4U_TO_LARB(fwspec->ids[0]);
		larbdev = data->larb_imu[larbid].dev;
		device_link_remove(dev, larbdev);
	}

	iommu_fwspec_free(dev);
}
@@ -820,19 +831,77 @@ static const struct component_master_ops mtk_iommu_com_ops = {
	.unbind		= mtk_iommu_unbind,
};

static int mtk_iommu_probe(struct platform_device *pdev)
static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match **match,
				  struct mtk_iommu_data *data)
{
	struct mtk_iommu_data   *data;
	struct device           *dev = &pdev->dev;
	struct device_node *larbnode, *smicomm_node;
	struct platform_device *plarbdev;
	struct device_link *link;
	int i, larb_nr, ret;

	larb_nr = of_count_phandle_with_args(dev->of_node, "mediatek,larbs", NULL);
	if (larb_nr < 0)
		return larb_nr;

	for (i = 0; i < larb_nr; i++) {
		u32 id;

		larbnode = of_parse_phandle(dev->of_node, "mediatek,larbs", i);
		if (!larbnode)
			return -EINVAL;

		if (!of_device_is_available(larbnode)) {
			of_node_put(larbnode);
			continue;
		}

		ret = of_property_read_u32(larbnode, "mediatek,larb-id", &id);
		if (ret)/* The id is consecutive if there is no this property */
			id = i;

		plarbdev = of_find_device_by_node(larbnode);
		if (!plarbdev) {
			of_node_put(larbnode);
			return -ENODEV;
		}
		if (!plarbdev->dev.driver) {
			of_node_put(larbnode);
			return -EPROBE_DEFER;
		}
		data->larb_imu[id].dev = &plarbdev->dev;

		component_match_add_release(dev, match, component_release_of,
					    component_compare_of, larbnode);
	}

	/* Get smi-common dev from the last larb. */
	smicomm_node = of_parse_phandle(larbnode, "mediatek,smi", 0);
	if (!smicomm_node)
		return -EINVAL;

	plarbdev = of_find_device_by_node(smicomm_node);
	of_node_put(smicomm_node);
	data->smicomm_dev = &plarbdev->dev;

	link = device_link_add(data->smicomm_dev, dev,
			       DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
	if (!link) {
		dev_err(dev, "Unable to link %s.\n", dev_name(data->smicomm_dev));
		return -EINVAL;
	}
	return 0;
}

static int mtk_iommu_probe(struct platform_device *pdev)
{
	struct mtk_iommu_data   *data;
	struct device           *dev = &pdev->dev;
	struct resource         *res;
	resource_size_t		ioaddr;
	struct component_match  *match = NULL;
	struct regmap		*infracfg;
	void                    *protect;
	int                     i, larb_nr, ret;
	int                     ret;
	u32			val;
	char                    *p;

@@ -887,60 +956,15 @@ static int mtk_iommu_probe(struct platform_device *pdev)
			return PTR_ERR(data->bclk);
	}

	larb_nr = of_count_phandle_with_args(dev->of_node,
					     "mediatek,larbs", NULL);
	if (larb_nr < 0)
		return larb_nr;

	for (i = 0; i < larb_nr; i++) {
		u32 id;

		larbnode = of_parse_phandle(dev->of_node, "mediatek,larbs", i);
		if (!larbnode)
			return -EINVAL;

		if (!of_device_is_available(larbnode)) {
			of_node_put(larbnode);
			continue;
		}

		ret = of_property_read_u32(larbnode, "mediatek,larb-id", &id);
		if (ret)/* The id is consecutive if there is no this property */
			id = i;

		plarbdev = of_find_device_by_node(larbnode);
		if (!plarbdev) {
			of_node_put(larbnode);
			return -ENODEV;
		}
		if (!plarbdev->dev.driver) {
			of_node_put(larbnode);
			return -EPROBE_DEFER;
		}
		data->larb_imu[id].dev = &plarbdev->dev;

		component_match_add_release(dev, &match, component_release_of,
					    component_compare_of, larbnode);
	}

	/* Get smi-common dev from the last larb. */
	smicomm_node = of_parse_phandle(larbnode, "mediatek,smi", 0);
	if (!smicomm_node)
		return -EINVAL;

	plarbdev = of_find_device_by_node(smicomm_node);
	of_node_put(smicomm_node);
	data->smicomm_dev = &plarbdev->dev;

	pm_runtime_enable(dev);

	link = device_link_add(data->smicomm_dev, dev,
			DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
	if (!link) {
		dev_err(dev, "Unable to link %s.\n", dev_name(data->smicomm_dev));
		ret = -EINVAL;
	if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
		ret = mtk_iommu_mm_dts_parse(dev, &match, data);
		if (ret) {
			dev_err(dev, "mm dts parse fail(%d).", ret);
			goto out_runtime_disable;
		}
	}

	platform_set_drvdata(pdev, data);
	mutex_init(&data->mutex);
@@ -971,9 +995,11 @@ static int mtk_iommu_probe(struct platform_device *pdev)
			goto out_list_del;
	}

	if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
		ret = component_master_add_with_match(dev, &mtk_iommu_com_ops, match);
		if (ret)
			goto out_bus_set_null;
	}
	return ret;

out_bus_set_null:
@@ -984,6 +1010,7 @@ static int mtk_iommu_probe(struct platform_device *pdev)
out_sysfs_remove:
	iommu_device_sysfs_remove(&data->iommu);
out_link_remove:
	if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM))
		device_link_remove(data->smicomm_dev, dev);
out_runtime_disable:
	pm_runtime_disable(dev);
@@ -999,10 +1026,12 @@ static int mtk_iommu_remove(struct platform_device *pdev)

	list_del(&data->list);

	if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) {
		device_link_remove(data->smicomm_dev, &pdev->dev);
		component_master_del(&pdev->dev, &mtk_iommu_com_ops);
	}
	pm_runtime_disable(&pdev->dev);
	devm_free_irq(&pdev->dev, data->irq, data);
	component_master_del(&pdev->dev, &mtk_iommu_com_ops);
	return 0;
}

@@ -1072,7 +1101,8 @@ static const struct dev_pm_ops mtk_iommu_pm_ops = {

static const struct mtk_iommu_plat_data mt2712_data = {
	.m4u_plat     = M4U_MT2712,
	.flags        = HAS_4GB_MODE | HAS_BCLK | HAS_VLD_PA_RNG | SHARE_PGTABLE,
	.flags        = HAS_4GB_MODE | HAS_BCLK | HAS_VLD_PA_RNG | SHARE_PGTABLE |
			MTK_IOMMU_TYPE_MM,
	.hw_list      = &m4ulist,
	.inv_sel_reg  = REG_MMU_INV_SEL_GEN1,
	.iova_region  = single_domain,
@@ -1082,7 +1112,8 @@ static const struct mtk_iommu_plat_data mt2712_data = {

static const struct mtk_iommu_plat_data mt6779_data = {
	.m4u_plat      = M4U_MT6779,
	.flags         = HAS_SUB_COMM_2BITS | OUT_ORDER_WR_EN | WR_THROT_EN,
	.flags         = HAS_SUB_COMM_2BITS | OUT_ORDER_WR_EN | WR_THROT_EN |
			 MTK_IOMMU_TYPE_MM,
	.inv_sel_reg   = REG_MMU_INV_SEL_GEN2,
	.iova_region   = single_domain,
	.iova_region_nr = ARRAY_SIZE(single_domain),
@@ -1091,7 +1122,7 @@ static const struct mtk_iommu_plat_data mt6779_data = {

static const struct mtk_iommu_plat_data mt8167_data = {
	.m4u_plat     = M4U_MT8167,
	.flags        = RESET_AXI | HAS_LEGACY_IVRP_PADDR,
	.flags        = RESET_AXI | HAS_LEGACY_IVRP_PADDR | MTK_IOMMU_TYPE_MM,
	.inv_sel_reg  = REG_MMU_INV_SEL_GEN1,
	.iova_region  = single_domain,
	.iova_region_nr = ARRAY_SIZE(single_domain),
@@ -1101,7 +1132,7 @@ static const struct mtk_iommu_plat_data mt8167_data = {
static const struct mtk_iommu_plat_data mt8173_data = {
	.m4u_plat     = M4U_MT8173,
	.flags	      = HAS_4GB_MODE | HAS_BCLK | RESET_AXI |
			HAS_LEGACY_IVRP_PADDR,
			HAS_LEGACY_IVRP_PADDR | MTK_IOMMU_TYPE_MM,
	.inv_sel_reg  = REG_MMU_INV_SEL_GEN1,
	.iova_region  = single_domain,
	.iova_region_nr = ARRAY_SIZE(single_domain),
@@ -1110,7 +1141,7 @@ static const struct mtk_iommu_plat_data mt8173_data = {

static const struct mtk_iommu_plat_data mt8183_data = {
	.m4u_plat     = M4U_MT8183,
	.flags        = RESET_AXI,
	.flags        = RESET_AXI | MTK_IOMMU_TYPE_MM,
	.inv_sel_reg  = REG_MMU_INV_SEL_GEN1,
	.iova_region  = single_domain,
	.iova_region_nr = ARRAY_SIZE(single_domain),
@@ -1120,7 +1151,7 @@ static const struct mtk_iommu_plat_data mt8183_data = {
static const struct mtk_iommu_plat_data mt8192_data = {
	.m4u_plat       = M4U_MT8192,
	.flags          = HAS_BCLK | HAS_SUB_COMM_2BITS | OUT_ORDER_WR_EN |
			  WR_THROT_EN | IOVA_34_EN,
			  WR_THROT_EN | IOVA_34_EN | MTK_IOMMU_TYPE_MM,
	.inv_sel_reg    = REG_MMU_INV_SEL_GEN2,
	.iova_region    = mt8192_multi_dom,
	.iova_region_nr = ARRAY_SIZE(mt8192_multi_dom),