diff options
Diffstat (limited to 'lib')
| -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); |
