aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/pci_sun4v.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/pci_sun4v.c')
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c32
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);