Skip to content

Commit 6b3106e

Browse files
rmurphy-armjoergroedel
authored andcommitted
iommu/amd: Simplify pagetable freeing
For reasons unclear, pagetable freeing is an effectively recursive method implemented via an elaborate system of templated functions that turns out to account for 25% of the object file size. Implementing it using regular straightforward recursion makes the code simpler, and seems like a good thing to do before we work on it further. As part of that, also fix the types to avoid all the needless casting back and forth which just gets in the way. Signed-off-by: Robin Murphy <[email protected]> Link: https://lore.kernel.org/r/d3d00c9f3fa0df4756b867072c201e6e82f9ce39.1639753638.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel <[email protected]>
1 parent 649ad98 commit 6b3106e

File tree

1 file changed

+34
-48
lines changed

1 file changed

+34
-48
lines changed

drivers/iommu/amd/io_pgtable.c

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -84,49 +84,45 @@ static void free_page_list(struct page *freelist)
8484
}
8585
}
8686

87-
static struct page *free_pt_page(unsigned long pt, struct page *freelist)
87+
static struct page *free_pt_page(u64 *pt, struct page *freelist)
8888
{
89-
struct page *p = virt_to_page((void *)pt);
89+
struct page *p = virt_to_page(pt);
9090

9191
p->freelist = freelist;
9292

9393
return p;
9494
}
9595

96-
#define DEFINE_FREE_PT_FN(LVL, FN) \
97-
static struct page *free_pt_##LVL (unsigned long __pt, struct page *freelist) \
98-
{ \
99-
unsigned long p; \
100-
u64 *pt; \
101-
int i; \
102-
\
103-
pt = (u64 *)__pt; \
104-
\
105-
for (i = 0; i < 512; ++i) { \
106-
/* PTE present? */ \
107-
if (!IOMMU_PTE_PRESENT(pt[i])) \
108-
continue; \
109-
\
110-
/* Large PTE? */ \
111-
if (PM_PTE_LEVEL(pt[i]) == 0 || \
112-
PM_PTE_LEVEL(pt[i]) == 7) \
113-
continue; \
114-
\
115-
p = (unsigned long)IOMMU_PTE_PAGE(pt[i]); \
116-
freelist = FN(p, freelist); \
117-
} \
118-
\
119-
return free_pt_page((unsigned long)pt, freelist); \
120-
}
96+
static struct page *free_pt_lvl(u64 *pt, struct page *freelist, int lvl)
97+
{
98+
u64 *p;
99+
int i;
100+
101+
for (i = 0; i < 512; ++i) {
102+
/* PTE present? */
103+
if (!IOMMU_PTE_PRESENT(pt[i]))
104+
continue;
121105

122-
DEFINE_FREE_PT_FN(l2, free_pt_page)
123-
DEFINE_FREE_PT_FN(l3, free_pt_l2)
124-
DEFINE_FREE_PT_FN(l4, free_pt_l3)
125-
DEFINE_FREE_PT_FN(l5, free_pt_l4)
126-
DEFINE_FREE_PT_FN(l6, free_pt_l5)
106+
/* Large PTE? */
107+
if (PM_PTE_LEVEL(pt[i]) == 0 ||
108+
PM_PTE_LEVEL(pt[i]) == 7)
109+
continue;
127110

128-
static struct page *free_sub_pt(unsigned long root, int mode,
129-
struct page *freelist)
111+
/*
112+
* Free the next level. No need to look at l1 tables here since
113+
* they can only contain leaf PTEs; just free them directly.
114+
*/
115+
p = IOMMU_PTE_PAGE(pt[i]);
116+
if (lvl > 2)
117+
freelist = free_pt_lvl(p, freelist, lvl - 1);
118+
else
119+
freelist = free_pt_page(p, freelist);
120+
}
121+
122+
return free_pt_page(pt, freelist);
123+
}
124+
125+
static struct page *free_sub_pt(u64 *root, int mode, struct page *freelist)
130126
{
131127
switch (mode) {
132128
case PAGE_MODE_NONE:
@@ -136,19 +132,11 @@ static struct page *free_sub_pt(unsigned long root, int mode,
136132
freelist = free_pt_page(root, freelist);
137133
break;
138134
case PAGE_MODE_2_LEVEL:
139-
freelist = free_pt_l2(root, freelist);
140-
break;
141135
case PAGE_MODE_3_LEVEL:
142-
freelist = free_pt_l3(root, freelist);
143-
break;
144136
case PAGE_MODE_4_LEVEL:
145-
freelist = free_pt_l4(root, freelist);
146-
break;
147137
case PAGE_MODE_5_LEVEL:
148-
freelist = free_pt_l5(root, freelist);
149-
break;
150138
case PAGE_MODE_6_LEVEL:
151-
freelist = free_pt_l6(root, freelist);
139+
free_pt_lvl(root, freelist, mode);
152140
break;
153141
default:
154142
BUG();
@@ -364,7 +352,7 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable,
364352

365353
static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
366354
{
367-
unsigned long pt;
355+
u64 *pt;
368356
int mode;
369357

370358
while (cmpxchg64(pte, pteval, 0) != pteval) {
@@ -375,7 +363,7 @@ static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
375363
if (!IOMMU_PTE_PRESENT(pteval))
376364
return freelist;
377365

378-
pt = (unsigned long)IOMMU_PTE_PAGE(pteval);
366+
pt = IOMMU_PTE_PAGE(pteval);
379367
mode = IOMMU_PTE_MODE(pteval);
380368

381369
return free_sub_pt(pt, mode, freelist);
@@ -512,7 +500,6 @@ static void v1_free_pgtable(struct io_pgtable *iop)
512500
struct amd_io_pgtable *pgtable = container_of(iop, struct amd_io_pgtable, iop);
513501
struct protection_domain *dom;
514502
struct page *freelist = NULL;
515-
unsigned long root;
516503

517504
if (pgtable->mode == PAGE_MODE_NONE)
518505
return;
@@ -529,8 +516,7 @@ static void v1_free_pgtable(struct io_pgtable *iop)
529516
BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
530517
pgtable->mode > PAGE_MODE_6_LEVEL);
531518

532-
root = (unsigned long)pgtable->root;
533-
freelist = free_sub_pt(root, pgtable->mode, freelist);
519+
freelist = free_sub_pt(pgtable->root, pgtable->mode, freelist);
534520

535521
free_page_list(freelist);
536522
}

0 commit comments

Comments
 (0)