[RFC PATCH 03/11] ppc: Create ops to choose between direct window and iommu based on device mask

Nishanth Aravamudan nacc at us.ibm.com
Sat Oct 9 04:33:04 EST 2010


Also allow the coherent ops to be iommu if only the coherent mask is too
small, mostly for driver that do not set set the coherent mask but also
don't use the coherent api.

Signed-off-by: Milton Miller <miltonm at bga.com>
Signed-off-by: Nishanth Aravamudan <nacc at us.ibm.com>
---
 arch/powerpc/include/asm/dma-mapping.h |    2 +
 arch/powerpc/kernel/Makefile           |    2 +-
 arch/powerpc/kernel/dma-choose64.c     |  167 ++++++++++++++++++++++++++++++++
 3 files changed, 170 insertions(+), 1 deletions(-)
 create mode 100644 arch/powerpc/kernel/dma-choose64.c

diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index 644103a..9ffb16a 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -68,6 +68,8 @@ static inline unsigned long device_to_mask(struct device *dev)
  */
 #ifdef CONFIG_PPC64
 extern struct dma_map_ops dma_iommu_ops;
+extern struct dma_map_ops dma_choose64_ops;
+extern struct dma_map_ops dma_iommu_coherent_ops;
 #endif
 extern struct dma_map_ops dma_direct_ops;
 
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 1dda701..21b8ea1 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -82,7 +82,7 @@ obj-y				+= time.o prom.o traps.o setup-common.o \
 				   udbg.o misc.o io.o dma.o \
 				   misc_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_PPC32)		+= entry_32.o setup_32.o
-obj-$(CONFIG_PPC64)		+= dma-iommu.o iommu.o
+obj-$(CONFIG_PPC64)		+= dma-iommu.o iommu.o dma-choose64.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
 obj-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE)	+= prom_init.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
diff --git a/arch/powerpc/kernel/dma-choose64.c b/arch/powerpc/kernel/dma-choose64.c
new file mode 100644
index 0000000..17c716f
--- /dev/null
+++ b/arch/powerpc/kernel/dma-choose64.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corporation
+ *
+ * Provide default implementations of the DMA mapping callbacks for
+ * directly mapped busses.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/bug.h>
+
+/*
+ * DMA operations that choose between a 64-bit direct mapping and and iommu
+ *
+ * This set of dma ops chooses between directing to a static 1:1 mapping
+ * that may require a 64 bit address and a iommu based on the declared
+ * streaming and coherent masks for the device.  The choice is made on
+ * the first dma map call.
+ */
+
+/* first BUG ops for calls out of sequence */
+
+void *dma_bug_alloc_coherent(struct device *dev, size_t size,
+				dma_addr_t *dma_handle, gfp_t flag)
+{
+	BUG();
+
+	return NULL;
+}
+
+void dma_bug_free_coherent(struct device *dev, size_t size,
+			      void *vaddr, dma_addr_t dma_handle)
+{
+	BUG();
+}
+
+static int dma_bug_dma_supported(struct device *dev, u64 mask)
+{
+	BUG();
+
+	return 0;
+}
+
+static int dma_bug_map_sg(struct device *dev, struct scatterlist *sgl,
+			     int nents, enum dma_data_direction direction,
+			     struct dma_attrs *attrs)
+{
+	BUG();
+
+	return 0;
+}
+
+
+static void dma_bug_unmap_sg(struct device *dev, struct scatterlist *sg,
+				int nents, enum dma_data_direction direction,
+				struct dma_attrs *attrs)
+{
+	BUG();
+}
+
+static dma_addr_t dma_bug_map_page(struct device *dev,
+					     struct page *page,
+					     unsigned long offset,
+					     size_t size,
+					     enum dma_data_direction dir,
+					     struct dma_attrs *attrs)
+{
+	BUG();
+
+	return DMA_ERROR_CODE;
+}
+
+
+static void dma_bug_unmap_page(struct device *dev,
+					 dma_addr_t dma_address,
+					 size_t size,
+					 enum dma_data_direction direction,
+					 struct dma_attrs *attrs)
+{
+	BUG();
+}
+
+
+static struct dma_map_ops *choose(struct device *dev)
+{
+	if (dma_direct_ops.dma_supported(dev, device_to_mask(dev))) {
+		if (dma_direct_ops.dma_supported(dev, dev->coherent_dma_mask))
+			return &dma_direct_ops;
+		return &dma_iommu_coherent_ops;
+	}
+	return &dma_iommu_ops;
+}
+
+void *dma_choose64_alloc_coherent(struct device *dev, size_t size,
+				dma_addr_t *dma_handle, gfp_t flag)
+{
+	struct dma_map_ops *new = choose(dev);
+
+	set_dma_ops(dev, new);
+	return new->alloc_coherent(dev, size, dma_handle, flag);
+}
+
+static int dma_choose64_map_sg(struct device *dev, struct scatterlist *sgl,
+			     int nents, enum dma_data_direction direction,
+			     struct dma_attrs *attrs)
+{
+	struct dma_map_ops *new = choose(dev);
+
+	set_dma_ops(dev, new);
+	return new->map_sg(dev, sgl, nents, direction, attrs);
+}
+
+
+static int dma_choose64_dma_supported(struct device *dev, u64 mask)
+{
+	return dma_direct_ops.dma_supported(dev, mask) ||
+		dma_iommu_ops.dma_supported(dev, mask);
+}
+
+static dma_addr_t dma_choose64_map_page(struct device *dev,
+					     struct page *page,
+					     unsigned long offset,
+					     size_t size,
+					     enum dma_data_direction dir,
+					     struct dma_attrs *attrs)
+{
+	struct dma_map_ops *new = choose(dev);
+
+	set_dma_ops(dev, new);
+	return new->map_page(dev, page, offset, size, dir, attrs);
+}
+
+struct dma_map_ops dma_choose64_ops = {
+	.alloc_coherent	= dma_choose64_alloc_coherent,
+	.free_coherent	= dma_bug_free_coherent,
+	.map_sg		= dma_choose64_map_sg,
+	.unmap_sg	= dma_bug_unmap_sg,
+	.dma_supported	= dma_choose64_dma_supported,
+	.map_page	= dma_choose64_map_page,
+	.unmap_page	= dma_bug_unmap_page,
+};
+EXPORT_SYMBOL(dma_choose64_ops);
+
+/* set these up to BUG() until we initialze them in the arch initcall below */
+struct dma_map_ops dma_iommu_coherent_ops = {
+	.alloc_coherent	= dma_bug_alloc_coherent,
+	.free_coherent	= dma_bug_free_coherent,
+	.map_sg		= dma_bug_map_sg,
+	.unmap_sg	= dma_bug_unmap_sg,
+	.dma_supported	= dma_bug_dma_supported,
+	.map_page	= dma_bug_map_page,
+	.unmap_page	= dma_bug_unmap_page,
+};
+EXPORT_SYMBOL(dma_iommu_coherent_ops);
+
+static int setup_choose64_ops(void)
+{
+	dma_iommu_coherent_ops = dma_direct_ops;
+	dma_iommu_coherent_ops.alloc_coherent = dma_iommu_ops.alloc_coherent;
+	dma_iommu_coherent_ops.free_coherent = dma_iommu_ops.free_coherent;
+
+	/* should we be stricter? */
+	dma_iommu_coherent_ops.dma_supported = dma_choose64_dma_supported;
+
+	return 0;
+}
+arch_initcall(setup_choose64_ops);
-- 
1.7.1



More information about the Linuxppc-dev mailing list