|
8 | 8 |
|
9 | 9 | #include <linux/device.h>
|
10 | 10 | #include <linux/kernel.h>
|
| 11 | +#include <linux/bits.h> |
11 | 12 | #include <linux/bug.h>
|
12 | 13 | #include <linux/types.h>
|
13 | 14 | #include <linux/init.h>
|
@@ -2378,30 +2379,22 @@ static size_t iommu_pgsize(struct iommu_domain *domain,
|
2378 | 2379 | unsigned long addr_merge, size_t size)
|
2379 | 2380 | {
|
2380 | 2381 | unsigned int pgsize_idx;
|
| 2382 | + unsigned long pgsizes; |
2381 | 2383 | size_t pgsize;
|
2382 | 2384 |
|
2383 |
| - /* Max page size that still fits into 'size' */ |
2384 |
| - pgsize_idx = __fls(size); |
| 2385 | + /* Page sizes supported by the hardware and small enough for @size */ |
| 2386 | + pgsizes = domain->pgsize_bitmap & GENMASK(__fls(size), 0); |
2385 | 2387 |
|
2386 |
| - /* need to consider alignment requirements ? */ |
2387 |
| - if (likely(addr_merge)) { |
2388 |
| - /* Max page size allowed by address */ |
2389 |
| - unsigned int align_pgsize_idx = __ffs(addr_merge); |
2390 |
| - pgsize_idx = min(pgsize_idx, align_pgsize_idx); |
2391 |
| - } |
2392 |
| - |
2393 |
| - /* build a mask of acceptable page sizes */ |
2394 |
| - pgsize = (1UL << (pgsize_idx + 1)) - 1; |
2395 |
| - |
2396 |
| - /* throw away page sizes not supported by the hardware */ |
2397 |
| - pgsize &= domain->pgsize_bitmap; |
| 2388 | + /* Constrain the page sizes further based on the maximum alignment */ |
| 2389 | + if (likely(addr_merge)) |
| 2390 | + pgsizes &= GENMASK(__ffs(addr_merge), 0); |
2398 | 2391 |
|
2399 |
| - /* make sure we're still sane */ |
2400 |
| - BUG_ON(!pgsize); |
| 2392 | + /* Make sure we have at least one suitable page size */ |
| 2393 | + BUG_ON(!pgsizes); |
2401 | 2394 |
|
2402 |
| - /* pick the biggest page */ |
2403 |
| - pgsize_idx = __fls(pgsize); |
2404 |
| - pgsize = 1UL << pgsize_idx; |
| 2395 | + /* Pick the biggest page size remaining */ |
| 2396 | + pgsize_idx = __fls(pgsizes); |
| 2397 | + pgsize = BIT(pgsize_idx); |
2405 | 2398 |
|
2406 | 2399 | return pgsize;
|
2407 | 2400 | }
|
|
0 commit comments