[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 7 of 9] swiotlb: Add support for systems with highmem
From: Becky Bruce <beckyb@xxxxxxxxxxxxxxxxxxx> On highmem systems, the original dma buffer might not have a virtual mapping - we need to kmap it in to perform the bounce. Extract the code that does the actual copy into a function that does the kmap if highmem is enabled, and defaults to the normal swiotlb memcpy if not. Signed-off-by: Becky Bruce <beckyb@xxxxxxxxxxxxxxxxxxx> --- lib/swiotlb.c | 53 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 45 insertions(+), 8 deletions(-) diff --git a/lib/swiotlb.c b/lib/swiotlb.c --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -14,6 +14,7 @@ * 04/07/.. ak Better overflow handling. Assorted fixes. * 05/09/10 linville Add support for syncing ranges, support syncing for * DMA_BIDIRECTIONAL mappings, miscellaneous cleanup. + * 08/12/11 beckyb Add highmem support */ #include <linux/cache.h> @@ -26,6 +27,7 @@ #include <linux/swiotlb.h> #include <linux/types.h> #include <linux/ctype.h> +#include <linux/highmem.h> #include <asm/io.h> #include <asm/dma.h> @@ -326,6 +328,45 @@ } /* + * Bounce: copy the swiotlb buffer back to the original dma location + */ +void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size, + enum dma_data_direction dir) +{ +#ifdef CONFIG_HIGHMEM + /* The buffer may not have a mapping. Map it in and copy */ + unsigned int offset = ((unsigned long)phys & + ((1 << PAGE_SHIFT) - 1)); + char *buffer; + unsigned int sz = 0; + unsigned long flags; + + while (size) { + sz = ((PAGE_SIZE - offset) > size) ? size : + PAGE_SIZE - offset; + local_irq_save(flags); + buffer = kmap_atomic(pfn_to_page(phys >> PAGE_SHIFT), + KM_BOUNCE_READ); + if (dir == DMA_TO_DEVICE) + memcpy(dma_addr, buffer + offset, sz); + else + memcpy(buffer + offset, dma_addr, sz); + kunmap_atomic(buffer, KM_BOUNCE_READ); + local_irq_restore(flags); + size -= sz; + phys += sz; + dma_addr += sz; + offset = 0; + } +#else + if (dir == DMA_TO_DEVICE) + memcpy(dma_addr, phys_to_virt(phys), size); + else + memcpy(phys_to_virt(phys), dma_addr, size); +#endif +} + +/* * Allocates bounce buffer and returns its kernel virtual address. */ static void * @@ -426,7 +467,7 @@ for (i = 0; i < nslots; i++) io_tlb_orig_addr[index+i] = phys + (i << IO_TLB_SHIFT); if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) - memcpy(dma_addr, phys_to_virt(phys), size); + swiotlb_bounce(phys, dma_addr, size, DMA_TO_DEVICE); return dma_addr; } @@ -446,11 +487,7 @@ * First, sync the memory before unmapping the entry */ if (phys && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))) - /* - * bounce... copy the data back into the original buffer * and - * delete the bounce buffer. - */ - memcpy(phys_to_virt(phys), dma_addr, size); + swiotlb_bounce(phys, dma_addr, size, DMA_FROM_DEVICE); /* * Return the buffer to the free list by setting the corresponding @@ -490,13 +527,13 @@ switch (target) { case SYNC_FOR_CPU: if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)) - memcpy(phys_to_virt(phys), dma_addr, size); + swiotlb_bounce(phys, dma_addr, size, DMA_FROM_DEVICE); else BUG_ON(dir != DMA_TO_DEVICE); break; case SYNC_FOR_DEVICE: if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) - memcpy(dma_addr, phys_to_virt(phys), size); + swiotlb_bounce(phys, dma_addr, size, DMA_TO_DEVICE); else BUG_ON(dir != DMA_FROM_DEVICE); break; _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |