Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dma-mapping: introduce dma_get_seg_boundary_nr_pages()

We found that callers of dma_get_seg_boundary mostly do an ALIGN
with page mask and then do a page shift to get number of pages:
ALIGN(boundary + 1, 1 << shift) >> shift

However, the boundary might be as large as ULONG_MAX, which means
that a device has no specific boundary limit. So either "+ 1" or
passing it to ALIGN() would potentially overflow.

According to kernel defines:
#define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
#define ALIGN(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1)

We can simplify the logic here into a helper function doing:
ALIGN(boundary + 1, 1 << shift) >> shift
= ALIGN_MASK(b + 1, (1 << s) - 1) >> s
= {[b + 1 + (1 << s) - 1] & ~[(1 << s) - 1]} >> s
= [b + 1 + (1 << s) - 1] >> s
= [b + (1 << s)] >> s
= (b >> s) + 1

This patch introduces and applies dma_get_seg_boundary_nr_pages()
as an overflow-free helper for the dma_get_seg_boundary() callers
to get numbers of pages. It also takes care of the NULL dev case
for non-DMA API callers.

Suggested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
Acked-by: Niklas Schnelle <schnelle@linux.ibm.com>
Acked-by: Michael Ellerman <mpe@ellerman.id.au> (powerpc)
Signed-off-by: Christoph Hellwig <hch@lst.de>

authored by

Nicolin Chen and committed by
Christoph Hellwig
1e9d90db 2281f797

