]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu: Use bitmap to calculate page size in iommu_pgsize()
authorWill Deacon <will@kernel.org>
Wed, 16 Jun 2021 13:38:46 +0000 (06:38 -0700)
committerJoerg Roedel <jroedel@suse.de>
Mon, 26 Jul 2021 10:37:07 +0000 (12:37 +0200)
Avoid the potential for shifting values by amounts greater than the
width of their type by using a bitmap to compute page size in
iommu_pgsize().

Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Isaac J. Manjarres <isaacm@codeaurora.org>
Signed-off-by: Georgi Djakov <quic_c_gdjako@quicinc.com>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Link: https://lore.kernel.org/r/1623850736-389584-6-git-send-email-quic_c_gdjako@quicinc.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/iommu.c

index 5419c4b9f27ada00f31f86b0a6eb3adc19f56753..80e471ada358161c3984d0f6c8b863fbac564a41 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/bits.h>
 #include <linux/bug.h>
 #include <linux/types.h>
 #include <linux/init.h>
@@ -2378,30 +2379,22 @@ static size_t iommu_pgsize(struct iommu_domain *domain,
                           unsigned long addr_merge, size_t size)
 {
        unsigned int pgsize_idx;
+       unsigned long pgsizes;
        size_t pgsize;
 
-       /* Max page size that still fits into 'size' */
-       pgsize_idx = __fls(size);
+       /* Page sizes supported by the hardware and small enough for @size */
+       pgsizes = domain->pgsize_bitmap & GENMASK(__fls(size), 0);
 
-       /* need to consider alignment requirements ? */
-       if (likely(addr_merge)) {
-               /* Max page size allowed by address */
-               unsigned int align_pgsize_idx = __ffs(addr_merge);
-               pgsize_idx = min(pgsize_idx, align_pgsize_idx);
-       }
-
-       /* build a mask of acceptable page sizes */
-       pgsize = (1UL << (pgsize_idx + 1)) - 1;
-
-       /* throw away page sizes not supported by the hardware */
-       pgsize &= domain->pgsize_bitmap;
+       /* Constrain the page sizes further based on the maximum alignment */
+       if (likely(addr_merge))
+               pgsizes &= GENMASK(__ffs(addr_merge), 0);
 
-       /* make sure we're still sane */
-       BUG_ON(!pgsize);
+       /* Make sure we have at least one suitable page size */
+       BUG_ON(!pgsizes);
 
-       /* pick the biggest page */
-       pgsize_idx = __fls(pgsize);
-       pgsize = 1UL << pgsize_idx;
+       /* Pick the biggest page size remaining */
+       pgsize_idx = __fls(pgsizes);
+       pgsize = BIT(pgsize_idx);
 
        return pgsize;
 }