* [PATCH 1/2] iommu/rockchip: Reduce rk_iommu_ops to pure data
2026-08-25 9:21 [PATCH 0/2] iommu/rockchip: turn rk_iommu_ops into data Simon Xue
@ 2026-08-25 9:21 ` Simon Xue
2026-08-25 9:21 ` [PATCH 2/2] iommu/rockchip: Reject unsupported physical addresses Simon Xue
1 sibling, 0 replies; 3+ messages in thread
From: Simon Xue @ 2026-08-25 9:21 UTC (permalink / raw)
To: Joerg Roedel (AMD), Will Deacon, Robin Murphy, Heiko Stuebner
Cc: Simon Xue, iommu, linux-arm-kernel, linux-rockchip, linux-kernel
Fold the per-version pt_address()/mk_dtentries()/mk_ptentries()
callbacks into single encoders that pick the layout at runtime. Only v2
can address more than 32 bits, so the layout is derived from paddr_mask.
rk_iommu_ops now carries only data.
Signed-off-by: Simon Xue <xxm@rock-chips.com>
---
drivers/iommu/rockchip-iommu.c | 105 ++++++++++++++++-----------------
1 file changed, 50 insertions(+), 55 deletions(-)
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 21af2f621c76..9a5aabb2b9c8 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -85,9 +85,7 @@
#define RK_IOMMU_PGSIZE_BITMAP 0x007ff000
struct rk_iommu_ops {
- phys_addr_t (*pt_address)(u32 dte);
- u32 (*mk_dtentries)(dma_addr_t pt_dma);
- u32 (*mk_ptentries)(phys_addr_t page, int prot);
+ phys_addr_t paddr_mask; /* valid physical-address bits */
u64 dma_bit_mask;
gfp_t gfp_flags;
};
@@ -182,11 +180,6 @@ static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom)
#define RK_DTE_PT_ADDRESS_MASK 0xfffff000
#define RK_DTE_PT_VALID BIT(0)
-static inline phys_addr_t rk_dte_pt_address(u32 dte)
-{
- return (phys_addr_t)dte & RK_DTE_PT_ADDRESS_MASK;
-}
-
/*
* In v2:
* 31:12 - PT address bit 31:0
@@ -203,15 +196,24 @@ static inline phys_addr_t rk_dte_pt_address(u32 dte)
#define PAGE_DESC_HI_MASK1 GENMASK_ULL(35, 32)
#define PAGE_DESC_HI_MASK2 GENMASK_ULL(39, 36)
-static inline phys_addr_t rk_dte_pt_address_v2(u32 dte)
+static inline bool rk_ops_is_v2(const struct rk_iommu_ops *ops)
{
- u64 dte_v2 = dte;
+ return ops->paddr_mask > DMA_BIT_MASK(32);
+}
+
+static inline phys_addr_t rk_dte_pt_address(const struct rk_iommu_ops *ops, u32 dte)
+{
+ if (rk_ops_is_v2(ops)) {
+ u64 dte_v2 = dte;
- dte_v2 = ((dte_v2 & DTE_HI_MASK2) << DTE_HI_SHIFT2) |
- ((dte_v2 & DTE_HI_MASK1) << DTE_HI_SHIFT1) |
- (dte_v2 & RK_DTE_PT_ADDRESS_MASK);
+ dte_v2 = ((dte_v2 & DTE_HI_MASK2) << DTE_HI_SHIFT2) |
+ ((dte_v2 & DTE_HI_MASK1) << DTE_HI_SHIFT1) |
+ (dte_v2 & RK_DTE_PT_ADDRESS_MASK);
- return (phys_addr_t)dte_v2;
+ return (phys_addr_t)dte_v2;
+ }
+
+ return (phys_addr_t)dte & RK_DTE_PT_ADDRESS_MASK;
}
static inline bool rk_dte_is_pt_valid(u32 dte)
@@ -219,18 +221,17 @@ static inline bool rk_dte_is_pt_valid(u32 dte)
return dte & RK_DTE_PT_VALID;
}
-static inline u32 rk_mk_dte(dma_addr_t pt_dma)
+static inline u32 rk_mk_dte(const struct rk_iommu_ops *ops, dma_addr_t pt_dma)
{
- return (pt_dma & RK_DTE_PT_ADDRESS_MASK) | RK_DTE_PT_VALID;
-}
+ if (rk_ops_is_v2(ops)) {
+ pt_dma = (pt_dma & RK_DTE_PT_ADDRESS_MASK) |
+ ((pt_dma & PAGE_DESC_HI_MASK1) >> DTE_HI_SHIFT1) |
+ (pt_dma & PAGE_DESC_HI_MASK2) >> DTE_HI_SHIFT2;
-static inline u32 rk_mk_dte_v2(dma_addr_t pt_dma)
-{
- pt_dma = (pt_dma & RK_DTE_PT_ADDRESS_MASK) |
- ((pt_dma & PAGE_DESC_HI_MASK1) >> DTE_HI_SHIFT1) |
- (pt_dma & PAGE_DESC_HI_MASK2) >> DTE_HI_SHIFT2;
+ return (pt_dma & RK_DTE_PT_ADDRESS_MASK_V2) | RK_DTE_PT_VALID;
+ }
- return (pt_dma & RK_DTE_PT_ADDRESS_MASK_V2) | RK_DTE_PT_VALID;
+ return (pt_dma & RK_DTE_PT_ADDRESS_MASK) | RK_DTE_PT_VALID;
}
/*
@@ -264,16 +265,6 @@ static inline bool rk_pte_is_page_valid(u32 pte)
return pte & RK_PTE_PAGE_VALID;
}
-/* TODO: set cache flags per prot IOMMU_CACHE */
-static u32 rk_mk_pte(phys_addr_t page, int prot)
-{
- u32 flags = 0;
- flags |= (prot & IOMMU_READ) ? RK_PTE_PAGE_READABLE : 0;
- flags |= (prot & IOMMU_WRITE) ? RK_PTE_PAGE_WRITABLE : 0;
- page &= RK_PTE_PAGE_ADDRESS_MASK;
- return page | flags | RK_PTE_PAGE_VALID;
-}
-
/*
* In v2:
* 31:12 - Page address bit 31:0
@@ -285,14 +276,22 @@ static u32 rk_mk_pte(phys_addr_t page, int prot)
* 0 - 1 if Page @ Page address is valid
*/
-static u32 rk_mk_pte_v2(phys_addr_t page, int prot)
+/* TODO: set cache flags per prot IOMMU_CACHE */
+static u32 rk_mk_pte(const struct rk_iommu_ops *ops, phys_addr_t page, int prot)
{
u32 flags = 0;
flags |= (prot & IOMMU_READ) ? RK_PTE_PAGE_READABLE : 0;
flags |= (prot & IOMMU_WRITE) ? RK_PTE_PAGE_WRITABLE : 0;
- return rk_mk_dte_v2(page) | flags;
+ /*
+ * v2 encodes the page address exactly like a DTE
+ */
+ if (rk_ops_is_v2(ops))
+ return rk_mk_dte(ops, page) | flags;
+
+ page &= RK_PTE_PAGE_ADDRESS_MASK;
+ return page | flags | RK_PTE_PAGE_VALID;
}
static u32 rk_mk_pte_invalid(u32 pte)
@@ -521,7 +520,7 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
* and verifying that upper 5 (v1) or 7 (v2) nybbles are read back.
*/
for (i = 0; i < iommu->num_mmu; i++) {
- dte_addr = iommu->rk_ops->pt_address(DTE_ADDR_DUMMY);
+ dte_addr = rk_dte_pt_address(iommu->rk_ops, DTE_ADDR_DUMMY);
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, dte_addr);
if (dte_addr != rk_iommu_read(iommu->bases[i], RK_MMU_DTE_ADDR)) {
@@ -562,7 +561,7 @@ static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
page_offset = rk_iova_page_offset(iova);
mmu_dte_addr = rk_iommu_read(base, RK_MMU_DTE_ADDR);
- mmu_dte_addr_phys = iommu->rk_ops->pt_address(mmu_dte_addr);
+ mmu_dte_addr_phys = rk_dte_pt_address(iommu->rk_ops, mmu_dte_addr);
dte_addr_phys = mmu_dte_addr_phys + (4 * dte_index);
dte_addr = phys_to_virt(dte_addr_phys);
@@ -571,14 +570,14 @@ static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
if (!rk_dte_is_pt_valid(dte))
goto print_it;
- pte_addr_phys = iommu->rk_ops->pt_address(dte) + (pte_index * 4);
+ pte_addr_phys = rk_dte_pt_address(iommu->rk_ops, dte) + (pte_index * 4);
pte_addr = phys_to_virt(pte_addr_phys);
pte = *pte_addr;
if (!rk_pte_is_page_valid(pte))
goto print_it;
- page_addr_phys = iommu->rk_ops->pt_address(pte) + page_offset;
+ page_addr_phys = rk_dte_pt_address(iommu->rk_ops, pte) + page_offset;
page_flags = pte & RK_PTE_PAGE_FLAGS_MASK;
print_it:
@@ -674,13 +673,13 @@ static phys_addr_t rk_iommu_iova_to_phys(struct iommu_domain *domain,
if (!rk_dte_is_pt_valid(dte))
goto out;
- pt_phys = rk_domain->rk_ops->pt_address(dte);
+ pt_phys = rk_dte_pt_address(rk_domain->rk_ops, dte);
page_table = (u32 *)phys_to_virt(pt_phys);
pte = page_table[rk_iova_pte_index(iova)];
if (!rk_pte_is_page_valid(pte))
goto out;
- phys = rk_domain->rk_ops->pt_address(pte) + rk_iova_page_offset(iova);
+ phys = rk_dte_pt_address(rk_domain->rk_ops, pte) + rk_iova_page_offset(iova);
out:
spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
@@ -753,13 +752,13 @@ static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
return ERR_PTR(-ENOMEM);
}
- dte = rk_domain->rk_ops->mk_dtentries(pt_dma);
+ dte = rk_mk_dte(rk_domain->rk_ops, pt_dma);
*dte_addr = dte;
rk_table_flush(rk_domain,
rk_domain->dt_dma + dte_index * sizeof(u32), 1);
done:
- pt_phys = rk_domain->rk_ops->pt_address(dte);
+ pt_phys = rk_dte_pt_address(rk_domain->rk_ops, dte);
return (u32 *)phys_to_virt(pt_phys);
}
@@ -801,7 +800,7 @@ static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr,
if (rk_pte_is_page_valid(pte))
goto unwind;
- pte_addr[pte_count] = rk_domain->rk_ops->mk_ptentries(paddr, prot);
+ pte_addr[pte_count] = rk_mk_pte(rk_domain->rk_ops, paddr, prot);
paddr += SPAGE_SIZE;
}
@@ -823,7 +822,7 @@ static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr,
pte_count * SPAGE_SIZE);
iova += pte_count * SPAGE_SIZE;
- page_phys = rk_domain->rk_ops->pt_address(pte_addr[pte_count]);
+ page_phys = rk_dte_pt_address(rk_domain->rk_ops, pte_addr[pte_count]);
pr_err("iova: %pad already mapped to %pa cannot remap to phys: %pa prot: %#x\n",
&iova, &page_phys, &paddr, prot);
@@ -860,7 +859,7 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
pte_index = rk_iova_pte_index(iova);
pte_addr = &page_table[pte_index];
- pte_dma = rk_domain->rk_ops->pt_address(dte_index) + pte_index * sizeof(u32);
+ pte_dma = rk_dte_pt_address(rk_domain->rk_ops, dte_index) + pte_index * sizeof(u32);
ret = rk_iommu_map_iova(rk_domain, pte_addr, pte_dma, iova,
paddr, size, prot);
@@ -898,7 +897,7 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
return 0;
}
- pt_phys = rk_domain->rk_ops->pt_address(dte);
+ pt_phys = rk_dte_pt_address(rk_domain->rk_ops, dte);
pte_addr = (u32 *)phys_to_virt(pt_phys) + rk_iova_pte_index(iova);
pte_dma = pt_phys + rk_iova_pte_index(iova) * sizeof(u32);
unmap_size = rk_iommu_unmap_iova(rk_domain, pte_addr, pte_dma, size);
@@ -957,7 +956,7 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
for (i = 0; i < iommu->num_mmu; i++) {
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR,
- iommu->rk_ops->mk_dtentries(rk_domain->dt_dma));
+ rk_mk_dte(iommu->rk_ops, rk_domain->dt_dma));
rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE);
rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, RK_MMU_IRQ_MASK);
@@ -1139,7 +1138,7 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
for (i = 0; i < NUM_DT_ENTRIES; i++) {
u32 dte = rk_domain->dt[i];
if (rk_dte_is_pt_valid(dte)) {
- phys_addr_t pt_phys = rk_domain->rk_ops->pt_address(dte);
+ phys_addr_t pt_phys = rk_dte_pt_address(rk_domain->rk_ops, dte);
u32 *page_table = phys_to_virt(pt_phys);
dma_unmap_single(rk_domain->dma_dev, pt_phys,
SPAGE_SIZE, DMA_TO_DEVICE);
@@ -1356,17 +1355,13 @@ static const struct dev_pm_ops rk_iommu_pm_ops = {
};
static struct rk_iommu_ops iommu_data_ops_v1 = {
- .pt_address = &rk_dte_pt_address,
- .mk_dtentries = &rk_mk_dte,
- .mk_ptentries = &rk_mk_pte,
+ .paddr_mask = DMA_BIT_MASK(32),
.dma_bit_mask = DMA_BIT_MASK(32),
.gfp_flags = GFP_DMA32,
};
static struct rk_iommu_ops iommu_data_ops_v2 = {
- .pt_address = &rk_dte_pt_address_v2,
- .mk_dtentries = &rk_mk_dte_v2,
- .mk_ptentries = &rk_mk_pte_v2,
+ .paddr_mask = DMA_BIT_MASK(40),
.dma_bit_mask = DMA_BIT_MASK(40),
.gfp_flags = 0,
};
--
2.34.1
^ permalink raw reply related [flat|nested] 3+ messages in thread