diff options
Diffstat (limited to 'arch/ia64/hp/common/sba_iommu.c')
-rw-r--r-- | arch/ia64/hp/common/sba_iommu.c | 56 |
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 | ||
464 | static 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 | */ |
473 | static SBA_INLINE unsigned long | 481 | static SBA_INLINE unsigned long |
474 | sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted, int use_hint) | 482 | sba_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 | */ |
607 | static int | 629 | static int |
608 | sba_alloc_range(struct ioc *ioc, size_t size) | 630 | sba_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 | } |