diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2008-03-04 17:29:28 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-03-04 19:35:17 -0500 |
commit | 466634488e80968f12e73dd1fe6af5c37a1fbfe2 (patch) | |
tree | d738011402f57e5366c42bd4b2a525637ffdbcd1 /drivers | |
parent | 7c8cda625acd9b704100994626fb6d2fb4ffb9c2 (diff) |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/parisc/Kconfig | 5 | ||||
-rw-r--r-- | drivers/parisc/ccio-dma.c | 23 | ||||
-rw-r--r-- | drivers/parisc/sba_iommu.c | 48 |
3 files changed, 58 insertions, 18 deletions
diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig index 1d3b84b4af3f..553a9905299a 100644 --- a/drivers/parisc/Kconfig +++ b/drivers/parisc/Kconfig | |||
@@ -103,6 +103,11 @@ config IOMMU_SBA | |||
103 | depends on PCI_LBA | 103 | depends on PCI_LBA |
104 | default PCI_LBA | 104 | default PCI_LBA |
105 | 105 | ||
106 | config IOMMU_HELPER | ||
107 | bool | ||
108 | depends on IOMMU_SBA || IOMMU_CCIO | ||
109 | default y | ||
110 | |||
106 | #config PCI_EPIC | 111 | #config PCI_EPIC |
107 | # bool "EPIC/SAGA PCI support" | 112 | # bool "EPIC/SAGA PCI support" |
108 | # depends on PCI | 113 | # depends on PCI |
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 1695facfca3a..60d338cd8009 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/proc_fs.h> | 43 | #include <linux/proc_fs.h> |
44 | #include <linux/seq_file.h> | 44 | #include <linux/seq_file.h> |
45 | #include <linux/scatterlist.h> | 45 | #include <linux/scatterlist.h> |
46 | #include <linux/iommu-helper.h> | ||
46 | 47 | ||
47 | #include <asm/byteorder.h> | 48 | #include <asm/byteorder.h> |
48 | #include <asm/cache.h> /* for L1_CACHE_BYTES */ | 49 | #include <asm/cache.h> /* for L1_CACHE_BYTES */ |
@@ -302,13 +303,17 @@ static int ioc_count; | |||
302 | */ | 303 | */ |
303 | #define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size) \ | 304 | #define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size) \ |
304 | for(; res_ptr < res_end; ++res_ptr) { \ | 305 | for(; res_ptr < res_end; ++res_ptr) { \ |
305 | if(0 == (*res_ptr & mask)) { \ | 306 | int ret;\ |
306 | *res_ptr |= mask; \ | 307 | unsigned int idx;\ |
307 | res_idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ | 308 | idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ |
308 | ioc->res_hint = res_idx + (size >> 3); \ | 309 | ret = iommu_is_span_boundary(idx << 3, pages_needed, 0, boundary_size);\ |
309 | goto resource_found; \ | 310 | if ((0 == (*res_ptr & mask)) && !ret) { \ |
310 | } \ | 311 | *res_ptr |= mask; \ |
311 | } | 312 | res_idx = idx;\ |
313 | ioc->res_hint = res_idx + (size >> 3); \ | ||
314 | goto resource_found; \ | ||
315 | } \ | ||
316 | } | ||
312 | 317 | ||
313 | #define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \ | 318 | #define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \ |
314 | u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ | 319 | u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ |
@@ -345,6 +350,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) | |||
345 | { | 350 | { |
346 | unsigned int pages_needed = size >> IOVP_SHIFT; | 351 | unsigned int pages_needed = size >> IOVP_SHIFT; |
347 | unsigned int res_idx; | 352 | unsigned int res_idx; |
353 | unsigned long boundary_size; | ||
348 | #ifdef CCIO_SEARCH_TIME | 354 | #ifdef CCIO_SEARCH_TIME |
349 | unsigned long cr_start = mfctl(16); | 355 | unsigned long cr_start = mfctl(16); |
350 | #endif | 356 | #endif |
@@ -360,6 +366,9 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) | |||
360 | ** ggg sacrifices another 710 to the computer gods. | 366 | ** ggg sacrifices another 710 to the computer gods. |
361 | */ | 367 | */ |
362 | 368 | ||
369 | boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, 1 << IOVP_SHIFT); | ||
370 | boundary_size >>= IOVP_SHIFT; | ||
371 | |||
363 | if (pages_needed <= 8) { | 372 | if (pages_needed <= 8) { |
364 | /* | 373 | /* |
365 | * LAN traffic will not thrash the TLB IFF the same NIC | 374 | * LAN traffic will not thrash the TLB IFF the same NIC |
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 7d58bd2019b9..e834127a8505 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/string.h> | 29 | #include <linux/string.h> |
30 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
31 | #include <linux/scatterlist.h> | 31 | #include <linux/scatterlist.h> |
32 | #include <linux/iommu-helper.h> | ||
32 | 33 | ||
33 | #include <asm/byteorder.h> | 34 | #include <asm/byteorder.h> |
34 | #include <asm/io.h> | 35 | #include <asm/io.h> |
@@ -313,6 +314,12 @@ sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) | |||
313 | #define RESMAP_MASK(n) (~0UL << (BITS_PER_LONG - (n))) | 314 | #define RESMAP_MASK(n) (~0UL << (BITS_PER_LONG - (n))) |
314 | #define RESMAP_IDX_MASK (sizeof(unsigned long) - 1) | 315 | #define RESMAP_IDX_MASK (sizeof(unsigned long) - 1) |
315 | 316 | ||
317 | unsigned long ptr_to_pide(struct ioc *ioc, unsigned long *res_ptr, | ||
318 | unsigned int bitshiftcnt) | ||
319 | { | ||
320 | return (((unsigned long)res_ptr - (unsigned long)ioc->res_map) << 3) | ||
321 | + bitshiftcnt; | ||
322 | } | ||
316 | 323 | ||
317 | /** | 324 | /** |
318 | * sba_search_bitmap - find free space in IO PDIR resource bitmap | 325 | * sba_search_bitmap - find free space in IO PDIR resource bitmap |
@@ -324,19 +331,36 @@ sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) | |||
324 | * Cool perf optimization: search for log2(size) bits at a time. | 331 | * Cool perf optimization: search for log2(size) bits at a time. |
325 | */ | 332 | */ |
326 | static SBA_INLINE unsigned long | 333 | static SBA_INLINE unsigned long |
327 | sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) | 334 | sba_search_bitmap(struct ioc *ioc, struct device *dev, |
335 | unsigned long bits_wanted) | ||
328 | { | 336 | { |
329 | unsigned long *res_ptr = ioc->res_hint; | 337 | unsigned long *res_ptr = ioc->res_hint; |
330 | unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); | 338 | unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); |
331 | unsigned long pide = ~0UL; | 339 | unsigned long pide = ~0UL, tpide; |
340 | unsigned long boundary_size; | ||
341 | unsigned long shift; | ||
342 | int ret; | ||
343 | |||
344 | boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, 1 << IOVP_SHIFT); | ||
345 | boundary_size >>= IOVP_SHIFT; | ||
346 | |||
347 | #if defined(ZX1_SUPPORT) | ||
348 | BUG_ON(ioc->ibase & ~IOVP_MASK); | ||
349 | shift = ioc->ibase >> IOVP_SHIFT; | ||
350 | #else | ||
351 | shift = 0; | ||
352 | #endif | ||
332 | 353 | ||
333 | if (bits_wanted > (BITS_PER_LONG/2)) { | 354 | if (bits_wanted > (BITS_PER_LONG/2)) { |
334 | /* Search word at a time - no mask needed */ | 355 | /* Search word at a time - no mask needed */ |
335 | for(; res_ptr < res_end; ++res_ptr) { | 356 | for(; res_ptr < res_end; ++res_ptr) { |
336 | if (*res_ptr == 0) { | 357 | tpide = ptr_to_pide(ioc, res_ptr, 0); |
358 | ret = iommu_is_span_boundary(tpide, bits_wanted, | ||
359 | shift, | ||
360 | boundary_size); | ||
361 | if ((*res_ptr == 0) && !ret) { | ||
337 | *res_ptr = RESMAP_MASK(bits_wanted); | 362 | *res_ptr = RESMAP_MASK(bits_wanted); |
338 | pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); | 363 | pide = tpide; |
339 | pide <<= 3; /* convert to bit address */ | ||
340 | break; | 364 | break; |
341 | } | 365 | } |
342 | } | 366 | } |
@@ -365,11 +389,13 @@ sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) | |||
365 | { | 389 | { |
366 | DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr); | 390 | DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr); |
367 | WARN_ON(mask == 0); | 391 | WARN_ON(mask == 0); |
368 | if(((*res_ptr) & mask) == 0) { | 392 | tpide = ptr_to_pide(ioc, res_ptr, bitshiftcnt); |
393 | ret = iommu_is_span_boundary(tpide, bits_wanted, | ||
394 | shift, | ||
395 | boundary_size); | ||
396 | if ((((*res_ptr) & mask) == 0) && !ret) { | ||
369 | *res_ptr |= mask; /* mark resources busy! */ | 397 | *res_ptr |= mask; /* mark resources busy! */ |
370 | pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); | 398 | pide = tpide; |
371 | pide <<= 3; /* convert to bit address */ | ||
372 | pide += bitshiftcnt; | ||
373 | break; | 399 | break; |
374 | } | 400 | } |
375 | mask >>= o; | 401 | mask >>= o; |
@@ -412,9 +438,9 @@ sba_alloc_range(struct ioc *ioc, struct device *dev, size_t size) | |||
412 | #endif | 438 | #endif |
413 | unsigned long pide; | 439 | unsigned long pide; |
414 | 440 | ||
415 | pide = sba_search_bitmap(ioc, pages_needed); | 441 | pide = sba_search_bitmap(ioc, dev, pages_needed); |
416 | if (pide >= (ioc->res_size << 3)) { | 442 | if (pide >= (ioc->res_size << 3)) { |
417 | pide = sba_search_bitmap(ioc, pages_needed); | 443 | pide = sba_search_bitmap(ioc, dev, pages_needed); |
418 | if (pide >= (ioc->res_size << 3)) | 444 | if (pide >= (ioc->res_size << 3)) |
419 | panic("%s: I/O MMU @ %p is out of mapping resources\n", | 445 | panic("%s: I/O MMU @ %p is out of mapping resources\n", |
420 | __FILE__, ioc->ioc_hpa); | 446 | __FILE__, ioc->ioc_hpa); |