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 | |
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>
-rw-r--r-- | drivers/xen/swiotlb-xen.c | 11 | ||||
-rw-r--r-- | include/linux/swiotlb.h | 6 | ||||
-rw-r--r-- | lib/swiotlb.c | 59 |
3 files changed, 49 insertions, 27 deletions
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index b8014bf2b2ed..3d048afcee38 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c | |||
@@ -405,7 +405,8 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, | |||
405 | */ | 405 | */ |
406 | trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force); | 406 | trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force); |
407 | 407 | ||
408 | map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir); | 408 | map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir, |
409 | attrs); | ||
409 | if (map == SWIOTLB_MAP_ERROR) | 410 | if (map == SWIOTLB_MAP_ERROR) |
410 | return DMA_ERROR_CODE; | 411 | return DMA_ERROR_CODE; |
411 | 412 | ||
@@ -419,7 +420,8 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, | |||
419 | if (dma_capable(dev, dev_addr, size)) | 420 | if (dma_capable(dev, dev_addr, size)) |
420 | return dev_addr; | 421 | return dev_addr; |
421 | 422 | ||
422 | swiotlb_tbl_unmap_single(dev, map, size, dir); | 423 | swiotlb_tbl_unmap_single(dev, map, size, dir, |
424 | attrs | DMA_ATTR_SKIP_CPU_SYNC); | ||
423 | 425 | ||
424 | return DMA_ERROR_CODE; | 426 | return DMA_ERROR_CODE; |
425 | } | 427 | } |
@@ -445,7 +447,7 @@ static void xen_unmap_single(struct device *hwdev, dma_addr_t dev_addr, | |||
445 | 447 | ||
446 | /* NOTE: We use dev_addr here, not paddr! */ | 448 | /* NOTE: We use dev_addr here, not paddr! */ |
447 | if (is_xen_swiotlb_buffer(dev_addr)) { | 449 | if (is_xen_swiotlb_buffer(dev_addr)) { |
448 | swiotlb_tbl_unmap_single(hwdev, paddr, size, dir); | 450 | swiotlb_tbl_unmap_single(hwdev, paddr, size, dir, attrs); |
449 | return; | 451 | return; |
450 | } | 452 | } |
451 | 453 | ||
@@ -558,11 +560,12 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, | |||
558 | start_dma_addr, | 560 | start_dma_addr, |
559 | sg_phys(sg), | 561 | sg_phys(sg), |
560 | sg->length, | 562 | sg->length, |
561 | dir); | 563 | dir, attrs); |
562 | if (map == SWIOTLB_MAP_ERROR) { | 564 | if (map == SWIOTLB_MAP_ERROR) { |
563 | dev_warn(hwdev, "swiotlb buffer is full\n"); | 565 | dev_warn(hwdev, "swiotlb buffer is full\n"); |
564 | /* Don't panic here, we expect map_sg users | 566 | /* Don't panic here, we expect map_sg users |
565 | to do proper error handling. */ | 567 | to do proper error handling. */ |
568 | attrs |= DMA_ATTR_SKIP_CPU_SYNC; | ||
566 | xen_swiotlb_unmap_sg_attrs(hwdev, sgl, i, dir, | 569 | xen_swiotlb_unmap_sg_attrs(hwdev, sgl, i, dir, |
567 | attrs); | 570 | attrs); |
568 | sg_dma_len(sgl) = 0; | 571 | sg_dma_len(sgl) = 0; |
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index f0d258967869..183f37c8a5e1 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h | |||
@@ -44,11 +44,13 @@ enum dma_sync_target { | |||
44 | extern phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, | 44 | extern phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, |
45 | dma_addr_t tbl_dma_addr, | 45 | dma_addr_t tbl_dma_addr, |
46 | phys_addr_t phys, size_t size, | 46 | phys_addr_t phys, size_t size, |
47 | enum dma_data_direction dir); | 47 | enum dma_data_direction dir, |
48 | unsigned long attrs); | ||
48 | 49 | ||
49 | extern void swiotlb_tbl_unmap_single(struct device *hwdev, | 50 | extern void swiotlb_tbl_unmap_single(struct device *hwdev, |
50 | phys_addr_t tlb_addr, | 51 | phys_addr_t tlb_addr, |
51 | size_t size, enum dma_data_direction dir); | 52 | size_t size, enum dma_data_direction dir, |
53 | unsigned long attrs); | ||
52 | 54 | ||
53 | extern void swiotlb_tbl_sync_single(struct device *hwdev, | 55 | extern void swiotlb_tbl_sync_single(struct device *hwdev, |
54 | phys_addr_t tlb_addr, | 56 | phys_addr_t tlb_addr, |
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); |