diff options
author | Alexander Duyck <alexander.h.duyck@intel.com> | 2016-11-02 07:13:02 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad@kernel.org> | 2016-11-07 15:06:33 -0500 |
commit | 0443fa003fa199f41bfbed3012f314d02c5b1f24 (patch) | |
tree | 401aaffdf993230e7ddf69279f531b28c5557ffb /lib/swiotlb.c | |
parent | 7641842164c34b672ef3e70e881e8a72735305c1 (diff) |
swiotlb: Add support for DMA_ATTR_SKIP_CPU_SYNC
As a first step to making DMA_ATTR_SKIP_CPU_SYNC apply to architectures
beyond just ARM I need to make it so that the swiotlb will respect the
flag. In order to do that I also need to update the swiotlb-xen since it
heavily makes use of the functionality.
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad@kernel.org>
Diffstat (limited to 'lib/swiotlb.c')
-rw-r--r-- | lib/swiotlb.c | 59 |
1 files changed, 38 insertions, 21 deletions
diff --git a/lib/swiotlb.c b/lib/swiotlb.c index bdcc0d8a7405..8e883c762728 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c | |||
@@ -425,7 +425,8 @@ static void swiotlb_bounce(phys_addr_t orig_addr, phys_addr_t tlb_addr, | |||
425 | phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, | 425 | phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, |
426 | dma_addr_t tbl_dma_addr, | 426 | dma_addr_t tbl_dma_addr, |
427 | phys_addr_t orig_addr, size_t size, | 427 | phys_addr_t orig_addr, size_t size, |
428 | enum dma_data_direction dir) | 428 | enum dma_data_direction dir, |
429 | unsigned long attrs) | ||
429 | { | 430 | { |
430 | unsigned long flags; | 431 | unsigned long flags; |
431 | phys_addr_t tlb_addr; | 432 | phys_addr_t tlb_addr; |
@@ -526,7 +527,8 @@ found: | |||
526 | */ | 527 | */ |
527 | for (i = 0; i < nslots; i++) | 528 | for (i = 0; i < nslots; i++) |
528 | io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT); | 529 | io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT); |
529 | if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) | 530 | if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && |
531 | (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) | ||
530 | swiotlb_bounce(orig_addr, tlb_addr, size, DMA_TO_DEVICE); | 532 | swiotlb_bounce(orig_addr, tlb_addr, size, DMA_TO_DEVICE); |
531 | 533 | ||
532 | return tlb_addr; | 534 | return tlb_addr; |
@@ -539,18 +541,20 @@ EXPORT_SYMBOL_GPL(swiotlb_tbl_map_single); | |||
539 | 541 | ||
540 | static phys_addr_t | 542 | static phys_addr_t |
541 | map_single(struct device *hwdev, phys_addr_t phys, size_t size, | 543 | map_single(struct device *hwdev, phys_addr_t phys, size_t size, |
542 | enum dma_data_direction dir) | 544 | enum dma_data_direction dir, unsigned long attrs) |
543 | { | 545 | { |
544 | dma_addr_t start_dma_addr = phys_to_dma(hwdev, io_tlb_start); | 546 | dma_addr_t start_dma_addr = phys_to_dma(hwdev, io_tlb_start); |
545 | 547 | ||
546 | return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size, dir); | 548 | return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size, |
549 | dir, attrs); | ||
547 | } | 550 | } |
548 | 551 | ||
549 | /* | 552 | /* |
550 | * dma_addr is the kernel virtual address of the bounce buffer to unmap. | 553 | * dma_addr is the kernel virtual address of the bounce buffer to unmap. |
551 | */ | 554 | */ |
552 | void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr, | 555 | void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr, |
553 | size_t size, enum dma_data_direction dir) | 556 | size_t size, enum dma_data_direction dir, |
557 | unsigned long attrs) | ||
554 | { | 558 | { |
555 | unsigned long flags; | 559 | unsigned long flags; |
556 | int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; | 560 | int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; |
@@ -561,6 +565,7 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr, | |||
561 | * First, sync the memory before unmapping the entry | 565 | * First, sync the memory before unmapping the entry |
562 | */ | 566 | */ |
563 | if (orig_addr != INVALID_PHYS_ADDR && | 567 | if (orig_addr != INVALID_PHYS_ADDR && |
568 | !(attrs & DMA_ATTR_SKIP_CPU_SYNC) && | ||
564 | ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))) | 569 | ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))) |
565 | swiotlb_bounce(orig_addr, tlb_addr, size, DMA_FROM_DEVICE); | 570 | swiotlb_bounce(orig_addr, tlb_addr, size, DMA_FROM_DEVICE); |
566 | 571 | ||
@@ -654,7 +659,8 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, | |||
654 | * GFP_DMA memory; fall back on map_single(), which | 659 | * GFP_DMA memory; fall back on map_single(), which |
655 | * will grab memory from the lowest available address range. | 660 | * will grab memory from the lowest available address range. |
656 | */ | 661 | */ |
657 | phys_addr_t paddr = map_single(hwdev, 0, size, DMA_FROM_DEVICE); | 662 | phys_addr_t paddr = map_single(hwdev, 0, size, |
663 | DMA_FROM_DEVICE, 0); | ||
658 | if (paddr == SWIOTLB_MAP_ERROR) | 664 | if (paddr == SWIOTLB_MAP_ERROR) |
659 | goto err_warn; | 665 | goto err_warn; |
660 | 666 | ||
@@ -667,9 +673,13 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, | |||
667 | (unsigned long long)dma_mask, | 673 | (unsigned long long)dma_mask, |
668 | (unsigned long long)dev_addr); | 674 | (unsigned long long)dev_addr); |
669 | 675 | ||
670 | /* DMA_TO_DEVICE to avoid memcpy in unmap_single */ | 676 | /* |
677 | * DMA_TO_DEVICE to avoid memcpy in unmap_single. | ||
678 | * The DMA_ATTR_SKIP_CPU_SYNC is optional. | ||
679 | */ | ||
671 | swiotlb_tbl_unmap_single(hwdev, paddr, | 680 | swiotlb_tbl_unmap_single(hwdev, paddr, |
672 | size, DMA_TO_DEVICE); | 681 | size, DMA_TO_DEVICE, |
682 | DMA_ATTR_SKIP_CPU_SYNC); | ||
673 | goto err_warn; | 683 | goto err_warn; |
674 | } | 684 | } |
675 | } | 685 | } |
@@ -698,8 +708,12 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, | |||
698 | if (!is_swiotlb_buffer(paddr)) | 708 | if (!is_swiotlb_buffer(paddr)) |
699 | free_pages((unsigned long)vaddr, get_order(size)); | 709 | free_pages((unsigned long)vaddr, get_order(size)); |
700 | else | 710 | else |
701 | /* DMA_TO_DEVICE to avoid memcpy in swiotlb_tbl_unmap_single */ | 711 | /* |
702 | swiotlb_tbl_unmap_single(hwdev, paddr, size, DMA_TO_DEVICE); | 712 | * DMA_TO_DEVICE to avoid memcpy in swiotlb_tbl_unmap_single. |
713 | * DMA_ATTR_SKIP_CPU_SYNC is optional. | ||
714 | */ | ||
715 | swiotlb_tbl_unmap_single(hwdev, paddr, size, DMA_TO_DEVICE, | ||
716 | DMA_ATTR_SKIP_CPU_SYNC); | ||
703 | } | 717 | } |
704 | EXPORT_SYMBOL(swiotlb_free_coherent); | 718 | EXPORT_SYMBOL(swiotlb_free_coherent); |
705 | 719 | ||
@@ -755,7 +769,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page, | |||
755 | trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force); | 769 | trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force); |
756 | 770 | ||
757 | /* Oh well, have to allocate and map a bounce buffer. */ | 771 | /* Oh well, have to allocate and map a bounce buffer. */ |
758 | map = map_single(dev, phys, size, dir); | 772 | map = map_single(dev, phys, size, dir, attrs); |
759 | if (map == SWIOTLB_MAP_ERROR) { | 773 | if (map == SWIOTLB_MAP_ERROR) { |
760 | swiotlb_full(dev, size, dir, 1); | 774 | swiotlb_full(dev, size, dir, 1); |
761 | return phys_to_dma(dev, io_tlb_overflow_buffer); | 775 | return phys_to_dma(dev, io_tlb_overflow_buffer); |
@@ -764,12 +778,13 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page, | |||
764 | dev_addr = phys_to_dma(dev, map); | 778 | dev_addr = phys_to_dma(dev, map); |
765 | 779 | ||
766 | /* Ensure that the address returned is DMA'ble */ | 780 | /* Ensure that the address returned is DMA'ble */ |
767 | if (!dma_capable(dev, dev_addr, size)) { | 781 | if (dma_capable(dev, dev_addr, size)) |
768 | swiotlb_tbl_unmap_single(dev, map, size, dir); | 782 | return dev_addr; |
769 | return phys_to_dma(dev, io_tlb_overflow_buffer); | 783 | |
770 | } | 784 | swiotlb_tbl_unmap_single(dev, map, size, dir, |
785 | attrs | DMA_ATTR_SKIP_CPU_SYNC); | ||
771 | 786 | ||
772 | return dev_addr; | 787 | return phys_to_dma(dev, io_tlb_overflow_buffer); |
773 | } | 788 | } |
774 | EXPORT_SYMBOL_GPL(swiotlb_map_page); | 789 | EXPORT_SYMBOL_GPL(swiotlb_map_page); |
775 | 790 | ||
@@ -782,14 +797,15 @@ EXPORT_SYMBOL_GPL(swiotlb_map_page); | |||
782 | * whatever the device wrote there. | 797 | * whatever the device wrote there. |
783 | */ | 798 | */ |
784 | static void unmap_single(struct device *hwdev, dma_addr_t dev_addr, | 799 | static void unmap_single(struct device *hwdev, dma_addr_t dev_addr, |
785 | size_t size, enum dma_data_direction dir) | 800 | size_t size, enum dma_data_direction dir, |
801 | unsigned long attrs) | ||
786 | { | 802 | { |
787 | phys_addr_t paddr = dma_to_phys(hwdev, dev_addr); | 803 | phys_addr_t paddr = dma_to_phys(hwdev, dev_addr); |
788 | 804 | ||
789 | BUG_ON(dir == DMA_NONE); | 805 | BUG_ON(dir == DMA_NONE); |
790 | 806 | ||
791 | if (is_swiotlb_buffer(paddr)) { | 807 | if (is_swiotlb_buffer(paddr)) { |
792 | swiotlb_tbl_unmap_single(hwdev, paddr, size, dir); | 808 | swiotlb_tbl_unmap_single(hwdev, paddr, size, dir, attrs); |
793 | return; | 809 | return; |
794 | } | 810 | } |
795 | 811 | ||
@@ -809,7 +825,7 @@ void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr, | |||
809 | size_t size, enum dma_data_direction dir, | 825 | size_t size, enum dma_data_direction dir, |
810 | unsigned long attrs) | 826 | unsigned long attrs) |
811 | { | 827 | { |
812 | unmap_single(hwdev, dev_addr, size, dir); | 828 | unmap_single(hwdev, dev_addr, size, dir, attrs); |
813 | } | 829 | } |
814 | EXPORT_SYMBOL_GPL(swiotlb_unmap_page); | 830 | EXPORT_SYMBOL_GPL(swiotlb_unmap_page); |
815 | 831 | ||
@@ -891,7 +907,7 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems, | |||
891 | if (swiotlb_force || | 907 | if (swiotlb_force || |
892 | !dma_capable(hwdev, dev_addr, sg->length)) { | 908 | !dma_capable(hwdev, dev_addr, sg->length)) { |
893 | phys_addr_t map = map_single(hwdev, sg_phys(sg), | 909 | phys_addr_t map = map_single(hwdev, sg_phys(sg), |
894 | sg->length, dir); | 910 | sg->length, dir, attrs); |
895 | if (map == SWIOTLB_MAP_ERROR) { | 911 | if (map == SWIOTLB_MAP_ERROR) { |
896 | /* Don't panic here, we expect map_sg users | 912 | /* Don't panic here, we expect map_sg users |
897 | to do proper error handling. */ | 913 | to do proper error handling. */ |
@@ -925,7 +941,8 @@ swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl, | |||
925 | BUG_ON(dir == DMA_NONE); | 941 | BUG_ON(dir == DMA_NONE); |
926 | 942 | ||
927 | for_each_sg(sgl, sg, nelems, i) | 943 | for_each_sg(sgl, sg, nelems, i) |
928 | unmap_single(hwdev, sg->dma_address, sg_dma_len(sg), dir); | 944 | unmap_single(hwdev, sg->dma_address, sg_dma_len(sg), dir, |
945 | attrs); | ||
929 | 946 | ||
930 | } | 947 | } |
931 | EXPORT_SYMBOL(swiotlb_unmap_sg_attrs); | 948 | EXPORT_SYMBOL(swiotlb_unmap_sg_attrs); |