[PATCH 3/7] iommupt: Add PT_FEAT_DETAILED_GATHER
Jason Gunthorpe
jgg at nvidia.com
Fri Apr 10 08:57:04 PDT 2026
Generating the ARM SMMUv3 and RISC-V invalidation commands optimally
requires some additional details from iommupt:
- leaf_levels_bitmap is used to compute the ARM Range Invalidation
Table Top Level hint
- leaf_levels_bitmap is also used to compute the stride when
generating single invalidations to invalidate once per leaf
- table_levels_bitmap also computes the ARM TTL for future cases when
there are no leaves
Put these under a feature since only two drivers need to calculate
them.
This is also useful for the coming kunit iotlb invalidation test to
know more about what invalidation is happening.
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
---
drivers/iommu/generic_pt/iommu_pt.h | 23 ++++++++++++++++++++++
include/linux/generic_pt/common.h | 5 +++++
include/linux/iommu.h | 30 ++++++++++++++++++++++++-----
3 files changed, 53 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h
index 5ec135cf43e2d6..61c6d79c712cfa 100644
--- a/drivers/iommu/generic_pt/iommu_pt.h
+++ b/drivers/iommu/generic_pt/iommu_pt.h
@@ -43,6 +43,8 @@ static void flush_writes_item(const struct pt_state *pts)
struct iommupt_pending_gather {
struct iommu_iotlb_gather *iotlb_gather;
struct iommu_pages_list free_list;
+ u8 leaf_levels_bitmap;
+ u8 table_levels_bitmap;
};
static void gather_add_table(struct iommupt_pending_gather *pending,
@@ -50,6 +52,17 @@ static void gather_add_table(struct iommupt_pending_gather *pending,
struct pt_table_p *table)
{
iommu_pages_list_add(&pending->free_list, table);
+ if (pts_feature(pts, PT_FEAT_DETAILED_GATHER))
+ pending->table_levels_bitmap |= BIT(pts->level);
+}
+
+static void gather_add_leaf(struct iommupt_pending_gather *pending,
+ const struct pt_state *pts)
+{
+ if (!pts_feature(pts, PT_FEAT_DETAILED_GATHER))
+ return;
+
+ pending->leaf_levels_bitmap |= BIT(pts->level);
}
static void gather_range_pending(struct iommupt_pending_gather *pending,
@@ -86,6 +99,15 @@ static void gather_range_pending(struct iommupt_pending_gather *pending,
iommu_pages_list_splice(&pending->free_list, &iotlb_gather->freelist);
INIT_LIST_HEAD(&pending->free_list.pages);
+
+ if (pt_feature(common, PT_FEAT_DETAILED_GATHER)) {
+ iotlb_gather->pt.leaf_levels_bitmap |=
+ pending->leaf_levels_bitmap;
+ iotlb_gather->pt.table_levels_bitmap |=
+ pending->table_levels_bitmap;
+ pending->leaf_levels_bitmap = 0;
+ pending->table_levels_bitmap = 0;
+ }
}
#define DOMAIN_NS(op) CONCATENATE(CONCATENATE(pt_iommu_, PTPFX), op)
@@ -1059,6 +1081,7 @@ static __maybe_unused int __unmap_range(struct pt_range *range, void *arg,
*/
num_contig_lg2 = pt_entry_num_contig_lg2(&pts);
pt_clear_entries(&pts, num_contig_lg2);
+ gather_add_leaf(&unmap->pending, &pts);
num_oas += log2_to_int(num_contig_lg2);
if (pts.index < flush_start_index)
flush_start_index = pts.index;
diff --git a/include/linux/generic_pt/common.h b/include/linux/generic_pt/common.h
index fc5d0b5edadc08..230347f00353bc 100644
--- a/include/linux/generic_pt/common.h
+++ b/include/linux/generic_pt/common.h
@@ -134,6 +134,11 @@ enum pt_features {
* significant amount of page table.
*/
PT_FEAT_FLUSH_RANGE_NO_GAPS,
+ /**
+ * @PT_FEAT_DETAILED_GATHER: Fill in the struct iommu_iotlb_gather pt
+ * sub structure with information about which levels were changed.
+ */
+ PT_FEAT_DETAILED_GATHER,
/* private: */
PT_FEAT_FMT_START,
};
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 47a559616706a1..0abe234fd12c33 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -360,11 +360,31 @@ struct iommu_iotlb_gather {
* flushed (inclusive)
*/
unsigned long end;
- /**
- * @pgsize: The interval at which to perform the flush, only used
- * by arm-smmu-v3
- */
- size_t pgsize;
+
+ union {
+ /**
+ * @pgsize: The interval at which to perform the flush, only
+ * used by arm-smmu-v3
+ */
+ size_t pgsize;
+ struct {
+ /**
+ * @pt.leaf_levels_bitmap: Bitmap of generic_pt
+ * levels where leaf entries were unmapped. Bit 0
+ * means the leaf only level. If 0 no leafs
+ * were unmapped.
+ */
+ u8 leaf_levels_bitmap;
+ /**
+ * @pt.table_levels_bitmap: Bitmap of generic_pt levels
+ * of table entries that were removed. Bit 0 is never
+ * set, bit 1 means a table of all leafs was removed.
+ * When freelist is empty this must be 0.
+ */
+ u8 table_levels_bitmap;
+ } pt;
+ };
+
/**
* @freelist: Removed pages to free after sync, only used by
* iommupt
--
2.43.0
More information about the linux-riscv
mailing list