[PATCH v2 01/14] iommufd: Convert struct iommufd_sw_msi_maps to a growable bitmap
Andrew Jones
andrew.jones at oss.qualcomm.com
Fri Jul 24 08:12:05 PDT 2026
struct iommufd_sw_msi_maps currently uses a fixed 64-bit bitmap,
capping the number of distinct SW MSI mappings a context or hwpt can
track. An upcoming caller needs one mapping per possible CPU.
Convert the fixed bitmap to a pointer plus size that grows on demand
via iommufd_sw_msi_maps_ensure(). Add iommufd_sw_msi_maps_test_bit()
alongside it: unlike the __set_bit() call sites, which always follow
their own successful iommufd_sw_msi_maps_ensure() call on the same id,
iommufd_group_setup_msi() tests an id from the fd-global sw_msi_list
against a specific group's required_sw_msi map, which may not have
been grown to cover that id yet.
Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
---
drivers/iommu/iommufd/device.c | 3 +-
drivers/iommu/iommufd/driver.c | 38 ++++++++++++++++---------
drivers/iommu/iommufd/hw_pagetable.c | 1 +
drivers/iommu/iommufd/iommufd_private.h | 38 +++++++++++++++++++++++--
4 files changed, 64 insertions(+), 16 deletions(-)
diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index 170a7005f0bc..402251c7b887 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -34,6 +34,7 @@ static void iommufd_group_release(struct kref *kref)
NULL, GFP_KERNEL);
iommu_group_put(igroup->group);
mutex_destroy(&igroup->lock);
+ kfree(igroup->required_sw_msi.bitmap);
kfree(igroup);
}
@@ -384,7 +385,7 @@ static int iommufd_group_setup_msi(struct iommufd_group *igroup,
int rc;
if (cur->sw_msi_start != igroup->sw_msi_start ||
- !test_bit(cur->id, igroup->required_sw_msi.bitmap))
+ !iommufd_sw_msi_maps_test_bit(&igroup->required_sw_msi, cur->id))
continue;
rc = iommufd_sw_msi_install(ictx, hwpt_paging, cur);
diff --git a/drivers/iommu/iommufd/driver.c b/drivers/iommu/iommufd/driver.c
index 3b8067976eac..3cd617dfc351 100644
--- a/drivers/iommu/iommufd/driver.c
+++ b/drivers/iommu/iommufd/driver.c
@@ -196,13 +196,15 @@ iommufd_sw_msi_get_map(struct iommufd_ctx *ictx, phys_addr_t msi_addr,
list_for_each_entry(cur, &ictx->sw_msi_list, sw_msi_item) {
if (cur->sw_msi_start != sw_msi_start)
continue;
+ if (cur->pgoff == UINT_MAX)
+ return ERR_PTR(-EOVERFLOW);
max_pgoff = max(max_pgoff, cur->pgoff + 1);
if (cur->msi_addr == msi_addr)
return cur;
}
- if (ictx->sw_msi_id >=
- BITS_PER_BYTE * sizeof_field(struct iommufd_sw_msi_maps, bitmap))
+ if (ictx->sw_msi_id == UINT_MAX ||
+ max_pgoff > (ULONG_MAX - sw_msi_start) / PAGE_SIZE)
return ERR_PTR(-EOVERFLOW);
cur = kzalloc_obj(*cur);
@@ -222,21 +224,26 @@ int iommufd_sw_msi_install(struct iommufd_ctx *ictx,
struct iommufd_sw_msi_map *msi_map)
{
unsigned long iova;
+ int rc;
lockdep_assert_held(&ictx->sw_msi_lock);
+ if (iommufd_sw_msi_maps_test_bit(&hwpt_paging->present_sw_msi,
+ msi_map->id))
+ return 0;
+
iova = msi_map->sw_msi_start + msi_map->pgoff * PAGE_SIZE;
- if (!test_bit(msi_map->id, hwpt_paging->present_sw_msi.bitmap)) {
- int rc;
-
- rc = iommu_map(hwpt_paging->common.domain, iova,
- msi_map->msi_addr, PAGE_SIZE,
- IOMMU_WRITE | IOMMU_READ | IOMMU_MMIO,
- GFP_KERNEL_ACCOUNT);
- if (rc)
- return rc;
- __set_bit(msi_map->id, hwpt_paging->present_sw_msi.bitmap);
- }
+ rc = iommufd_sw_msi_maps_ensure(&hwpt_paging->present_sw_msi, msi_map->id);
+ if (rc)
+ return rc;
+
+ rc = iommu_map(hwpt_paging->common.domain, iova,
+ msi_map->msi_addr, PAGE_SIZE,
+ IOMMU_WRITE | IOMMU_READ | IOMMU_MMIO,
+ GFP_KERNEL_ACCOUNT);
+ if (rc)
+ return rc;
+ __set_bit(msi_map->id, hwpt_paging->present_sw_msi.bitmap);
return 0;
}
EXPORT_SYMBOL_NS_GPL(iommufd_sw_msi_install, "IOMMUFD_INTERNAL");
@@ -290,6 +297,11 @@ int iommufd_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
if (IS_ERR(msi_map))
return PTR_ERR(msi_map);
+ rc = iommufd_sw_msi_maps_ensure(&handle->idev->igroup->required_sw_msi,
+ msi_map->id);
+ if (rc)
+ return rc;
+
rc = iommufd_sw_msi_install(ictx, hwpt_paging, msi_map);
if (rc)
return rc;
diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c
index 623cc608ca0c..54873de43eb0 100644
--- a/drivers/iommu/iommufd/hw_pagetable.c
+++ b/drivers/iommu/iommufd/hw_pagetable.c
@@ -32,6 +32,7 @@ void iommufd_hwpt_paging_destroy(struct iommufd_object *obj)
}
__iommufd_hwpt_destroy(&hwpt_paging->common);
+ kfree(hwpt_paging->present_sw_msi.bitmap);
refcount_dec(&hwpt_paging->ioas->obj.users);
}
diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index 43fbc5bed8de..44d6dc94fb6b 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -29,11 +29,45 @@ struct iommufd_sw_msi_map {
unsigned int id;
};
-/* Bitmap of struct iommufd_sw_msi_map::id */
+/* Bitmap of struct iommufd_sw_msi_map::id; starts empty, grows on demand. */
struct iommufd_sw_msi_maps {
- DECLARE_BITMAP(bitmap, 64);
+ unsigned long *bitmap;
+ unsigned int nbits;
};
+/* Grow bitmap to accommodate id. Must be called under ictx->sw_msi_lock. */
+static inline int iommufd_sw_msi_maps_ensure(struct iommufd_sw_msi_maps *maps,
+ unsigned int id)
+{
+ unsigned long *new_bitmap;
+ unsigned int new_nbits;
+
+ if (id < maps->nbits)
+ return 0;
+
+ new_nbits = ALIGN(max(maps->nbits ? maps->nbits * 2 : 64U, id + 1),
+ BITS_PER_LONG);
+ if (new_nbits <= id)
+ return -EOVERFLOW;
+ new_bitmap = krealloc(maps->bitmap,
+ BITS_TO_LONGS(new_nbits) * sizeof(unsigned long),
+ GFP_KERNEL_ACCOUNT);
+ if (!new_bitmap)
+ return -ENOMEM;
+ bitmap_clear(new_bitmap, maps->nbits, new_nbits - maps->nbits);
+ maps->bitmap = new_bitmap;
+ maps->nbits = new_nbits;
+ return 0;
+}
+
+static inline bool iommufd_sw_msi_maps_test_bit(const struct iommufd_sw_msi_maps *maps,
+ unsigned int id)
+{
+ if (id >= maps->nbits)
+ return false;
+ return test_bit(id, maps->bitmap);
+}
+
#ifdef CONFIG_IRQ_MSI_IOMMU
int iommufd_sw_msi_install(struct iommufd_ctx *ictx,
struct iommufd_hwpt_paging *hwpt_paging,
--
2.43.0
More information about the linux-riscv
mailing list