RFC: dma_mmap_coherent() for powerpc/ppc architecture and ALSA?

Takashi Iwai tiwai at suse.de
Mon Jun 12 20:51:16 EST 2006


At Sat, 10 Jun 2006 10:22:23 +0200,
Gerhard Pircher wrote:
> 
> > -------- Original-Nachricht --------
> > Datum: Fri, 09 Jun 2006 20:46:32 -0400
> > Von: Lee Revell <rlrevell at joe-job.com>
> > An: Benjamin Herrenschmidt <benh at kernel.crashing.org>
> > Betreff: Re: RFC: dma_mmap_coherent() for powerpc/ppc architecture and 
> > ALSA?
> > 
> > On Sat, 2006-06-10 at 10:34 +1000, Benjamin Herrenschmidt wrote:
> > > > This leads me to the question, if there are any plans to include the 
> > > > dma_mmap_coherent() function (for powerpc/ppc and/or any other
> > > > platform) in one of the next kernel versions and if an adapation of
> > > > the ALSA drivers is planned. Or is there a simple way (hack) to fix
> > > > this problem?
> > > 
> > > You are welcome to do a patch implementing this :)
> > 
> > Please cc: alsa-devel when you do so.
> 
> :)
> 
> Well, implementing the dma_mmap_coherent() function isn't the
> problem, because it is already implemented for the ARM
> architecture.

Actually, I wrote dma_coherent_mmap patch long time ago but it has
been left forgotten.  The patch attached below seems applicable to
2.6.17 tree, but I'm not sure whether it still works properly.
It's untested on most of architectures.


> But as far as I understand this would require a
> rewrite of all the ALSA drivers (or at least a rewrite of the ALSA's
> DMA helper functions). 

Yes.  The change of ALSA side has been also on my tree.  But it was
still pending since I'm not satisfied with the design yet.
If you're interested in it, let me know.  I'll post the patch.


Takashi


