aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-07-03 17:39:43 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-07-03 18:28:31 -0400
commitdd3641fc3cf6d10b7cf4e266c2f651517779e727 (patch)
tree2f6a90b735f26aeaea94ace887f8576bebbb2b30 /arch/arm/common
parent23bc9873ba60ee661d8e9f3a6b22fc3bcc4b7015 (diff)
ARM: dmabounce: move decision for bouncing into __dma_map_page()
Move the decision whether to bounce into __dma_map_page(), before the check for high pages. This avoids triggering the high page check for devices which aren't using dmabounce. Fix the unmap path to cope too. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/common')
-rw-r--r--arch/arm/common/dmabounce.c124
1 files changed, 58 insertions, 66 deletions
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 643e1d660677..6ae292cc43bf 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -246,88 +246,58 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
246 enum dma_data_direction dir) 246 enum dma_data_direction dir)
247{ 247{
248 struct dmabounce_device_info *device_info = dev->archdata.dmabounce; 248 struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
249 dma_addr_t dma_addr; 249 struct safe_buffer *buf;
250 int ret;
251 250
252 if (device_info) 251 if (device_info)
253 DO_STATS ( device_info->map_op_count++ ); 252 DO_STATS ( device_info->map_op_count++ );
254 253
255 dma_addr = virt_to_dma(dev, ptr); 254 buf = alloc_safe_buffer(device_info, ptr, size, dir);
256 255 if (buf == 0) {
257 ret = needs_bounce(dev, dma_addr, size); 256 dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
258 if (ret < 0) 257 __func__, ptr);
259 return ~0; 258 return ~0;
259 }
260 260
261 if (ret > 0) { 261 dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
262 struct safe_buffer *buf; 262 __func__, buf->ptr, virt_to_dma(dev, buf->ptr),
263 263 buf->safe, buf->safe_dma_addr);
264 buf = alloc_safe_buffer(device_info, ptr, size, dir);
265 if (buf == 0) {
266 dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
267 __func__, ptr);
268 return ~0;
269 }
270
271 dev_dbg(dev,
272 "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
273 __func__, buf->ptr, virt_to_dma(dev, buf->ptr),
274 buf->safe, buf->safe_dma_addr);
275
276 if ((dir == DMA_TO_DEVICE) ||
277 (dir == DMA_BIDIRECTIONAL)) {
278 dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n",
279 __func__, ptr, buf->safe, size);
280 memcpy(buf->safe, ptr, size);
281 }
282 ptr = buf->safe;
283 264
284 dma_addr = buf->safe_dma_addr; 265 if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) {
285 } else { 266 dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n",
286 /* 267 __func__, ptr, buf->safe, size);
287 * We don't need to sync the DMA buffer since 268 memcpy(buf->safe, ptr, size);
288 * it was allocated via the coherent allocators.
289 */
290 __dma_single_cpu_to_dev(ptr, size, dir);
291 } 269 }
292 270
293 return dma_addr; 271 return buf->safe_dma_addr;
294} 272}
295 273
296static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, 274static inline void unmap_single(struct device *dev, struct safe_buffer *buf,
297 size_t size, enum dma_data_direction dir) 275 size_t size, enum dma_data_direction dir)
298{ 276{
299 struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap"); 277 BUG_ON(buf->size != size);
300 278 BUG_ON(buf->direction != dir);
301 if (buf) {
302 BUG_ON(buf->size != size);
303 BUG_ON(buf->direction != dir);
304 279
305 dev_dbg(dev, 280 dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
306 "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", 281 __func__, buf->ptr, virt_to_dma(dev, buf->ptr),
307 __func__, buf->ptr, virt_to_dma(dev, buf->ptr), 282 buf->safe, buf->safe_dma_addr);
308 buf->safe, buf->safe_dma_addr);
309 283
310 DO_STATS(dev->archdata.dmabounce->bounce_count++); 284 DO_STATS(dev->archdata.dmabounce->bounce_count++);
311 285
312 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { 286 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
313 void *ptr = buf->ptr; 287 void *ptr = buf->ptr;
314 288
315 dev_dbg(dev, 289 dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n",
316 "%s: copy back safe %p to unsafe %p size %d\n", 290 __func__, buf->safe, ptr, size);
317 __func__, buf->safe, ptr, size); 291 memcpy(ptr, buf->safe, size);
318 memcpy(ptr, buf->safe, size);
319 292
320 /* 293 /*
321 * Since we may have written to a page cache page, 294 * Since we may have written to a page cache page,
322 * we need to ensure that the data will be coherent 295 * we need to ensure that the data will be coherent
323 * with user mappings. 296 * with user mappings.
324 */ 297 */
325 __cpuc_flush_dcache_area(ptr, size); 298 __cpuc_flush_dcache_area(ptr, size);
326 }
327 free_safe_buffer(dev->archdata.dmabounce, buf);
328 } else {
329 __dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir);
330 } 299 }
300 free_safe_buffer(dev->archdata.dmabounce, buf);
331} 301}
332 302
333/* ************************************************** */ 303/* ************************************************** */
@@ -341,12 +311,25 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
341dma_addr_t __dma_map_page(struct device *dev, struct page *page, 311dma_addr_t __dma_map_page(struct device *dev, struct page *page,
342 unsigned long offset, size_t size, enum dma_data_direction dir) 312 unsigned long offset, size_t size, enum dma_data_direction dir)
343{ 313{
314 dma_addr_t dma_addr;
315 int ret;
316
344 dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", 317 dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n",
345 __func__, page, offset, size, dir); 318 __func__, page, offset, size, dir);
346 319
320 dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset;
321
322 ret = needs_bounce(dev, dma_addr, size);
323 if (ret < 0)
324 return ~0;
325
326 if (ret == 0) {
327 __dma_page_cpu_to_dev(page, offset, size, dir);
328 return dma_addr;
329 }
330
347 if (PageHighMem(page)) { 331 if (PageHighMem(page)) {
348 dev_err(dev, "DMA buffer bouncing of HIGHMEM pages " 332 dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n");
349 "is not supported\n");
350 return ~0; 333 return ~0;
351 } 334 }
352 335
@@ -363,10 +346,19 @@ EXPORT_SYMBOL(__dma_map_page);
363void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, 346void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
364 enum dma_data_direction dir) 347 enum dma_data_direction dir)
365{ 348{
349 struct safe_buffer *buf;
350
366 dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", 351 dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
367 __func__, (void *) dma_addr, size, dir); 352 __func__, (void *) dma_addr, size, dir);
368 353
369 unmap_single(dev, dma_addr, size, dir); 354 buf = find_safe_buffer_dev(dev, dma_addr, __func__);
355 if (!buf) {
356 __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)),
357 dma_addr & ~PAGE_MASK, size, dir);
358 return;
359 }
360
361 unmap_single(dev, buf, size, dir);
370} 362}
371EXPORT_SYMBOL(__dma_unmap_page); 363EXPORT_SYMBOL(__dma_unmap_page);
372 364