diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-07-03 17:39:43 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-07-03 18:28:31 -0400 |
commit | dd3641fc3cf6d10b7cf4e266c2f651517779e727 (patch) | |
tree | 2f6a90b735f26aeaea94ace887f8576bebbb2b30 /arch/arm/common | |
parent | 23bc9873ba60ee661d8e9f3a6b22fc3bcc4b7015 (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.c | 124 |
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 | ||
296 | static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, | 274 | static 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, | |||
341 | dma_addr_t __dma_map_page(struct device *dev, struct page *page, | 311 | dma_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); | |||
363 | void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, | 346 | void __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 | } |
371 | EXPORT_SYMBOL(__dma_unmap_page); | 363 | EXPORT_SYMBOL(__dma_unmap_page); |
372 | 364 | ||