diff --git a/arch/frv/mb93090-mb00/pci-dma-nommu.c b/arch/frv/mb93090-mb00/pci-dma-nommu.c
index 4985466..17a3064 100644
--- a/arch/frv/mb93090-mb00/pci-dma-nommu.c
+++ b/arch/frv/mb93090-mb00/pci-dma-nommu.c
@@ -106,6 +106,14 @@ void dma_free_coherent(struct device *hw
 
 EXPORT_SYMBOL(dma_free_coherent);
 
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	return -ENXIO;
+}
+
+EXPORT_SYMBOL(dma_mmap_coherent);
+
 /*
  * Map a single buffer of the indicated size for DMA in streaming mode.
  * The 32-bit bus address to use is returned.
diff --git a/arch/frv/mb93090-mb00/pci-dma.c b/arch/frv/mb93090-mb00/pci-dma.c
index 671ce1e..d4a8326 100644
--- a/arch/frv/mb93090-mb00/pci-dma.c
+++ b/arch/frv/mb93090-mb00/pci-dma.c
@@ -37,6 +37,21 @@ void dma_free_coherent(struct device *hw
 
 EXPORT_SYMBOL(dma_free_coherent);
 
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn;
+
+	/* bus is equivalent with phys */
+	pfn = ((unsigned long)handle) >> PAGE_SHIFT;
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
+EXPORT_SYMBOL(dma_mmap_coherent);
+
 /*
  * Map a single buffer of the indicated size for DMA in streaming mode.
  * The 32-bit bus address to use is returned.
diff --git a/arch/mips/mm/dma-coherent.c b/arch/mips/mm/dma-coherent.c
index f6b3c72..2b591e4 100644
--- a/arch/mips/mm/dma-coherent.c
+++ b/arch/mips/mm/dma-coherent.c
@@ -59,6 +59,24 @@ void dma_free_coherent(struct device *de
 
 EXPORT_SYMBOL(dma_free_coherent);
 
+int dma_mmap_noncoherent(struct device *dev, struct vm_area_struct *vma,
+			 void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
+EXPORT_SYMBOL(dma_mmap_noncoherent);
+
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t handle, size_t size)
+	__attribute__((alias("dma_mmap_noncoherent")));
+
+EXPORT_SYMBOL(dma_mmap_coherent);
+
 dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
 	enum dma_data_direction direction)
 {
diff --git a/arch/mips/mm/dma-ip27.c b/arch/mips/mm/dma-ip27.c
index 8da19fd..db453eb 100644
--- a/arch/mips/mm/dma-ip27.c
+++ b/arch/mips/mm/dma-ip27.c
@@ -64,6 +64,27 @@ void dma_free_coherent(struct device *de
 
 EXPORT_SYMBOL(dma_free_coherent);
 
+int dma_mmap_noncoherent(struct device *dev, struct vm_area_struct *vma,
+			 void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
+EXPORT_SYMBOL(dma_mmap_noncoherent);
+
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	return dma_mmap_noncoherent(dev, vma, cpu_addr, handle, size);
+}
+
+EXPORT_SYMBOL(dma_mmap_coherent);
+
 dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
 	enum dma_data_direction direction)
 {
diff --git a/arch/mips/mm/dma-ip32.c b/arch/mips/mm/dma-ip32.c
index ec54ed0..7cf348e 100644
--- a/arch/mips/mm/dma-ip32.c
+++ b/arch/mips/mm/dma-ip32.c
@@ -95,6 +95,29 @@ void dma_free_coherent(struct device *de
 
 EXPORT_SYMBOL(dma_free_coherent);
 
+int dma_mmap_noncoherent(struct device *dev, struct vm_area_struct *vma,
+			 void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
+EXPORT_SYMBOL(dma_mmap_noncoherent);
+
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	return dma_mmap_noncoherent(dev, vma,
+				    (void *)CAC_ADDR((unsigned long)cpu_addr),
+				    handle, size);
+}
+
+EXPORT_SYMBOL(dma_mmap_coherent);
+
 static inline void __dma_sync(unsigned long addr, size_t size,
 	enum dma_data_direction direction)
 {
diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c
index cd4ea84..64ac8fd 100644
--- a/arch/mips/mm/dma-noncoherent.c
+++ b/arch/mips/mm/dma-noncoherent.c
@@ -79,6 +79,29 @@ void dma_free_coherent(struct device *de
 
 EXPORT_SYMBOL(dma_free_coherent);
 
+int dma_mmap_noncoherent(struct device *dev, struct vm_area_struct *vma,
+			 void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
+EXPORT_SYMBOL(dma_mmap_noncoherent);
+
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	return dma_mmap_noncoherent(dev, vma,
+				    (void *)CAC_ADDR((unsigned long)cpu_addr),
+				    handle, size);
+}
+
+EXPORT_SYMBOL(dma_mmap_coherent);
+
 static inline void __dma_sync(unsigned long addr, size_t size,
 	enum dma_data_direction direction)
 {
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
index a6caf10..76481b3 100644
--- a/arch/parisc/kernel/pci-dma.c
+++ b/arch/parisc/kernel/pci-dma.c
@@ -396,6 +396,23 @@ static void pa11_dma_free_consistent (st
 	free_pages((unsigned long)__va(dma_handle), order);
 }
 
+static int pa11_mmap_noncoherent(struct device *dev, struct vm_area_struct *vma,
+				 void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = (unsigned long)handle >> PAGE_SHIFT;
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
+static int pa11_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+			      void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	return pa11_mmap_noncoherent(dev, vma, cpu_addr, handle, size);
+}
+
 static dma_addr_t pa11_dma_map_single(struct device *dev, void *addr, size_t size, enum dma_data_direction direction)
 {
 	if (direction == DMA_NONE) {
@@ -509,6 +526,8 @@ struct hppa_dma_ops pcxl_dma_ops = {
 	.dma_sync_single_for_device = pa11_dma_sync_single_for_device,
 	.dma_sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu,
 	.dma_sync_sg_for_device = pa11_dma_sync_sg_for_device,
+	.mmap_coherent =	pa11_mmap_coherent,
+	.mmap_noncoherent =	pa11_mmap_noncoherent,
 };
 
 static void *fail_alloc_consistent(struct device *dev, size_t size,
@@ -537,6 +556,12 @@ static void pa11_dma_free_noncoherent(st
 	return;
 }
 
+static int fail_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+			      void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	return -ENXIO;
+}
+
 struct hppa_dma_ops pcx_dma_ops = {
 	.dma_supported =	pa11_dma_supported,
 	.alloc_consistent =	fail_alloc_consistent,
@@ -550,6 +575,8 @@ struct hppa_dma_ops pcx_dma_ops = {
 	.dma_sync_single_for_device =	pa11_dma_sync_single_for_device,
 	.dma_sync_sg_for_cpu =		pa11_dma_sync_sg_for_cpu,
 	.dma_sync_sg_for_device =	pa11_dma_sync_sg_for_device,
+	.mmap_coherent =	fail_mmap_coherent,
+	.mmap_noncoherent =	fail_mmap_coherent,
 };
 
 
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index ee73e30..097a0bf 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -59,6 +59,15 @@ void consistent_free(void *vaddr, size_t
 	}
 }
 
+int consistent_mmap(struct vm_area_struct *vma, void *vaddr, size_t size)
+{
+	vaddr = (void *)P1SEGADDR((unsigned long)vaddr);
+	return remap_pfn_range(vma, vma->vm_start,
+			       page_to_pfn(virt_to_page(vaddr)) + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
 void consistent_sync(void *vaddr, size_t size, int direction)
 {
 	void * p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
@@ -80,5 +89,6 @@ void consistent_sync(void *vaddr, size_t
 
 EXPORT_SYMBOL(consistent_alloc);
 EXPORT_SYMBOL(consistent_free);
+EXPORT_SYMBOL(consistent_mmap);
 EXPORT_SYMBOL(consistent_sync);
 
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index f9ff297..46e1fc3 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -508,6 +508,22 @@ void pci_free_consistent(struct pci_dev 
 	free_pages(pgp, get_order(n));
 }
 
+/* Mmap a consistent area allocated via pci_alloc_consistent */
+int pci_mmap_consistent(struct pci_dev *pdev, struct vm_area_struct *vma,
+			void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn;
+
+	/* calculate pfn from bus address */
+	pfn = pfn_base + (((unsigned long)handle - phys_base) >> PAGE_SHIFT);
+
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
+
 /* Map a single buffer of the indicated size for DMA in streaming mode.
  * The 32-bit bus address to use is returned.
  *
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 4b376fa..a48766a 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -198,6 +198,7 @@ EXPORT_SYMBOL(insl);
 EXPORT_SYMBOL(outsl);
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pci_mmap_consistent);
 EXPORT_SYMBOL(pci_map_single);
 EXPORT_SYMBOL(pci_unmap_single);
 EXPORT_SYMBOL(pci_dma_sync_single_for_cpu);
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index 82e5455..50e4691 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -290,6 +290,18 @@ static void pci_4u_free_consistent(struc
 		free_pages((unsigned long)cpu, order);
 }
 
+/* Mmap a consistent area allocated via pci_alloc_consistent */
+int pci_mmap_consistent(struct pci_dev *pdev, struct vm_area_struct *vma,
+			void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
 /* Map a single buffer at PTR of SZ bytes for PCI DMA
  * in streaming mode.
  */
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 62d8a99..609abca 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -223,6 +223,7 @@ EXPORT_SYMBOL(isa_chain);
 EXPORT_SYMBOL(pci_memspace_mask);
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pci_mmap_consistent);
 EXPORT_SYMBOL(pci_map_single);
 EXPORT_SYMBOL(pci_unmap_single);
 EXPORT_SYMBOL(pci_map_sg);
diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c
index a9275c9..93f9120 100644
--- a/arch/x86_64/kernel/pci-dma.c
+++ b/arch/x86_64/kernel/pci-dma.c
@@ -166,6 +166,22 @@ void dma_free_coherent(struct device *de
 }
 EXPORT_SYMBOL(dma_free_coherent);
 
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn;
+
+	if (dma_ops->mmap_coherent)
+		return dma_ops->mmap_coherent(dev, vma, cpu_addr, handle, size);
+
+	pfn = page_to_pfn(virt_to_page(cpu_addr));
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+EXPORT_SYMBOL(dma_mmap_coherent);
+
 int dma_supported(struct device *dev, u64 mask)
 {
 	if (dma_ops->dma_supported)
diff --git a/include/asm-alpha/dma-mapping.h b/include/asm-alpha/dma-mapping.h
index 62d0d66..a2dc0a5 100644
--- a/include/asm-alpha/dma-mapping.h
+++ b/include/asm-alpha/dma-mapping.h
@@ -50,8 +50,20 @@ #define dma_mapping_error(addr)  (0)
 
 #endif	/* !CONFIG_PCI */
 
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
 #define dma_alloc_noncoherent(d, s, h, f)	dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h)	dma_free_coherent(d, s, v, h)
+#define dma_mmap_noncoherent(d, v, a, h, s)	dma_mmap_coherent(d, v, a, h, s)
 #define dma_is_consistent(dev)			(1)
 
 int dma_set_mask(struct device *dev, u64 mask);
diff --git a/include/asm-cris/dma-mapping.h b/include/asm-cris/dma-mapping.h
index cbf1a98..d2a629e 100644
--- a/include/asm-cris/dma-mapping.h
+++ b/include/asm-cris/dma-mapping.h
@@ -12,6 +12,7 @@ #include <asm/scatterlist.h>
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_mmap_noncoherent(d, v, a, h, s) dma_mmap_coherent(d, v, a, h, s)
 
 #ifdef CONFIG_PCI
 void *dma_alloc_coherent(struct device *dev, size_t size,
@@ -19,6 +20,18 @@ void *dma_alloc_coherent(struct device *
 
 void dma_free_coherent(struct device *dev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle);
+
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
 #else
 static inline void *
 dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
@@ -34,6 +47,15 @@ dma_free_coherent(struct device *dev, si
 {
         BUG();
 }
+
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	BUG();
+	return -ENXIO;
+}
+
 #endif
 static inline dma_addr_t
 dma_map_single(struct device *dev, void *ptr, size_t size,
diff --git a/include/asm-frv/dma-mapping.h b/include/asm-frv/dma-mapping.h
index e9fc1d4..7cd67fb 100644
--- a/include/asm-frv/dma-mapping.h
+++ b/include/asm-frv/dma-mapping.h
@@ -9,12 +9,16 @@ #include <asm/io.h>
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_mmap_noncoherent(d, v, a, h, s) dma_mmap_coherent(d, v, a, h, s)
 
 extern unsigned long __nongprelbss dma_coherent_mem_start;
 extern unsigned long __nongprelbss dma_coherent_mem_end;
 
 void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp);
 void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle);
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t handle, size_t size);
+
 
 /*
  * These macros should be used after a pci_map_sg call has been done
diff --git a/include/asm-generic/dma-mapping-broken.h b/include/asm-generic/dma-mapping-broken.h
index a7f1a55..fcf656e 100644
--- a/include/asm-generic/dma-mapping-broken.h
+++ b/include/asm-generic/dma-mapping-broken.h
@@ -19,4 +19,12 @@ dma_free_coherent(struct device *dev, si
 	BUG();
 }
 
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	BUG();
+	return -ENXIO;
+}
+
 #endif /* _ASM_GENERIC_DMA_MAPPING_H */
diff --git a/include/asm-generic/dma-mapping.h b/include/asm-generic/dma-mapping.h
index 1b35620..95d31d0 100644
--- a/include/asm-generic/dma-mapping.h
+++ b/include/asm-generic/dma-mapping.h
@@ -37,9 +37,13 @@ static inline void *
 dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
 		   gfp_t flag)
 {
+#ifdef CONFIG_MMU
 	BUG_ON(dev->bus != &pci_bus_type);
 
 	return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
+#else
+	return -ENXIO;
+#endif
 }
 
 static inline void
@@ -51,6 +55,15 @@ dma_free_coherent(struct device *dev, si
 	pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle);
 }
 
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	BUG_ON(dev->bus != &pci_bus_type);
+
+	return pci_mmap_consistent(to_pci_dev(dev), vma, cpu_addr, handle, size);
+}
+
 static inline dma_addr_t
 dma_map_single(struct device *dev, void *cpu_addr, size_t size,
 	       enum dma_data_direction direction)
@@ -181,6 +194,14 @@ dma_free_coherent(struct device *dev, si
 	BUG();
 }
 
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	BUG();
+	return -ENXIO;
+}
+
 static inline dma_addr_t
 dma_map_single(struct device *dev, void *cpu_addr, size_t size,
 	       enum dma_data_direction direction)
@@ -267,6 +288,7 @@ #endif
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_mmap_noncoherent(d, v, a, h, s) dma_mmap_coherent(d, v, a, h, s)
 #define dma_is_consistent(d)	(1)
 
 static inline int
diff --git a/include/asm-i386/dma-mapping.h b/include/asm-i386/dma-mapping.h
index 9cf20ca..144b5c7 100644
--- a/include/asm-i386/dma-mapping.h
+++ b/include/asm-i386/dma-mapping.h
@@ -10,6 +10,7 @@ #include <asm/bug.h>
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_mmap_noncoherent(d, v, a, h, s) dma_mmap_coherent(d, v, a, h, s)
 
 void *dma_alloc_coherent(struct device *dev, size_t size,
 			   dma_addr_t *dma_handle, gfp_t flag);
@@ -17,6 +18,17 @@ void *dma_alloc_coherent(struct device *
 void dma_free_coherent(struct device *dev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle);
 
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
 static inline dma_addr_t
 dma_map_single(struct device *dev, void *ptr, size_t size,
 	       enum dma_data_direction direction)
diff --git a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h
index df67d40..d441031 100644
--- a/include/asm-ia64/dma-mapping.h
+++ b/include/asm-ia64/dma-mapping.h
@@ -12,6 +12,20 @@ #define dma_alloc_coherent	platform_dma_
 #define dma_alloc_noncoherent	platform_dma_alloc_coherent	/* coherent mem. is cheap */
 #define dma_free_coherent	platform_dma_free_coherent
 #define dma_free_noncoherent	platform_dma_free_coherent
+
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
+#define dma_mmap_noncoherent	dma_mmap_coherent
+
 #define dma_map_single		platform_dma_map_single
 #define dma_map_sg		platform_dma_map_sg
 #define dma_unmap_single	platform_dma_unmap_single
diff --git a/include/asm-m32r/dma-mapping.h b/include/asm-m32r/dma-mapping.h
index a7fa030..d00e400 100644
--- a/include/asm-m32r/dma-mapping.h
+++ b/include/asm-m32r/dma-mapping.h
@@ -1,23 +1 @@
-#ifndef _ASM_M32R_DMA_MAPPING_H
-#define _ASM_M32R_DMA_MAPPING_H
-
-/*
- * NOTE: Do not include <asm-generic/dma-mapping.h>
- * Because it requires PCI stuffs, but current M32R don't provide these.
- */
-
-static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-		   gfp_t flag)
-{
-	return (void *)NULL;
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-		    dma_addr_t dma_handle)
-{
-	return;
-}
-
-#endif /* _ASM_M32R_DMA_MAPPING_H */
+#include <asm-generic/dma-mapping-broken.h>
diff --git a/include/asm-mips/dma-mapping.h b/include/asm-mips/dma-mapping.h
index 4328863..391abbd 100644
--- a/include/asm-mips/dma-mapping.h
+++ b/include/asm-mips/dma-mapping.h
@@ -16,6 +16,12 @@ void *dma_alloc_coherent(struct device *
 void dma_free_coherent(struct device *dev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle);
 
+int dma_mmap_noncoherent(struct device *dev, struct vm_area_struct *vma,
+			 void *cpu_addr, dma_addr_t handle, size_t size);
+
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		      void *cpu_addr, dma_addr_t handle, size_t size);
+
 extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
 	enum dma_data_direction direction);
 extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
