diff options
Diffstat (limited to 'arch/sparc64')
| -rw-r--r-- | arch/sparc64/kernel/iommu.c | 39 | ||||
| -rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 32 |
2 files changed, 43 insertions, 28 deletions
diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c index b35a62167e9c..db3ffcf7a120 100644 --- a/arch/sparc64/kernel/iommu.c +++ b/arch/sparc64/kernel/iommu.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/device.h> | 10 | #include <linux/device.h> |
| 11 | #include <linux/dma-mapping.h> | 11 | #include <linux/dma-mapping.h> |
| 12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
| 13 | #include <linux/scatterlist.h> | ||
| 13 | 14 | ||
| 14 | #ifdef CONFIG_PCI | 15 | #ifdef CONFIG_PCI |
| 15 | #include <linux/pci.h> | 16 | #include <linux/pci.h> |
| @@ -480,7 +481,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, | |||
| 480 | unsigned long iopte_protection) | 481 | unsigned long iopte_protection) |
| 481 | { | 482 | { |
| 482 | struct scatterlist *dma_sg = sg; | 483 | struct scatterlist *dma_sg = sg; |
| 483 | struct scatterlist *sg_end = sg + nelems; | 484 | struct scatterlist *sg_end = sg_last(sg, nelems); |
| 484 | int i; | 485 | int i; |
| 485 | 486 | ||
| 486 | for (i = 0; i < nused; i++) { | 487 | for (i = 0; i < nused; i++) { |
| @@ -515,7 +516,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, | |||
| 515 | len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); | 516 | len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); |
| 516 | break; | 517 | break; |
| 517 | } | 518 | } |
| 518 | sg++; | 519 | sg = sg_next(sg); |
| 519 | } | 520 | } |
| 520 | 521 | ||
| 521 | pteval = iopte_protection | (pteval & IOPTE_PAGE); | 522 | pteval = iopte_protection | (pteval & IOPTE_PAGE); |
| @@ -528,24 +529,24 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, | |||
| 528 | } | 529 | } |
| 529 | 530 | ||
| 530 | pteval = (pteval & IOPTE_PAGE) + len; | 531 | pteval = (pteval & IOPTE_PAGE) + len; |
| 531 | sg++; | 532 | sg = sg_next(sg); |
| 532 | 533 | ||
| 533 | /* Skip over any tail mappings we've fully mapped, | 534 | /* Skip over any tail mappings we've fully mapped, |
| 534 | * adjusting pteval along the way. Stop when we | 535 | * adjusting pteval along the way. Stop when we |
| 535 | * detect a page crossing event. | 536 | * detect a page crossing event. |
| 536 | */ | 537 | */ |
| 537 | while (sg < sg_end && | 538 | while (sg != sg_end && |
| 538 | (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && | 539 | (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && |
| 539 | (pteval == SG_ENT_PHYS_ADDRESS(sg)) && | 540 | (pteval == SG_ENT_PHYS_ADDRESS(sg)) && |
| 540 | ((pteval ^ | 541 | ((pteval ^ |
| 541 | (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { | 542 | (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { |
| 542 | pteval += sg->length; | 543 | pteval += sg->length; |
| 543 | sg++; | 544 | sg = sg_next(sg); |
| 544 | } | 545 | } |
| 545 | if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) | 546 | if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) |
| 546 | pteval = ~0UL; | 547 | pteval = ~0UL; |
| 547 | } while (dma_npages != 0); | 548 | } while (dma_npages != 0); |
| 548 | dma_sg++; | 549 | dma_sg = sg_next(dma_sg); |
| 549 | } | 550 | } |
| 550 | } | 551 | } |
| 551 | 552 | ||
| @@ -606,7 +607,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, | |||
| 606 | sgtmp = sglist; | 607 | sgtmp = sglist; |
| 607 | while (used && sgtmp->dma_length) { | 608 | while (used && sgtmp->dma_length) { |
| 608 | sgtmp->dma_address += dma_base; | 609 | sgtmp->dma_address += dma_base; |
| 609 | sgtmp++; | 610 | sgtmp = sg_next(sgtmp); |
| 610 | used--; | 611 | used--; |
| 611 | } | 612 | } |
| 612 | used = nelems - used; | 613 | used = nelems - used; |
| @@ -642,6 +643,7 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, | |||
| 642 | struct strbuf *strbuf; | 643 | struct strbuf *strbuf; |
| 643 | iopte_t *base; | 644 | iopte_t *base; |
| 644 | unsigned long flags, ctx, i, npages; | 645 | unsigned long flags, ctx, i, npages; |
| 646 | struct scatterlist *sg, *sgprv; | ||
| 645 | u32 bus_addr; | 647 | u32 bus_addr; |
| 646 | 648 | ||
| 647 | if (unlikely(direction == DMA_NONE)) { | 649 | if (unlikely(direction == DMA_NONE)) { |
| @@ -654,11 +656,14 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, | |||
| 654 | 656 | ||
| 655 | bus_addr = sglist->dma_address & IO_PAGE_MASK; | 657 | bus_addr = sglist->dma_address & IO_PAGE_MASK; |
| 656 | 658 | ||
| 657 | for (i = 1; i < nelems; i++) | 659 | sgprv = NULL; |
| 658 | if (sglist[i].dma_length == 0) | 660 | for_each_sg(sglist, sg, nelems, i) { |
| 661 | if (sg->dma_length == 0) | ||
| 659 | break; | 662 | break; |
| 660 | i--; | 663 | sgprv = sg; |
| 661 | npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - | 664 | } |
| 665 | |||
| 666 | npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) - | ||
| 662 | bus_addr) >> IO_PAGE_SHIFT; | 667 | bus_addr) >> IO_PAGE_SHIFT; |
| 663 | 668 | ||
| 664 | base = iommu->page_table + | 669 | base = iommu->page_table + |
| @@ -730,6 +735,7 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev, | |||
| 730 | struct iommu *iommu; | 735 | struct iommu *iommu; |
| 731 | struct strbuf *strbuf; | 736 | struct strbuf *strbuf; |
| 732 | unsigned long flags, ctx, npages, i; | 737 | unsigned long flags, ctx, npages, i; |
| 738 | struct scatterlist *sg, *sgprv; | ||
| 733 | u32 bus_addr; | 739 | u32 bus_addr; |
| 734 | 740 | ||
| 735 | iommu = dev->archdata.iommu; | 741 | iommu = dev->archdata.iommu; |
| @@ -753,11 +759,14 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev, | |||
| 753 | 759 | ||
| 754 | /* Step 2: Kick data out of streaming buffers. */ | 760 | /* Step 2: Kick data out of streaming buffers. */ |
| 755 | bus_addr = sglist[0].dma_address & IO_PAGE_MASK; | 761 | bus_addr = sglist[0].dma_address & IO_PAGE_MASK; |
| 756 | for(i = 1; i < nelems; i++) | 762 | sgprv = NULL; |
| 757 | if (!sglist[i].dma_length) | 763 | for_each_sg(sglist, sg, nelems, i) { |
| 764 | if (sg->dma_length == 0) | ||
| 758 | break; | 765 | break; |
| 759 | i--; | 766 | sgprv = sg; |
| 760 | npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) | 767 | } |
| 768 | |||
| 769 | npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) | ||
| 761 | - bus_addr) >> IO_PAGE_SHIFT; | 770 | - bus_addr) >> IO_PAGE_SHIFT; |
| 762 | strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); | 771 | strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); |
| 763 | 772 | ||
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 95de1444ee67..cacacfae5451 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
| 14 | #include <linux/msi.h> | 14 | #include <linux/msi.h> |
| 15 | #include <linux/log2.h> | 15 | #include <linux/log2.h> |
| 16 | #include <linux/scatterlist.h> | ||
| 16 | 17 | ||
| 17 | #include <asm/iommu.h> | 18 | #include <asm/iommu.h> |
| 18 | #include <asm/irq.h> | 19 | #include <asm/irq.h> |
| @@ -373,7 +374,7 @@ static inline long fill_sg(long entry, struct device *dev, | |||
| 373 | int nused, int nelems, unsigned long prot) | 374 | int nused, int nelems, unsigned long prot) |
| 374 | { | 375 | { |
| 375 | struct scatterlist *dma_sg = sg; | 376 | struct scatterlist *dma_sg = sg; |
| 376 | struct scatterlist *sg_end = sg + nelems; | 377 | struct scatterlist *sg_end = sg_last(sg, nelems); |
| 377 | unsigned long flags; | 378 | unsigned long flags; |
| 378 | int i; | 379 | int i; |
| 379 | 380 | ||
| @@ -413,7 +414,7 @@ static inline long fill_sg(long entry, struct device *dev, | |||
| 413 | len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); | 414 | len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); |
| 414 | break; | 415 | break; |
| 415 | } | 416 | } |
| 416 | sg++; | 417 | sg = sg_next(sg); |
| 417 | } | 418 | } |
| 418 | 419 | ||
| 419 | pteval = (pteval & IOPTE_PAGE); | 420 | pteval = (pteval & IOPTE_PAGE); |
| @@ -431,24 +432,25 @@ static inline long fill_sg(long entry, struct device *dev, | |||
| 431 | } | 432 | } |
| 432 | 433 | ||
| 433 | pteval = (pteval & IOPTE_PAGE) + len; | 434 | pteval = (pteval & IOPTE_PAGE) + len; |
| 434 | sg++; | 435 | sg = sg_next(sg); |
| 435 | 436 | ||
| 436 | /* Skip over any tail mappings we've fully mapped, | 437 | /* Skip over any tail mappings we've fully mapped, |
| 437 | * adjusting pteval along the way. Stop when we | 438 | * adjusting pteval along the way. Stop when we |
| 438 | * detect a page crossing event. | 439 | * detect a page crossing event. |
| 439 | */ | 440 | */ |
| 440 | while (sg < sg_end && | 441 | while ((pteval << (64 - IO_PAGE_SHIFT)) != 0UL && |
| 441 | (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && | ||
| 442 | (pteval == SG_ENT_PHYS_ADDRESS(sg)) && | 442 | (pteval == SG_ENT_PHYS_ADDRESS(sg)) && |
| 443 | ((pteval ^ | 443 | ((pteval ^ |
| 444 | (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { | 444 | (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { |
| 445 | pteval += sg->length; | 445 | pteval += sg->length; |
| 446 | sg++; | 446 | if (sg == sg_end) |
| 447 | break; | ||
| 448 | sg = sg_next(sg); | ||
| 447 | } | 449 | } |
| 448 | if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) | 450 | if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) |
| 449 | pteval = ~0UL; | 451 | pteval = ~0UL; |
| 450 | } while (dma_npages != 0); | 452 | } while (dma_npages != 0); |
| 451 | dma_sg++; | 453 | dma_sg = sg_next(dma_sg); |
| 452 | } | 454 | } |
| 453 | 455 | ||
| 454 | if (unlikely(iommu_batch_end() < 0L)) | 456 | if (unlikely(iommu_batch_end() < 0L)) |
| @@ -510,7 +512,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, | |||
| 510 | sgtmp = sglist; | 512 | sgtmp = sglist; |
| 511 | while (used && sgtmp->dma_length) { | 513 | while (used && sgtmp->dma_length) { |
| 512 | sgtmp->dma_address += dma_base; | 514 | sgtmp->dma_address += dma_base; |
| 513 | sgtmp++; | 515 | sgtmp = sg_next(sgtmp); |
| 514 | used--; | 516 | used--; |
| 515 | } | 517 | } |
| 516 | used = nelems - used; | 518 | used = nelems - used; |
| @@ -545,6 +547,7 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, | |||
| 545 | struct pci_pbm_info *pbm; | 547 | struct pci_pbm_info *pbm; |
| 546 | struct iommu *iommu; | 548 | struct iommu *iommu; |
| 547 | unsigned long flags, i, npages; | 549 | unsigned long flags, i, npages; |
| 550 | struct scatterlist *sg, *sgprv; | ||
| 548 | long entry; | 551 | long entry; |
| 549 | u32 devhandle, bus_addr; | 552 | u32 devhandle, bus_addr; |
| 550 | 553 | ||
| @@ -558,12 +561,15 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, | |||
| 558 | devhandle = pbm->devhandle; | 561 | devhandle = pbm->devhandle; |
| 559 | 562 | ||
| 560 | bus_addr = sglist->dma_address & IO_PAGE_MASK; | 563 | bus_addr = sglist->dma_address & IO_PAGE_MASK; |
| 561 | 564 | sgprv = NULL; | |
| 562 | for (i = 1; i < nelems; i++) | 565 | for_each_sg(sglist, sg, nelems, i) { |
| 563 | if (sglist[i].dma_length == 0) | 566 | if (sg->dma_length == 0) |
| 564 | break; | 567 | break; |
| 565 | i--; | 568 | |
| 566 | npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - | 569 | sgprv = sg; |
| 570 | } | ||
| 571 | |||
| 572 | npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) - | ||
| 567 | bus_addr) >> IO_PAGE_SHIFT; | 573 | bus_addr) >> IO_PAGE_SHIFT; |
| 568 | 574 | ||
| 569 | entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); | 575 | entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); |
