Skip to content

Commit d160411

Browse files
hegdevasantjoergroedel
authored andcommitted
iommu/amd: xarray to track protection_domain->iommu list
Use xarray to track IOMMU attached to protection domain instead of static array of MAX_IOMMUS. Also add lockdep assertion. Signed-off-by: Vasant Hegde <vasant.hegde@amd.com> Reviewed-by: Joerg Roedel <jroedel@suse.de> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/20241030063556.6104-5-vasant.hegde@amd.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
1 parent 743a4ba commit d160411

File tree

2 files changed

+77
-20
lines changed

2 files changed

+77
-20
lines changed

drivers/iommu/amd/amd_iommu_types.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,12 @@ struct pdom_dev_data {
565565
struct list_head list;
566566
};
567567

568+
/* Keeps track of the IOMMUs attached to protection domain */
569+
struct pdom_iommu_info {
570+
struct amd_iommu *iommu; /* IOMMUs attach to protection domain */
571+
u32 refcnt; /* Count of attached dev/pasid per domain/IOMMU */
572+
};
573+
568574
/*
569575
* This structure contains generic data for IOMMU protection domains
570576
* independent of their use.
@@ -578,7 +584,7 @@ struct protection_domain {
578584
u16 id; /* the domain id written to the device table */
579585
enum protection_domain_mode pd_mode; /* Track page table type */
580586
bool dirty_tracking; /* dirty tracking is enabled in the domain */
581-
unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */
587+
struct xarray iommu_array; /* per-IOMMU reference count */
582588

583589
struct mmu_notifier mn; /* mmu notifier for the SVA domain */
584590
struct list_head dev_data_list; /* List of pdom_dev_data */

drivers/iommu/amd/iommu.c

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,18 +1257,17 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
12571257

12581258
static void domain_flush_complete(struct protection_domain *domain)
12591259
{
1260-
int i;
1260+
struct pdom_iommu_info *pdom_iommu_info;
1261+
unsigned long i;
12611262

1262-
for (i = 0; i < amd_iommu_get_num_iommus(); ++i) {
1263-
if (domain && !domain->dev_iommu[i])
1264-
continue;
1263+
lockdep_assert_held(&domain->lock);
12651264

1266-
/*
1267-
* Devices of this domain are behind this IOMMU
1268-
* We need to wait for completion of all commands.
1269-
*/
1270-
iommu_completion_wait(amd_iommus[i]);
1271-
}
1265+
/*
1266+
* Devices of this domain are behind this IOMMU
1267+
* We need to wait for completion of all commands.
1268+
*/
1269+
xa_for_each(&domain->iommu_array, i, pdom_iommu_info)
1270+
iommu_completion_wait(pdom_iommu_info->iommu);
12721271
}
12731272

