[patch 0/6] Implement dma_*map*_attrs() and DMA_ATTR_STRONG_ORDERING, use on Cell
From: <hidden>
Date: 2008-05-26 04:19:32
Subsystems: the rest · Maintainer: Linus Torvalds
Series: 6 patches touching 15 files, +290/-107
7 messages, 1 author, 2008-05-26 · open the first message on its own page
From: <hidden>
Date: 2008-05-26 04:19:32
-- This is a resend of the patchset sent out on 2008-05-01 titled "Implement dma_*map*_attrs() and DMA_ATTR_WEAK_ORDERING, use on Cell". The first five patches are the same, but patch #6 has been redone because on Cell the default should be to use weakly ordered mappings rather than strongly ordered. Thus the DMA attribute that is added in this patch has been changed from DMA_ATTR_WEAK_ORDERING to DMA_ATTR_STRONG_ORDERING. Thanks! Mark.
From: <hidden>
Date: 2008-05-26 04:19:32
Make iommu_map_sg take a struct iommu_table. It did so before commit 740c3ce66700640a6e6136ff679b067e92125794 (iommu sg merging: ppc: make iommu respect the segment size limits). This stops the function looking in the archdata.dma_data for the iommu table because in the future it will be called with a device that has no table there. This also has the nice side effect of making iommu_map_sg() match the other map functions. Signed-off-by: Mark Nelson <redacted> --- arch/powerpc/kernel/dma_64.c | 2 +- arch/powerpc/kernel/iommu.c | 7 +++---- include/asm-powerpc/iommu.h | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) Index: upstream/arch/powerpc/kernel/dma_64.c ===================================================================
--- upstream.orig/arch/powerpc/kernel/dma_64.c
+++ upstream/arch/powerpc/kernel/dma_64.c@@ -68,7 +68,7 @@ static void dma_iommu_unmap_single(struc static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { - return iommu_map_sg(dev, sglist, nelems, + return iommu_map_sg(dev, dev->archdata.dma_data, sglist, nelems, device_to_mask(dev), direction); }
Index: upstream/arch/powerpc/kernel/iommu.c ===================================================================
--- upstream.orig/arch/powerpc/kernel/iommu.c
+++ upstream/arch/powerpc/kernel/iommu.c@@ -267,11 +267,10 @@ static void iommu_free(struct iommu_tabl spin_unlock_irqrestore(&(tbl->it_lock), flags); } -int iommu_map_sg(struct device *dev, struct scatterlist *sglist, - int nelems, unsigned long mask, - enum dma_data_direction direction) +int iommu_map_sg(struct device *dev, struct iommu_table *tbl, + struct scatterlist *sglist, int nelems, + unsigned long mask, enum dma_data_direction direction) { - struct iommu_table *tbl = dev->archdata.dma_data; dma_addr_t dma_next = 0, dma_addr; unsigned long flags; struct scatterlist *s, *outs, *segstart;
Index: upstream/include/asm-powerpc/iommu.h ===================================================================
--- upstream.orig/include/asm-powerpc/iommu.h
+++ upstream/include/asm-powerpc/iommu.h@@ -79,9 +79,9 @@ extern void iommu_free_table(struct iomm extern struct iommu_table *iommu_init_table(struct iommu_table * tbl, int nid); -extern int iommu_map_sg(struct device *dev, struct scatterlist *sglist, - int nelems, unsigned long mask, - enum dma_data_direction direction); +extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl, + struct scatterlist *sglist, int nelems, + unsigned long mask, enum dma_data_direction direction); extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, int nelems, enum dma_data_direction direction);
--
From: <hidden>
Date: 2008-05-26 04:19:32
Update powerpc to use the new dma_*map*_attrs() interfaces. In doing so update struct dma_mapping_ops to accept a struct dma_attrs and propagate these changes through to all users of the code (generic IOMMU and the 64bit DMA code, and the iseries and ps3 platform code). The old dma_*map_*() interfaces are reimplemented as calls to the corresponding new interfaces. Signed-off-by: Mark Nelson <redacted> --- arch/powerpc/Kconfig | 1 arch/powerpc/kernel/dma_64.c | 34 ++++++--- arch/powerpc/kernel/ibmebus.c | 12 ++- arch/powerpc/kernel/iommu.c | 11 +-- arch/powerpc/platforms/iseries/iommu.c | 4 - arch/powerpc/platforms/ps3/system-bus.c | 17 ++-- include/asm-powerpc/dma-mapping.h | 116 +++++++++++++++++++++++--------- include/asm-powerpc/iommu.h | 12 ++- 8 files changed, 144 insertions(+), 63 deletions(-) Index: upstream/arch/powerpc/Kconfig ===================================================================
--- upstream.orig/arch/powerpc/Kconfig
+++ upstream/arch/powerpc/Kconfig@@ -110,6 +110,7 @@ config PPC select HAVE_KPROBES select HAVE_KRETPROBES select HAVE_LMB + select HAVE_DMA_ATTRS config EARLY_PRINTK bool
Index: upstream/arch/powerpc/kernel/dma_64.c ===================================================================
--- upstream.orig/arch/powerpc/kernel/dma_64.c
+++ upstream/arch/powerpc/kernel/dma_64.c@@ -50,32 +50,38 @@ static void dma_iommu_free_coherent(stru */ static dma_addr_t dma_iommu_map_single(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { return iommu_map_single(dev, dev->archdata.dma_data, vaddr, size, - device_to_mask(dev), direction); + device_to_mask(dev), direction, attrs); } static void dma_iommu_unmap_single(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { - iommu_unmap_single(dev->archdata.dma_data, dma_handle, size, direction); + iommu_unmap_single(dev->archdata.dma_data, dma_handle, size, direction, + attrs); } static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) + int nelems, enum dma_data_direction direction, + struct dma_attrs *attrs) { return iommu_map_sg(dev, dev->archdata.dma_data, sglist, nelems, - device_to_mask(dev), direction); + device_to_mask(dev), direction, attrs); } static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) + int nelems, enum dma_data_direction direction, + struct dma_attrs *attrs) { - iommu_unmap_sg(dev->archdata.dma_data, sglist, nelems, direction); + iommu_unmap_sg(dev->archdata.dma_data, sglist, nelems, direction, + attrs); } /* We support DMA to/from any memory page via the iommu */
@@ -148,19 +154,22 @@ static void dma_direct_free_coherent(str static dma_addr_t dma_direct_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { return virt_to_abs(ptr) + get_dma_direct_offset(dev); } static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { } static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) { struct scatterlist *sg; int i;
@@ -174,7 +183,8 @@ static int dma_direct_map_sg(struct devi } static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) { }
Index: upstream/arch/powerpc/kernel/ibmebus.c ===================================================================
--- upstream.orig/arch/powerpc/kernel/ibmebus.c
+++ upstream/arch/powerpc/kernel/ibmebus.c@@ -82,7 +82,8 @@ static void ibmebus_free_coherent(struct static dma_addr_t ibmebus_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { return (dma_addr_t)(ptr); }
@@ -90,14 +91,16 @@ static dma_addr_t ibmebus_map_single(str static void ibmebus_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { return; } static int ibmebus_map_sg(struct device *dev, struct scatterlist *sgl, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) { struct scatterlist *sg; int i;
@@ -112,7 +115,8 @@ static int ibmebus_map_sg(struct device static void ibmebus_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) { return; }
Index: upstream/arch/powerpc/kernel/iommu.c ===================================================================
--- upstream.orig/arch/powerpc/kernel/iommu.c
+++ upstream/arch/powerpc/kernel/iommu.c@@ -269,7 +269,8 @@ static void iommu_free(struct iommu_tabl int iommu_map_sg(struct device *dev, struct iommu_table *tbl, struct scatterlist *sglist, int nelems, - unsigned long mask, enum dma_data_direction direction) + unsigned long mask, enum dma_data_direction direction, + struct dma_attrs *attrs) { dma_addr_t dma_next = 0, dma_addr; unsigned long flags;
@@ -411,7 +412,8 @@ int iommu_map_sg(struct device *dev, str void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) + int nelems, enum dma_data_direction direction, + struct dma_attrs *attrs) { struct scatterlist *sg; unsigned long flags;
@@ -553,7 +555,7 @@ void iommu_free_table(struct iommu_table */ dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl, void *vaddr, size_t size, unsigned long mask, - enum dma_data_direction direction) + enum dma_data_direction direction, struct dma_attrs *attrs) { dma_addr_t dma_handle = DMA_ERROR_CODE; unsigned long uaddr;
@@ -586,7 +588,8 @@ dma_addr_t iommu_map_single(struct devic } void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) + size_t size, enum dma_data_direction direction, + struct dma_attrs *attrs) { unsigned int npages;
Index: upstream/arch/powerpc/platforms/iseries/iommu.c ===================================================================
--- upstream.orig/arch/powerpc/platforms/iseries/iommu.c
+++ upstream/arch/powerpc/platforms/iseries/iommu.c@@ -214,13 +214,13 @@ dma_addr_t iseries_hv_map(void *vaddr, s enum dma_data_direction direction) { return iommu_map_single(NULL, &vio_iommu_table, vaddr, size, - DMA_32BIT_MASK, direction); + DMA_32BIT_MASK, direction, NULL); } void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { - iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction); + iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction, NULL); } void __init iommu_vio_init(void)
Index: upstream/arch/powerpc/platforms/ps3/system-bus.c ===================================================================
--- upstream.orig/arch/powerpc/platforms/ps3/system-bus.c
+++ upstream/arch/powerpc/platforms/ps3/system-bus.c@@ -550,7 +550,7 @@ static void ps3_free_coherent(struct dev */ static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, struct dma_attrs *attrs) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int result;
@@ -570,7 +570,8 @@ static dma_addr_t ps3_sb_map_single(stru static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int result;
@@ -603,7 +604,7 @@ static dma_addr_t ps3_ioc0_map_single(st } static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction direction) + size_t size, enum dma_data_direction direction, struct dma_attrs *attrs) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int result;
@@ -617,7 +618,7 @@ static void ps3_unmap_single(struct devi } static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sgl, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, struct dma_attrs *attrs) { #if defined(CONFIG_PS3_DYNAMIC_DMA) BUG_ON("do");
@@ -646,14 +647,15 @@ static int ps3_sb_map_sg(struct device * static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { BUG(); return 0; } static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, struct dma_attrs *attrs) { #if defined(CONFIG_PS3_DYNAMIC_DMA) BUG_ON("do");
@@ -661,7 +663,8 @@ static void ps3_sb_unmap_sg(struct devic } static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) { BUG(); }
Index: upstream/include/asm-powerpc/dma-mapping.h ===================================================================
--- upstream.orig/include/asm-powerpc/dma-mapping.h
+++ upstream/include/asm-powerpc/dma-mapping.h@@ -13,6 +13,7 @@ /* need struct page definitions */ #include <linux/mm.h> #include <linux/scatterlist.h> +#include <linux/dma-attrs.h> #include <asm/io.h> #define DMA_ERROR_CODE (~(dma_addr_t)0x0)
@@ -53,13 +54,17 @@ struct dma_mapping_ops { void (*free_coherent)(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle); dma_addr_t (*map_single)(struct device *dev, void *ptr, - size_t size, enum dma_data_direction direction); + size_t size, enum dma_data_direction direction, + struct dma_attrs *attrs); void (*unmap_single)(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction direction); + size_t size, enum dma_data_direction direction, + struct dma_attrs *attrs); int (*map_sg)(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction); + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs); void (*unmap_sg)(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction); + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs); int (*dma_supported)(struct device *dev, u64 mask); int (*set_dma_mask)(struct device *dev, u64 dma_mask); };
@@ -109,6 +114,77 @@ static inline int dma_set_mask(struct de return 0; } +static inline dma_addr_t dma_map_single_attrs(struct device *dev, + void *cpu_addr, + size_t size, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); + + BUG_ON(!dma_ops); + return dma_ops->map_single(dev, cpu_addr, size, direction, attrs); +} + +static inline void dma_unmap_single_attrs(struct device *dev, + dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); + + BUG_ON(!dma_ops); + dma_ops->unmap_single(dev, dma_addr, size, direction, attrs); +} + +static inline dma_addr_t dma_map_page_attrs(struct device *dev, + struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); + + BUG_ON(!dma_ops); + return dma_ops->map_single(dev, page_address(page) + offset, size, + direction, attrs); +} + +static inline void dma_unmap_page_attrs(struct device *dev, + dma_addr_t dma_address, + size_t size, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); + + BUG_ON(!dma_ops); + dma_ops->unmap_single(dev, dma_address, size, direction, attrs); +} + +static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); + + BUG_ON(!dma_ops); + return dma_ops->map_sg(dev, sg, nents, direction, attrs); +} + +static inline void dma_unmap_sg_attrs(struct device *dev, + struct scatterlist *sg, + int nhwentries, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + struct dma_mapping_ops *dma_ops = get_dma_ops(dev); + + BUG_ON(!dma_ops); + dma_ops->unmap_sg(dev, sg, nhwentries, direction, attrs); +} + static inline void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) {
@@ -131,63 +207,43 @@ static inline dma_addr_t dma_map_single( size_t size, enum dma_data_direction direction) { - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - BUG_ON(!dma_ops); - return dma_ops->map_single(dev, cpu_addr, size, direction); + return dma_map_single_attrs(dev, cpu_addr, size, direction, NULL); } static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction) { - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - BUG_ON(!dma_ops); - dma_ops->unmap_single(dev, dma_addr, size, direction); + dma_unmap_single_attrs(dev, dma_addr, size, direction, NULL); } static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction direction) { - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - BUG_ON(!dma_ops); - return dma_ops->map_single(dev, page_address(page) + offset, size, - direction); + return dma_map_page_attrs(dev, page, offset, size, direction, NULL); } static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, enum dma_data_direction direction) { - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - BUG_ON(!dma_ops); - dma_ops->unmap_single(dev, dma_address, size, direction); + dma_unmap_page_attrs(dev, dma_address, size, direction, NULL); } static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction) { - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - BUG_ON(!dma_ops); - return dma_ops->map_sg(dev, sg, nents, direction); + return dma_map_sg_attrs(dev, sg, nents, direction, NULL); } static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, enum dma_data_direction direction) { - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - BUG_ON(!dma_ops); - dma_ops->unmap_sg(dev, sg, nhwentries, direction); + dma_unmap_sg_attrs(dev, sg, nhwentries, direction, NULL); } - /* * Available generic sets of operations */
Index: upstream/include/asm-powerpc/iommu.h ===================================================================
--- upstream.orig/include/asm-powerpc/iommu.h
+++ upstream/include/asm-powerpc/iommu.h@@ -81,9 +81,11 @@ extern struct iommu_table *iommu_init_ta extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl, struct scatterlist *sglist, int nelems, - unsigned long mask, enum dma_data_direction direction); + unsigned long mask, enum dma_data_direction direction, + struct dma_attrs *attrs); extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction); + int nelems, enum dma_data_direction direction, + struct dma_attrs *attrs); extern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, size_t size, dma_addr_t *dma_handle,
@@ -92,9 +94,11 @@ extern void iommu_free_coherent(struct i void *vaddr, dma_addr_t dma_handle); extern dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl, void *vaddr, size_t size, unsigned long mask, - enum dma_data_direction direction); + enum dma_data_direction direction, + struct dma_attrs *attrs); extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction); + size_t size, enum dma_data_direction direction, + struct dma_attrs *attrs); extern void iommu_init_early_pSeries(void); extern void iommu_init_early_iSeries(void);
--
From: <hidden>
Date: 2008-05-26 04:19:32
Make cell_dma_dev_setup_iommu() return a pointer to the struct iommu_table (or NULL if no table can be found) rather than putting this pointer into dev->archdata.dma_data (let the caller do that), and rename this function to cell_get_iommu_table() to reflect this change. This will allow us to get the iommu table for a device that doesn't have the table in the archdata. Signed-off-by: Mark Nelson <redacted> --- arch/powerpc/platforms/cell/iommu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) Index: upstream/arch/powerpc/platforms/cell/iommu.c ===================================================================
--- upstream.orig/arch/powerpc/platforms/cell/iommu.c
+++ upstream/arch/powerpc/platforms/cell/iommu.c@@ -541,7 +541,7 @@ static unsigned long cell_dma_direct_off static unsigned long dma_iommu_fixed_base; struct dma_mapping_ops dma_iommu_fixed_ops; -static void cell_dma_dev_setup_iommu(struct device *dev) +static struct iommu_table *cell_get_iommu_table(struct device *dev) { struct iommu_window *window; struct cbe_iommu *iommu;
@@ -556,11 +556,11 @@ static void cell_dma_dev_setup_iommu(str printk(KERN_ERR "iommu: missing iommu for %s (node %d)\n", archdata->of_node ? archdata->of_node->full_name : "?", archdata->numa_node); - return; + return NULL; } window = list_entry(iommu->windows.next, struct iommu_window, list); - archdata->dma_data = &window->table; + return &window->table; } static void cell_dma_dev_setup_fixed(struct device *dev);
@@ -573,7 +573,7 @@ static void cell_dma_dev_setup(struct de if (get_dma_ops(dev) == &dma_iommu_fixed_ops) cell_dma_dev_setup_fixed(dev); else if (get_pci_dma_ops() == &dma_iommu_ops) - cell_dma_dev_setup_iommu(dev); + archdata->dma_data = cell_get_iommu_table(dev); else if (get_pci_dma_ops() == &dma_direct_ops) archdata->dma_data = (void *)cell_dma_direct_offset; else
--
From: <hidden>
Date: 2008-05-26 04:19:33
Move device_to_mask() to dma-mapping.h because we need to use it from outside dma_64.c in a later patch. Signed-off-by: Mark Nelson <redacted> --- arch/powerpc/kernel/dma_64.c | 9 --------- include/asm-powerpc/dma-mapping.h | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) Index: upstream/arch/powerpc/kernel/dma_64.c ===================================================================
--- upstream.orig/arch/powerpc/kernel/dma_64.c
+++ upstream/arch/powerpc/kernel/dma_64.c@@ -15,15 +15,6 @@ * Generic iommu implementation */ -static inline unsigned long device_to_mask(struct device *dev) -{ - if (dev->dma_mask && *dev->dma_mask) - return *dev->dma_mask; - /* Assume devices without mask can take 32 bit addresses */ - return 0xfffffffful; -} - - /* Allocates a contiguous real buffer and creates mappings over it. * Returns the virtual address of the buffer and sets dma_handle * to the dma address (mapping) of the first page.
Index: upstream/include/asm-powerpc/dma-mapping.h ===================================================================
--- upstream.orig/include/asm-powerpc/dma-mapping.h
+++ upstream/include/asm-powerpc/dma-mapping.h@@ -45,6 +45,15 @@ extern void __dma_sync_page(struct page #endif /* ! CONFIG_NOT_COHERENT_CACHE */ #ifdef CONFIG_PPC64 + +static inline unsigned long device_to_mask(struct device *dev) +{ + if (dev->dma_mask && *dev->dma_mask) + return *dev->dma_mask; + /* Assume devices without mask can take 32 bit addresses */ + return 0xfffffffful; +} + /* * DMA operations are abstracted for G5 vs. i/pSeries, PCI vs. VIO */
--
From: <hidden>
Date: 2008-05-26 04:19:33
Introduce a new dma attriblue DMA_ATTR_STRONG_ORDERING to use strong ordering on DMA mappings in the Cell processor. Add the code to the Cell's IOMMU implementation to use this. The current Cell IOMMU implementation sets the IOPTE_SO_RW bits in all IOTPEs (for both the dynamic and fixed mappings) which enforces strong ordering of both reads and writes. This patch makes the default behaviour weak ordering (the IOPTE_SO_RW bits not set) and to request a strongly ordered mapping the new DMA_ATTR_STRONG_ORDERING needs to be used. Dynamic mappings can be weakly or strongly ordered on an individual basis but the fixed mapping is always weakly ordered. Signed-off-by: Mark Nelson <redacted> --- Documentation/DMA-attributes.txt | 12 ++++ arch/powerpc/platforms/cell/iommu.c | 93 +++++++++++++++++++++++++++++++++--- include/linux/dma-attrs.h | 1 3 files changed, 99 insertions(+), 7 deletions(-) Index: upstream/arch/powerpc/platforms/cell/iommu.c ===================================================================
--- upstream.orig/arch/powerpc/platforms/cell/iommu.c
+++ upstream/arch/powerpc/platforms/cell/iommu.c@@ -194,11 +194,13 @@ static void tce_build_cell(struct iommu_ const unsigned long prot = 0xc48; base_pte = ((prot << (52 + 4 * direction)) & (IOPTE_PP_W | IOPTE_PP_R)) - | IOPTE_M | IOPTE_SO_RW | (window->ioid & IOPTE_IOID_Mask); + | IOPTE_M | (window->ioid & IOPTE_IOID_Mask); #else - base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | + base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | (window->ioid & IOPTE_IOID_Mask); #endif + if (unlikely(dma_get_attr(DMA_ATTR_STRONG_ORDERING, attrs))) + base_pte |= IOPTE_SO_RW; io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
@@ -539,7 +541,6 @@ static struct cbe_iommu *cell_iommu_for_ static unsigned long cell_dma_direct_offset; static unsigned long dma_iommu_fixed_base; -struct dma_mapping_ops dma_iommu_fixed_ops; static struct iommu_table *cell_get_iommu_table(struct device *dev) {
@@ -563,6 +564,85 @@ static struct iommu_table *cell_get_iomm return &window->table; } +static void *dma_fixed_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) +{ + return dma_direct_ops.alloc_coherent(dev, size, dma_handle, flag); +} + +static void dma_fixed_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + dma_direct_ops.free_coherent(dev, size, vaddr, dma_handle); +} + +static dma_addr_t dma_fixed_map_single(struct device *dev, void *ptr, + size_t size, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + if (dma_get_attr(DMA_ATTR_STRONG_ORDERING, attrs)) + return iommu_map_single(dev, cell_get_iommu_table(dev), ptr, + size, device_to_mask(dev), direction, + attrs); + else + return dma_direct_ops.map_single(dev, ptr, size, direction, + attrs); +} + +static void dma_fixed_unmap_single(struct device *dev, dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + if (dma_get_attr(DMA_ATTR_STRONG_ORDERING, attrs)) + iommu_unmap_single(cell_get_iommu_table(dev), dma_addr, size, + direction, attrs); + else + dma_direct_ops.unmap_single(dev, dma_addr, size, direction, + attrs); +} + +static int dma_fixed_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + if (dma_get_attr(DMA_ATTR_STRONG_ORDERING, attrs)) + return iommu_map_sg(dev, cell_get_iommu_table(dev), sg, nents, + device_to_mask(dev), direction, attrs); + else + return dma_direct_ops.map_sg(dev, sg, nents, direction, attrs); +} + +static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + if (dma_get_attr(DMA_ATTR_STRONG_ORDERING, attrs)) + iommu_unmap_sg(cell_get_iommu_table(dev), sg, nents, direction, + attrs); + else + dma_direct_ops.unmap_sg(dev, sg, nents, direction, attrs); +} + +static int dma_fixed_dma_supported(struct device *dev, u64 mask) +{ + return mask == DMA_64BIT_MASK; +} + +static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask); + +struct dma_mapping_ops dma_iommu_fixed_ops = { + .alloc_coherent = dma_fixed_alloc_coherent, + .free_coherent = dma_fixed_free_coherent, + .map_single = dma_fixed_map_single, + .unmap_single = dma_fixed_unmap_single, + .map_sg = dma_fixed_map_sg, + .unmap_sg = dma_fixed_unmap_sg, + .dma_supported = dma_fixed_dma_supported, + .set_dma_mask = dma_set_mask_and_switch, +}; + static void cell_dma_dev_setup_fixed(struct device *dev); static void cell_dma_dev_setup(struct device *dev)
@@ -919,9 +999,11 @@ static void cell_iommu_setup_fixed_ptab( pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase); - base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW + base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask); + pr_info("IOMMU: Using weak ordering for fixed mapping\n"); + for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) { /* Don't touch the dynamic region */ ioaddr = uaddr + fbase;
@@ -1037,9 +1119,6 @@ static int __init cell_iommu_fixed_mappi cell_iommu_setup_window(iommu, np, dbase, dsize, 0); } - dma_iommu_fixed_ops = dma_direct_ops; - dma_iommu_fixed_ops.set_dma_mask = dma_set_mask_and_switch; - dma_iommu_ops.set_dma_mask = dma_set_mask_and_switch; set_pci_dma_ops(&dma_iommu_ops);
Index: upstream/Documentation/DMA-attributes.txt ===================================================================
--- upstream.orig/Documentation/DMA-attributes.txt
+++ upstream/Documentation/DMA-attributes.txt@@ -22,3 +22,15 @@ ready and available in memory. The DMA could race with data DMA. Mapping the memory used for completion indications with DMA_ATTR_WRITE_BARRIER would prevent the race. + +DMA_ATTR_STRONG_ORDERING +---------------------- + +DMA_ATTR_STRONG_ORDERING specifies that previous reads and writes are +performed in the order in which they're received by the IOMMU; thus +reads and writes may not pass each other. + +Platforms that are strongly ordered by default will ignore this new +attribute but platforms that are weakly ordered by default should not +ignore this new attribute. Instead, they should return an error if a +strongly ordered mapping cannot be used when one is requested.
Index: upstream/include/linux/dma-attrs.h ===================================================================
--- upstream.orig/include/linux/dma-attrs.h
+++ upstream/include/linux/dma-attrs.h@@ -12,6 +12,7 @@ */ enum dma_attr { DMA_ATTR_WRITE_BARRIER, + DMA_ATTR_STRONG_ORDERING, DMA_ATTR_MAX, };
--
From: <hidden>
Date: 2008-05-26 04:19:33
Update iommu_alloc() to take the struct dma_attrs and pass them on to tce_build(). This change propagates down to the tce_build functions of all the platforms. Signed-off-by: Mark Nelson <redacted> --- arch/powerpc/kernel/iommu.c | 13 ++++++++----- arch/powerpc/platforms/cell/iommu.c | 5 +++-- arch/powerpc/platforms/iseries/iommu.c | 3 ++- arch/powerpc/platforms/pasemi/iommu.c | 3 ++- arch/powerpc/platforms/pseries/iommu.c | 13 ++++++++----- arch/powerpc/sysdev/dart_iommu.c | 3 ++- include/asm-powerpc/machdep.h | 3 ++- 7 files changed, 27 insertions(+), 16 deletions(-) Index: upstream/arch/powerpc/kernel/iommu.c ===================================================================
--- upstream.orig/arch/powerpc/kernel/iommu.c
+++ upstream/arch/powerpc/kernel/iommu.c@@ -186,7 +186,8 @@ static unsigned long iommu_range_alloc(s static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, void *page, unsigned int npages, enum dma_data_direction direction, - unsigned long mask, unsigned int align_order) + unsigned long mask, unsigned int align_order, + struct dma_attrs *attrs) { unsigned long entry, flags; dma_addr_t ret = DMA_ERROR_CODE;
@@ -205,7 +206,7 @@ static dma_addr_t iommu_alloc(struct dev /* Put the TCEs in the HW table */ ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & IOMMU_PAGE_MASK, - direction); + direction, attrs); /* Flush/invalidate TLB caches if necessary */
@@ -336,7 +337,8 @@ int iommu_map_sg(struct device *dev, str npages, entry, dma_addr); /* Insert into HW table */ - ppc_md.tce_build(tbl, entry, npages, vaddr & IOMMU_PAGE_MASK, direction); + ppc_md.tce_build(tbl, entry, npages, vaddr & IOMMU_PAGE_MASK, + direction, attrs); /* If we are in an open segment, try merging */ if (segstart != s) {
@@ -573,7 +575,8 @@ dma_addr_t iommu_map_single(struct devic align = PAGE_SHIFT - IOMMU_PAGE_SHIFT; dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction, - mask >> IOMMU_PAGE_SHIFT, align); + mask >> IOMMU_PAGE_SHIFT, align, + attrs); if (dma_handle == DMA_ERROR_CODE) { if (printk_ratelimit()) { printk(KERN_INFO "iommu_alloc failed, "
@@ -642,7 +645,7 @@ void *iommu_alloc_coherent(struct device nio_pages = size >> IOMMU_PAGE_SHIFT; io_order = get_iommu_order(size); mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL, - mask >> IOMMU_PAGE_SHIFT, io_order); + mask >> IOMMU_PAGE_SHIFT, io_order, NULL); if (mapping == DMA_ERROR_CODE) { free_pages((unsigned long)ret, order); return NULL;
Index: upstream/arch/powerpc/platforms/cell/iommu.c ===================================================================
--- upstream.orig/arch/powerpc/platforms/cell/iommu.c
+++ upstream/arch/powerpc/platforms/cell/iommu.c@@ -173,7 +173,8 @@ static void invalidate_tce_cache(struct } static void tce_build_cell(struct iommu_table *tbl, long index, long npages, - unsigned long uaddr, enum dma_data_direction direction) + unsigned long uaddr, enum dma_data_direction direction, + struct dma_attrs *attrs) { int i; unsigned long *io_pte, base_pte;
@@ -519,7 +520,7 @@ cell_iommu_setup_window(struct cbe_iommu __set_bit(0, window->table.it_map); tce_build_cell(&window->table, window->table.it_offset, 1, - (unsigned long)iommu->pad_page, DMA_TO_DEVICE); + (unsigned long)iommu->pad_page, DMA_TO_DEVICE, NULL); window->table.it_hint = window->table.it_blocksize; return window;
Index: upstream/arch/powerpc/platforms/iseries/iommu.c ===================================================================
--- upstream.orig/arch/powerpc/platforms/iseries/iommu.c
+++ upstream/arch/powerpc/platforms/iseries/iommu.c@@ -42,7 +42,8 @@ #include <asm/iseries/iommu.h> static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, - unsigned long uaddr, enum dma_data_direction direction) + unsigned long uaddr, enum dma_data_direction direction, + struct dma_attrs *attrs) { u64 rc; u64 tce, rpn;
Index: upstream/arch/powerpc/platforms/pasemi/iommu.c ===================================================================
--- upstream.orig/arch/powerpc/platforms/pasemi/iommu.c
+++ upstream/arch/powerpc/platforms/pasemi/iommu.c@@ -85,7 +85,8 @@ static int iommu_table_iobmap_inited; static void iobmap_build(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { u32 *ip; u32 rpn;
Index: upstream/arch/powerpc/platforms/pseries/iommu.c ===================================================================
--- upstream.orig/arch/powerpc/platforms/pseries/iommu.c
+++ upstream/arch/powerpc/platforms/pseries/iommu.c@@ -50,7 +50,8 @@ static void tce_build_pSeries(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { u64 proto_tce; u64 *tcep;
@@ -95,7 +96,8 @@ static unsigned long tce_get_pseries(str static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages, unsigned long uaddr, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { u64 rc; u64 proto_tce, tce;
@@ -127,7 +129,8 @@ static DEFINE_PER_CPU(u64 *, tce_page) = static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages, unsigned long uaddr, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { u64 rc; u64 proto_tce;
@@ -137,7 +140,7 @@ static void tce_buildmulti_pSeriesLP(str if (npages == 1) return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, - direction); + direction, attrs); tcep = __get_cpu_var(tce_page);
@@ -149,7 +152,7 @@ static void tce_buildmulti_pSeriesLP(str /* If allocation fails, fall back to the loop implementation */ if (!tcep) return tce_build_pSeriesLP(tbl, tcenum, npages, - uaddr, direction); + uaddr, direction, attrs); __get_cpu_var(tce_page) = tcep; }
Index: upstream/arch/powerpc/sysdev/dart_iommu.c ===================================================================
--- upstream.orig/arch/powerpc/sysdev/dart_iommu.c
+++ upstream/arch/powerpc/sysdev/dart_iommu.c@@ -149,7 +149,8 @@ static void dart_flush(struct iommu_tabl static void dart_build(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { unsigned int *dp; unsigned int rpn;
Index: upstream/include/asm-powerpc/machdep.h ===================================================================
--- upstream.orig/include/asm-powerpc/machdep.h
+++ upstream/include/asm-powerpc/machdep.h@@ -80,7 +80,8 @@ struct machdep_calls { long index, long npages, unsigned long uaddr, - enum dma_data_direction direction); + enum dma_data_direction direction, + struct dma_attrs *attrs); void (*tce_free)(struct iommu_table *tbl, long index, long npages);
--