[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.