iommupt: Add PT_FEAT_DETAILED_GATHER

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@nvidia.com>
Reviewed-by: Pranjal Shrivastava <praan@google.com>
Tested-by: Andrew Jones <andrew.jones@oss.qualcomm.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
This commit is contained in:
Jason Gunthorpe 2026-05-08 11:53:02 -03:00 committed by Joerg Roedel
parent f0e4b7f5f8
commit 89792629d4
3 changed files with 53 additions and 5 deletions

View File

@ -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;

View File

@ -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,
};

View File

@ -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