diff options
Diffstat (limited to 'arch/sparc64/kernel/pci_sun4v.c')
-rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 170 |
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 | |||
370 | static 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 | |||
461 | iommu_map_failed: | ||
462 | local_irq_restore(flags); | ||
463 | return -1L; | ||
464 | } | ||
465 | |||
466 | static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, | 368 | static 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 | ||
528 | bad: | 445 | bad: |
529 | if (printk_ratelimit()) | 446 | if (printk_ratelimit()) |
@@ -541,12 +458,11 @@ iommu_map_failed: | |||
541 | static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, | 458 | static 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 | ||