]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommupt: Add PT_FEAT_DETAILED_GATHER
authorJason Gunthorpe <jgg@nvidia.com>
Fri, 8 May 2026 14:53:02 +0000 (11:53 -0300)
committerJoerg Roedel <joerg.roedel@amd.com>
Tue, 19 May 2026 08:45:38 +0000 (10:45 +0200)
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>
drivers/iommu/generic_pt/iommu_pt.h
include/linux/generic_pt/common.h
include/linux/iommu.h

index 5ec135cf43e2d6cd394b7ea02bbea4988ded2422..61c6d79c712cfaecedc5cea3a4c7c4f385151986 100644 (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 @@ 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;
index 2683e5b38998748d7b0be68b410fe048c84254b5..07ef1c8341a4f8ced7b584b9ab3c428498c3b666 100644 (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,
 };
index a9e89911c90f24d2cc36c90668c637678a802731..bf8a77a164e4db7598343b1d7ee573e63c661d69 100644 (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