Messages in this thread Patch in this message | | | From | Chanho Park <> | Subject | [PATCH] swiotlb: manipulate orig_addr when tlb_addr has offset | Date | Mon, 10 May 2021 17:30:57 +0900 |
| |
From: Bumyong Lee <bumyong.lee@samsung.com>
in case of driver wants to sync part of ranges with offset, swiotlb_tbl_sync_single() copies from orig_addr base to tlb_addr with offset it makes data mismatch
it removed from "swiotlb: don't modify orig_addr in swiotlb_tbl_sync_single", but it have to be recovered
1. Get dma_addr_t from dma_map_single() dma_addr_t tlb_addr = dma_map_single(dev, vaddr, vsize, DMA_TO_DEVICE);
|<---------------vsize------------->| +-----------------------------------+ | | original buffer +-----------------------------------+ vaddr
swiotlb_align_offset |<----->|<---------------vsize------------->| +-------+-----------------------------------+ | | | swiotlb buffer +-------+-----------------------------------+ tlb_addr
2. Do something 3. Sync dma_addr_t through dma_sync_single_for_device(..) dma_sync_single_for_device(dev, tlb_addr + offset, size, DMA_TO_DEVICE);
Error case. copy data to original buffer. but it is from base addr in original buffer
|<----->|<- offset ->|<- size ->| +-------+-----------------------------------+ | | |##########| | swiotlb buffer +-------+-----------------------------------+ tlb_addr
swiotlb_align_offset |<----->|<- offset ->|<- size ->| +-------+-----------------------------------+ | | |##########| | swiotlb buffer +-------+-----------------------------------+ tlb_addr
|<- size ->| +-----------------------------------+ |##########| | original buffer +-----------------------------------+ vaddr
FIX. copy data to original buffer. but it is from base addr in original buffer
swiotlb_align_offset |<----->|<- offset ->|<- size ->| +-------+-----------------------------------+ | | |##########| | swiotlb buffer +-------+-----------------------------------+ tlb_addr
|<- offset ->|<- size ->| +-----------------------------------+ | |##########| | original buffer +-----------------------------------+ vaddr
Fixes: 16fc3cef33a0 ("swiotlb: don't modify orig_addr in swiotlb_tbl_sync_single") Signed-off-by: Bumyong Lee <bumyong.lee@samsung.com> Signed-off-by: Chanho Park <chanho61.park@samsung.com> --- kernel/dma/swiotlb.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 8ca7d505d61c..e8243725e298 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -334,6 +334,7 @@ void __init swiotlb_exit(void) io_tlb_default_mem = NULL; } +static unsigned int swiotlb_align_offset(struct device *dev, u64 addr); /* * Bounce: copy the swiotlb buffer from or back to the original dma location */ @@ -346,10 +347,17 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size size_t alloc_size = mem->slots[index].alloc_size; unsigned long pfn = PFN_DOWN(orig_addr); unsigned char *vaddr = phys_to_virt(tlb_addr); + unsigned int tlb_offset; if (orig_addr == INVALID_PHYS_ADDR) return; + tlb_offset = (unsigned int)tlb_addr & (IO_TLB_SIZE - 1); + tlb_offset -= swiotlb_align_offset(dev, orig_addr); + + orig_addr += tlb_offset; + alloc_size -= tlb_offset; + if (size > alloc_size) { dev_WARN_ONCE(dev, 1, "Buffer overflow detected. Allocation size: %zu. Mapping size: %zu.\n", -- 2.31.1
| |