Skip to content

Commit 1226c37

Browse files
committed
iommu/amd: Let free_pagetable() not rely on domain->pt_root
Use 'struct domain_pgtable' instead to free_pagetable(). This solves the problem that amd_iommu_domain_direct_map() needs to restore domain->pt_root after the device table has been updated just to make free_pagetable release the domain page-table. Signed-off-by: Joerg Roedel <[email protected]> Reviewed-by: Suravee Suthikulpanit <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent fb1b695 commit 1226c37

File tree

1 file changed

+16
-20
lines changed

1 file changed

+16
-20
lines changed

drivers/iommu/amd_iommu.c

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,20 +1391,19 @@ static struct page *free_sub_pt(unsigned long root, int mode,
13911391
return freelist;
13921392
}
13931393

1394-
static void free_pagetable(struct protection_domain *domain)
1394+
static void free_pagetable(struct domain_pgtable *pgtable)
13951395
{
1396-
struct domain_pgtable pgtable;
13971396
struct page *freelist = NULL;
13981397
unsigned long root;
13991398

1400-
amd_iommu_domain_get_pgtable(domain, &pgtable);
1401-
atomic64_set(&domain->pt_root, 0);
1399+
if (pgtable->mode == PAGE_MODE_NONE)
1400+
return;
14021401

1403-
BUG_ON(pgtable.mode < PAGE_MODE_NONE ||
1404-
pgtable.mode > PAGE_MODE_6_LEVEL);
1402+
BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
1403+
pgtable->mode > PAGE_MODE_6_LEVEL);
14051404

1406-
root = (unsigned long)pgtable.root;
1407-
freelist = free_sub_pt(root, pgtable.mode, freelist);
1405+
root = (unsigned long)pgtable->root;
1406+
freelist = free_sub_pt(root, pgtable->mode, freelist);
14081407

14091408
free_page_list(freelist);
14101409
}
@@ -1823,12 +1822,16 @@ static void free_gcr3_table(struct protection_domain *domain)
18231822
*/
18241823
static void dma_ops_domain_free(struct protection_domain *domain)
18251824
{
1825+
struct domain_pgtable pgtable;
1826+
18261827
if (!domain)
18271828
return;
18281829

18291830
iommu_put_dma_cookie(&domain->domain);
18301831

1831-
free_pagetable(domain);
1832+
amd_iommu_domain_get_pgtable(domain, &pgtable);
1833+
atomic64_set(&domain->pt_root, 0);
1834+
free_pagetable(&pgtable);
18321835

18331836
if (domain->id)
18341837
domain_id_free(domain->id);
@@ -2496,9 +2499,8 @@ static void amd_iommu_domain_free(struct iommu_domain *dom)
24962499
break;
24972500
default:
24982501
amd_iommu_domain_get_pgtable(domain, &pgtable);
2499-
2500-
if (pgtable.mode != PAGE_MODE_NONE)
2501-
free_pagetable(domain);
2502+
atomic64_set(&domain->pt_root, 0);
2503+
free_pagetable(&pgtable);
25022504

25032505
if (domain->flags & PD_IOMMUV2_MASK)
25042506
free_gcr3_table(domain);
@@ -2796,26 +2798,20 @@ void amd_iommu_domain_direct_map(struct iommu_domain *dom)
27962798
struct protection_domain *domain = to_pdomain(dom);
27972799
struct domain_pgtable pgtable;
27982800
unsigned long flags;
2799-
u64 pt_root;
28002801

28012802
spin_lock_irqsave(&domain->lock, flags);
28022803

28032804
/* First save pgtable configuration*/
28042805
amd_iommu_domain_get_pgtable(domain, &pgtable);
28052806

28062807
/* Update data structure */
2807-
pt_root = amd_iommu_domain_encode_pgtable(NULL, PAGE_MODE_NONE);
2808-
atomic64_set(&domain->pt_root, pt_root);
2808+
atomic64_set(&domain->pt_root, 0);
28092809

28102810
/* Make changes visible to IOMMUs */
28112811
update_domain(domain);
28122812

2813-
/* Restore old pgtable in domain->ptroot to free page-table */
2814-
pt_root = amd_iommu_domain_encode_pgtable(pgtable.root, pgtable.mode);
2815-
atomic64_set(&domain->pt_root, pt_root);
2816-
28172813
/* Page-table is not visible to IOMMU anymore, so free it */
2818-
free_pagetable(domain);
2814+
free_pagetable(&pgtable);
28192815

28202816
spin_unlock_irqrestore(&domain->lock, flags);
28212817
}

0 commit comments

Comments
 (0)