diff --git a/include/asm-parisc/dma-mapping.h b/include/asm-parisc/dma-mapping.h
index 74d4ac6..c5cb337 100644
--- a/include/asm-parisc/dma-mapping.h
+++ b/include/asm-parisc/dma-mapping.h
@@ -20,6 +20,10 @@ struct hppa_dma_ops {
 	void (*dma_sync_single_for_device)(struct device *dev, dma_addr_t iova, unsigned long offset, size_t size, enum dma_data_direction direction);
 	void (*dma_sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction);
 	void (*dma_sync_sg_for_device)(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction);
+	int (*mmap_coherent)(struct device *dev, struct vm_area_struct *vma,
+			     void *cpu_addr, dma_addr_t handle, size_t size);
+	int (*mmap_noncoherent)(struct device *dev, struct vm_area_struct *vma,
+				void *cpu_addr, dma_addr_t handle, size_t size);
 };
 
 /*
@@ -75,6 +79,20 @@ dma_free_noncoherent(struct device *dev,
 	hppa_dma_ops->free_consistent(dev, size, vaddr, dma_handle);
 }
 
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	hppa_dma_ops->mmap_coherent(dev, vma, cpu_addr, handle, size);
+}
+
+static inline int
+dma_mmap_noncoherent(struct device *dev, struct vm_area_struct *vma,
+		     void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	hppa_dma_ops->mmap_noncoherent(dev, vma, cpu_addr, handle, size);
+}
+
 static inline dma_addr_t
 dma_map_single(struct device *dev, void *ptr, size_t size,
 	       enum dma_data_direction direction)
diff --git a/include/asm-powerpc/dma-mapping.h b/include/asm-powerpc/dma-mapping.h
index 2ac63f5..7e74385 100644
--- a/include/asm-powerpc/dma-mapping.h
+++ b/include/asm-powerpc/dma-mapping.h
@@ -167,6 +167,17 @@ #define dma_unmap_sg(dev, sg, nents, dir
 
 #endif /* CONFIG_PPC64 */
 
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
 static inline void dma_sync_single_for_cpu(struct device *dev,
 		dma_addr_t dma_handle, size_t size,
 		enum dma_data_direction direction)
