diff options
| -rw-r--r-- | arch/ia64/Kconfig | 3 | ||||
| -rw-r--r-- | arch/ia64/hp/common/sba_iommu.c | 56 |
2 files changed, 42 insertions, 17 deletions
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 8fa3faf5ef1b..1b73ffe746d9 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
| @@ -611,6 +611,9 @@ config IRQ_PER_CPU | |||
| 611 | bool | 611 | bool |
| 612 | default y | 612 | default y |
| 613 | 613 | ||
| 614 | config IOMMU_HELPER | ||
| 615 | def_bool (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC) | ||
| 616 | |||
| 614 | source "arch/ia64/hp/sim/Kconfig" | 617 | source "arch/ia64/hp/sim/Kconfig" |
| 615 | 618 | ||
| 616 | source "arch/ia64/Kconfig.debug" | 619 | source "arch/ia64/Kconfig.debug" |
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 | } |
