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

iommu: parisc: make the IOMMUs respect the segment boundary limits

Make PARISC's two IOMMU implementations not allocate a memory area spanning
LLD's segment boundary.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Kyle McMartin <kyle@parisc-linux.org>
Cc: Matthew Wilcox <matthew@wil.cx>
Cc: Grant Grundler <grundler@parisc-linux.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

FUJITA Tomonori and committed by
Linus Torvalds
46663448 7c8cda62

+58 -18
+5
drivers/parisc/Kconfig
··· 103 103 depends on PCI_LBA 104 104 default PCI_LBA 105 105 106 + config IOMMU_HELPER 107 + bool 108 + depends on IOMMU_SBA || IOMMU_CCIO 109 + default y 110 + 106 111 #config PCI_EPIC 107 112 # bool "EPIC/SAGA PCI support" 108 113 # depends on PCI
+16 -7
drivers/parisc/ccio-dma.c
··· 43 43 #include <linux/proc_fs.h> 44 44 #include <linux/seq_file.h> 45 45 #include <linux/scatterlist.h> 46 + #include <linux/iommu-helper.h> 46 47 47 48 #include <asm/byteorder.h> 48 49 #include <asm/cache.h> /* for L1_CACHE_BYTES */ ··· 303 302 */ 304 303 #define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size) \ 305 304 for(; res_ptr < res_end; ++res_ptr) { \ 306 - if(0 == (*res_ptr & mask)) { \ 307 - *res_ptr |= mask; \ 308 - res_idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ 309 - ioc->res_hint = res_idx + (size >> 3); \ 310 - goto resource_found; \ 311 - } \ 312 - } 305 + int ret;\ 306 + unsigned int idx;\ 307 + idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ 308 + ret = iommu_is_span_boundary(idx << 3, pages_needed, 0, boundary_size);\ 309 + if ((0 == (*res_ptr & mask)) && !ret) { \ 310 + *res_ptr |= mask; \ 311 + res_idx = idx;\ 312 + ioc->res_hint = res_idx + (size >> 3); \ 313 + goto resource_found; \ 314 + } \ 315 + } 313 316 314 317 #define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \ 315 318 u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ ··· 350 345 { 351 346 unsigned int pages_needed = size >> IOVP_SHIFT; 352 347 unsigned int res_idx; 348 + unsigned long boundary_size; 353 349 #ifdef CCIO_SEARCH_TIME 354 350 unsigned long cr_start = mfctl(16); 355 351 #endif ··· 365 359 ** "seek and ye shall find"...praying never hurts either... 366 360 ** ggg sacrifices another 710 to the computer gods. 367 361 */ 362 + 363 + boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, 1 << IOVP_SHIFT); 364 + boundary_size >>= IOVP_SHIFT; 368 365 369 366 if (pages_needed <= 8) { 370 367 /*
+37 -11
drivers/parisc/sba_iommu.c
··· 29 29 #include <linux/string.h> 30 30 #include <linux/pci.h> 31 31 #include <linux/scatterlist.h> 32 + #include <linux/iommu-helper.h> 32 33 33 34 #include <asm/byteorder.h> 34 35 #include <asm/io.h> ··· 314 313 #define RESMAP_MASK(n) (~0UL << (BITS_PER_LONG - (n))) 315 314 #define RESMAP_IDX_MASK (sizeof(unsigned long) - 1) 316 315 316 + unsigned long ptr_to_pide(struct ioc *ioc, unsigned long *res_ptr, 317 + unsigned int bitshiftcnt) 318 + { 319 + return (((unsigned long)res_ptr - (unsigned long)ioc->res_map) << 3) 320 + + bitshiftcnt; 321 + } 317 322 318 323 /** 319 324 * sba_search_bitmap - find free space in IO PDIR resource bitmap ··· 331 324 * Cool perf optimization: search for log2(size) bits at a time. 332 325 */ 333 326 static SBA_INLINE unsigned long 334 - sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) 327 + sba_search_bitmap(struct ioc *ioc, struct device *dev, 328 + unsigned long bits_wanted) 335 329 { 336 330 unsigned long *res_ptr = ioc->res_hint; 337 331 unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); 338 - unsigned long pide = ~0UL; 332 + unsigned long pide = ~0UL, tpide; 333 + unsigned long boundary_size; 334 + unsigned long shift; 335 + int ret; 336 + 337 + boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, 1 << IOVP_SHIFT); 338 + boundary_size >>= IOVP_SHIFT; 339 + 340 + #if defined(ZX1_SUPPORT) 341 + BUG_ON(ioc->ibase & ~IOVP_MASK); 342 + shift = ioc->ibase >> IOVP_SHIFT; 343 + #else 344 + shift = 0; 345 + #endif 339 346 340 347 if (bits_wanted > (BITS_PER_LONG/2)) { 341 348 /* Search word at a time - no mask needed */ 342 349 for(; res_ptr < res_end; ++res_ptr) { 343 - if (*res_ptr == 0) { 350 + tpide = ptr_to_pide(ioc, res_ptr, 0); 351 + ret = iommu_is_span_boundary(tpide, bits_wanted, 352 + shift, 353 + boundary_size); 354 + if ((*res_ptr == 0) && !ret) { 344 355 *res_ptr = RESMAP_MASK(bits_wanted); 345 - pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); 346 - pide <<= 3; /* convert to bit address */ 356 + pide = tpide; 347 357 break; 348 358 } 349 359 } ··· 389 365 { 390 366 DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr); 391 367 WARN_ON(mask == 0); 392 - if(((*res_ptr) & mask) == 0) { 368 + tpide = ptr_to_pide(ioc, res_ptr, bitshiftcnt); 369 + ret = iommu_is_span_boundary(tpide, bits_wanted, 370 + shift, 371 + boundary_size); 372 + if ((((*res_ptr) & mask) == 0) && !ret) { 393 373 *res_ptr |= mask; /* mark resources busy! */ 394 - pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); 395 - pide <<= 3; /* convert to bit address */ 396 - pide += bitshiftcnt; 374 + pide = tpide; 397 375 break; 398 376 } 399 377 mask >>= o; ··· 438 412 #endif 439 413 unsigned long pide; 440 414 441 - pide = sba_search_bitmap(ioc, pages_needed); 415 + pide = sba_search_bitmap(ioc, dev, pages_needed); 442 416 if (pide >= (ioc->res_size << 3)) { 443 - pide = sba_search_bitmap(ioc, pages_needed); 417 + pide = sba_search_bitmap(ioc, dev, pages_needed); 444 418 if (pide >= (ioc->res_size << 3)) 445 419 panic("%s: I/O MMU @ %p is out of mapping resources\n", 446 420 __FILE__, ioc->ioc_hpa);