12741273
static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid)
@@ -1450,21 +1449,22 @@ static int domain_flush_pages_v2(struct protection_domain *pdom,
14501449
static int domain_flush_pages_v1(struct protection_domain *pdom,
14511450
u64 address, size_t size)
14521451
{
1452+
struct pdom_iommu_info *pdom_iommu_info;
14531453
struct iommu_cmd cmd;
1454-
int ret = 0, i;
1454+
int ret = 0;
1455+
unsigned long i;
1456+
1457+
lockdep_assert_held(&pdom->lock);
14551458

14561459
build_inv_iommu_pages(&cmd, address, size,
14571460
pdom->id, IOMMU_NO_PASID, false);
14581461

1459-
for (i = 0; i < amd_iommu_get_num_iommus(); ++i) {
1460-
if (!pdom->dev_iommu[i])
1461-
continue;
1462-
1462+
xa_for_each(&pdom->iommu_array, i, pdom_iommu_info) {
14631463
/*
14641464
* Devices of this domain are behind this IOMMU
14651465
* We need a TLB flush
14661466
*/
1467-
ret |= iommu_queue_command(amd_iommus[i], &cmd);
1467+
ret |= iommu_queue_command(pdom_iommu_info->iommu, &cmd);
14681468
}
14691469

14701470
return ret;
@@ -1503,6 +1503,8 @@ static void __domain_flush_pages(struct protection_domain *domain,
15031503
void amd_iommu_domain_flush_pages(struct protection_domain *domain,
15041504
u64 address, size_t size)
15051505
{
1506+
lockdep_assert_held(&domain->lock);
1507+
15061508
if (likely(!amd_iommu_np_cache)) {
15071509
__domain_flush_pages(domain, address, size);
15081510

@@ -2014,6 +2016,50 @@ static void destroy_gcr3_table(struct iommu_dev_data *dev_data,
20142016
free_gcr3_table(gcr3_info);
20152017
}
20162018

2019+
static int pdom_attach_iommu(struct amd_iommu *iommu,
2020+
struct protection_domain *pdom)
2021+
{
2022+
struct pdom_iommu_info *pdom_iommu_info, *curr;
2023+
2024+
pdom_iommu_info = xa_load(&pdom->iommu_array, iommu->index);
2025+
if (pdom_iommu_info) {
2026+
pdom_iommu_info->refcnt++;
2027+
return 0;
2028+
}
2029+
2030+
pdom_iommu_info = kzalloc(sizeof(*pdom_iommu_info), GFP_ATOMIC);
2031+
if (!pdom_iommu_info)
2032+
return -ENOMEM;
2033+
2034+
pdom_iommu_info->iommu = iommu;
2035+
pdom_iommu_info->refcnt = 1;
2036+
2037+
curr = xa_cmpxchg(&pdom->iommu_array, iommu->index,
2038+
NULL, pdom_iommu_info, GFP_ATOMIC);
2039+
if (curr) {
2040+
kfree(pdom_iommu_info);
2041+
return -ENOSPC;
2042+
}
2043+
2044+
return 0;
2045+
}
2046+
2047+
static void pdom_detach_iommu(struct amd_iommu *iommu,
2048+
struct protection_domain *pdom)
2049+
{
2050+
struct pdom_iommu_info *pdom_iommu_info;
2051+
2052+
pdom_iommu_info = xa_load(&pdom->iommu_array, iommu->index);
2053+
if (!pdom_iommu_info)
2054+
return;
2055+
2056+
pdom_iommu_info->refcnt--;
2057+
if (pdom_iommu_info->refcnt == 0) {
2058+
xa_erase(&pdom->iommu_array, iommu->index);
2059+
kfree(pdom_iommu_info);
2060+
}
2061+
}
2062+
20172063
static int do_attach(struct iommu_dev_data *dev_data,
20182064
struct protection_domain *domain)
20192065
{
@@ -2030,13 +2076,17 @@ static int do_attach(struct iommu_dev_data *dev_data,
20302076
cfg->amd.nid = dev_to_node(dev_data->dev);
20312077

20322078
/* Do reference counting */
2033-
domain->dev_iommu[iommu->index] += 1;
2079+
ret = pdom_attach_iommu(iommu, domain);
2080+
if (ret)
2081+
return ret;
20342082

20352083
/* Setup GCR3 table */
20362084
if (pdom_is_sva_capable(domain)) {
20372085
ret = init_gcr3_table(dev_data, domain);
2038-
if (ret)
2086+
if (ret) {
2087+
pdom_detach_iommu(iommu, domain);
20392088
return ret;
2089+
}
20402090
}
20412091

20422092
return ret;
@@ -2062,7 +2112,7 @@ static void do_detach(struct iommu_dev_data *dev_data)
20622112
list_del(&dev_data->list);
20632113

20642114
/* decrease reference counters - needs to happen after the flushes */
2065-
domain->dev_iommu[iommu->index] -= 1;
2115+
pdom_detach_iommu(iommu, domain);
20662116
}
20672117

20682118
/*
@@ -2258,6 +2308,7 @@ static void protection_domain_init(struct protection_domain *domain, int nid)
22582308
spin_lock_init(&domain->lock);
22592309
INIT_LIST_HEAD(&domain->dev_list);
22602310
INIT_LIST_HEAD(&domain->dev_data_list);
2311+
xa_init(&domain->iommu_array);
22612312
domain->iop.pgtbl.cfg.amd.nid = nid;
22622313
}
22632314

0 commit comments

Comments
 (0)