aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/pci_sun4v.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@huronp11.davemloft.net>2008-02-06 06:50:26 -0500
committerDavid S. Miller <davem@davemloft.net>2008-02-06 07:12:25 -0500
commit38192d52f159bc06b7f523800c10b583cdd661d5 (patch)
tree4cf695d583c0a657133642c0299cbfa536e25663 /arch/sparc64/kernel/pci_sun4v.c
parentb3ff81dd8ae29ec431f6cc91aff601a51ef6fb8c (diff)
[SPARC64]: Temporarily remove IOMMU merging code.
Changeset fde6a3c82d67f592eb587be4d12222b0ae6d4321 ("iommu sg merging: sparc64: make iommu respect the segment size limits") broke sparc64 because whilst it added the segment limiting code to the first pass of SG mapping (in prepare_sg()) it did not add matching code to the second pass handling (in fill_sg()) As a result the two passes disagree where the segment boundaries should be, resulting in OOPSes, DMA corruption, and corrupted superblocks. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/pci_sun4v.c')
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c170
1 files changed, 39 insertions, 131 deletions
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 5ea2eab1ccda..61baf8dc095e 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -365,113 +365,14 @@ static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr,
365 spin_unlock_irqrestore(&iommu->lock, flags); 365 spin_unlock_irqrestore(&iommu->lock, flags);
366} 366}
367 367
368#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG))))
369
370static long fill_sg(long entry, struct device *dev,
371 struct scatterlist *sg,
372 int nused, int nelems, unsigned long prot)
373{
374 struct scatterlist *dma_sg = sg;
375 unsigned long flags;
376 int i;
377
378 local_irq_save(flags);
379
380 iommu_batch_start(dev, prot, entry);
381
382 for (i = 0; i < nused; i++) {
383 unsigned long pteval = ~0UL;
384 u32 dma_npages;
385
386 dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
387 dma_sg->dma_length +
388 ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
389 do {
390 unsigned long offset;
391 signed int len;
392
393 /* If we are here, we know we have at least one
394 * more page to map. So walk forward until we
395 * hit a page crossing, and begin creating new
396 * mappings from that spot.
397 */
398 for (;;) {
399 unsigned long tmp;
400
401 tmp = SG_ENT_PHYS_ADDRESS(sg);
402 len = sg->length;
403 if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
404 pteval = tmp & IO_PAGE_MASK;
405 offset = tmp & (IO_PAGE_SIZE - 1UL);
406 break;
407 }
408 if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
409 pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
410 offset = 0UL;
411 len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
412 break;
413 }
414 sg = sg_next(sg);
415 nelems--;
416 }
417
418 pteval = (pteval & IOPTE_PAGE);
419 while (len > 0) {
420 long err;
421
422 err = iommu_batch_add(pteval);
423 if (unlikely(err < 0L))
424 goto iommu_map_failed;
425
426 pteval += IO_PAGE_SIZE;
427 len -= (IO_PAGE_SIZE - offset);
428 offset = 0;
429 dma_npages--;
430 }
431
432 pteval = (pteval & IOPTE_PAGE) + len;
433 sg = sg_next(sg);
434 nelems--;
435
436 /* Skip over any tail mappings we've fully mapped,
437 * adjusting pteval along the way. Stop when we
438 * detect a page crossing event.
439 */
440 while (nelems &&
441 (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
442 (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
443 ((pteval ^
444 (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
445 pteval += sg->length;
446 sg = sg_next(sg);
447 nelems--;
448 }
449 if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
450 pteval = ~0UL;
451 } while (dma_npages != 0);
452 dma_sg = sg_next(dma_sg);
453 }
454
455 if (unlikely(iommu_batch_end() < 0L))
456 goto iommu_map_failed;
457
458 local_irq_restore(flags);
459 return 0;
460
461iommu_map_failed:
462 local_irq_restore(flags);
463 return -1L;
464}
465
466static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, 368static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
467 int nelems, enum dma_data_direction direction) 369 int nelems, enum dma_data_direction direction)
468{ 370{
371 unsigned long flags, npages, i, prot;
372 struct scatterlist *sg;
469 struct iommu *iommu; 373 struct iommu *iommu;
470 unsigned long flags, npages, prot;
471 u32 dma_base;
472 struct scatterlist *sgtmp;
473 long entry, err; 374 long entry, err;
474 int used; 375 u32 dma_base;
475 376
476 /* Fast path single entry scatterlists. */ 377 /* Fast path single entry scatterlists. */
477 if (nelems == 1) { 378 if (nelems == 1) {
@@ -489,10 +390,8 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
489 if (unlikely(direction == DMA_NONE)) 390 if (unlikely(direction == DMA_NONE))
490 goto bad; 391 goto bad;
491 392
492 /* Step 1: Prepare scatter list. */ 393 npages = calc_npages(sglist, nelems);
493 npages = prepare_sg(dev, sglist, nelems);
494 394
495 /* Step 2: Allocate a cluster and context, if necessary. */
496 spin_lock_irqsave(&iommu->lock, flags); 395 spin_lock_irqsave(&iommu->lock, flags);
497 entry = arena_alloc(&iommu->arena, npages); 396 entry = arena_alloc(&iommu->arena, npages);
498 spin_unlock_irqrestore(&iommu->lock, flags); 397 spin_unlock_irqrestore(&iommu->lock, flags);
@@ -503,27 +402,45 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
503 dma_base = iommu->page_table_map_base + 402 dma_base = iommu->page_table_map_base +
504 (entry << IO_PAGE_SHIFT); 403 (entry << IO_PAGE_SHIFT);
505 404
506 /* Step 3: Normalize DMA addresses. */
507 used = nelems;
508
509 sgtmp = sglist;
510 while (used && sgtmp->dma_length) {
511 sgtmp->dma_address += dma_base;
512 sgtmp = sg_next(sgtmp);
513 used--;
514 }
515 used = nelems - used;
516
517 /* Step 4: Create the mappings. */
518 prot = HV_PCI_MAP_ATTR_READ; 405 prot = HV_PCI_MAP_ATTR_READ;
519 if (direction != DMA_TO_DEVICE) 406 if (direction != DMA_TO_DEVICE)
520 prot |= HV_PCI_MAP_ATTR_WRITE; 407 prot |= HV_PCI_MAP_ATTR_WRITE;
521 408
522 err = fill_sg(entry, dev, sglist, used, nelems, prot); 409 local_irq_save(flags);
410
411 iommu_batch_start(dev, prot, entry);
412
413 for_each_sg(sglist, sg, nelems, i) {
414 unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg);
415 unsigned long slen = sg->length;
416 unsigned long this_npages;
417
418 this_npages = iommu_num_pages(paddr, slen);
419
420 sg->dma_address = dma_base | (paddr & ~IO_PAGE_MASK);
421 sg->dma_length = slen;
422
423 paddr &= IO_PAGE_MASK;
424 while (this_npages--) {
425 err = iommu_batch_add(paddr);
426 if (unlikely(err < 0L)) {
427 local_irq_restore(flags);
428 goto iommu_map_failed;
429 }
430
431 paddr += IO_PAGE_SIZE;
432 dma_base += IO_PAGE_SIZE;
433 }
434 }
435
436 err = iommu_batch_end();
437
438 local_irq_restore(flags);
439
523 if (unlikely(err < 0L)) 440 if (unlikely(err < 0L))
524 goto iommu_map_failed; 441 goto iommu_map_failed;
525 442
526 return used; 443 return nelems;
527 444
528bad: 445bad:
529 if (printk_ratelimit()) 446 if (printk_ratelimit())
@@ -541,12 +458,11 @@ iommu_map_failed:
541static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, 458static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
542 int nelems, enum dma_data_direction direction) 459 int nelems, enum dma_data_direction direction)
543{ 460{
461 unsigned long flags, npages;
544 struct pci_pbm_info *pbm; 462 struct pci_pbm_info *pbm;
463 u32 devhandle, bus_addr;
545 struct iommu *iommu; 464 struct iommu *iommu;
546 unsigned long flags, i, npages;
547 struct scatterlist *sg, *sgprv;
548 long entry; 465 long entry;
549 u32 devhandle, bus_addr;
550 466
551 if (unlikely(direction == DMA_NONE)) { 467 if (unlikely(direction == DMA_NONE)) {
552 if (printk_ratelimit()) 468 if (printk_ratelimit())
@@ -558,16 +474,8 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
558 devhandle = pbm->devhandle; 474 devhandle = pbm->devhandle;
559 475
560 bus_addr = sglist->dma_address & IO_PAGE_MASK; 476 bus_addr = sglist->dma_address & IO_PAGE_MASK;
561 sgprv = NULL;
562 for_each_sg(sglist, sg, nelems, i) {
563 if (sg->dma_length == 0)
564 break;
565
566 sgprv = sg;
567 }
568 477
569 npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) - 478 npages = calc_npages(sglist, nelems);
570 bus_addr) >> IO_PAGE_SHIFT;
571 479
572 entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); 480 entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
573 481