@@ -218,6 +229,7 @@ #endif
 
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_mmap_noncoherent(d, v, a, h, s) dma_mmap_coherent(d, v, a, h, s)
 #ifdef CONFIG_NOT_COHERENT_CACHE
 #define dma_is_consistent(d)	(0)
 #else
diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h
index 48f1f42..7c84cbf 100644
--- a/include/asm-sh/dma-mapping.h
+++ b/include/asm-sh/dma-mapping.h
@@ -12,6 +12,7 @@ extern struct bus_type pci_bus_type;
 /* arch/sh/mm/consistent.c */
 extern void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle);
 extern void consistent_free(void *vaddr, size_t size);
+extern int consistent_mmap(struct vm_area_struct *vma, void *vaddr, size_t size);
 extern void consistent_sync(void *vaddr, size_t size, int direction);
 
 #define dma_supported(dev, mask)	(1)
@@ -54,6 +55,16 @@ static inline void dma_free_coherent(str
 	consistent_free(vaddr, size);
 }
 
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	if (sh_mv.mv_consistent_alloc)
+		return -ENXIO;
+	else
+		return consistent_mmap(vma, cpu_addr, size);
+}
+
 static inline void dma_cache_sync(void *vaddr, size_t size,
 				  enum dma_data_direction dir)
 {
diff --git a/include/asm-sh64/dma-mapping.h b/include/asm-sh64/dma-mapping.h
index cc9a2e8..66cceaf 100644
--- a/include/asm-sh64/dma-mapping.h
+++ b/include/asm-sh64/dma-mapping.h
@@ -11,6 +11,8 @@ extern void *consistent_alloc(struct pci
 				    dma_addr_t *dma_handle);
 extern void consistent_free(struct pci_dev *hwdev, size_t size,
 				  void *vaddr, dma_addr_t dma_handle);
+extern int consistent_mmap(struct vm_area_struct *vma, void *vaddr,
+			   dma_addr_t handle, size_t size);
 
 #define dma_supported(dev, mask)	(1)
 
@@ -36,6 +38,21 @@ static inline void dma_free_coherent(str
 	consistent_free(NULL, size, vaddr, dma_handle);
 }
 
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	unsigned long pfn;
+
+	/* dma_handle is equivalent with phys addr */
+	pfn = (unsigned long)handle >> PAGE_SHIFT;
+	return remap_pfn_range(vma, vma->vm_start,
+			       pfn + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+
+}
+
 static inline void dma_cache_sync(void *vaddr, size_t size,
 				  enum dma_data_direction dir)
 {
diff --git a/include/asm-sparc/dma-mapping.h b/include/asm-sparc/dma-mapping.h
index d7c3b0f..22380c0 100644
--- a/include/asm-sparc/dma-mapping.h
+++ b/include/asm-sparc/dma-mapping.h
@@ -6,20 +6,7 @@ #include <linux/config.h>
 #ifdef CONFIG_PCI
 #include <asm-generic/dma-mapping.h>
 #else
-
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-			 dma_addr_t *dma_handle, gfp_t flag)
-{
-	BUG();
-	return NULL;
-}
-
-static inline void dma_free_coherent(struct device *dev, size_t size,
-		       void *vaddr, dma_addr_t dma_handle)
-{
-	BUG();
-}
-
+#include <asm-generic/dma-mapping-broken.h>
 #endif /* PCI */
 
 #endif /* _ASM_SPARC_DMA_MAPPING_H */
diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h
index a8d39f2..8ea0082 100644
--- a/include/asm-sparc64/dma-mapping.h
+++ b/include/asm-sparc64/dma-mapping.h
@@ -145,22 +145,7 @@ dma_mapping_error(dma_addr_t dma_addr)
 }
 
 #else
