* [PATCH v2 0/2] iommu/vt-d: Use ida for domain ID management
@ 2025-04-30 2:11 Lu Baolu
2025-04-30 2:11 ` [PATCH v2 1/2] iommu/vt-d: Use ida to manage domain id Lu Baolu
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Lu Baolu @ 2025-04-30 2:11 UTC (permalink / raw)
To: Joerg Roedel, Will Deacon, Robin Murphy, Jason Gunthorpe,
Kevin Tian
Cc: iommu, linux-kernel, Lu Baolu
This converts the Intel iommu driver's domain ID management from a
fixed-size bitmap to the dynamic ida allocator. This improves memory
efficiency by only allocating resources for the domain IDs actually in
use, rather than the maximum possible number.
The also includes necessary cleanups after the ida conversion, including
locking adjustment for the ida.
---
Change log:
v2:
- Drop the last patch which simplified the code with __free(). There
needs a helper like xa_store_or_{reset,kfree}(). Thus I plan to put
it a separated series with broader reviewers.
v1: https://lore.kernel.org/linux-iommu/20250423031020.2189546-1-baolu.lu@linux.intel.com/
Lu Baolu (2):
iommu/vt-d: Use ida to manage domain id
iommu/vt-d: Replace spin_lock with mutex to protect domain ida
drivers/iommu/intel/dmar.c | 4 ++
drivers/iommu/intel/iommu.c | 90 ++++++++-----------------------------
drivers/iommu/intel/iommu.h | 21 +++++++--
3 files changed, 40 insertions(+), 75 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/2] iommu/vt-d: Use ida to manage domain id
2025-04-30 2:11 [PATCH v2 0/2] iommu/vt-d: Use ida for domain ID management Lu Baolu
@ 2025-04-30 2:11 ` Lu Baolu
2025-05-06 17:29 ` Jason Gunthorpe
2025-04-30 2:11 ` [PATCH v2 2/2] iommu/vt-d: Replace spin_lock with mutex to protect domain ida Lu Baolu
2025-05-12 6:37 ` [PATCH v2 0/2] iommu/vt-d: Use ida for domain ID management Baolu Lu
2 siblings, 1 reply; 6+ messages in thread
From: Lu Baolu @ 2025-04-30 2:11 UTC (permalink / raw)
To: Joerg Roedel, Will Deacon, Robin Murphy, Jason Gunthorpe,
Kevin Tian
Cc: iommu, linux-kernel, Lu Baolu
Switch the intel iommu driver to use the ida mechanism for managing domain
IDs, replacing the previous fixed-size bitmap.
The previous approach allocated a bitmap large enough to cover the maximum
number of domain IDs supported by the hardware, regardless of the actual
number of domains in use. This led to unnecessary memory consumption,
especially on systems supporting a large number of iommu units but only
utilizing a small number of domain IDs.
The ida allocator dynamically manages the allocation and freeing of integer
IDs, only consuming memory for the IDs that are currently in use. This
significantly optimizes memory usage compared to the fixed-size bitmap.
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/dmar.c | 3 ++
drivers/iommu/intel/iommu.c | 80 ++++++++-----------------------------
drivers/iommu/intel/iommu.h | 19 +++++++--
3 files changed, 34 insertions(+), 68 deletions(-)
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index e540092d664d..0e35969c026b 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -1099,6 +1099,8 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
spin_lock_init(&iommu->device_rbtree_lock);
mutex_init(&iommu->iopf_lock);
iommu->node = NUMA_NO_NODE;
+ spin_lock_init(&iommu->lock);
+ ida_init(&iommu->domain_ida);
ver = readl(iommu->reg + DMAR_VER_REG);
pr_info("%s: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n",
@@ -1195,6 +1197,7 @@ static void free_iommu(struct intel_iommu *iommu)
if (iommu->reg)
unmap_iommu(iommu);
+ ida_destroy(&iommu->domain_ida);
ida_free(&dmar_seq_ids, iommu->seq_id);
kfree(iommu);
}
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index b29da2d96d0b..39832d2125be 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -1289,52 +1289,13 @@ static void iommu_disable_translation(struct intel_iommu *iommu)
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
}
-static int iommu_init_domains(struct intel_iommu *iommu)
-{
- u32 ndomains;
-
- ndomains = cap_ndoms(iommu->cap);
- pr_debug("%s: Number of Domains supported <%d>\n",
- iommu->name, ndomains);
-
- spin_lock_init(&iommu->lock);
-
- iommu->domain_ids = bitmap_zalloc(ndomains, GFP_KERNEL);
- if (!iommu->domain_ids)
- return -ENOMEM;
-
- /*
- * If Caching mode is set, then invalid translations are tagged
- * with domain-id 0, hence we need to pre-allocate it. We also
- * use domain-id 0 as a marker for non-allocated domain-id, so
- * make sure it is not used for a real domain.
- */
- set_bit(0, iommu->domain_ids);
-
- /*
- * Vt-d spec rev3.0 (section 6.2.3.1) requires that each pasid
- * entry for first-level or pass-through translation modes should
- * be programmed with a domain id different from those used for
- * second-level or nested translation. We reserve a domain id for
- * this purpose. This domain id is also used for identity domain
- * in legacy mode.
- */
- set_bit(FLPT_DEFAULT_DID, iommu->domain_ids);
-
- return 0;
-}
-
static void disable_dmar_iommu(struct intel_iommu *iommu)
{
- if (!iommu->domain_ids)
- return;
-
/*
* All iommu domains must have been detached from the devices,
* hence there should be no domain IDs in use.
*/
- if (WARN_ON(bitmap_weight(iommu->domain_ids, cap_ndoms(iommu->cap))
- > NUM_RESERVED_DID))
+ if (WARN_ON(!ida_is_empty(&iommu->domain_ida)))
return;
if (iommu->gcmd & DMA_GCMD_TE)
@@ -1343,11 +1304,6 @@ static void disable_dmar_iommu(struct intel_iommu *iommu)
static void free_dmar_iommu(struct intel_iommu *iommu)
{
- if (iommu->domain_ids) {
- bitmap_free(iommu->domain_ids);
- iommu->domain_ids = NULL;
- }
-
if (iommu->copied_tables) {
bitmap_free(iommu->copied_tables);
iommu->copied_tables = NULL;
@@ -1380,7 +1336,6 @@ static bool first_level_by_default(struct intel_iommu *iommu)
int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
{
struct iommu_domain_info *info, *curr;
- unsigned long ndomains;
int num, ret = -ENOSPC;
if (domain->domain.type == IOMMU_DOMAIN_SVA)
@@ -1399,14 +1354,13 @@ int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
return 0;
}
- ndomains = cap_ndoms(iommu->cap);
- num = find_first_zero_bit(iommu->domain_ids, ndomains);
- if (num >= ndomains) {
+ num = ida_alloc_range(&iommu->domain_ida, IDA_START_DID,
+ cap_ndoms(iommu->cap) - 1, GFP_ATOMIC);
+ if (num < 0) {
pr_err("%s: No free domain ids\n", iommu->name);
goto err_unlock;
}
- set_bit(num, iommu->domain_ids);
info->refcnt = 1;
info->did = num;
info->iommu = iommu;
@@ -1421,7 +1375,7 @@ int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
return 0;
err_clear:
- clear_bit(info->did, iommu->domain_ids);
+ ida_free(&iommu->domain_ida, info->did);
err_unlock:
spin_unlock(&iommu->lock);
kfree(info);
@@ -1438,7 +1392,7 @@ void domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
spin_lock(&iommu->lock);
info = xa_load(&domain->iommu_array, iommu->seq_id);
if (--info->refcnt == 0) {
- clear_bit(info->did, iommu->domain_ids);
+ ida_free(&iommu->domain_ida, info->did);
xa_erase(&domain->iommu_array, iommu->seq_id);
domain->nid = NUMA_NO_NODE;
kfree(info);
@@ -2042,7 +1996,7 @@ static int copy_context_table(struct intel_iommu *iommu,
did = context_domain_id(&ce);
if (did >= 0 && did < cap_ndoms(iommu->cap))
- set_bit(did, iommu->domain_ids);
+ ida_alloc_range(&iommu->domain_ida, did, did, GFP_KERNEL);
set_context_copied(iommu, bus, devfn);
new_ce[idx] = ce;
@@ -2169,11 +2123,6 @@ static int __init init_dmars(void)
}
intel_iommu_init_qi(iommu);
-
- ret = iommu_init_domains(iommu);
- if (ret)
- goto free_iommu;
-
init_translation_status(iommu);
if (translation_pre_enabled(iommu) && !is_kdump_kernel()) {
@@ -2651,9 +2600,7 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
if (iommu->gcmd & DMA_GCMD_TE)
iommu_disable_translation(iommu);
- ret = iommu_init_domains(iommu);
- if (ret == 0)
- ret = iommu_alloc_root_entry(iommu);
+ ret = iommu_alloc_root_entry(iommu);
if (ret)
goto out;
@@ -2972,9 +2919,14 @@ static ssize_t domains_used_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_iommu *iommu = dev_to_intel_iommu(dev);
- return sysfs_emit(buf, "%d\n",
- bitmap_weight(iommu->domain_ids,
- cap_ndoms(iommu->cap)));
+ unsigned int count = 0;
+ int id;
+
+ for (id = 0; id < cap_ndoms(iommu->cap); id++)
+ if (ida_exists(&iommu->domain_ida, id))
+ count++;
+
+ return sysfs_emit(buf, "%d\n", count);
}
static DEVICE_ATTR_RO(domains_used);
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index c4916886da5a..25faf3aadd24 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -722,7 +722,7 @@ struct intel_iommu {
unsigned char name[16]; /* Device Name */
#ifdef CONFIG_INTEL_IOMMU
- unsigned long *domain_ids; /* bitmap of domains */
+ struct ida domain_ida; /* domain id allocator */
unsigned long *copied_tables; /* bitmap of copied tables */
spinlock_t lock; /* protect context, domain ids */
struct root_entry *root_entry; /* virtual address */
@@ -809,11 +809,22 @@ static inline struct dmar_domain *to_dmar_domain(struct iommu_domain *dom)
}
/*
- * Domain ID reserved for pasid entries programmed for first-level
- * only and pass-through transfer modes.
+ * Domain ID 0 and 1 are reserved:
+ *
+ * If Caching mode is set, then invalid translations are tagged
+ * with domain-id 0, hence we need to pre-allocate it. We also
+ * use domain-id 0 as a marker for non-allocated domain-id, so
+ * make sure it is not used for a real domain.
+ *
+ * Vt-d spec rev3.0 (section 6.2.3.1) requires that each pasid
+ * entry for first-level or pass-through translation modes should
+ * be programmed with a domain id different from those used for
+ * second-level or nested translation. We reserve a domain id for
+ * this purpose. This domain id is also used for identity domain
+ * in legacy mode.
*/
#define FLPT_DEFAULT_DID 1
-#define NUM_RESERVED_DID 2
+#define IDA_START_DID 2
/* Retrieve the domain ID which has allocated to the domain */
static inline u16
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] iommu/vt-d: Replace spin_lock with mutex to protect domain ida
2025-04-30 2:11 [PATCH v2 0/2] iommu/vt-d: Use ida for domain ID management Lu Baolu
2025-04-30 2:11 ` [PATCH v2 1/2] iommu/vt-d: Use ida to manage domain id Lu Baolu
@ 2025-04-30 2:11 ` Lu Baolu
2025-05-06 17:29 ` Jason Gunthorpe
2025-05-12 6:37 ` [PATCH v2 0/2] iommu/vt-d: Use ida for domain ID management Baolu Lu
2 siblings, 1 reply; 6+ messages in thread
From: Lu Baolu @ 2025-04-30 2:11 UTC (permalink / raw)
To: Joerg Roedel, Will Deacon, Robin Murphy, Jason Gunthorpe,
Kevin Tian
Cc: iommu, linux-kernel, Lu Baolu
The domain ID allocator is currently protected by a spin_lock. However,
ida_alloc_range can potentially block if it needs to allocate memory to
grow its internal structures.
Replace the spin_lock with a mutex which allows sleep on block. Thus,
the memory allocation flags can be updated from GFP_ATOMIC to GFP_KERNEL
to allow blocking memory allocations if necessary.
Introduce a new mutex, did_lock, specifically for protecting the domain
ida. The existing spinlock will remain for protecting other intel_iommu
fields.
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/dmar.c | 1 +
drivers/iommu/intel/iommu.c | 12 ++++--------
drivers/iommu/intel/iommu.h | 2 ++
3 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index 0e35969c026b..9e17e8e56308 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -1101,6 +1101,7 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
iommu->node = NUMA_NO_NODE;
spin_lock_init(&iommu->lock);
ida_init(&iommu->domain_ida);
+ mutex_init(&iommu->did_lock);
ver = readl(iommu->reg + DMAR_VER_REG);
pr_info("%s: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n",
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 39832d2125be..d117417975d8 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -1345,17 +1345,16 @@ int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
if (!info)
return -ENOMEM;
- spin_lock(&iommu->lock);
+ guard(mutex)(&iommu->did_lock);
curr = xa_load(&domain->iommu_array, iommu->seq_id);
if (curr) {
curr->refcnt++;
- spin_unlock(&iommu->lock);
kfree(info);
return 0;
}
num = ida_alloc_range(&iommu->domain_ida, IDA_START_DID,
- cap_ndoms(iommu->cap) - 1, GFP_ATOMIC);
+ cap_ndoms(iommu->cap) - 1, GFP_KERNEL);
if (num < 0) {
pr_err("%s: No free domain ids\n", iommu->name);
goto err_unlock;
@@ -1365,19 +1364,17 @@ int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
info->did = num;
info->iommu = iommu;
curr = xa_cmpxchg(&domain->iommu_array, iommu->seq_id,
- NULL, info, GFP_ATOMIC);
+ NULL, info, GFP_KERNEL);
if (curr) {
ret = xa_err(curr) ? : -EBUSY;
goto err_clear;
}
- spin_unlock(&iommu->lock);
return 0;
err_clear:
ida_free(&iommu->domain_ida, info->did);
err_unlock:
- spin_unlock(&iommu->lock);
kfree(info);
return ret;
}
@@ -1389,7 +1386,7 @@ void domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
if (domain->domain.type == IOMMU_DOMAIN_SVA)
return;
- spin_lock(&iommu->lock);
+ guard(mutex)(&iommu->did_lock);
info = xa_load(&domain->iommu_array, iommu->seq_id);
if (--info->refcnt == 0) {
ida_free(&iommu->domain_ida, info->did);
@@ -1397,7 +1394,6 @@ void domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
domain->nid = NUMA_NO_NODE;
kfree(info);
}
- spin_unlock(&iommu->lock);
}
static void domain_exit(struct dmar_domain *domain)
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index 25faf3aadd24..5f140892fae0 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -722,6 +722,8 @@ struct intel_iommu {
unsigned char name[16]; /* Device Name */
#ifdef CONFIG_INTEL_IOMMU
+ /* mutex to protect domain_ida */
+ struct mutex did_lock;
struct ida domain_ida; /* domain id allocator */
unsigned long *copied_tables; /* bitmap of copied tables */
spinlock_t lock; /* protect context, domain ids */
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] iommu/vt-d: Use ida to manage domain id
2025-04-30 2:11 ` [PATCH v2 1/2] iommu/vt-d: Use ida to manage domain id Lu Baolu
@ 2025-05-06 17:29 ` Jason Gunthorpe
0 siblings, 0 replies; 6+ messages in thread
From: Jason Gunthorpe @ 2025-05-06 17:29 UTC (permalink / raw)
To: Lu Baolu
Cc: Joerg Roedel, Will Deacon, Robin Murphy, Kevin Tian, iommu,
linux-kernel
On Wed, Apr 30, 2025 at 10:11:34AM +0800, Lu Baolu wrote:
> Switch the intel iommu driver to use the ida mechanism for managing domain
> IDs, replacing the previous fixed-size bitmap.
>
> The previous approach allocated a bitmap large enough to cover the maximum
> number of domain IDs supported by the hardware, regardless of the actual
> number of domains in use. This led to unnecessary memory consumption,
> especially on systems supporting a large number of iommu units but only
> utilizing a small number of domain IDs.
>
> The ida allocator dynamically manages the allocation and freeing of integer
> IDs, only consuming memory for the IDs that are currently in use. This
> significantly optimizes memory usage compared to the fixed-size bitmap.
>
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
> ---
> drivers/iommu/intel/dmar.c | 3 ++
> drivers/iommu/intel/iommu.c | 80 ++++++++-----------------------------
> drivers/iommu/intel/iommu.h | 19 +++++++--
> 3 files changed, 34 insertions(+), 68 deletions(-)
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Jason
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 2/2] iommu/vt-d: Replace spin_lock with mutex to protect domain ida
2025-04-30 2:11 ` [PATCH v2 2/2] iommu/vt-d: Replace spin_lock with mutex to protect domain ida Lu Baolu
@ 2025-05-06 17:29 ` Jason Gunthorpe
0 siblings, 0 replies; 6+ messages in thread
From: Jason Gunthorpe @ 2025-05-06 17:29 UTC (permalink / raw)
To: Lu Baolu
Cc: Joerg Roedel, Will Deacon, Robin Murphy, Kevin Tian, iommu,
linux-kernel
On Wed, Apr 30, 2025 at 10:11:35AM +0800, Lu Baolu wrote:
> The domain ID allocator is currently protected by a spin_lock. However,
> ida_alloc_range can potentially block if it needs to allocate memory to
> grow its internal structures.
>
> Replace the spin_lock with a mutex which allows sleep on block. Thus,
> the memory allocation flags can be updated from GFP_ATOMIC to GFP_KERNEL
> to allow blocking memory allocations if necessary.
>
> Introduce a new mutex, did_lock, specifically for protecting the domain
> ida. The existing spinlock will remain for protecting other intel_iommu
> fields.
>
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
> ---
> drivers/iommu/intel/dmar.c | 1 +
> drivers/iommu/intel/iommu.c | 12 ++++--------
> drivers/iommu/intel/iommu.h | 2 ++
> 3 files changed, 7 insertions(+), 8 deletions(-)
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Jason
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 0/2] iommu/vt-d: Use ida for domain ID management
2025-04-30 2:11 [PATCH v2 0/2] iommu/vt-d: Use ida for domain ID management Lu Baolu
2025-04-30 2:11 ` [PATCH v2 1/2] iommu/vt-d: Use ida to manage domain id Lu Baolu
2025-04-30 2:11 ` [PATCH v2 2/2] iommu/vt-d: Replace spin_lock with mutex to protect domain ida Lu Baolu
@ 2025-05-12 6:37 ` Baolu Lu
2 siblings, 0 replies; 6+ messages in thread
From: Baolu Lu @ 2025-05-12 6:37 UTC (permalink / raw)
To: Joerg Roedel, Will Deacon, Robin Murphy, Jason Gunthorpe,
Kevin Tian
Cc: iommu, linux-kernel
On 4/30/25 10:11, Lu Baolu wrote:
> This converts the Intel iommu driver's domain ID management from a
> fixed-size bitmap to the dynamic ida allocator. This improves memory
> efficiency by only allocating resources for the domain IDs actually in
> use, rather than the maximum possible number.
>
> The also includes necessary cleanups after the ida conversion, including
> locking adjustment for the ida.
>
> ---
> Change log:
> v2:
> - Drop the last patch which simplified the code with __free(). There
> needs a helper like xa_store_or_{reset,kfree}(). Thus I plan to put
> it a separated series with broader reviewers.
>
> v1:https://lore.kernel.org/linux-iommu/20250423031020.2189546-1-
> baolu.lu@linux.intel.com/
>
> Lu Baolu (2):
> iommu/vt-d: Use ida to manage domain id
> iommu/vt-d: Replace spin_lock with mutex to protect domain ida
Queued for v6.16-rc1.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-05-12 6:42 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-30 2:11 [PATCH v2 0/2] iommu/vt-d: Use ida for domain ID management Lu Baolu
2025-04-30 2:11 ` [PATCH v2 1/2] iommu/vt-d: Use ida to manage domain id Lu Baolu
2025-05-06 17:29 ` Jason Gunthorpe
2025-04-30 2:11 ` [PATCH v2 2/2] iommu/vt-d: Replace spin_lock with mutex to protect domain ida Lu Baolu
2025-05-06 17:29 ` Jason Gunthorpe
2025-05-12 6:37 ` [PATCH v2 0/2] iommu/vt-d: Use ida for domain ID management Baolu Lu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox