From: Jason Gunthorpe Date: Fri, 8 May 2026 14:53:02 +0000 (-0300) Subject: iommupt: Add PT_FEAT_DETAILED_GATHER X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=89792629d4b260104555f9719ac84c1afc9a2012;p=thirdparty%2Fkernel%2Flinux.git 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 Reviewed-by: Pranjal Shrivastava Tested-by: Andrew Jones Signed-off-by: Joerg Roedel --- diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h index 5ec135cf43e2d..61c6d79c712cf 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 @@ start_oa: */ 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 2683e5b389987..07ef1c8341a4f 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 a9e89911c90f2..bf8a77a164e4d 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