-
-struct device;
-
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-			 dma_addr_t *dma_handle, gfp_t flag)
-{
-	BUG();
-	return NULL;
-}
-
-static inline void dma_free_coherent(struct device *dev, size_t size,
-		       void *vaddr, dma_addr_t dma_handle)
-{
-	BUG();
-}
-
+#include <asm-generic/dma-mapping-broken.h>
 #endif /* PCI */
 
 #endif /* _ASM_SPARC64_DMA_MAPPING_H */
diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h
index 49a81a6..c3a9b25 100644
--- a/include/asm-x86_64/dma-mapping.h
+++ b/include/asm-x86_64/dma-mapping.h
@@ -49,6 +49,10 @@ struct dma_mapping_ops {
 				struct scatterlist *sg, int nents,
 				int direction);
 	int             (*dma_supported)(struct device *hwdev, u64 mask);
+	int		(*mmap_coherent)(struct device *hwdev,
+					 struct vm_area_struct *vma,
+					 void *cpu_addr, dma_addr_t handle,
+					 size_t size);
 	int		is_phys;
 };
 
@@ -69,6 +73,9 @@ extern void *dma_alloc_coherent(struct d
 extern void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
 			      dma_addr_t dma_handle);
 
+extern int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+			     void *cpu_addr, dma_addr_t handle, size_t size);
+
 static inline dma_addr_t
 dma_map_single(struct device *hwdev, void *ptr, size_t size,
 	       int direction)
diff --git a/include/asm-xtensa/dma-mapping.h b/include/asm-xtensa/dma-mapping.h
index c425f10..e0b1ca9 100644
--- a/include/asm-xtensa/dma-mapping.h
+++ b/include/asm-xtensa/dma-mapping.h
@@ -33,6 +33,17 @@ void *dma_alloc_coherent(struct device *
 void dma_free_coherent(struct device *dev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle);
 
+static inline int
+dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+		  void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	struct page *page = virt_to_page(bus_to_virt(handle));
+	return remap_pfn_range(vma, vma->vm_start,
+			       page_to_pfn(page) + vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
 static inline dma_addr_t
 dma_map_single(struct device *dev, void *ptr, size_t size,
 	       enum dma_data_direction direction)



More information about the Linuxppc-dev mailing list