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)
*/
fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
&fbi->map_dma);
&fbi->map_dma, PTE_BUFFERABLE);
if (fbi->map_cpu) {
fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
......
......@@ -14,7 +14,7 @@
* devices. This is the "generic" version. The PCI specific version
* 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_sync(void *kaddr, size_t size, int rw);
......@@ -84,12 +84,12 @@ static inline int dma_is_consistent(dma_addr_t handle)
static inline void *
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)
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)
static inline void *
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) ||
hwdev->dma_mask != 0xffffffff)
gfp |= GFP_DMA;
return consistent_alloc(gfp, size, handle);
return consistent_alloc(gfp, size, handle, 0);
}
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