X86: integrate CMA with DMA-mapping subsystem
authorMarek Szyprowski <m.szyprowski@samsung.com>
Thu, 29 Dec 2011 12:09:51 +0000 (13:09 +0100)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Mon, 21 May 2012 13:09:38 +0000 (15:09 +0200)
This patch adds support for CMA to dma-mapping subsystem for x86
architecture that uses common pci-dma/pci-nommu implementation. This
allows to test CMA on KVM/QEMU and a lot of common x86 boxes.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
CC: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
arch/x86/Kconfig
arch/x86/include/asm/dma-contiguous.h [new file with mode: 0644]
arch/x86/include/asm/dma-mapping.h
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-nommu.c
arch/x86/kernel/setup.c

index c9866b0b77d81d678e97ebbacd48ed5d5e659a77..7cbdfdac3c7c79227ea92acea2d74333d041c085 100644 (file)
@@ -31,6 +31,7 @@ config X86
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_WANT_FRAME_POINTERS
        select HAVE_DMA_ATTRS
+       select HAVE_DMA_CONTIGUOUS if !SWIOTLB
        select HAVE_KRETPROBES
        select HAVE_OPTPROBES
        select HAVE_FTRACE_MCOUNT_RECORD
diff --git a/arch/x86/include/asm/dma-contiguous.h b/arch/x86/include/asm/dma-contiguous.h
new file mode 100644 (file)
index 0000000..c092416
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef ASMX86_DMA_CONTIGUOUS_H
+#define ASMX86_DMA_CONTIGUOUS_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <asm-generic/dma-contiguous.h>
+
+static inline void
+dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { }
+
+#endif
+#endif
index 4b4331d71935c7cf0d477e1c3a06b93072e4b463..7b9227b44b9b072422b4ef5a17ddde38008817fe 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/io.h>
 #include <asm/swiotlb.h>
 #include <asm-generic/dma-coherent.h>
+#include <linux/dma-contiguous.h>
 
 #ifdef CONFIG_ISA
 # define ISA_DMA_BIT_MASK DMA_BIT_MASK(24)
@@ -62,6 +63,10 @@ extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
                                        dma_addr_t *dma_addr, gfp_t flag,
                                        struct dma_attrs *attrs);
 
+extern void dma_generic_free_coherent(struct device *dev, size_t size,
+                                     void *vaddr, dma_addr_t dma_addr,
+                                     struct dma_attrs *attrs);
+
 static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
 {
        if (!dev->dma_mask)
index 3003250ac51dbcdc5be17a2fa37a84d9aae4a4e1..62c9457ccd2f1c4ccad62a757aebdcd520498cc3 100644 (file)
@@ -100,14 +100,18 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
                                 struct dma_attrs *attrs)
 {
        unsigned long dma_mask;
-       struct page *page;
+       struct page *page = NULL;
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        dma_addr_t addr;
 
        dma_mask = dma_alloc_coherent_mask(dev, flag);
 
        flag |= __GFP_ZERO;
 again:
-       page = alloc_pages_node(dev_to_node(dev), flag, get_order(size));
+       if (!(flag & GFP_ATOMIC))
+               page = dma_alloc_from_contiguous(dev, count, get_order(size));
+       if (!page)
+               page = alloc_pages_node(dev_to_node(dev), flag, get_order(size));
        if (!page)
                return NULL;
 
@@ -127,6 +131,16 @@ again:
        return page_address(page);
 }
 
+void dma_generic_free_coherent(struct device *dev, size_t size, void *vaddr,
+                              dma_addr_t dma_addr, struct dma_attrs *attrs)
+{
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       struct page *page = virt_to_page(vaddr);
+
+       if (!dma_release_from_contiguous(dev, page, count))
+               free_pages((unsigned long)vaddr, get_order(size));
+}
+
 /*
  * See <Documentation/x86/x86_64/boot-options.txt> for the iommu kernel
  * parameter documentation.
index f96050685b46eb16504f3731ea02096464750829..871be4a84c7d752c1a322ed990ff18093b192c0b 100644 (file)
@@ -74,12 +74,6 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
        return nents;
 }
 
-static void nommu_free_coherent(struct device *dev, size_t size, void *vaddr,
-                               dma_addr_t dma_addr, struct dma_attrs *attrs)
-{
-       free_pages((unsigned long)vaddr, get_order(size));
-}
-
 static void nommu_sync_single_for_device(struct device *dev,
                        dma_addr_t addr, size_t size,
                        enum dma_data_direction dir)
@@ -97,7 +91,7 @@ static void nommu_sync_sg_for_device(struct device *dev,
 
 struct dma_map_ops nommu_dma_ops = {
        .alloc                  = dma_generic_alloc_coherent,
-       .free                   = nommu_free_coherent,
+       .free                   = dma_generic_free_coherent,
        .map_sg                 = nommu_map_sg,
        .map_page               = nommu_map_page,
        .sync_single_for_device = nommu_sync_single_for_device,
index 1a2901562059a48a4ec863c64e4150b881ed9271..d6c956e674cc1c44e58556abaf7898050c2b312b 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/pci-direct.h>
 #include <linux/init_ohci1394_dma.h>
 #include <linux/kvm_para.h>
+#include <linux/dma-contiguous.h>
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -934,6 +935,7 @@ void __init setup_arch(char **cmdline_p)
        }
 #endif
        memblock.current_limit = get_max_mapped();
+       dma_contiguous_reserve(0);
 
        /*
         * NOTE: On x86-32, only from this point on, fixmaps are ready for use.