]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommu/amd: Simplify build_inv_address()
authorJason Gunthorpe <jgg@nvidia.com>
Fri, 27 Mar 2026 15:23:55 +0000 (12:23 -0300)
committerJoerg Roedel <joerg.roedel@amd.com>
Fri, 12 Jun 2026 07:17:05 +0000 (09:17 +0200)
This function is doing more work than it needs to:

 - iommu_num_pages() is pointless, the fls() is going to compute the
   required page size already.

 - It is easier to understand as sz_lg2, which is 12 if size is 4K,
   than msb_diff which is 11 if size is 4K.

 - Simplify the control flow to early exit on the out of range cases.

 - Use the usual last instead of end to signify an inclusive last
   address.

 - Use GENMASK to compute the 1's mask.

 - Use GENMASK to compute the address mask for the command layout,
   not PAGE_MASK.

 - Directly reference the spec language that defines the 52 bit
   limit.

No functional change intended.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Wei Wang <wei.w.wang@hotmail.com>
Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava@amd.com>
Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
drivers/iommu/amd/iommu.c

index 0c042668b32d0b1b731b896217d1d5f7ab18411b..09b22a1873ebe3e3dd10d12874781d39ab567d15 100644 (file)
@@ -1268,39 +1268,37 @@ static void build_inv_dte(struct iommu_cmd *cmd, u16 devid)
  */
 static inline u64 build_inv_address(u64 address, size_t size)
 {
-       u64 pages, end, msb_diff;
+       u64 last = address + size - 1;
+       unsigned int sz_lg2;
 
-       pages = iommu_num_pages(address, size, PAGE_SIZE);
-
-       if (pages == 1)
-               return address & PAGE_MASK;
-
-       end = address + size - 1;
+       address &= GENMASK_U64(63, 12);
+       sz_lg2 = fls64(address ^ last);
+       if (sz_lg2 <= 12)
+               return address;
 
        /*
-        * msb_diff would hold the index of the most significant bit that
-        * flipped between the start and end.
+        * Encode sz_lg2 according to Table 14: Example Page Size Encodings
+        *
+        * See "Note *":
+        *   Address bits 51:32 can be used to encode page sizes greater
+        *   that 4 Gbytes.
+        * Which we take to mean that the highest page size has bit
+        *  [51]=0, [50:12]=1
+        * and that coding happens when sz_lg2 is 52. Fall back to full
+        * invalidation if the size is too big.
+        *
         */
-       msb_diff = fls64(end ^ address) - 1;
+       if (unlikely(sz_lg2 > 52))
+               return (CMD_INV_IOMMU_ALL_PAGES_ADDRESS & PAGE_MASK) |
+                      CMD_INV_IOMMU_PAGES_SIZE_MASK;
 
        /*
-        * Bits 63:52 are sign extended. If for some reason bit 51 is different
-        * between the start and the end, invalidate everything.
+        * The sz_lg2 calculation with fls() ensures that:
+        *   address & BIT(sz_lg2 - 1) == 0
+        * Therefore only the 1's need to be added. 8KB requires no 1's
         */
-       if (unlikely(msb_diff > 51)) {
-               address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
-       } else {
-               /*
-                * The msb-bit must be clear on the address. Just set all the
-                * lower bits.
-                */
-               address |= (1ull << msb_diff) - 1;
-       }
-
-       /* Clear bits 11:0 */
-       address &= PAGE_MASK;
-
-       /* Set the size bit - we flush more than one 4kb page */
+       if (sz_lg2 > 13)
+               address |= GENMASK_U64(sz_lg2 - 2, 12);
        return address | CMD_INV_IOMMU_PAGES_SIZE_MASK;
 }