From 33e043d0593480e3f0d9bcc2ec07668ea46cd279 Mon Sep 17 00:00:00 2001 From: kfraser Date: Mon, 9 Jul 2007 20:15:53 +0100 Subject: [PATCH] swiotlb: Allow sync on arbitrary offsets into dma-mapped region. Signed-off-by: Keir Fraser --- arch/i386/kernel/swiotlb.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/arch/i386/kernel/swiotlb.c b/arch/i386/kernel/swiotlb.c index dc03ca5c..8d3ab21e 100644 --- a/arch/i386/kernel/swiotlb.c +++ b/arch/i386/kernel/swiotlb.c @@ -378,12 +378,10 @@ map_single(struct device *hwdev, struct phys_addr buffer, size_t size, int dir) */ slot_buf = buffer; for (i = 0; i < nslots; i++) { + slot_buf.page += slot_buf.offset >> PAGE_SHIFT; + slot_buf.offset &= PAGE_SIZE - 1; io_tlb_orig_addr[index+i] = slot_buf; slot_buf.offset += 1 << IO_TLB_SHIFT; - if (slot_buf.offset >= PAGE_SIZE) { - slot_buf.page++; - slot_buf.offset -= PAGE_SIZE; - } } if ((dir == DMA_TO_DEVICE) || (dir == DMA_BIDIRECTIONAL)) __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE); @@ -391,6 +389,16 @@ map_single(struct device *hwdev, struct phys_addr buffer, size_t size, int dir) return dma_addr; } +struct phys_addr dma_addr_to_phys_addr(char *dma_addr) +{ + int index = (dma_addr - iotlb_virt_start) >> IO_TLB_SHIFT; + struct phys_addr buffer = io_tlb_orig_addr[index]; + buffer.offset += (long)dma_addr & ((1 << IO_TLB_SHIFT) - 1); + buffer.page += buffer.offset >> PAGE_SHIFT; + buffer.offset &= PAGE_SIZE - 1; + return buffer; +} + /* * dma_addr is the kernel virtual address of the bounce buffer to unmap. */ @@ -400,7 +408,7 @@ unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir) unsigned long flags; int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; int index = (dma_addr - iotlb_virt_start) >> IO_TLB_SHIFT; - struct phys_addr buffer = io_tlb_orig_addr[index]; + struct phys_addr buffer = dma_addr_to_phys_addr(dma_addr); /* * First, sync the memory before unmapping the entry @@ -440,8 +448,7 @@ unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir) static void sync_single(struct device *hwdev, char *dma_addr, size_t size, int dir) { - int index = (dma_addr - iotlb_virt_start) >> IO_TLB_SHIFT; - struct phys_addr buffer = io_tlb_orig_addr[index]; + struct phys_addr buffer = dma_addr_to_phys_addr(dma_addr); BUG_ON((dir != DMA_FROM_DEVICE) && (dir != DMA_TO_DEVICE)); __sync_single(buffer, dma_addr, size, dir); } -- 2.39.5