diff options
Diffstat (limited to 'arch/sparc64/kernel/pci_sun4v.c')
-rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 32 |
1 files changed, 19 insertions, 13 deletions
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); |