[PATCH RFC 05/17] iommu: Make iommu_fwspec->ids a distinct allocation
Jason Gunthorpe
jgg at nvidia.com
Fri Nov 3 09:44:50 PDT 2023
The optimization of kreallocing the entire fwspec only works if the fwspec
pointer is always stored in the dev->iommu. Since we want to change this
remove the optimization and make the ids array a distinct allocation.
Allow a single id to be stored inside the iommu_fwspec as a common case
optimization.
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
---
drivers/iommu/iommu.c | 20 ++++++++++++--------
include/linux/iommu.h | 3 ++-
2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index c9a05bb49bfa17..d5e86985f6d363 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2948,8 +2948,7 @@ int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
if (!dev_iommu_get(dev))
return -ENOMEM;
- /* Preallocate for the overwhelmingly common case of 1 ID */
- fwspec = kzalloc(struct_size(fwspec, ids, 1), GFP_KERNEL);
+ fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL);
if (!fwspec)
return -ENOMEM;
@@ -2982,13 +2981,18 @@ int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
return -EINVAL;
new_num = fwspec->num_ids + num_ids;
- if (new_num > 1) {
- fwspec = krealloc(fwspec, struct_size(fwspec, ids, new_num),
- GFP_KERNEL);
- if (!fwspec)
+ if (new_num <= 1) {
+ if (fwspec->ids != &fwspec->single_id)
+ kfree(fwspec->ids);
+ fwspec->ids = &fwspec->single_id;
+ } else if (new_num > fwspec->num_ids) {
+ ids = krealloc_array(
+ fwspec->ids != &fwspec->single_id ? fwspec->ids : NULL,
+ new_num, sizeof(fwspec->ids[0]),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!ids)
return -ENOMEM;
-
- dev_iommu_fwspec_set(dev, fwspec);
+ fwspec->ids = ids;
}
for (i = 0; i < num_ids; i++)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index ddc25d2391063b..66ea1d08dc3f58 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -668,7 +668,8 @@ struct iommu_fwspec {
struct fwnode_handle *iommu_fwnode;
u32 flags;
unsigned int num_ids;
- u32 ids[];
+ u32 single_id;
+ u32 *ids;
};
/* ATS is supported */
--
2.42.0
More information about the linux-riscv
mailing list