]> xenbits.xensource.com Git - xenclient/kernel.git/commitdiff
Xen dma: avoid unnecessarily SWIOTLB bounce buffering.
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 31 Mar 2008 09:32:25 +0000 (10:32 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 31 Mar 2008 09:32:25 +0000 (10:32 +0100)
On Xen kernels, BIOVEC_PHYS_MERGEABLE permits merging of disk IOs that
span multiple pages, provided that the pages are both
pseudophysically- AND machine-contiguous ---

        (((bvec_to_phys((vec1)) + (vec1)->bv_len) ==
        bvec_to_phys((vec2))) && \
         ((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \
          bvec_to_pseudophys((vec2))))

However, this best-effort merging of adjacent pages can occur in
regions of dom0 memory which just happen, by virtue of having been
initially set up that way, to be machine-contiguous.  Such pages
which occur outside of a range created by xen_create_contiguous_
region won't be seen as contiguous by range_straddles_page_boundary(),
so the pci-dma-xen.c code for dma_map_sg() will send these regions
to the swiotlb for bounce buffering.

This patch adds a new check, check_pages_physically_contiguous(),
to the test for pages stradding page boundaries both in
swiotlb_map_sg() and dma_map_sg(), to capture these ranges and map
them directly via virt_to_bus() mapping rather than through the
swiotlb.

Signed-off-by: Stephen Tweedie <sct@redhat.com>
arch/i386/kernel/pci-dma-xen.c
include/asm-i386/mach-xen/asm/dma-mapping.h

index 9c8b6435a4d17ed7bff870331c088819037c4cb8..1d487458f574275caac00a8f66c25139fab5ceb9 100644 (file)
@@ -77,6 +77,39 @@ do {                                                 \
        }                                               \
 } while (0)
 
+static int check_pages_physically_contiguous(unsigned long pfn, 
+                                            unsigned int offset,
+                                            size_t length)
+{
+       unsigned long next_mfn;
+       int i;
+       int nr_pages;
+       
+       next_mfn = pfn_to_mfn(pfn);
+       nr_pages = (offset + length + PAGE_SIZE-1) >> PAGE_SHIFT;
+       
+       for (i = 1; i < nr_pages; i++) {
+               if (pfn_to_mfn(++pfn) != ++next_mfn) 
+                       return 0;
+       }
+       return 1;
+}
+
+int range_straddles_page_boundary(paddr_t p, size_t size)
+{
+       extern unsigned long *contiguous_bitmap;
+       unsigned long pfn = p >> PAGE_SHIFT;
+       unsigned int offset = p & ~PAGE_MASK;
+
+       if (offset + size <= PAGE_SIZE)
+               return 0;
+       if (test_bit(pfn, contiguous_bitmap))
+               return 0;
+       if (check_pages_physically_contiguous(pfn, offset, size))
+               return 0;
+       return 1;
+}
+
 int
 dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
           enum dma_data_direction direction)
index 14fffa0acae49cdfddba5df0e081fa7e7de4a06d..6019be58e380847cb5a9939d2ec3588543cdc238 100644 (file)
@@ -22,13 +22,7 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr)
        return (addr & ~mask) != 0;
 }
 
-static inline int
-range_straddles_page_boundary(paddr_t p, size_t size)
-{
-       extern unsigned long *contiguous_bitmap;
-       return ((((p & ~PAGE_MASK) + size) > PAGE_SIZE) &&
-               !test_bit(p >> PAGE_SHIFT, contiguous_bitmap));
-}
+extern int range_straddles_page_boundary(paddr_t p, size_t size);
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)