+33 -38
+1 -6
arch/alpha/kernel/pci_iommu.c
··· 141 141 unsigned long boundary_size; 142 142 143 143 base = arena->dma_base >> PAGE_SHIFT; 144 - if (dev) { 145 - boundary_size = dma_get_seg_boundary(dev) + 1; 146 - boundary_size >>= PAGE_SHIFT; 147 - } else { 148 - boundary_size = 1UL << (32 - PAGE_SHIFT); 149 - } 144 + boundary_size = dma_get_seg_boundary_nr_pages(dev, PAGE_SHIFT); 150 145 151 146 /* Search forward for the first mask-aligned sequence of N free ptes */ 152 147 ptes = arena->ptes;
+1 -2
arch/ia64/hp/common/sba_iommu.c
··· 485 485 ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0); 486 486 ASSERT(res_ptr < res_end); 487 487 488 - boundary_size = (unsigned long long)dma_get_seg_boundary(dev) + 1; 489 - boundary_size = ALIGN(boundary_size, 1ULL << iovp_shift) >> iovp_shift; 488 + boundary_size = dma_get_seg_boundary_nr_pages(dev, iovp_shift); 490 489 491 490 BUG_ON(ioc->ibase & ~iovp_mask); 492 491 shift = ioc->ibase >> iovp_shift;
+2 -9
arch/powerpc/kernel/iommu.c
··· 172 172 int largealloc = npages > 15; 173 173 int pass = 0; 174 174 unsigned long align_mask; 175 - unsigned long boundary_size; 176 175 unsigned long flags; 177 176 unsigned int pool_nr; 178 177 struct iommu_pool *pool; ··· 235 236 } 236 237 } 237 238 238 - if (dev) 239 - boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, 240 - 1 << tbl->it_page_shift); 241 - else 242 - boundary_size = ALIGN(1UL << 32, 1 << tbl->it_page_shift); 243 - /* 4GB boundary for iseries_hv_alloc and iseries_hv_map */ 244 - 245 239 n = iommu_area_alloc(tbl->it_map, limit, start, npages, tbl->it_offset, 246 - boundary_size >> tbl->it_page_shift, align_mask); 240 + dma_get_seg_boundary_nr_pages(dev, tbl->it_page_shift), 241 + align_mask); 247 242 if (n == -1) { 248 243 if (likely(pass == 0)) { 249 244 /* First try the pool from the start */
+2 -4
arch/s390/pci/pci_dma.c
··· 261 261 unsigned long start, int size) 262 262 { 263 263 struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); 264 - unsigned long boundary_size; 265 264 266 - boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, 267 - PAGE_SIZE) >> PAGE_SHIFT; 268 265 return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages, 269 266 start, size, zdev->start_dma >> PAGE_SHIFT, 270 - boundary_size, 0); 267 + dma_get_seg_boundary_nr_pages(dev, PAGE_SHIFT), 268 + 0); 271 269 } 272 270 273 271 static dma_addr_t dma_alloc_address(struct device *dev, int size)
+3 -7
arch/sparc/kernel/iommu-common.c
··· 166 166 } 167 167 } 168 168 169 - if (dev) 170 - boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, 171 - 1 << iommu->table_shift); 172 - else 173 - boundary_size = ALIGN(1ULL << 32, 1 << iommu->table_shift); 174 - 175 - boundary_size = boundary_size >> iommu->table_shift; 176 169 /* 177 170 * if the skip_span_boundary_check had been set during init, we set 178 171 * things up so that iommu_is_span_boundary() merely checks if the ··· 174 181 if ((iommu->flags & IOMMU_NO_SPAN_BOUND) != 0) { 175 182 shift = 0; 176 183 boundary_size = iommu->poolsize * iommu->nr_pools; 184 + } else { 185 + boundary_size = dma_get_seg_boundary_nr_pages(dev, 186 + iommu->table_shift); 177 187 } 178 188 n = iommu_area_alloc(iommu->map, limit, start, npages, shift, 179 189 boundary_size, align_mask);
+1 -2
arch/sparc/kernel/iommu.c
··· 472 472 outs->dma_length = 0; 473 473 474 474 max_seg_size = dma_get_max_seg_size(dev); 475 - seg_boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, 476 - IO_PAGE_SIZE) >> IO_PAGE_SHIFT; 475 + seg_boundary_size = dma_get_seg_boundary_nr_pages(dev, IO_PAGE_SHIFT); 477 476 base_shift = iommu->tbl.table_map_base >> IO_PAGE_SHIFT; 478 477 for_each_sg(sglist, s, nelems, i) { 479 478 unsigned long paddr, npages, entry, out_entry = 0, slen;
+1 -2
arch/sparc/kernel/pci_sun4v.c
··· 508 508 iommu_batch_start(dev, prot, ~0UL); 509 509 510 510 max_seg_size = dma_get_max_seg_size(dev); 511 - seg_boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, 512 - IO_PAGE_SIZE) >> IO_PAGE_SHIFT; 511 + seg_boundary_size = dma_get_seg_boundary_nr_pages(dev, IO_PAGE_SHIFT); 513 512 514 513 mask = *dev->dma_mask; 515 514 if (!iommu_use_atu(iommu, mask))
+1 -2
arch/x86/kernel/amd_gart_64.c
··· 96 96 97 97 base_index = ALIGN(iommu_bus_base & dma_get_seg_boundary(dev), 98 98 PAGE_SIZE) >> PAGE_SHIFT; 99 - boundary_size = ALIGN((u64)dma_get_seg_boundary(dev) + 1, 100 - PAGE_SIZE) >> PAGE_SHIFT; 99 + boundary_size = dma_get_seg_boundary_nr_pages(dev, PAGE_SHIFT); 101 100 102 101 spin_lock_irqsave(&iommu_bitmap_lock, flags); 103 102 offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, next_bit,
+1 -2
drivers/parisc/ccio-dma.c
··· 356 356 ** ggg sacrifices another 710 to the computer gods. 357 357 */ 358 358 359 - boundary_size = ALIGN((unsigned long long)dma_get_seg_boundary(dev) + 1, 360 - 1ULL << IOVP_SHIFT) >> IOVP_SHIFT; 359 + boundary_size = dma_get_seg_boundary_nr_pages(dev, IOVP_SHIFT); 361 360 362 361 if (pages_needed <= 8) { 363 362 /*
+1 -2
drivers/parisc/sba_iommu.c
··· 342 342 unsigned long shift; 343 343 int ret; 344 344 345 - boundary_size = ALIGN((unsigned long long)dma_get_seg_boundary(dev) + 1, 346 - 1ULL << IOVP_SHIFT) >> IOVP_SHIFT; 345 + boundary_size = dma_get_seg_boundary_nr_pages(dev, IOVP_SHIFT); 347 346 348 347 #if defined(ZX1_SUPPORT) 349 348 BUG_ON(ioc->ibase & ~IOVP_MASK);
+19
include/linux/dma-mapping.h
··· 632 632 return DMA_BIT_MASK(32); 633 633 } 634 634 635 + /** 636 + * dma_get_seg_boundary_nr_pages - return the segment boundary in "page" units 637 + * @dev: device to guery the boundary for 638 + * @page_shift: ilog() of the IOMMU page size 639 + * 640 + * Return the segment boundary in IOMMU page units (which may be different from 641 + * the CPU page size) for the passed in device. 642 + * 643 + * If @dev is NULL a boundary of U32_MAX is assumed, this case is just for 644 + * non-DMA API callers. 645 + */ 646 + static inline unsigned long dma_get_seg_boundary_nr_pages(struct device *dev, 647 + unsigned int page_shift) 648 + { 649 + if (!dev) 650 + return (U32_MAX >> page_shift) + 1; 651 + return (dma_get_seg_boundary(dev) >> page_shift) + 1; 652 + } 653 + 635 654 static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask) 636 655 { 637 656 if (dev->dma_parms) {