1 From 8e95f90487d2fb46fd862744ddb34f47c30b0c5a Mon Sep 17 00:00:00 2001
2 From: Ian Molton <spyro@f2s.com>
3 Date: Fri, 4 Jan 2008 18:27:50 +0000
4 Subject: [PATCH 02/64] Modify dma_alloc_coherent on ARM so that it supports device local DMA.
7 arch/arm/mm/consistent.c | 125 +++++++++++++++++++++++++++++++++++++++++
8 include/asm-arm/dma-mapping.h | 37 +++++++------
9 2 files changed, 145 insertions(+), 17 deletions(-)
11 diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
12 index 333a82a..3da0f94 100644
13 --- a/arch/arm/mm/consistent.c
14 +++ b/arch/arm/mm/consistent.c
17 * Copyright (C) 2000-2004 Russell King
19 + * Device local coherent memory support added by Ian Molton (spyro@f2s.com)
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License version 2 as
23 * published by the Free Software Foundation.
26 #include <asm/memory.h>
27 #include <asm/cacheflush.h>
29 #include <asm/tlbflush.h>
30 #include <asm/sizes.h>
33 #define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
34 #define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
36 +struct dma_coherent_mem {
41 + unsigned long *bitmap;
45 * These are the page tables (2MB each) covering uncached, DMA consistent allocations
46 @@ -153,6 +163,13 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
48 u64 mask = ISA_DMA_THRESHOLD, limit;
50 + /* Following is a work-around (a.k.a. hack) to prevent pages
51 + * with __GFP_COMP being passed to split_page() which cannot
52 + * handle them. The real problem is that this flag probably
53 + * should be 0 on ARM as it is not supported on this
54 + * platform--see CONFIG_HUGETLB_PAGE. */
55 + gfp &= ~(__GFP_COMP);
57 if (!consistent_pte[0]) {
58 printk(KERN_ERR "%s: not initialised\n", __func__);
60 @@ -160,6 +177,26 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
66 + unsigned long flags;
70 + spin_lock_irqsave(&consistent_lock, flags);
71 + pgnum = bitmap_find_free_region(dev->dma_mem->bitmap,
74 + spin_unlock_irqrestore(&consistent_lock, flags);
77 + *handle = dev->dma_mem->device_base + (pgnum << PAGE_SHIFT);
78 + ret = dev->dma_mem->virt_base + (pgnum << PAGE_SHIFT);
79 + memset(ret, 0, size);
84 mask = dev->coherent_dma_mask;
87 @@ -177,6 +214,9 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
88 mask, (unsigned long long)ISA_DMA_THRESHOLD);
92 + if (dev->dma_mem && dev->dma_mem->flags & DMA_MEMORY_EXCLUSIVE)
97 @@ -359,6 +399,8 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
101 + struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
102 + unsigned long order;
104 WARN_ON(irqs_disabled());
106 @@ -368,6 +410,15 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
109 size = PAGE_ALIGN(size);
110 + order = get_order(size);
112 + /* What if mem is valid and the range is not? */
113 + if (mem && cpu_addr >= mem->virt_base && cpu_addr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
114 + int page = (cpu_addr - mem->virt_base) >> PAGE_SHIFT;
116 + bitmap_release_region(mem->bitmap, page, order);
120 spin_lock_irqsave(&consistent_lock, flags);
121 c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
122 @@ -437,6 +488,80 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
124 EXPORT_SYMBOL(dma_free_coherent);
126 +int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
127 + dma_addr_t device_addr, size_t size, int flags)
129 + void __iomem *mem_base;
130 + int pages = size >> PAGE_SHIFT;
131 + int bitmap_size = (pages + 31)/32;
133 + if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
140 + /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
141 + mem_base = ioremap_nocache(bus_addr, size);
145 + dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
148 + memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem));
149 + dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
150 + if (!dev->dma_mem->bitmap)
153 + dev->dma_mem->virt_base = mem_base;
154 + dev->dma_mem->device_base = device_addr;
155 + dev->dma_mem->size = pages;
156 + dev->dma_mem->flags = flags;
158 + if (flags & DMA_MEMORY_MAP)
159 + return DMA_MEMORY_MAP;
161 + return DMA_MEMORY_IO;
164 + kfree(dev->dma_mem->bitmap);
168 +EXPORT_SYMBOL(dma_declare_coherent_memory);
170 +void dma_release_declared_memory(struct device *dev)
172 + struct dma_coherent_mem *mem = dev->dma_mem;
176 + dev->dma_mem = NULL;
177 + kfree(mem->bitmap);
180 +EXPORT_SYMBOL(dma_release_declared_memory);
182 +void *dma_mark_declared_memory_occupied(struct device *dev,
183 + dma_addr_t device_addr, size_t size)
185 + struct dma_coherent_mem *mem = dev->dma_mem;
186 + int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
190 + return ERR_PTR(-EINVAL);
192 + pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
193 + err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
195 + return ERR_PTR(err);
196 + return mem->virt_base + (pos << PAGE_SHIFT);
198 +EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
201 * Initialise the consistent memory allocation.
203 diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h
204 index e99406a..f18ba05 100644
205 --- a/include/asm-arm/dma-mapping.h
206 +++ b/include/asm-arm/dma-mapping.h
209 #include <linux/scatterlist.h>
211 +#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
213 +dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
214 + dma_addr_t device_addr, size_t size, int flags);
217 +dma_release_declared_memory(struct device *dev);
220 +dma_mark_declared_memory_occupied(struct device *dev,
221 + dma_addr_t device_addr, size_t size);
225 * DMA-consistent mapping functions. These allocate/free a region of
226 * uncached, unwrite-buffered mapped memory space for use with DMA
227 @@ -433,23 +446,13 @@ extern int dmabounce_register_dev(struct device *, unsigned long, unsigned long)
229 extern void dmabounce_unregister_dev(struct device *);
234 - * @dev: valid struct device pointer
235 - * @dma_handle: dma_handle of unbounced buffer
236 - * @size: size of region being mapped
238 - * Platforms that utilize the dmabounce mechanism must implement
241 - * The dmabounce routines call this function whenever a dma-mapping
242 - * is requested to determine whether a given buffer needs to be bounced
243 - * or not. The function must return 0 if the buffer is OK for
244 - * DMA access and 1 if the buffer needs to be bounced.
247 -extern int dma_needs_bounce(struct device*, dma_addr_t, size_t);
248 +typedef int (*dmabounce_check)(struct device *dev, dma_addr_t dma, size_t size, void *data);
249 +extern int dmabounce_register_checker(dmabounce_check, void *data);
250 +extern void dmabounce_remove_checker(dmabounce_check, void *data);
251 +#ifdef CONFIG_PLATFORM_DMABOUNCE
252 +extern int platform_dma_needs_bounce(struct device *dev, dma_addr_t dma, size_t size, void *data);
255 #endif /* CONFIG_DMABOUNCE */
257 #endif /* __KERNEL__ */