[PATCH 2.6.39] V4L: videobuf-dma-contig: fix mmap_mapper broken on ARM

Janusz Krzysztofik jkrzyszt at tis.icnet.pl
Sun Apr 10 18:47:59 EDT 2011


After switching from mem->dma_handle to virt_to_phys(mem->vaddr) used 
for obtaining page frame number passed to remap_pfn_range()
(commit 35d9f510b67b10338161aba6229d4f55b4000f5b), videobuf-dma-contig 
stopped working on my ARM based board. The ARM architecture maintainer, 
Russell King, confirmed that using something like 
virt_to_phys(dma_alloc_coherent()) is not supported on ARM, and can be 
broken on other architectures as well. The author of the change, Jiri 
Slaby, also confirmed that his code may not work on all architectures.

The patch takes two different countermeasures against this regression:

1. On architectures which provide dma_mmap_coherent() function (ARM for 
   now), use it instead of just remap_pfn_range(). The code is stollen 
   from sound/core/pcm_native.c:snd_pcm_default_mmap().
   Set vma->vm_pgoff to 0 before calling dma_mmap_coherent(), or it 
   fails.

2. On other architectures, use virt_to_phys(bus_to_virt(mem->dma_handle)) 
   instead of problematic virt_to_phys(mem->vaddr). This should work 
   even if those translations would occure inaccurate for DMA addresses, 
   since possible errors introduced by both calculations, performed in 
   opposite directions, should compensate.

Both solutions tested on ARM OMAP1 based Amstrad Delta board.

Signed-off-by: Janusz Krzysztofik <jkrzyszt at tis.icnet.pl>
---
 drivers/media/video/videobuf-dma-contig.c |   17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

--- linux-2.6.39-rc2/drivers/media/video/videobuf-dma-contig.c.orig	2011-04-09 00:38:45.000000000 +0200
+++ linux-2.6.39-rc2/drivers/media/video/videobuf-dma-contig.c	2011-04-10 15:00:23.000000000 +0200
@@ -295,13 +295,26 @@ static int __videobuf_mmap_mapper(struct
 
 	/* Try to remap memory */
 
+#ifndef ARCH_HAS_DMA_MMAP_COHERENT
+/* This should be defined / handled globally! */
+#ifdef CONFIG_ARM
+#define ARCH_HAS_DMA_MMAP_COHERENT
+#endif
+#endif
+
+#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+	vma->vm_pgoff = 0;
+	retval = dma_mmap_coherent(q->dev, vma, mem->vaddr, mem->dma_handle,
+			mem->size);
+#else
 	size = vma->vm_end - vma->vm_start;
 	size = (size < mem->size) ? size : mem->size;
 
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	retval = remap_pfn_range(vma, vma->vm_start,
-				 PFN_DOWN(virt_to_phys(mem->vaddr)),
-				 size, vma->vm_page_prot);
+			PFN_DOWN(virt_to_phys(bus_to_virt(mem->dma_handle))),
+			size, vma->vm_page_prot);
+#endif
 	if (retval) {
 		dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
 		dma_free_coherent(q->dev, mem->size,



More information about the linux-arm-kernel mailing list