aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/hp/common
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2008-03-28 17:27:03 -0400
committerTony Luck <tony.luck@intel.com>2008-04-09 13:37:21 -0400
commitb34eb53cdcb4f49fd31d78d0e385240820ed9063 (patch)
treefc0bf8ab64fb703bd9a7c104973cd488719f52ab /arch/ia64/hp/common
parent34e1ceb1881ec895ad9b1b52d073f414f3aa87a9 (diff)
[IA64] make IOMMU respect the segment boundary limits
IA64's IOMMU implementation allocates memory areas spanning LLD's segment boundary limit. It forces low level drivers to have a workaround to adjust scatter lists that the IOMMU builds. We are in the process of making all the IOMMUs respect the segment boundary limits to remove such work around in LLDs. This patch is for IA64's IOMMU. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/hp/common')
-rw-r--r--arch/ia64/hp/common/sba_iommu.c56
1 files changed, 39 insertions, 17 deletions
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 523eae6d3e49..9409de5c9441 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -35,6 +35,7 @@
35#include <linux/nodemask.h> 35#include <linux/nodemask.h>
36#include <linux/bitops.h> /* hweight64() */ 36#include <linux/bitops.h> /* hweight64() */
37#include <linux/crash_dump.h> 37#include <linux/crash_dump.h>
38#include <linux/iommu-helper.h>
38 39
39#include <asm/delay.h> /* ia64_get_itc() */ 40#include <asm/delay.h> /* ia64_get_itc() */
40#include <asm/io.h> 41#include <asm/io.h>
@@ -460,6 +461,13 @@ get_iovp_order (unsigned long size)
460 return order; 461 return order;
461} 462}
462 463
464static unsigned long ptr_to_pide(struct ioc *ioc, unsigned long *res_ptr,
465 unsigned int bitshiftcnt)
466{
467 return (((unsigned long)res_ptr - (unsigned long)ioc->res_map) << 3)
468 + bitshiftcnt;
469}
470
463/** 471/**
464 * sba_search_bitmap - find free space in IO PDIR resource bitmap 472 * sba_search_bitmap - find free space in IO PDIR resource bitmap
465 * @ioc: IO MMU structure which owns the pdir we are interested in. 473 * @ioc: IO MMU structure which owns the pdir we are interested in.
@@ -471,15 +479,25 @@ get_iovp_order (unsigned long size)
471 * Cool perf optimization: search for log2(size) bits at a time. 479 * Cool perf optimization: search for log2(size) bits at a time.
472 */ 480 */
473static SBA_INLINE unsigned long 481static SBA_INLINE unsigned long
474sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted, int use_hint) 482sba_search_bitmap(struct ioc *ioc, struct device *dev,
483 unsigned long bits_wanted, int use_hint)
475{ 484{
476 unsigned long *res_ptr; 485 unsigned long *res_ptr;
477 unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); 486 unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]);
478 unsigned long flags, pide = ~0UL; 487 unsigned long flags, pide = ~0UL, tpide;
488 unsigned long boundary_size;
489 unsigned long shift;
490 int ret;
479 491
480 ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0); 492 ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0);
481 ASSERT(res_ptr < res_end); 493 ASSERT(res_ptr < res_end);
482 494
495 boundary_size = (unsigned long long)dma_get_seg_boundary(dev) + 1;
496 boundary_size = ALIGN(boundary_size, 1ULL << iovp_shift) >> iovp_shift;
497
498 BUG_ON(ioc->ibase & ~iovp_mask);
499 shift = ioc->ibase >> iovp_shift;
500
483 spin_lock_irqsave(&ioc->res_lock, flags); 501 spin_lock_irqsave(&ioc->res_lock, flags);
484 502
485 /* Allow caller to force a search through the entire resource space */ 503 /* Allow caller to force a search through the entire resource space */
@@ -504,9 +522,7 @@ sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted, int use_hint)
504 if (likely(*res_ptr != ~0UL)) { 522 if (likely(*res_ptr != ~0UL)) {
505 bitshiftcnt = ffz(*res_ptr); 523 bitshiftcnt = ffz(*res_ptr);
506 *res_ptr |= (1UL << bitshiftcnt); 524 *res_ptr |= (1UL << bitshiftcnt);
507 pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); 525 pide = ptr_to_pide(ioc, res_ptr, bitshiftcnt);
508 pide <<= 3; /* convert to bit address */
509 pide += bitshiftcnt;
510 ioc->res_bitshift = bitshiftcnt + bits_wanted; 526 ioc->res_bitshift = bitshiftcnt + bits_wanted;
511 goto found_it; 527 goto found_it;
512 } 528 }
@@ -535,11 +551,13 @@ sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted, int use_hint)
535 DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr); 551 DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr);
536 ASSERT(0 != mask); 552 ASSERT(0 != mask);
537 for (; mask ; mask <<= o, bitshiftcnt += o) { 553 for (; mask ; mask <<= o, bitshiftcnt += o) {
538 if(0 == ((*res_ptr) & mask)) { 554 tpide = ptr_to_pide(ioc, res_ptr, bitshiftcnt);
555 ret = iommu_is_span_boundary(tpide, bits_wanted,
556 shift,
557 boundary_size);
558 if ((0 == ((*res_ptr) & mask)) && !ret) {
539 *res_ptr |= mask; /* mark resources busy! */ 559 *res_ptr |= mask; /* mark resources busy! */
540 pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); 560 pide = tpide;
541 pide <<= 3; /* convert to bit address */
542 pide += bitshiftcnt;
543 ioc->res_bitshift = bitshiftcnt + bits_wanted; 561 ioc->res_bitshift = bitshiftcnt + bits_wanted;
544 goto found_it; 562 goto found_it;
545 } 563 }
@@ -560,6 +578,11 @@ sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted, int use_hint)
560 end = res_end - qwords; 578 end = res_end - qwords;
561 579
562 for (; res_ptr < end; res_ptr++) { 580 for (; res_ptr < end; res_ptr++) {
581 tpide = ptr_to_pide(ioc, res_ptr, 0);
582 ret = iommu_is_span_boundary(tpide, bits_wanted,
583 shift, boundary_size);
584 if (ret)
585 goto next_ptr;
563 for (i = 0 ; i < qwords ; i++) { 586 for (i = 0 ; i < qwords ; i++) {
564 if (res_ptr[i] != 0) 587 if (res_ptr[i] != 0)
565 goto next_ptr; 588 goto next_ptr;
@@ -572,8 +595,7 @@ sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted, int use_hint)
572 res_ptr[i] = ~0UL; 595 res_ptr[i] = ~0UL;
573 res_ptr[i] |= RESMAP_MASK(bits); 596 res_ptr[i] |= RESMAP_MASK(bits);
574 597
575 pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); 598 pide = tpide;
576 pide <<= 3; /* convert to bit address */
577 res_ptr += qwords; 599 res_ptr += qwords;
578 ioc->res_bitshift = bits; 600 ioc->res_bitshift = bits;
579 goto found_it; 601 goto found_it;
@@ -605,7 +627,7 @@ found_it:
605 * resource bit map. 627 * resource bit map.
606 */ 628 */
607static int 629static int
608sba_alloc_range(struct ioc *ioc, size_t size) 630sba_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
609{ 631{
610 unsigned int pages_needed = size >> iovp_shift; 632 unsigned int pages_needed = size >> iovp_shift;
611#ifdef PDIR_SEARCH_TIMING 633#ifdef PDIR_SEARCH_TIMING
@@ -622,9 +644,9 @@ sba_alloc_range(struct ioc *ioc, size_t size)
622 /* 644 /*
623 ** "seek and ye shall find"...praying never hurts either... 645 ** "seek and ye shall find"...praying never hurts either...
624 */ 646 */
625 pide = sba_search_bitmap(ioc, pages_needed, 1); 647 pide = sba_search_bitmap(ioc, dev, pages_needed, 1);
626 if (unlikely(pide >= (ioc->res_size << 3))) { 648 if (unlikely(pide >= (ioc->res_size << 3))) {
627 pide = sba_search_bitmap(ioc, pages_needed, 0); 649 pide = sba_search_bitmap(ioc, dev, pages_needed, 0);
628 if (unlikely(pide >= (ioc->res_size << 3))) { 650 if (unlikely(pide >= (ioc->res_size << 3))) {
629#if DELAYED_RESOURCE_CNT > 0 651#if DELAYED_RESOURCE_CNT > 0
630 unsigned long flags; 652 unsigned long flags;
@@ -653,7 +675,7 @@ sba_alloc_range(struct ioc *ioc, size_t size)
653 } 675 }
654 spin_unlock_irqrestore(&ioc->saved_lock, flags); 676 spin_unlock_irqrestore(&ioc->saved_lock, flags);
655 677
656 pide = sba_search_bitmap(ioc, pages_needed, 0); 678 pide = sba_search_bitmap(ioc, dev, pages_needed, 0);
657 if (unlikely(pide >= (ioc->res_size << 3))) 679 if (unlikely(pide >= (ioc->res_size << 3)))
658 panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n", 680 panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n",
659 ioc->ioc_hpa); 681 ioc->ioc_hpa);
@@ -936,7 +958,7 @@ sba_map_single(struct device *dev, void *addr, size_t size, int dir)
936 spin_unlock_irqrestore(&ioc->res_lock, flags); 958 spin_unlock_irqrestore(&ioc->res_lock, flags);
937#endif 959#endif
938 960
939 pide = sba_alloc_range(ioc, size); 961 pide = sba_alloc_range(ioc, dev, size);
940 962
941 iovp = (dma_addr_t) pide << iovp_shift; 963 iovp = (dma_addr_t) pide << iovp_shift;
942 964
@@ -1373,7 +1395,7 @@ sba_coalesce_chunks(struct ioc *ioc, struct device *dev,
1373 dma_len = (dma_len + dma_offset + ~iovp_mask) & iovp_mask; 1395 dma_len = (dma_len + dma_offset + ~iovp_mask) & iovp_mask;
1374 ASSERT(dma_len <= DMA_CHUNK_SIZE); 1396 ASSERT(dma_len <= DMA_CHUNK_SIZE);
1375 dma_sg->dma_address = (dma_addr_t) (PIDE_FLAG 1397 dma_sg->dma_address = (dma_addr_t) (PIDE_FLAG
1376 | (sba_alloc_range(ioc, dma_len) << iovp_shift) 1398 | (sba_alloc_range(ioc, dev, dma_len) << iovp_shift)
1377 | dma_offset); 1399 | dma_offset);
1378 n_mappings++; 1400 n_mappings++;
1379 } 1401 }