From 927c70c93d929f4c2dcaf72f51b31bb7d118a51a Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 16 Jun 2024 23:40:52 +0100 Subject: iommu: sun50i: clear bypass register The Allwinner H6 IOMMU has a bypass register, which allows to circumvent the page tables for each possible master. The reset value for this register is 0, which disables the bypass. The Allwinner H616 IOMMU resets this register to 0x7f, which activates the bypass for all masters, which is not what we want. Always clear this register to 0, to enforce the usage of page tables, and make this driver compatible with the H616 in this respect. Signed-off-by: Jernej Skrabec Signed-off-by: Andre Przywara Reviewed-by: Chen-Yu Tsai Link: https://lore.kernel.org/r/20240616224056.29159-2-andre.przywara@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/sun50i-iommu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c index c519b991749d..dd3f07384624 100644 --- a/drivers/iommu/sun50i-iommu.c +++ b/drivers/iommu/sun50i-iommu.c @@ -452,6 +452,7 @@ static int sun50i_iommu_enable(struct sun50i_iommu *iommu) IOMMU_TLB_PREFETCH_MASTER_ENABLE(3) | IOMMU_TLB_PREFETCH_MASTER_ENABLE(4) | IOMMU_TLB_PREFETCH_MASTER_ENABLE(5)); + iommu_write(iommu, IOMMU_BYPASS_REG, 0); iommu_write(iommu, IOMMU_INT_ENABLE_REG, IOMMU_INT_MASK); iommu_write(iommu, IOMMU_DM_AUT_CTRL_REG(SUN50I_IOMMU_ACI_NONE), IOMMU_DM_AUT_CTRL_RD_UNAVAIL(SUN50I_IOMMU_ACI_NONE, 0) | -- cgit From 7b9331a3ae93adfae54c6a56d23513e1f7db5dcb Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sun, 16 Jun 2024 23:40:53 +0100 Subject: iommu: sun50i: allocate page tables from below 4 GiB The Allwinner IOMMU is a strict 32-bit device, with its input addresses, the page table root pointer as well as both level's page tables and also the target addresses all required to be below 4GB. The Allwinner H6 SoC only supports 32-bit worth of physical addresses anyway, so this isn't a problem so far, but the H616 and later SoCs extend the PA space beyond 32 bit to accommodate more DRAM. To make sure we stay within the 32-bit PA range required by the IOMMU, force the memory for the page tables to come from below 4GB. by using allocations with the DMA32 flag. Also reject any attempt to map target addresses beyond 4GB, and print a warning to give users a hint while this fails. Signed-off-by: Andre Przywara Reviewed-by: Chen-Yu Tsai Link: https://lore.kernel.org/r/20240616224056.29159-3-andre.przywara@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/sun50i-iommu.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c index dd3f07384624..20a07f829085 100644 --- a/drivers/iommu/sun50i-iommu.c +++ b/drivers/iommu/sun50i-iommu.c @@ -602,6 +602,14 @@ static int sun50i_iommu_map(struct iommu_domain *domain, unsigned long iova, u32 *page_table, *pte_addr; int ret = 0; + /* the IOMMU can only handle 32-bit addresses, both input and output */ + if ((uint64_t)paddr >> 32) { + ret = -EINVAL; + dev_warn_once(iommu->dev, + "attempt to map address beyond 4GB\n"); + goto out; + } + page_table = sun50i_dte_get_page_table(sun50i_domain, iova, gfp); if (IS_ERR(page_table)) { ret = PTR_ERR(page_table); @@ -682,7 +690,8 @@ sun50i_iommu_domain_alloc_paging(struct device *dev) if (!sun50i_domain) return NULL; - sun50i_domain->dt = iommu_alloc_pages(GFP_KERNEL, get_order(DT_SIZE)); + sun50i_domain->dt = iommu_alloc_pages(GFP_KERNEL | GFP_DMA32, + get_order(DT_SIZE)); if (!sun50i_domain->dt) goto err_free_domain; @@ -997,7 +1006,7 @@ static int sun50i_iommu_probe(struct platform_device *pdev) iommu->pt_pool = kmem_cache_create(dev_name(&pdev->dev), PT_SIZE, PT_SIZE, - SLAB_HWCACHE_ALIGN, + SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA32, NULL); if (!iommu->pt_pool) return -ENOMEM; -- cgit From 2d1d1969a7e5b0dd043df4a6ca02156717401856 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sun, 16 Jun 2024 23:40:54 +0100 Subject: dt-bindings: iommu: add new compatible strings The Allwinner H616 and A523 contain IOMMU IP very similar to the H6, but use a different reset value for the bypass register, which makes them strictly speaking incompatible. Add a new compatible string for the H616, and a version for the A523, falling back to the H616. Signed-off-by: Andre Przywara Acked-by: Krzysztof Kozlowski Reviewed-by: Chen-Yu Tsai Link: https://lore.kernel.org/r/20240616224056.29159-4-andre.przywara@arm.com Signed-off-by: Joerg Roedel --- .../devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml b/Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml index e20016f12017..a8409db4a3e3 100644 --- a/Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml +++ b/Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml @@ -17,7 +17,12 @@ properties: The content of the cell is the master ID. compatible: - const: allwinner,sun50i-h6-iommu + oneOf: + - const: allwinner,sun50i-h6-iommu + - const: allwinner,sun50i-h616-iommu + - items: + - const: allwinner,sun55i-a523-iommu + - const: allwinner,sun50i-h616-iommu reg: maxItems: 1 -- cgit From 8db07ce532c0b51fea974613002cdc6a27732929 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sun, 16 Jun 2024 23:40:55 +0100 Subject: iommu: sun50i: Add H616 compatible string The IOMMU IP in the Allwinner H616 SoC is *almost* compatible to the H6, but uses a different reset value for the bypass register, and adds some more registers. While a driver *can* be written to support both variants (which we in fact do), the hardware itself is not fully compatible, so we require a separate compatible string. Add the new compatible string to the list, but without changing the behaviour, since the driver already supports both variants. Signed-off-by: Andre Przywara Reviewed-by: Chen-Yu Tsai Link: https://lore.kernel.org/r/20240616224056.29159-5-andre.przywara@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/sun50i-iommu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c index 20a07f829085..8d8f11854676 100644 --- a/drivers/iommu/sun50i-iommu.c +++ b/drivers/iommu/sun50i-iommu.c @@ -1067,6 +1067,7 @@ err_free_cache: static const struct of_device_id sun50i_iommu_dt[] = { { .compatible = "allwinner,sun50i-h6-iommu", }, + { .compatible = "allwinner,sun50i-h616-iommu", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, sun50i_iommu_dt); -- cgit