Skip to content

Commit 7b9331a

Browse files
Andre-ARMjoergroedel
authored andcommitted
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 <[email protected]> Reviewed-by: Chen-Yu Tsai <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 927c70c commit 7b9331a

File tree

1 file changed

+11
-2
lines changed

1 file changed

+11
-2
lines changed

drivers/iommu/sun50i-iommu.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,14 @@ static int sun50i_iommu_map(struct iommu_domain *domain, unsigned long iova,
602602
u32 *page_table, *pte_addr;
603603
int ret = 0;
604604

605+
/* the IOMMU can only handle 32-bit addresses, both input and output */
606+
if ((uint64_t)paddr >> 32) {
607+
ret = -EINVAL;
608+
dev_warn_once(iommu->dev,
609+
"attempt to map address beyond 4GB\n");
610+
goto out;
611+
}
612+
605613
page_table = sun50i_dte_get_page_table(sun50i_domain, iova, gfp);
606614
if (IS_ERR(page_table)) {
607615
ret = PTR_ERR(page_table);
@@ -682,7 +690,8 @@ sun50i_iommu_domain_alloc_paging(struct device *dev)
682690
if (!sun50i_domain)
683691
return NULL;
684692

685-
sun50i_domain->dt = iommu_alloc_pages(GFP_KERNEL, get_order(DT_SIZE));
693+
sun50i_domain->dt = iommu_alloc_pages(GFP_KERNEL | GFP_DMA32,
694+
get_order(DT_SIZE));
686695
if (!sun50i_domain->dt)
687696
goto err_free_domain;
688697

@@ -997,7 +1006,7 @@ static int sun50i_iommu_probe(struct platform_device *pdev)
9971006

9981007
iommu->pt_pool = kmem_cache_create(dev_name(&pdev->dev),
9991008
PT_SIZE, PT_SIZE,
1000-
SLAB_HWCACHE_ALIGN,
1009+
SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA32,
10011010
NULL);
10021011
if (!iommu->pt_pool)
10031012
return -ENOMEM;

0 commit comments

Comments
 (0)