]> Gentwo Git Trees - linux/.git/commitdiff
iommupt: Add basic support for SW bits in the page table
authorJason Gunthorpe <jgg@nvidia.com>
Thu, 23 Oct 2025 18:22:30 +0000 (15:22 -0300)
committerJoerg Roedel <joerg.roedel@amd.com>
Wed, 5 Nov 2025 08:47:44 +0000 (09:47 +0100)
SW bits can be placed on items, including table entries, single OA's and
individual items within a contiguous OA. They are guaranteed to be ignored
by the HW. The API is very basic since the only use case so far is a
single bit.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
drivers/iommu/generic_pt/pt_common.h
drivers/iommu/generic_pt/pt_fmt_defaults.h

index f64f800725dbb7352ec7f94b0232c7cc644ff55f..b5628f47e0db404d356d6c6cedce6281e7b09f1f 100644 (file)
@@ -342,6 +342,35 @@ static inline struct pt_table_p *pt_table_ptr(const struct pt_state *pts)
        return __va(pt_table_pa(pts));
 }
 
+/**
+ * pt_max_sw_bit() - Return the maximum software bit usable for any level and
+ *                   entry
+ * @common: Page table
+ *
+ * The swbit can be passed as bitnr to the other sw_bit functions.
+ */
+static inline unsigned int pt_max_sw_bit(struct pt_common *common);
+
+/**
+ * pt_test_sw_bit_acquire() - Read a software bit in an item
+ * @pts: Entry to set
+ *
+ * Software bits are ignored by HW and can be used for any purpose by the
+ * software. This does a test bit and acquire operation.
+ */
+static inline bool pt_test_sw_bit_acquire(struct pt_state *pts,
+                                         unsigned int bitnr);
+
+/**
+ * pt_set_sw_bit_release() - Set a software bit in an item
+ * @pts: Entry to set
+ *
+ * Software bits are ignored by HW and can be used for any purpose by the
+ * software. This does a set bit and release operation.
+ */
+static inline void pt_set_sw_bit_release(struct pt_state *pts,
+                                        unsigned int bitnr);
+
 /**
  * pt_load_entry() - Read from the location pts points at into the pts
  * @pts: Table index to load
index 60d594bbb1063e12be66a6a8f56027a35e9507ce..69fb7c2314ca10ede92294b6969293a08dfb189b 100644 (file)
@@ -202,6 +202,68 @@ static inline void pt_clear_entries(struct pt_state *pts,
 #define pt_clear_entries pt_clear_entries
 #endif
 
+/* If not supplied then SW bits are not supported */
+#ifdef pt_sw_bit
+static inline bool pt_test_sw_bit_acquire(struct pt_state *pts,
+                                         unsigned int bitnr)
+{
+       /* Acquire, pairs with pt_set_sw_bit_release() */
+       smp_mb();
+       /* For a contiguous entry the sw bit is only stored in the first item. */
+       return pts->entry & pt_sw_bit(bitnr);
+}
+#define pt_test_sw_bit_acquire pt_test_sw_bit_acquire
+
+static inline void pt_set_sw_bit_release(struct pt_state *pts,
+                                        unsigned int bitnr)
+{
+#if !IS_ENABLED(CONFIG_GENERIC_ATOMIC64)
+       if (PT_ITEM_WORD_SIZE == sizeof(u64)) {
+               u64 *entryp = pt_cur_table(pts, u64) + pts->index;
+               u64 old_entry = pts->entry;
+               u64 new_entry;
+
+               do {
+                       new_entry = old_entry | pt_sw_bit(bitnr);
+               } while (!try_cmpxchg64_release(entryp, &old_entry, new_entry));
+               pts->entry = new_entry;
+               return;
+       }
+#endif
+       if (PT_ITEM_WORD_SIZE == sizeof(u32)) {
+               u32 *entryp = pt_cur_table(pts, u32) + pts->index;
+               u32 old_entry = pts->entry;
+               u32 new_entry;
+
+               do {
+                       new_entry = old_entry | pt_sw_bit(bitnr);
+               } while (!try_cmpxchg_release(entryp, &old_entry, new_entry));
+               pts->entry = new_entry;
+       } else
+               BUILD_BUG();
+}
+#define pt_set_sw_bit_release pt_set_sw_bit_release
+#else
+static inline unsigned int pt_max_sw_bit(struct pt_common *common)
+{
+       return 0;
+}
+
+extern void __pt_no_sw_bit(void);
+static inline bool pt_test_sw_bit_acquire(struct pt_state *pts,
+                                         unsigned int bitnr)
+{
+       __pt_no_sw_bit();
+       return false;
+}
+
+static inline void pt_set_sw_bit_release(struct pt_state *pts,
+                                        unsigned int bitnr)
+{
+       __pt_no_sw_bit();
+}
+#endif
+
 /*
  * Format can call in the pt_install_leaf_entry() to check the arguments are all
  * aligned correctly.