aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/iommu.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@huronp11.davemloft.net>2008-02-09 06:11:01 -0500
committerDavid S. Miller <davem@davemloft.net>2008-02-09 06:15:36 -0500
commit13fa14e185614066d96f90f09da08eebe58cbc8f (patch)
tree153e69e8ea564109b7509ad4a0ce6daacbedb860 /arch/sparc64/kernel/iommu.c
parentd284142cbad66832d5072a0aebeca7bd9ca841b7 (diff)
[SPARC64]: Add SG merging support back into IOMMU code.
Mimicks almost perfectly the powerpc IOMMU code, except that it doesn't have the IOMMU_PAGE_SIZE != PAGE_SIZE handling, and it also lacks the device dma mask support bits. I'll add that later as time permits, but this gets us at least back to where we were beforehand. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/iommu.c')
-rw-r--r--arch/sparc64/kernel/iommu.c231
1 files changed, 158 insertions, 73 deletions
diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c
index 90a5907080a1..d3276ebcfb47 100644
--- a/arch/sparc64/kernel/iommu.c
+++ b/arch/sparc64/kernel/iommu.c
@@ -512,124 +512,209 @@ static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr,
512static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, 512static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
513 int nelems, enum dma_data_direction direction) 513 int nelems, enum dma_data_direction direction)
514{ 514{
515 unsigned long flags, ctx, i, npages, iopte_protection; 515 struct scatterlist *s, *outs, *segstart;
516 struct scatterlist *sg; 516 unsigned long flags, handle, prot, ctx;
517 dma_addr_t dma_next = 0, dma_addr;
518 unsigned int max_seg_size;
519 int outcount, incount, i;
517 struct strbuf *strbuf; 520 struct strbuf *strbuf;
518 struct iommu *iommu; 521 struct iommu *iommu;
519 iopte_t *base; 522
520 u32 dma_base; 523 BUG_ON(direction == DMA_NONE);
521
522 /* Fast path single entry scatterlists. */
523 if (nelems == 1) {
524 sglist->dma_address =
525 dma_4u_map_single(dev, sg_virt(sglist),
526 sglist->length, direction);
527 if (unlikely(sglist->dma_address == DMA_ERROR_CODE))
528 return 0;
529 sglist->dma_length = sglist->length;
530 return 1;
531 }
532 524
533 iommu = dev->archdata.iommu; 525 iommu = dev->archdata.iommu;
534 strbuf = dev->archdata.stc; 526 strbuf = dev->archdata.stc;
535 527 if (nelems == 0 || !iommu)
536 if (unlikely(direction == DMA_NONE)) 528 return 0;
537 goto bad_no_ctx;
538
539 npages = calc_npages(sglist, nelems);
540 529
541 spin_lock_irqsave(&iommu->lock, flags); 530 spin_lock_irqsave(&iommu->lock, flags);
542 531
543 base = alloc_npages(dev, iommu, npages);
544 ctx = 0; 532 ctx = 0;
545 if (iommu->iommu_ctxflush) 533 if (iommu->iommu_ctxflush)
546 ctx = iommu_alloc_ctx(iommu); 534 ctx = iommu_alloc_ctx(iommu);
547 535
548 spin_unlock_irqrestore(&iommu->lock, flags);
549
550 if (base == NULL)
551 goto bad;
552
553 dma_base = iommu->page_table_map_base +
554 ((base - iommu->page_table) << IO_PAGE_SHIFT);
555
556 if (strbuf->strbuf_enabled) 536 if (strbuf->strbuf_enabled)
557 iopte_protection = IOPTE_STREAMING(ctx); 537 prot = IOPTE_STREAMING(ctx);
558 else 538 else
559 iopte_protection = IOPTE_CONSISTENT(ctx); 539 prot = IOPTE_CONSISTENT(ctx);
560 if (direction != DMA_TO_DEVICE) 540 if (direction != DMA_TO_DEVICE)
561 iopte_protection |= IOPTE_WRITE; 541 prot |= IOPTE_WRITE;
562 542
563 for_each_sg(sglist, sg, nelems, i) { 543 outs = s = segstart = &sglist[0];
564 unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg); 544 outcount = 1;
565 unsigned long slen = sg->length; 545 incount = nelems;
566 unsigned long this_npages; 546 handle = 0;
547
548 /* Init first segment length for backout at failure */
549 outs->dma_length = 0;
550
551 max_seg_size = dma_get_max_seg_size(dev);
552 for_each_sg(sglist, s, nelems, i) {
553 unsigned long paddr, npages, entry, slen;
554 iopte_t *base;
555
556 slen = s->length;
557 /* Sanity check */
558 if (slen == 0) {
559 dma_next = 0;
560 continue;
561 }
562 /* Allocate iommu entries for that segment */
563 paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s);
564 npages = iommu_num_pages(paddr, slen);
565 entry = iommu_range_alloc(dev, iommu, npages, &handle);
566
567 /* Handle failure */
568 if (unlikely(entry == DMA_ERROR_CODE)) {
569 if (printk_ratelimit())
570 printk(KERN_INFO "iommu_alloc failed, iommu %p paddr %lx"
571 " npages %lx\n", iommu, paddr, npages);
572 goto iommu_map_failed;
573 }
567 574
568 this_npages = iommu_num_pages(paddr, slen); 575 base = iommu->page_table + entry;
569 576
570 sg->dma_address = dma_base | (paddr & ~IO_PAGE_MASK); 577 /* Convert entry to a dma_addr_t */
571 sg->dma_length = slen; 578 dma_addr = iommu->page_table_map_base +
579 (entry << IO_PAGE_SHIFT);
580 dma_addr |= (s->offset & ~IO_PAGE_MASK);
572 581
582 /* Insert into HW table */
573 paddr &= IO_PAGE_MASK; 583 paddr &= IO_PAGE_MASK;
574 while (this_npages--) { 584 while (npages--) {
575 iopte_val(*base) = iopte_protection | paddr; 585 iopte_val(*base) = prot | paddr;
576
577 base++; 586 base++;
578 paddr += IO_PAGE_SIZE; 587 paddr += IO_PAGE_SIZE;
579 dma_base += IO_PAGE_SIZE;
580 } 588 }
589
590 /* If we are in an open segment, try merging */
591 if (segstart != s) {
592 /* We cannot merge if:
593 * - allocated dma_addr isn't contiguous to previous allocation
594 */
595 if ((dma_addr != dma_next) ||
596 (outs->dma_length + s->length > max_seg_size)) {
597 /* Can't merge: create a new segment */
598 segstart = s;
599 outcount++;
600 outs = sg_next(outs);
601 } else {
602 outs->dma_length += s->length;
603 }
604 }
605
606 if (segstart == s) {
607 /* This is a new segment, fill entries */
608 outs->dma_address = dma_addr;
609 outs->dma_length = slen;
610 }
611
612 /* Calculate next page pointer for contiguous check */
613 dma_next = dma_addr + slen;
581 } 614 }
582 615
583 return nelems; 616 spin_unlock_irqrestore(&iommu->lock, flags);
617
618 if (outcount < incount) {
619 outs = sg_next(outs);
620 outs->dma_address = DMA_ERROR_CODE;
621 outs->dma_length = 0;
622 }
623
624 return outcount;
625
626iommu_map_failed:
627 for_each_sg(sglist, s, nelems, i) {
628 if (s->dma_length != 0) {
629 unsigned long vaddr, npages, entry, i;
630 iopte_t *base;
631
632 vaddr = s->dma_address & IO_PAGE_MASK;
633 npages = iommu_num_pages(s->dma_address, s->dma_length);
634 iommu_range_free(iommu, vaddr, npages);
635
636 entry = (vaddr - iommu->page_table_map_base)
637 >> IO_PAGE_SHIFT;
638 base = iommu->page_table + entry;
639
640 for (i = 0; i < npages; i++)
641 iopte_make_dummy(iommu, base + i);
642
643 s->dma_address = DMA_ERROR_CODE;
644 s->dma_length = 0;
645 }
646 if (s == outs)
647 break;
648 }
649 spin_unlock_irqrestore(&iommu->lock, flags);
584 650
585bad:
586 iommu_free_ctx(iommu, ctx);
587bad_no_ctx:
588 if (printk_ratelimit())
589 WARN_ON(1);
590 return 0; 651 return 0;
591} 652}
592 653
654/* If contexts are being used, they are the same in all of the mappings
655 * we make for a particular SG.
656 */
657static unsigned long fetch_sg_ctx(struct iommu *iommu, struct scatterlist *sg)
658{
659 unsigned long ctx = 0;
660
661 if (iommu->iommu_ctxflush) {
662 iopte_t *base;
663 u32 bus_addr;
664
665 bus_addr = sg->dma_address & IO_PAGE_MASK;
666 base = iommu->page_table +
667 ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
668
669 ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
670 }
671 return ctx;
672}
673
593static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, 674static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
594 int nelems, enum dma_data_direction direction) 675 int nelems, enum dma_data_direction direction)
595{ 676{
596 unsigned long flags, ctx, i, npages; 677 unsigned long flags, ctx;
678 struct scatterlist *sg;
597 struct strbuf *strbuf; 679 struct strbuf *strbuf;
598 struct iommu *iommu; 680 struct iommu *iommu;
599 iopte_t *base;
600 u32 bus_addr;
601 681
602 if (unlikely(direction == DMA_NONE)) { 682 BUG_ON(direction == DMA_NONE);
603 if (printk_ratelimit())
604 WARN_ON(1);
605 }
606 683
607 iommu = dev->archdata.iommu; 684 iommu = dev->archdata.iommu;
608 strbuf = dev->archdata.stc; 685 strbuf = dev->archdata.stc;
609 686
610 bus_addr = sglist->dma_address & IO_PAGE_MASK; 687 ctx = fetch_sg_ctx(iommu, sglist);
611 688
612 npages = calc_npages(sglist, nelems); 689 spin_lock_irqsave(&iommu->lock, flags);
613 690
614 base = iommu->page_table + 691 sg = sglist;
615 ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); 692 while (nelems--) {
693 dma_addr_t dma_handle = sg->dma_address;
694 unsigned int len = sg->dma_length;
695 unsigned long npages, entry;
696 iopte_t *base;
697 int i;
616 698
617 spin_lock_irqsave(&iommu->lock, flags); 699 if (!len)
700 break;
701 npages = iommu_num_pages(dma_handle, len);
702 iommu_range_free(iommu, dma_handle, npages);
618 703
619 /* Record the context, if any. */ 704 entry = ((dma_handle - iommu->page_table_map_base)
620 ctx = 0; 705 >> IO_PAGE_SHIFT);
621 if (iommu->iommu_ctxflush) 706 base = iommu->page_table + entry;
622 ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
623 707
624 /* Step 1: Kick data out of streaming buffers if necessary. */ 708 dma_handle &= IO_PAGE_MASK;
625 if (strbuf->strbuf_enabled) 709 if (strbuf->strbuf_enabled)
626 strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); 710 strbuf_flush(strbuf, iommu, dma_handle, ctx,
711 npages, direction);
627 712
628 /* Step 2: Clear out the TSB entries. */ 713 for (i = 0; i < npages; i++)
629 for (i = 0; i < npages; i++) 714 iopte_make_dummy(iommu, base + i);
630 iopte_make_dummy(iommu, base + i);
631 715
632 iommu_range_free(iommu, bus_addr, npages); 716 sg = sg_next(sg);
717 }
633 718
634 iommu_free_ctx(iommu, ctx); 719 iommu_free_ctx(iommu, ctx);
635 720