Commit 9804476c authored by Russell King's avatar Russell King

[ARM] Fix consistent_alloc()

The old consistent memory allocator, which sat behind
dma_coherent_alloc() and pci_consistent_alloc() was completely unable
to handle allocations from interrupt context because we traditionally
used ioremap, which in turn:
  - allocates memory using GFP_KERNEL for the vm_struct
    and the page tables themselves.
  - calls get_vm_area, which uses write_lock, and therefore
    is unsafe to call from interrupt context.

In order to address this issue, a new consistent_alloc() which avoids
the above issues has been implemented.  Essentially, we set aside
a section of the kernel VM space, and pre-allocate page tables to
cover this area.  We allocate "consistent" memory within this region.

The handling of the allocation is designed to be generic; it should
be possible to replace the vmalloc(), ioremap() and module_alloc()
without too much hastle, but that would clearly be a 2.7 thing at
this stage.
parent 28faab99
This diff is collapsed.
...@@ -1642,7 +1642,7 @@ static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi) ...@@ -1642,7 +1642,7 @@ static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
*/ */
fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size, fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
&fbi->map_dma); &fbi->map_dma, PTE_BUFFERABLE);
if (fbi->map_cpu) { if (fbi->map_cpu) {
fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE; fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* devices. This is the "generic" version. The PCI specific version * devices. This is the "generic" version. The PCI specific version
* is in pci.h * is in pci.h
*/ */
extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle); extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, unsigned long flags);
extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle); extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle);
extern void consistent_sync(void *kaddr, size_t size, int rw); extern void consistent_sync(void *kaddr, size_t size, int rw);
...@@ -84,12 +84,12 @@ static inline int dma_is_consistent(dma_addr_t handle) ...@@ -84,12 +84,12 @@ static inline int dma_is_consistent(dma_addr_t handle)
static inline void * static inline void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle) dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle)
{ {
int gfp = GFP_KERNEL; int gfp = GFP_ATOMIC;
if (dev == NULL || dmadev_is_sa1111(dev) || *dev->dma_mask != 0xffffffff) if (dev == NULL || dmadev_is_sa1111(dev) || *dev->dma_mask != 0xffffffff)
gfp |= GFP_DMA; gfp |= GFP_DMA;
return consistent_alloc(gfp, size, handle); return consistent_alloc(gfp, size, handle, 0);
} }
/** /**
......
...@@ -40,13 +40,13 @@ static inline void pcibios_penalize_isa_irq(int irq) ...@@ -40,13 +40,13 @@ static inline void pcibios_penalize_isa_irq(int irq)
static inline void * static inline void *
pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *handle) pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *handle)
{ {
int gfp = GFP_KERNEL; int gfp = GFP_ATOMIC;
if (hwdev == NULL || pcidev_is_sa1111(hwdev) || if (hwdev == NULL || pcidev_is_sa1111(hwdev) ||
hwdev->dma_mask != 0xffffffff) hwdev->dma_mask != 0xffffffff)
gfp |= GFP_DMA; gfp |= GFP_DMA;
return consistent_alloc(gfp, size, handle); return consistent_alloc(gfp, size, handle, 0);
} }
static inline void static inline void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment