Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / drivers / base / dma-coherent.c
index f369e27..1b85949 100644 (file)
@@ -4,11 +4,13 @@
  */
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/dma-mapping.h>
 
 struct dma_coherent_mem {
        void            *virt_base;
        dma_addr_t      device_base;
+       phys_addr_t     pfn_base;
        int             size;
        int             flags;
        unsigned long   *bitmap;
@@ -43,6 +45,7 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
 
        dev->dma_mem->virt_base = mem_base;
        dev->dma_mem->device_base = device_addr;
+       dev->dma_mem->pfn_base = PFN_DOWN(bus_addr);
        dev->dma_mem->size = pages;
        dev->dma_mem->flags = flags;
 
@@ -175,3 +178,43 @@ int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
        return 0;
 }
 EXPORT_SYMBOL(dma_release_from_coherent);
+
+/**
+ * dma_mmap_from_coherent() - try to mmap the memory allocated from
+ * per-device coherent memory pool to userspace
+ * @dev:       device from which the memory was allocated
+ * @vma:       vm_area for the userspace memory
+ * @vaddr:     cpu address returned by dma_alloc_from_coherent
+ * @size:      size of the memory buffer allocated by dma_alloc_from_coherent
+ *
+ * This checks whether the memory was allocated from the per-device
+ * coherent memory pool and if so, maps that memory to the provided vma.
+ *
+ * Returns 1 if we correctly mapped the memory, or 0 if
+ * dma_release_coherent() should proceed with mapping memory from
+ * generic pools.
+ */
+int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
+                          void *vaddr, size_t size, int *ret)
+{
+       struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
+
+       if (mem && vaddr >= mem->virt_base && vaddr + size <=
+                  (mem->virt_base + (mem->size << PAGE_SHIFT))) {
+               unsigned long off = vma->vm_pgoff;
+               int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+               int user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+               int count = size >> PAGE_SHIFT;
+
+               *ret = -ENXIO;
+               if (off < count && user_count <= count - off) {
+                       unsigned pfn = mem->pfn_base + start + off;
+                       *ret = remap_pfn_range(vma, vma->vm_start, pfn,
+                                              user_count << PAGE_SHIFT,
+                                              vma->vm_page_prot);
+               }
+               return 1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(dma_mmap_from_coherent);