common non-cache coherent direct dma mapping ops
Subsystems (16)
Hi all,
this series continues consolidating the dma-mapping code, with a focus on architectures that do not (always) provide cache coherence for DMA. Three architectures (arm, mips and powerpc) are still left to be converted later due to complexity of their dma ops selection.
The dma-noncoherent ops calls the dma-direct ops for the actual translation of streaming mappins and allow the architecture to provide any cache flushing required for cpu to device and/or device to cpu ownership transfers. The dma coherent allocator is for now still left entirely to architecture supplied implementations due the amount of variations. Hopefully we can do some consolidation for them later on as well.
A lot of architectures are currently doing very questionable things in their dma mapping routines, which are documented in the changelogs for each patch. Please review them very careful and correct me on incorrect assumptions.
Because this series sits on top of two previously submitted series a git tree might be useful to actually test it. It is provided here:
git://git.infradead.org/users/hch/misc.git generic-dma-noncoherent
Gitweb:
http://git.infradead.org/users/hch/misc.git/shortlog/refs/heads/generic-dma-noncoherent
Changes since RFC:
- fix a typo accidentally disabling the device to cpu transfer sync
- fixed a few compile failures
PATCH 1/20 dma-mapping: simplify Kconfig dependencies
ARCH_DMA_ADDR_T_64BIT is always true for 64-bit architectures now, so we can skip the clause requiring it. 'n' is the default default, so no need to explicitly state it.
--- lib/Kconfig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
lib/Kconfig +2 -4
@@ -443,13 +443,11 @@ config IOMMU_HELPER config DMA_DIRECT_OPS bool - depends on HAS_DMA && (!64BIT || ARCH_DMA_ADDR_T_64BIT) - default n + depends on HAS_DMA config DMA_VIRT_OPS bool - depends on HAS_DMA && (!64BIT || ARCH_DMA_ADDR_T_64BIT) - default n + depends on HAS_DMA config SWIOTLB bool
Signature · 1 line
2.17.0
PATCH 2/20 dma-mapping: provide a generic dma-noncoherent implementation
In reply to Christoph HellwigAdd a new dma_map_ops implementation that uses dma-direct for the address mapping of streaming mappings, and which requires arch-specific implemenations of coherent allocate/free.
Architectures have to provide flushing helpers to ownership trasnfers to the device and/or CPU, and can provide optional implementations of the coherent mmap functionality, and the cache_flush routines for non-coherent long term allocations.
--- MAINTAINERS | 2 + include/asm-generic/dma-mapping.h | 9 +++ include/linux/dma-direct.h | 7 ++- include/linux/dma-mapping.h | 1 + include/linux/dma-noncoherent.h | 47 ++++++++++++++ lib/Kconfig | 20 ++++++ lib/Makefile | 1 + lib/dma-direct.c | 8 +-- lib/dma-noncoherent.c | 101 ++++++++++++++++++++++++++++++ 9 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 include/linux/dma-noncoherent.h create mode 100644 lib/dma-noncoherent.c
MAINTAINERS +2 -0
@@ -4334,12 +4334,14 @@ W: http://git.infradead.org/users/hch/dma-mapping.git S: Supported F: lib/dma-debug.c F: lib/dma-direct.c +F: lib/dma-noncoherent.c F: lib/dma-virt.c F: drivers/base/dma-mapping.c F: drivers/base/dma-coherent.c F: include/asm-generic/dma-mapping.h F: include/linux/dma-direct.h F: include/linux/dma-mapping.h +F: include/linux/dma-noncoherent.h DME1737 HARDWARE MONITOR DRIVER M: Juerg Haefliger <[email protected]>
include/asm-generic/dma-mapping.h +9 -0
@@ -4,7 +4,16 @@static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) { +/* +* Use the non-coherent ops if available. If an architecture wants a +* more fine-grained selection of operations it will have to implement +* get_arch_dma_ops itself or use the per-device dma_ops. +*/ +#ifdef CONFIG_DMA_NONCOHERENT_OPS +return &dma_noncoherent_ops; +#else return &dma_direct_ops; +#endif }#endif /* _ASM_GENERIC_DMA_MAPPING_H */
include/linux/dma-direct.h +6 -1
@@ -59,6 +59,11 @@ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs);void dma_direct_free (struct device *dev,size_t size,void *cpu_addr,dma_addr_t dma_addr,unsigned long attrs); +dma_addr_t dma_direct_map_page (struct device *dev,struct page *page, +unsigned long offset,size_t size,enum dma_data_direction dir, +unsigned long attrs); +int dma_direct_map_sg (struct device *dev,struct scatterlist *sgl,int nents, +enum dma_data_direction dir,unsigned long attrs);int dma_direct_supported (struct device *dev,u64 mask); - +int dma_direct_mapping_error (struct device *dev,dma_addr_t dma_addr);#endif /* _LINUX_DMA_DIRECT_H */
include/linux/dma-mapping.h +1 -0
@@ -136,6 +136,7 @@ struct dma_map_ops { };extern const struct dma_map_ops dma_direct_ops; +extern const struct dma_map_ops dma_noncoherent_ops;extern const struct dma_map_ops dma_virt_ops;#define DMA_BIT_MASK (n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
include/linux/dma-noncoherent.h new file +47 -0
47 lines not on this page · raw message
lib/Kconfig +20 -0
@@ -441,10 +441,30 @@ config ARCH_DMA_ADDR_T_64BIT config IOMMU_HELPER bool +config ARCH_HAS_SYNC_DMA_FOR_DEVICE + bool + +config ARCH_HAS_SYNC_DMA_FOR_CPU + bool + select NEED_DMA_MAP_STATE + config DMA_DIRECT_OPS bool depends on HAS_DMA +config DMA_NONCOHERENT_OPS + bool + depends on HAS_DMA + select DMA_DIRECT_OPS + +config DMA_NONCOHERENT_MMAP + bool + depends on DMA_NONCOHERENT_OPS + +config DMA_NONCOHERENT_CACHE_SYNC + bool + depends on DMA_NONCOHERENT_OPS + config DMA_VIRT_OPS bool depends on HAS_DMA
lib/Makefile +1 -0
@@ -30,6 +30,7 @@ lib-$(CONFIG_PRINTK) += dump_stack.o lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o lib-$(CONFIG_DMA_DIRECT_OPS) += dma-direct.o +lib-$(CONFIG_DMA_NONCOHERENT_OPS) += dma-noncoherent.o lib-$(CONFIG_DMA_VIRT_OPS) += dma-virt.o lib-y += kobject.o klist.o
lib/dma-direct.c +4 -4
@@ -128,7 +128,7 @@ void dma_direct_free(struct device *dev, size_t size, void *cpu_addr,free_pages ((unsigned long )cpu_addr, page_order); } -static dma_addr_t dma_direct_map_page (struct device *dev,struct page *page, +dma_addr_t dma_direct_map_page (struct device *dev,struct page *page,unsigned long offset,size_t size,enum dma_data_direction dir,unsigned long attrs) {
@@ -139,8 +139,8 @@ static dma_addr_t dma_direct_map_page(struct device *dev, struct page *page,return dma_addr; } -static int dma_direct_map_sg (struct device *dev,struct scatterlist *sgl, -int nents,enum dma_data_direction dir,unsigned long attrs) +int dma_direct_map_sg (struct device *dev,struct scatterlist *sgl,int nents, +enum dma_data_direction dir,unsigned long attrs) {int i;struct scatterlist *sg;
@@ -175,7 +175,7 @@ int dma_direct_supported(struct device *dev, u64 mask)return 1 ; } -static int dma_direct_mapping_error (struct device *dev,dma_addr_t dma_addr) +int dma_direct_mapping_error (struct device *dev,dma_addr_t dma_addr) {return dma_addr ==DIRECT_MAPPING_ERROR ; }
lib/dma-noncoherent.c new file +101 -0
101 lines not on this page · raw message
Signature · 1 line
2.17.0
Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation
Hi Christoph,
On Fri, 2018-05-11 at 09:59 +0200, Christoph Hellwig wrote:
[snip]
There seems to be one subtle issue with map/unmap code.
While investigating problems on ARC I added instrumentation as below:
---------------------------------------->8------------------------------------
arch/arc/mm/dma.c +23 -0
@@ -152,14 +152,37 @@ static void _dma_cache_sync(struct device *dev, phys_addr_t paddr, size_t size, } } +static const char *dir_to_str (enum dma_data_direction dir) +{ +switch (dir) { +case DMA_BIDIRECTIONAL :return "DMA_BIDIRECTIONAL" ; +case DMA_TO_DEVICE :return "DMA_TO_DEVICE" ; +case DMA_FROM_DEVICE :return "DMA_FROM_DEVICE" ; +case DMA_NONE :return "DMA_NONE" ; +default :return "WRONG_VALUE!" ; + } +} +void arch_sync_dma_for_device (struct device *dev,phys_addr_t paddr,size_t size,enum dma_data_direction dir) { +if (dir !=DMA_TO_DEVICE ){ +dump_stack (); +printk (" *** %s@%d: DMA direction is %s instead of %s\n" , + __func__, __LINE__,dir_to_str (dir),dir_to_str (DMA_TO_DEVICE )); + } +return _dma_cache_sync (dev, paddr, size, dir); }void arch_sync_dma_for_cpu (struct device *dev,phys_addr_t paddr,size_t size,enum dma_data_direction dir) { +if (dir !=DMA_FROM_DEVICE ) { +dump_stack (); +printk (" *** %s@%d: DMA direction is %s instead of %s\n" , + __func__, __LINE__,dir_to_str (dir),dir_to_str (DMA_FROM_DEVICE )); + } +return _dma_cache_sync (dev, paddr, size, dir); }
---------------------------------------->8------------------------------------
And with that I noticed a bit unexpected output, see below:
---------------------------------------->8------------------------------------ Stack Trace:
arc_unwind_core.constprop.1+0xd4/0xf8 dump_stack+0x68/0x80 arch_sync_dma_for_device+0x34/0xc4 dma_noncoherent_map_sg+0x80/0x94 __dw_mci_start_request+0x1ee/0x868 dw_mci_request+0x17e/0x1c8 mmc_wait_for_req+0x106/0x1ac mmc_app_sd_status+0x108/0x130 mmc_sd_setup_card+0xc6/0x2e8 mmc_attach_sd+0x1b6/0x394 mmc_rescan+0x2f4/0x3bc process_one_work+0x194/0x348 worker_thread+0xf2/0x478 kthread+0x120/0x13c ret_from_fork+0x18/0x1c *** arch_sync_dma_for_device@172: DMA direction is DMA_FROM_DEVICE instead of DMA_TO_DEVICE ... Stack Trace: arc_unwind_core.constprop.1+0xd4/0xf8 dump_stack+0x68/0x80 arch_sync_dma_for_device+0x34/0xc4 dma_noncoherent_map_page+0x86/0x8c usb_hcd_map_urb_for_dma+0x49e/0x53c usb_hcd_submit_urb+0x43c/0x8c4 usb_control_msg+0xbe/0x16c hub_port_init+0x5e0/0xb0c hub_event+0x4e6/0x1164 process_one_work+0x194/0x348 worker_thread+0xf2/0x478 kthread+0x120/0x13c ret_from_fork+0x18/0x1c mmcblk0: p1 p2 *** arch_sync_dma_for_device@172: DMA direction is DMA_FROM_DEVICE instead of DMA_TO_DEVICE
...
and quite some more of the similar
...
---------------------------------------->8------------------------------------
In case of MMC/DW_MCI (AKA DesignWare MobileStorage controller) that's an execution flow:
1) __dw_mci_start_request()
2) dw_mci_pre_dma_transfer()
3) dma_map_sg(..., mmc_get_dma_dir(data))
Note mmc_get_dma_dir() is just "data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE". I.e. if we're preparing for sending data dma_noncoherent_map_sg() will have DMA_TO_DEVICE which is quite OK for passing to dma_noncoherent_sync_sg_for_device() but in case of reading we'll have DMA_FROM_DEVICE which we'll pass to dma_noncoherent_sync_sg_for_device() in dma_noncoherent_map_sg().
I'd say this is not entirely correct because IMHO arch_sync_dma_for_cpu() is supposed to only be used in case of DMA_FROM_DEVICE and arch_sync_dma_for_device() only in case of DMA_TO_DEVICE.
Quoted 10 lines
(quoted diff) +10
-0+static dma_addr_t dma_noncoherent_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction dir, + unsigned long attrs) +{ + dma_addr_t addr; + + addr = dma_direct_map_page(dev, page, offset, size, dir, attrs); + if (!dma_mapping_error(dev, addr) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) + arch_sync_dma_for_device(dev, page_to_phys(page), size, dir); + return addr;
Review
Quoted 10 lines
(quoted diff) +10
-0+} + +static int dma_noncoherent_map_sg(struct device *dev, struct scatterlist *sgl, + int nents, enum dma_data_direction dir, unsigned long attrs) +{ + nents = dma_direct_map_sg(dev, sgl, nents, dir, attrs); + if (nents > 0 && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) + dma_noncoherent_sync_sg_for_device(dev, sgl, nents, dir); + return nents; +}
The same is for unmap functions.
My guess is we need to respect direction in map/unmap functions and use either dma_noncoherent_sync_single_for_cpu(..., DMA_FROM_DEVICE) or dma_noncoherent_sync_single_for_device(...,DMA_TO_DEVICE).
Quoted 4 lines
(quoted diff) +4
-0+static void dma_noncoherent_unmap_page(struct device *dev, dma_addr_t addr, + size_t size, enum dma_data_direction dir, unsigned long attrs) +{ + if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
Review
Quoted 10 lines
(quoted diff) +10
-0+ dma_noncoherent_sync_single_for_cpu(dev, addr, size, dir); +} + +static void dma_noncoherent_unmap_sg(struct device *dev, struct scatterlist *sgl, + int nents, enum dma_data_direction dir, unsigned long attrs) +{ + if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) + dma_noncoherent_sync_sg_for_cpu(dev, sgl, nents, dir); +} +#endif
But the real fix of my problem is:
---------------------------------------->8------------------------------------
lib/dma-noncoherent.c +1 -2
@@ -35,7 +35,7 @@ static dma_addr_t dma_noncoherent_map_page(struct device *dev, struct page *page addr =dma_direct_map_page (dev, page, offset, size, dir, attrs);if (!dma_mapping_error (dev, addr) && !(attrs &DMA_ATTR_SKIP_CPU_SYNC )) -arch_sync_dma_for_device (dev,page_to_phys (page), size, dir); +arch_sync_dma_for_device (dev,page_to_phys (page) + offset, size, dir);return addr; } ---------------------------------------->8------------------------------------
You seem to lost an offset in the page so if we happen to have a buffer not aligned to a page boundary then we were obviously corrupting data outside our data :)
-Alexey
Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation
Quoted 7 lines · Alexey Brodkin
Note
mmc_get_dma_dir()is just "data->flags&MMC_DATA_WRITE?DMA_TO_DEVICE:DMA_FROM_DEVICE". I.e. if we're preparing for sending datadma_noncoherent_map_sg()will haveDMA_TO_DEVICEwhich is quite OK for passing todma_noncoherent_sync_sg_for_device()but in case of reading we'll haveDMA_FROM_DEVICEwhich we'll pass todma_noncoherent_sync_sg_for_device()indma_noncoherent_map_sg().I'd say this is not entirely correct because IMHO
arch_sync_dma_for_cpu()is supposed to only be used in case ofDMA_FROM_DEVICEandarch_sync_dma_for_device()only in case ofDMA_TO_DEVICE.
arc overrides the dir paramter of the dma_sync_single_for_device/ dma_sync_single_for_cpu calls. My patches dropped that, and I have restored that, and audit for the other architectures is pending.
That being said the existing arc code still looks rather odd as it didn't do the same thing for the scatterlist versions of the calls. I've thrown in a few patches into my new tree to make the sg versions make the normal calls, and to clean up the area a bit.
Quoted 2 lines
You seem to lost an offset in the page so if we happen to have a buffer not aligned to a page boundary then we were obviously corrupting data outside our data :)
Oops! Thank you for all the debugging!
Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation
Hi Christoph,
Quoted 6 lines · On Fri, 2018-05-18 at 15:27 +0200, [email protected] wrote:
Quoted 5 lines · Alexey Brodkin
Note
mmc_get_dma_dir()is just "data->flags&MMC_DATA_WRITE?DMA_TO_DEVICE:DMA_FROM_DEVICE". I.e. if we're preparing for sending datadma_noncoherent_map_sg()will haveDMA_TO_DEVICEwhich is quite OK for passing todma_noncoherent_sync_sg_for_device()but in case of reading we'll haveDMA_FROM_DEVICEwhich we'll pass todma_noncoherent_sync_sg_for_device()indma_noncoherent_map_sg().
Quoted 6 lines
Quoted 2 lines
I'd say this is not entirely correct because IMHO
arch_sync_dma_for_cpu()is supposed to only be used in case ofDMA_FROM_DEVICEandarch_sync_dma_for_device()only in case ofDMA_TO_DEVICE.arc overrides the dir paramter of the dma_sync_single_for_device/
dma_sync_single_for_cpucalls. My patches dropped that, and I have restored that, and audit for the other architectures is pending.
Well at least for me that's a confusion what is a reason to pass direction to function which purpose is already known.
I'd say that XXX_sync_for_device() doesn't need _variable_ direction as an argument, otherwise what does that mean if we pass DMA_FROM_DEVICE to that function?
Quoted 2 lines
That being said the existing arc code still looks rather odd as it didn't do the same thing for the scatterlist versions of the calls.
That might easily be the case so good we caught that now and it will be fixed :)
Quoted 2 lines
I've thrown in a few patches into my new tree to make the sg versions make the normal calls, and to clean up the area a bit.
I'll try your newer series now, thanks!
-Alexey
Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation
In reply to [email protected]Quoted 11 lines · On 05/18/2018 06:23 AM, [email protected] wrote:
Quoted 7 lines · Alexey Brodkin
Note
mmc_get_dma_dir()is just "data->flags&MMC_DATA_WRITE?DMA_TO_DEVICE:DMA_FROM_DEVICE". I.e. if we're preparing for sending datadma_noncoherent_map_sg()will haveDMA_TO_DEVICEwhich is quite OK for passing todma_noncoherent_sync_sg_for_device()but in case of reading we'll haveDMA_FROM_DEVICEwhich we'll pass todma_noncoherent_sync_sg_for_device()indma_noncoherent_map_sg().I'd say this is not entirely correct because IMHO
arch_sync_dma_for_cpu()is supposed to only be used in case ofDMA_FROM_DEVICEandarch_sync_dma_for_device()only in case ofDMA_TO_DEVICE.arc overrides the dir paramter of the dma_sync_single_for_device/
dma_sync_single_for_cpucalls. My patches dropped that, and I have restored that, and audit for the other architectures is pending.
Right, for now lets retain that and do a sweeping audit of @direction - to me it seems extraneous (as it did 10 years ago), but I'm not an expert in this are so perhaps it is needed for some device / arches and it would be good to understand that finally.
Quoted 4 lines
That being said the existing arc code still looks rather odd as it didn't do the same thing for the scatterlist versions of the calls. I've thrown in a few patches into my new tree to make the sg versions make the normal calls, and to clean up the area a bit.
Not calling names or anything here, but it doesn't exist for sg variants, because I didn't write that code :-) It was introduced by your commi:
2016-01-20 052c96dbe33b arc: convert to dma_map_ops
dma_sync_*_for_cpu and direction=TO_DEVICE (was Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation)
In reply to Alexey BrodkinQuoted 23 lines · Alexey Brodkin
void arch_sync_dma_for_device(struct device *dev,
phys_addr_tpaddr,
size_tsize, enumdma_data_directiondir)
{arch/arc/mm/dma.c +12
-0+if (dir !=DMA_TO_DEVICE ){ +dump_stack (); +printk (" *** %s@%d: DMA direction is %s instead of %s\n" , + __func__, __LINE__,dir_to_str (dir),dir_to_str (DMA_TO_DEVICE )); + } +return _dma_cache_sync (dev, paddr, size, dir); }void arch_sync_dma_for_cpu (struct device *dev,phys_addr_t paddr,size_t size,enum dma_data_direction dir) { +if (dir !=DMA_FROM_DEVICE ) { +dump_stack (); +printk (" *** %s@%d: DMA direction is %s instead of %s\n" , + __func__, __LINE__,dir_to_str (dir),dir_to_str (DMA_FROM_DEVICE )); + } +return _dma_cache_sync (dev, paddr, size, dir); }
...
Quoted 5 lines
In case of MMC/DW_MCI (AKA DesignWare MobileStorage controller) that's an execution flow:
1)__dw_mci_start_request()
2)dw_mci_pre_dma_transfer()
3)dma_map_sg(..., mmc_get_dma_dir(data))
Quoted 7 lines
Note
mmc_get_dma_dir()is just "data->flags&MMC_DATA_WRITE?DMA_TO_DEVICE:DMA_FROM_DEVICE". I.e. if we're preparing for sending datadma_noncoherent_map_sg()will haveDMA_TO_DEVICEwhich is quite OK for passing todma_noncoherent_sync_sg_for_device()but in case of reading we'll haveDMA_FROM_DEVICEwhich we'll pass todma_noncoherent_sync_sg_for_device()indma_noncoherent_map_sg().I'd say this is not entirely correct because IMHO
arch_sync_dma_for_cpu()is supposed to only be used in case ofDMA_FROM_DEVICEandarch_sync_dma_for_device()only in case ofDMA_TO_DEVICE.
So roughly 10 years ago, some kernel rookie name Vineet Gupta, asked the exact same question :-)
I never understood the need for this direction. And if memory serves me right, at that time I was seeing twice the amount of cache flushing !
Quoted 14 lines
But the real fix of my problem is:
---------------------------------------->8------------------------------------lib/dma-noncoherent.c +1
-2@@ -35,7 +35,7 @@ static dma_addr_t dma_noncoherent_map_page(struct device *dev, struct page *page addr =dma_direct_map_page (dev, page, offset, size, dir, attrs);if (!dma_mapping_error (dev, addr) && !(attrs &DMA_ATTR_SKIP_CPU_SYNC )) -arch_sync_dma_for_device (dev,page_to_phys (page), size, dir); +arch_sync_dma_for_device (dev,page_to_phys (page) + offset, size, dir);return addr; } ---------------------------------------->8------------------------------------
Quoted 2 lines
You seem to lost an offset in the page so if we happen to have a buffer not aligned to a page boundary then we were obviously corrupting data outside our data :)
Neat !
Russell King - ARM Linux
maintainerRe: dma_sync_*_for_cpu and direction=TO_DEVICE (was Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation)
Quoted 2 lines · Vineet Gupta
I never understood the need for this direction. And if memory serves me right, at that time I was seeing twice the amount of cache flushing !
It's necessary. Take a moment to think carefully about this:
dma_map_single(, dir)
dma_sync_single_for_cpu(, dir)
dma_sync_single_for_device(, dir)
dma_unmap_single(, dir)
In the case of a DMA-incoherent architecture, the operations done at each stage depend on the direction argument:
map for_cpu for_device unmapTO_DEV writeback none writeback noneTO_CPU invalidate invalidate* invalidate invalidate*
BIDIR writeback invalidate writeback invalidate
* - only necessary if the CPU speculatively prefetches.
The multiple invalidations for the TO_CPU case handles different conditions that can result in data corruption, and for some CPUs, all four are necessary.
This is what is implemented for 32-bit ARM, depending on the CPU capabilities, as we have DMA incoherent devices and we have CPUs that speculatively prefetch data, and so may load data into the caches while DMA is in operation.
Things get more interesting if the implementation behind the DMA API has to copy data between the buffer supplied to the mapping and some DMA accessible buffer:
map for_cpu for_device unmapTO_DEV copy to dma none copy to dma noneTO_CPU none copy to cpu none copy to cpu
BIDIR copy to dma copy to cpu copy to dma copy to cpu
So, in both cases, the value of the direction argument defines what you need to do in each call.
Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up According to speedtest.net: 8.21Mbps down 510kbps up
Re: dma_sync_*_for_cpu and direction=TO_DEVICE (was Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation)
Hi Russel,
Quoted 13 lines · Russell King - ARM Linux
It's necessary. Take a moment to think carefully about this:
dma_map_single(, dir)
dma_sync_single_for_cpu(, dir)
dma_sync_single_for_device(, dir)
dma_unmap_single(, dir)In the case of a DMA-incoherent architecture, the operations done at each stage depend on the direction argument:
Quoted 6 lines
map for_cpu for_device unmap TO_DEV writeback none writeback none TO_CPU invalidate invalidate* invalidate invalidate* BIDIR writeback invalidate writeback invalidate* - only necessary if the CPU speculatively prefetches.
I think invalidation of DMA buffer is required on for_cpu(TO_CPU) even if CPU doesn't preferch - what if we reuse the same buffer for multiple reads from DMA device?
Quoted 3 lines
The multiple invalidations for the
TO_CPUcase handles different conditions that can result in data corruption, and for some CPUs, all four are necessary.
I would agree that map()/unmap() a quite a special cases and so depending on direction we need to execute in them either for_cpu() or for_device() call-backs depending on direction.
As for invalidation in case of for_device(TO_CPU) I still don't see a rationale behind it. Would be interesting to see a real example where we benefit from this.
Quoted 10 lines
This is what is implemented for 32-bit ARM, depending on the CPU capabilities, as we have DMA incoherent devices and we have CPUs that speculatively prefetch data, and so may load data into the caches while DMA is in operation.
Things get more interesting if the implementation behind the DMA API has to copy data between the buffer supplied to the mapping and some DMA accessible buffer:
Quoted 7 lines
map for_cpu for_device unmap TO_DEV copy to dma none copy to dma none TO_CPU none copy to cpu none copy to cpu BIDIR copy to dma copy to cpu copy to dma copy to cpuSo, in both cases, the value of the direction argument defines what you need to do in each call.
Interesting enough in your seond table (which describes more complicated case indeed) you set "none" for for_device(TO_CPU) which looks logical to me.
So IMHO that's what make sense:
---------------------------->8-----------------------------
map for_cpu for_device unmap TO_DEV writeback none writeback none TO_CPU none invalidate none invalidate* BIDIR writeback invalidate writeback invalidate*
---------------------------->8-----------------------------
* is the case for prefetching CPU.
-Alexey
Russell King - ARM Linux
maintainerRe: dma_sync_*_for_cpu and direction=TO_DEVICE (was Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation)
Quoted 1 line · Alexey Brodkin
Hi Russel,
That's Russell.
Quoted 19 lines · Russell King - ARM Linux
Quoted 18 lines
It's necessary. Take a moment to think carefully about this:
dma_map_single(, dir)
dma_sync_single_for_cpu(, dir)
dma_sync_single_for_device(, dir)
dma_unmap_single(, dir)In the case of a DMA-incoherent architecture, the operations done at each stage depend on the direction argument:
map for_cpu for_device unmap TO_DEV writeback none writeback none TO_CPU invalidate invalidate* invalidate invalidate* BIDIR writeback invalidate writeback invalidate
Quoted 5 lines
Quoted 1 line
* - only necessary if the CPU speculatively prefetches.
I think invalidation of DMA buffer is required on
for_cpu(TO_CPU)even if CPU doesn't preferch - what if we reuse the same buffer for multiple reads from DMA device?
That's fine - for non-coherent DMA, the CPU caches will only end up containing data for that memory if:
- the CPU speculatively fetches data from that memory, or
- the CPU explicitly touches that memory
Quoted 11 lines
Quoted 3 lines
The multiple invalidations for the
TO_CPUcase handles different conditions that can result in data corruption, and for some CPUs, all four are necessary.I would agree that map()/unmap() a quite a special cases and so depending on direction we need to execute in them either
for_cpu()orfor_device()call-backs depending on direction.As for invalidation in case of
for_device(TO_CPU)I still don't see a rationale behind it. Would be interesting to see a real example where we benefit from this.
Yes, you could avoid that, but depending how you structure the architecture implementation, it can turn out to be a corner case. The above table is precisely how 32-bit ARM is implemented, because the way we implement them is based on who owns the memory - the "map" and "for_device" operations translate internally to a cpu-to-device ownership transition of the buffer. Similar for "unmap" and "to_cpu". It basically avoids having to add additional functions at the lower implementation levels.
Quoted 16 lines
Quoted 11 lines
Things get more interesting if the implementation behind the DMA API has to copy data between the buffer supplied to the mapping and some DMA accessible buffer:
map for_cpu for_device unmap TO_DEV copy to dma none copy to dma none TO_CPU none copy to cpu none copy to cpu BIDIR copy to dma copy to cpu copy to dma copy to cpuSo, in both cases, the value of the direction argument defines what you need to do in each call.
Interesting enough in your seond table (which describes more complicated case indeed) you set "none" for
for_device(TO_CPU)which looks logical to me.
Quoted 7 lines
So IMHO that's what make sense:
---------------------------->8-----------------------------map for_cpu for_device unmap TO_DEV writeback none writeback none TO_CPU none invalidate none invalidate* BIDIR writeback invalidate writeback invalidate*---------------------------->8-----------------------------
That doesn't make sense for the TO_CPU case. If the caches contain dirty cache lines, and you're DMAing from the device to the system RAM, other system activity can cause the dirty cache lines to be evicted (written back) to memory which the DMA has already overwritten. The result is data corruption. So, you really can't have "none" in the "map" case there.
Given that, the "for_cpu" case becomes dependent on whether the CPU speculatively prefetches.
Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up According to speedtest.net: 8.21Mbps down 510kbps up
Re: dma_sync_*_for_cpu and direction=TO_DEVICE (was Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation)
In reply to Russell King - ARM LinuxQuoted 5 lines · Russell King - ARM Linux
Quoted 2 lines · Vineet Gupta
I never understood the need for this direction. And if memory serves me right, at that time I was seeing twice the amount of cache flushing !
It's necessary. Take a moment to think carefully about this:
Quoted 7 lines
dma_map_single(, dir)
dma_sync_single_for_cpu(, dir)
dma_sync_single_for_device(, dir)
dma_unmap_single(, dir)
As an aside, do these imply a state machine of sorts - does a driver needs to always call map_single first ?
My original point of contention/confusion is the specific combinations of API and direction, specifically for_cpu(TO_DEV) and for_device(TO_CPU)
Semantically what does dma_sync_single_for_cpu(TO_DEV) even imply for a non dma coherent arch. Your tables below have "none" for both, implying it is unlikely to be a real combination (for ARM and ARC atleast).
The other case, actually @dir TO_CPU, independent of for_{cpu, device}Â implies driver intends to touch it after the call, so it would invalidate any stray lines, unconditionally (and not just for speculative prefetch case).
Quoted 8 lines
In the case of a DMA-incoherent architecture, the operations done at each stage depend on the direction argument:
map
for_cpufor_deviceunmapTO_DEVwriteback none writeback noneTO_CPUinvalidate invalidate* invalidate invalidate*
BIDIR writeback invalidate writeback invalidate
Quoted 5 lines
* - only necessary if the CPU speculatively prefetches.
The multiple invalidations for the
TO_CPUcase handles different conditions that can result in data corruption, and for some CPUs, all four are necessary.
Can you please explain in some more detail, TO_CPU row, why invalidate is conditional sometimes.
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Russell King - ARM Linux
maintainerRe: dma_sync_*_for_cpu and direction=TO_DEVICE (was Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation)
Quoted 8 lines · Vineet Gupta
Quoted 7 lines · Russell King - ARM Linux
Quoted 2 lines · Vineet Gupta
I never understood the need for this direction. And if memory serves me right, at that time I was seeing twice the amount of cache flushing !
It's necessary. Take a moment to think carefully about this:
dma_map_single(, dir)
Quoted 8 lines
Quoted 5 lines
dma_sync_single_for_cpu(, dir)
dma_sync_single_for_device(, dir)
dma_unmap_single(, dir)As an aside, do these imply a state machine of sorts - does a driver needs to always call
map_singlefirst ?
Kind-of, but some drivers do omit some of the dma_sync_*() calls. For example, if a buffer is written to, then mapped with TO_DEVICE, and then the CPU wishes to write to it, it's fairly common that a driver omits the dma_sync_single_for_cpu() call. If you think about the cases I gave and what cache operations happen, such a scenario practically turns out to be safe.
Quoted 2 lines
My original point of contention/confusion is the specific combinations of API and direction, specifically
for_cpu(TO_DEV)andfor_device(TO_CPU)
Remember that it is expected that all calls for a mapping use the same direction argument while that mapping exists. In other words, if you call dma_map_single(TO_DEVICE) and then use any of the other functions, the other functions will also use TO_DEVICE. The DMA direction argument describes the direction of the DMA operation being performed on the buffer, not on the individual dma_* operation.
What isn't expected at arch level is for drivers to do:
dma_map_single(TO_DEVICE)
dma_sync_single_for_cpu(FROM_DEVICE)
or vice versa.
Quoted 5 lines
Semantically what does
dma_sync_single_for_cpu(TO_DEV)even imply for a non dma coherent arch.Your tables below have "none" for both, implying it is unlikely to be a real combination (for ARM and ARC atleast).
Very little for the cases that I've stated (and as I mentioned above, some drivers do omit the call in that case.)
Quoted 4 lines
The other case, actually @dir
TO_CPU, independent of for_{cpu, device} implies driver intends to touch it after the call, so it would invalidate any stray lines, unconditionally (and not just for speculative prefetch case).
If you don't have a CPU that speculatively prefetches, and you've already had to invalidate the cache lines (to avoid write-backs corrupting DMA'd data) then there's no need for the architecture to do any work at the for_cpu(TO_CPU) case - the CPU shouldn't be touching cache lines that are part of the buffer while it is mapped, which means a non-speculating CPU won't pull in any cache lines without an explicit access.
Speculating CPUs are different. The action of the speculation is to try and guess what data the program wants to access ahead of the program flow. That causes the CPU to prefetch data into the cache. The point in the program flow that this happens is not really determinant to the programmer. This means that if you try to read from the DMA buffer after the DMA operation has complete without invalidating the cache between the DMA completing and the CPU reading, you have no guarantee that you're reading the data that the DMA operation has been written. The cache may have loaded itself with data before the DMA operation completed, and the CPU may see that stale data.
The difference between non-speculating CPUs and speculating CPUs is that for non-speculating CPUs, caches work according to explicit accesses by the program, and the program is stalled while the data is fetched from external memory. Speculating CPUs try to predict ahead of time what data the program will require in the future, and attempt to load that data into the caches _before_ the program requires it - which means that the program suffers fewer stalls.
Quoted 8 lines
Quoted 8 lines
In the case of a DMA-incoherent architecture, the operations done at each stage depend on the direction argument:
map
for_cpufor_deviceunmapTO_DEVwriteback none writeback noneTO_CPUinvalidate invalidate* invalidate invalidate*
BIDIR writeback invalidate writeback invalidate
Quoted 8 lines
Quoted 5 lines
* - only necessary if the CPU speculatively prefetches.
The multiple invalidations for the
TO_CPUcase handles different conditions that can result in data corruption, and for some CPUs, all four are necessary.Can you please explain in some more detail,
TO_CPUrow, why invalidate is conditional sometimes.
See above - I hope my explanation above is sufficient.
Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up According to speedtest.net: 8.21Mbps down 510kbps up
Helge Deller
maintainerRe: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation
In reply to Alexey BrodkinQuoted 14 lines · Alexey Brodkin
But the real fix of my problem is:
---------------------------------------->8------------------------------------lib/dma-noncoherent.c +1
-2@@ -35,7 +35,7 @@ static dma_addr_t dma_noncoherent_map_page(struct device *dev, struct page *page addr =dma_direct_map_page (dev, page, offset, size, dir, attrs);if (!dma_mapping_error (dev, addr) && !(attrs &DMA_ATTR_SKIP_CPU_SYNC )) -arch_sync_dma_for_device (dev,page_to_phys (page), size, dir); +arch_sync_dma_for_device (dev,page_to_phys (page) + offset, size, dir);return addr; } ---------------------------------------->8------------------------------------
Quoted 2 lines
You seem to lost an offset in the page so if we happen to have a buffer not aligned to a page boundary then we were obviously corrupting data outside our data :)
Good.
This patch seems to fix the dma issues I faced on my 32bit B160L parisc box.
So it leaves only one open issue on parisc:
Now every 32 bit parisc system is unnecessarily non-coherent.
Helge
Re: [PATCH 02/20] dma-mapping: provide a generic dma-noncoherent implementation
Quoted 4 lines · Helge Deller
This patch seems to fix the dma issues I faced on my 32bit B160L parisc box.
So it leaves only one open issue on parisc:
Now every 32 bit parisc system is unnecessarily non-coherent.
I diagree with those comments, let me resend the refactored patch to make it more clear.
PATCH 3/20 arc: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
--- arch/arc/Kconfig | 4 + arch/arc/include/asm/Kbuild | 1 + arch/arc/include/asm/dma-mapping.h | 21 ----- arch/arc/mm/dma.c | 141 +++-------------------------- 4 files changed, 19 insertions(+), 148 deletions(-) delete mode 100644 arch/arc/include/asm/dma-mapping.h
arch/arc/Kconfig +4 -0
@@ -9,11 +9,15 @@ config ARC def_bool y select ARC_TIMERS + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SG_CHAIN select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC select BUILDTIME_EXTABLE_SORT select CLONE_BACKWARDS select COMMON_CLK + select DMA_NONCOHERENT_OPS + select DMA_NONCOHERENT_MMAP select GENERIC_ATOMIC64 if !ISA_ARCV2 || !(ARC_HAS_LL64 && ARC_HAS_LLSC) select GENERIC_CLOCKEVENTS select GENERIC_FIND_FIRST_BIT
arch/arc/include/asm/Kbuild +1 -0
@@ -2,6 +2,7 @@ generic-y += bugs.h generic-y += device.h generic-y += div64.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += extable.h generic-y += fb.h
arch/arc/include/asm/dma-mapping.h deleted +0 -21
@@ -1,21 +0,0 @@ -/* -* DMA Mapping glue for ARC -* -* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -*/ - -#ifndef ASM_ARC_DMA_MAPPING_H -#define ASM_ARC_DMA_MAPPING_H - -extern const struct dma_map_ops arc_dma_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -return &arc_dma_ops; -} - -#endif
arch/arc/mm/dma.c +14 -127
176 lines not on this page · raw message
Signature · 1 line
2.17.0
Re: [PATCH 03/20] arc: use generic dma_noncoherent_ops
Hi Christoph,
Quoted 10 lines · Christoph Hellwig
Switch to the generic noncoherent direct mapping implementation.
Signed-off-by Christoph Hellwig <[email protected]>--- arch/arc/Kconfig | 4 + arch/arc/include/asm/Kbuild | 1 + arch/arc/include/asm/dma-mapping.h | 21 ----- arch/arc/mm/dma.c | 141 +++-------------------------- 4 files changed, 19 insertions(+), 148 deletions(-) delete mode 100644 arch/arc/include/asm/dma-mapping.h
Sorry I didn't try your proposed fix earlier - was away for a couple of days.
But that newer version with fixed lib/dma-noncoherent.c still doesn't work on ARC.
USB ECHI controller fails like that:
------------------------->8------------------------- usb 1-1: new high-speed USB device number 2 using ehci-platform usb 1-1: can't set config #1, error -32 ------------------------->8-------------------------
Again with entire series reverted USB starts to work.
Let's wait for other arches previously affected to update on their status.
-Alexey
PATCH 4/20 arm-nommu: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation for the nommu dma map implementation.
--- arch/arc/Kconfig | 1 + arch/arm/Kconfig | 4 + arch/arm/mm/dma-mapping-nommu.c | 139 +++++--------------------------- 3 files changed, 23 insertions(+), 121 deletions(-)
arch/arc/Kconfig +1 -0
@@ -9,6 +9,7 @@ config ARC def_bool y select ARC_TIMERS + select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SG_CHAIN
arch/arm/Kconfig +4 -0
@@ -12,6 +12,8 @@ config ARM select ARCH_HAS_PHYS_TO_DMA select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL select ARCH_HAS_STRICT_MODULE_RWX if MMU + select ARCH_HAS_SYNC_DMA_FOR_CPU if !MMU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE if !MMU select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAVE_CUSTOM_GPIO_H select ARCH_HAS_GCOV_PROFILE_ALL
@@ -27,6 +29,8 @@ config ARM select CPU_PM if (SUSPEND || CPU_IDLE) select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS select DMA_DIRECT_OPS if !MMU + select DMA_NONCOHERENT_OPS if !MMU + select DMA_NONCOHERENT_MMAP if !MMU select EDAC_SUPPORT select EDAC_ATOMIC_SCRUB select GENERIC_ALLOCATOR
arch/arm/mm/dma-mapping-nommu.c +18 -121
196 lines not on this page · raw message
Signature · 1 line
2.17.0
Russell King - ARM Linux
maintainerRe: [PATCH 04/20] arm-nommu: use generic dma_noncoherent_ops
Quoted 105 lines · Christoph Hellwig
Switch to the generic noncoherent direct mapping implementation for the nommu dma map implementation.
Signed-off-by Christoph Hellwig <[email protected]>--- arch/arc/Kconfig | 1 + arch/arm/Kconfig | 4 + arch/arm/mm/dma-mapping-nommu.c | 139 +++++--------------------------- 3 files changed, 23 insertions(+), 121 deletions(-)arch/arc/Kconfig +1
-0@@ -9,6 +9,7 @@ config ARC def_bool y select ARC_TIMERS + select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SG_CHAINarch/arm/Kconfig +4
-0@@ -12,6 +12,8 @@ config ARM select ARCH_HAS_PHYS_TO_DMA select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL select ARCH_HAS_STRICT_MODULE_RWX if MMU + select ARCH_HAS_SYNC_DMA_FOR_CPU if !MMU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE if !MMU select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAVE_CUSTOM_GPIO_H select ARCH_HAS_GCOV_PROFILE_ALL@@ -27,6 +29,8 @@ config ARM select CPU_PM if (SUSPEND || CPU_IDLE) select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS select DMA_DIRECT_OPS if !MMU + select DMA_NONCOHERENT_OPS if !MMU + select DMA_NONCOHERENT_MMAP if !MMU select EDAC_SUPPORT select EDAC_ATOMIC_SCRUB select GENERIC_ALLOCATORarch/arm/mm/dma-mapping-nommu.c +10
-12@@ -12,6 +12,7 @@#include <linux/export.h> #include <linux/mm.h> #include <linux/dma-direct.h> +#include <linux/dma-noncoherent.h> #include <linux/scatterlist.h> #include <asm/cachetype.h> @@ -26,18 +27,16 @@* - MMU/MPU is off * - cpu is v7m w/o cache support * - device is coherent -* otherwise arm_nommu_dma_ops is used. +* otherwise dma_noncoherent_ops is used. * -* arm_nommu_dma_ops rely on consistent DMA memory (please, refer to +* dma_noncoherent_ops rely on consistent DMA memory (please, refer to * [1] on how to declare such memory). * * [1] Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt */ -static void *arm_nommu_dma_alloc (struct device *dev,size_t size, -dma_addr_t *dma_handle,gfp_t gfp, -unsigned long attrs) - +void *arch_dma_alloc (struct device *dev,size_t size,dma_addr_t *dma_handle, +gfp_t gfp,unsigned long attrs) {void *ret;@@ -65,9 +64,8 @@ static void *arm_nommu_dma_alloc(struct device *dev, size_t size,return ret; } -static void arm_nommu_dma_free (struct device *dev,size_t size, -void *cpu_addr,dma_addr_t dma_addr, -unsigned long attrs) +void arch_dma_free (struct device *dev,size_t size,void *cpu_addr, +dma_addr_t dma_addr,unsigned long attrs) {if (attrs &DMA_ATTR_NON_CONSISTENT ) {dma_direct_free (dev, size, cpu_addr, dma_addr, attrs);@@ -81,9 +79,9 @@ static void arm_nommu_dma_free(struct device *dev, size_t size,return ; } -static int arm_nommu_dma_mmap (struct device *dev,struct vm_area_struct *vma, -void *cpu_addr,dma_addr_t dma_addr,size_t size, -unsigned long attrs) +int arch_dma_mmap (struct device *dev,struct vm_area_struct *vma, +void *cpu_addr,dma_addr_t dma_addr,size_t size, +unsigned long attrs) {int ret;
arch/arm/mm/dma-mapping-nommu.c static int arm_nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma, · line 95
Quoted 8 lines
arch/arm/mm/dma-mapping-nommu.c +2
-3@@ -93,9 +91,8 @@ static int arm_nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,return dma_common_mmap (dev, vma, cpu_addr, dma_addr, size); } - -static void __dma_page_cpu_to_dev (phys_addr_t paddr,size_t size, -enum dma_data_direction dir) +void arch_sync_dma_for_device (struct device *dev,phys_addr_t paddr, +size_t size,enum dma_data_direction dir)
Please no. There is a lot of history of these (__dma_page_cpu_to_dev etc) functions being abused by out of tree drivers, because they think they know better. This is stopped by making them static and ensuring that drivers have no access to these functions.
Please do not re-expose these to the global kernel.
While it may make things easier for a cross-architecture point of view, it makes it a lot easier for people to abuse these private APIs.
Signature · 3 lines
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up According to speedtest.net: 8.21Mbps down 510kbps up
Re: [PATCH 04/20] arm-nommu: use generic dma_noncoherent_ops
Quoted 8 lines · Russell King - ARM Linux
arch/arm/mm/dma-mapping-nommu.c static int arm_nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma, · line 95
Quoted 2 lines
arch/arm/mm/dma-mapping-nommu.c +2
-0+void arch_sync_dma_for_device (struct device *dev,phys_addr_t paddr, +size_t size,enum dma_data_direction dir)Please no. There is a lot of history of these (
__dma_page_cpu_to_devetc) functions being abused by out of tree drivers, because they think they know better. This is stopped by making them static and ensuring that drivers have no access to these functions.
Quoted 4 lines
Please do not re-expose these to the global kernel.
While it may make things easier for a cross-architecture point of view, it makes it a lot easier for people to abuse these private APIs.
The point of this series, which isn't fully archived yet, is to consolidate the direct mapping dma code, that is all dma_map_ops instances except for iommus. It is in fact in many ways modelled after the ARM code. For that we need the architectures to supply the cache maintainance routines.
However, even if they now appear in dma-noncoherent.h they are NOT and will NOT be exported, so using them directly from drivers won't easily be possible.
I'll drop the arm-nommu patch for now, but I will pester your with this again once arm is the last architecture not sharing the common code.
Quoted 5 lines
Signature · 4 lines
-- RMK's Patch system: http://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up According to speedtest.net: 8.21Mbps down 510kbps up
---end quoted text---
Re: [PATCH 04/20] arm-nommu: use generic dma_noncoherent_ops
In reply to Christoph HellwigQuoted 15 lines · Christoph Hellwig
Switch to the generic noncoherent direct mapping implementation for the nommu dma map implementation.
Signed-off-by Christoph Hellwig <[email protected]>--- arch/arc/Kconfig | 1 + arch/arm/Kconfig | 4 + arch/arm/mm/dma-mapping-nommu.c | 139 +++++--------------------------- 3 files changed, 23 insertions(+), 121 deletions(-)arch/arc/Kconfig +0
-0
arch/arc/Kconfig line 14
Quoted 6 lines
arch/arc/Kconfig +1
-0@@ -9,6 +9,7 @@ config ARC def_bool y select ARC_TIMERS + select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_DEVICE
I guess that this arc change is here by accident, no? And isn't ARCH_HAS_SYNC_DMA_FOR_DEVICE already selected (by 3/20)?
Quoted 5 lines
arch/arc/Kconfig +0
-0select ARCH_HAS_SG_CHAINarch/arm/Kconfig +0
-0
PATCH 5/20 c6x: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
--- arch/c6x/Kconfig | 3 + arch/c6x/include/asm/Kbuild | 1 + arch/c6x/include/asm/dma-mapping.h | 28 ------ arch/c6x/include/asm/setup.h | 2 + arch/c6x/kernel/Makefile | 2 +- arch/c6x/kernel/dma.c | 138 ----------------------------- arch/c6x/mm/dma-coherent.c | 40 ++++++++- 7 files changed, 44 insertions(+), 170 deletions(-) delete mode 100644 arch/c6x/include/asm/dma-mapping.h delete mode 100644 arch/c6x/kernel/dma.c
arch/c6x/Kconfig +3 -0
@@ -6,7 +6,10 @@ config C6X def_bool y + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE select CLKDEV_LOOKUP + select DMA_NONCOHERENT_OPS select GENERIC_ATOMIC64 select GENERIC_IRQ_SHOW select HAVE_ARCH_TRACEHOOK
arch/c6x/include/asm/Kbuild +1 -0
@@ -5,6 +5,7 @@ generic-y += current.h generic-y += device.h generic-y += div64.h generic-y += dma.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h generic-y += extable.h
arch/c6x/include/asm/dma-mapping.h deleted +0 -28
@@ -1,28 +0,0 @@ -/* -* Port on Texas Instruments TMS320C6x architecture -* -* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated -* Author: Aurelien Jacquiot <[email protected]> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -*/ -#ifndef _ASM_C6X_DMA_MAPPING_H -#define _ASM_C6X_DMA_MAPPING_H - -extern const struct dma_map_ops c6x_dma_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -return &c6x_dma_ops; -} - -extern void coherent_mem_init (u32 start,u32 size); -void *c6x_dma_alloc (struct device *dev,size_t size,dma_addr_t *handle, -gfp_t gfp,unsigned long attrs); -void c6x_dma_free (struct device *dev,size_t size,void *vaddr, -dma_addr_t dma_handle,unsigned long attrs); - -#endif /* _ASM_C6X_DMA_MAPPING_H */
arch/c6x/include/asm/setup.h +2 -0
@@ -28,5 +28,7 @@ extern unsigned char c6x_fuse_mac[6];extern void machine_init (unsigned long dt_ptr);extern void time_init (void ); +extern void coherent_mem_init (u32 start,u32 size); +#endif /* !__ASSEMBLY__ */ #endif /* _ASM_C6X_SETUP_H */
arch/c6x/kernel/Makefile +1 -1
@@ -8,6 +8,6 @@ extra-y := head.o vmlinux.lds obj-y := process.o traps.o irq.o signal.o ptrace.o obj-y += setup.o sys_c6x.o time.o devicetree.o obj-y += switch_to.o entry.o vectors.o c6x_ksyms.o -obj-y += soc.o dma.o +obj-y += soc.o obj-$(CONFIG_MODULES) += module.o
arch/c6x/kernel/dma.c deleted +0 -138
138 lines not on this page · raw message
arch/c6x/mm/dma-coherent.c +37 -3
@@ -19,10 +19,12 @@#include <linux/bitops.h> #include <linux/module.h> #include <linux/interrupt.h> -#include <linux/dma-mapping.h> +#include <linux/dma-noncoherent.h> #include <linux/memblock.h> +#include <asm/cacheflush.h> #include <asm/page.h> +#include <asm/setup.h> /* * DMA coherent memory management, can be redefined using the memdma=
@@ -73,7 +75,7 @@ static void __free_dma_pages(u32 addr, int order)* Allocate DMA coherent memory space and return both the kernel * virtual and DMA address for that space. */ -void *c6x_dma_alloc (struct device *dev,size_t size,dma_addr_t *handle, +void *arch_dma_alloc (struct device *dev,size_t size,dma_addr_t *handle,gfp_t gfp,unsigned long attrs) {u32 paddr;
@@ -98,7 +100,7 @@ void *c6x_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,/* * Free DMA coherent memory as defined by the above mapping. */ -void c6x_dma_free (struct device *dev,size_t size,void *vaddr, +void arch_dma_free (struct device *dev,size_t size,void *vaddr,dma_addr_t dma_handle,unsigned long attrs) {int order;
@@ -139,3 +141,35 @@ void __init coherent_mem_init(phys_addr_t start, u32 size) dma_bitmap =phys_to_virt (bitmap_phys);memset (dma_bitmap,0 , dma_pages *PAGE_SIZE ); } + +static void c6x_dma_sync (struct device *dev,phys_addr_t paddr,size_t size, +enum dma_data_direction dir) +{ +BUG_ON (!valid_dma_direction (dir)); + +switch (dir) { +case DMA_FROM_DEVICE : +L2_cache_block_invalidate (paddr, paddr + size); +break ; +case DMA_TO_DEVICE : +L2_cache_block_writeback (paddr, paddr + size); +break ; +case DMA_BIDIRECTIONAL : +L2_cache_block_writeback_invalidate (paddr, paddr + size); +break ; +default : +break ; + } +} + +void arch_sync_dma_for_device (struct device *dev,phys_addr_t paddr, +size_t size,enum dma_data_direction dir) +{ +return c6x_dma_sync (dev, paddr, size, dir); +} + +void arch_sync_dma_for_cpu (struct device *dev,phys_addr_t paddr, +size_t size,enum dma_data_direction dir) +{ +return c6x_dma_sync (dev, paddr, size, dir); +}
Signature · 1 line
2.17.0
Re: [Linux-c6x-dev] [PATCH 05/20] c6x: use generic dma_noncoherent_ops
Quoted 306 lines · Christoph Hellwig
Switch to the generic noncoherent direct mapping implementation.
Signed-off-by Christoph Hellwig <[email protected]>--- arch/c6x/Kconfig | 3 + arch/c6x/include/asm/Kbuild | 1 + arch/c6x/include/asm/dma-mapping.h | 28 ------ arch/c6x/include/asm/setup.h | 2 + arch/c6x/kernel/Makefile | 2 +- arch/c6x/kernel/dma.c | 138 ----------------------------- arch/c6x/mm/dma-coherent.c | 40 ++++++++- 7 files changed, 44 insertions(+), 170 deletions(-) delete mode 100644 arch/c6x/include/asm/dma-mapping.h delete mode 100644 arch/c6x/kernel/dma.carch/c6x/Kconfig +3
-0@@ -6,7 +6,10 @@ config C6X def_bool y + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE select CLKDEV_LOOKUP + select DMA_NONCOHERENT_OPS select GENERIC_ATOMIC64 select GENERIC_IRQ_SHOW select HAVE_ARCH_TRACEHOOKarch/c6x/include/asm/Kbuild +1
-0@@ -5,6 +5,7 @@ generic-y += current.h generic-y += device.h generic-y += div64.h generic-y += dma.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h generic-y += extable.harch/c6x/include/asm/dma-mapping.h deleted +0
-28@@ -1,28 +0,0 @@ -/* -* Port on Texas Instruments TMS320C6x architecture -* -* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated -* Author: Aurelien Jacquiot <[email protected]> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -*/ -#ifndef _ASM_C6X_DMA_MAPPING_H -#define _ASM_C6X_DMA_MAPPING_H - -extern const struct dma_map_ops c6x_dma_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -return &c6x_dma_ops; -} - -extern void coherent_mem_init (u32 start,u32 size); -void *c6x_dma_alloc (struct device *dev,size_t size,dma_addr_t *handle, -gfp_t gfp,unsigned long attrs); -void c6x_dma_free (struct device *dev,size_t size,void *vaddr, -dma_addr_t dma_handle,unsigned long attrs); - -#endif /* _ASM_C6X_DMA_MAPPING_H */ arch/c6x/include/asm/setup.h +2
-0@@ -28,5 +28,7 @@ extern unsigned char c6x_fuse_mac[6];extern void machine_init (unsigned long dt_ptr);extern void time_init (void ); +extern void coherent_mem_init (u32 start,u32 size); +#endif /* !__ASSEMBLY__ */ #endif /* _ASM_C6X_SETUP_H */ arch/c6x/kernel/Makefile +1
-1@@ -8,6 +8,6 @@ extra-y := head.o vmlinux.lds obj-y := process.o traps.o irq.o signal.o ptrace.o obj-y += setup.o sys_c6x.o time.o devicetree.o obj-y += switch_to.o entry.o vectors.o c6x_ksyms.o -obj-y += soc.o dma.o +obj-y += soc.o obj-$(CONFIG_MODULES) += module.oarch/c6x/kernel/dma.c deleted +0
-138@@ -1,138 +0,0 @@ -/* -* Copyright (C) 2011 Texas Instruments Incorporated -* Author: Mark Salter <[email protected]> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -*/ -#include <linux/module.h> -#include <linux/dma-mapping.h> -#include <linux/mm.h> -#include <linux/mm_types.h> -#include <linux/scatterlist.h> - -#include <asm/cacheflush.h> - -static void c6x_dma_sync (dma_addr_t handle,size_t size, -enum dma_data_direction dir) -{ -unsigned long paddr = handle; - -BUG_ON (!valid_dma_direction (dir)); - -switch (dir) { -case DMA_FROM_DEVICE : -L2_cache_block_invalidate (paddr, paddr + size); -break ; -case DMA_TO_DEVICE : -L2_cache_block_writeback (paddr, paddr + size); -break ; -case DMA_BIDIRECTIONAL : -L2_cache_block_writeback_invalidate (paddr, paddr + size); -break ; -default : -break ; - } -} - -static dma_addr_t c6x_dma_map_page (struct device *dev,struct page *page, -unsigned long offset,size_t size,enum dma_data_direction dir, -unsigned long attrs) -{ -dma_addr_t handle =virt_to_phys (page_address (page) + offset); - -if (!(attrs &DMA_ATTR_SKIP_CPU_SYNC )) -c6x_dma_sync (handle, size, dir); - -return handle; -} - -static void c6x_dma_unmap_page (struct device *dev,dma_addr_t handle, -size_t size,enum dma_data_direction dir,unsigned long attrs) -{ -if (!(attrs &DMA_ATTR_SKIP_CPU_SYNC )) -c6x_dma_sync (handle, size, dir); -} - -static int c6x_dma_map_sg (struct device *dev,struct scatterlist *sglist, -int nents,enum dma_data_direction dir,unsigned long attrs) -{ -struct scatterlist *sg; -int i; - -for_each_sg (sglist, sg, nents, i) { - sg->dma_address =sg_phys (sg); -if (!(attrs &DMA_ATTR_SKIP_CPU_SYNC )) -c6x_dma_sync (sg->dma_address, sg->length, dir); - } - -return nents; -} - -static void c6x_dma_unmap_sg (struct device *dev,struct scatterlist *sglist, -int nents,enum dma_data_direction dir,unsigned long attrs) -{ -struct scatterlist *sg; -int i; - -if (attrs &DMA_ATTR_SKIP_CPU_SYNC ) -return ; - -for_each_sg (sglist, sg, nents, i) -c6x_dma_sync (sg_dma_address (sg), sg->length, dir); -} - -static void c6x_dma_sync_single_for_cpu (struct device *dev,dma_addr_t handle, -size_t size,enum dma_data_direction dir) -{ -c6x_dma_sync (handle, size, dir); - -} - -static void c6x_dma_sync_single_for_device (struct device *dev, -dma_addr_t handle,size_t size,enum dma_data_direction dir) -{ -c6x_dma_sync (handle, size, dir); - -} - -static void c6x_dma_sync_sg_for_cpu (struct device *dev, -struct scatterlist *sglist,int nents, -enum dma_data_direction dir) -{ -struct scatterlist *sg; -int i; - -for_each_sg (sglist, sg, nents, i) -c6x_dma_sync_single_for_cpu (dev,sg_dma_address (sg), - sg->length, dir); - -} - -static void c6x_dma_sync_sg_for_device (struct device *dev, -struct scatterlist *sglist,int nents, -enum dma_data_direction dir) -{ -struct scatterlist *sg; -int i; - -for_each_sg (sglist, sg, nents, i) -c6x_dma_sync_single_for_device (dev,sg_dma_address (sg), - sg->length, dir); - -} - -const struct dma_map_ops c6x_dma_ops = { - .alloc = c6x_dma_alloc, - .free = c6x_dma_free, - .map_page = c6x_dma_map_page, - .unmap_page = c6x_dma_unmap_page, - .map_sg = c6x_dma_map_sg, - .unmap_sg = c6x_dma_unmap_sg, - .sync_single_for_device = c6x_dma_sync_single_for_device, - .sync_single_for_cpu = c6x_dma_sync_single_for_cpu, - .sync_sg_for_device = c6x_dma_sync_sg_for_device, - .sync_sg_for_cpu = c6x_dma_sync_sg_for_cpu, -}; -EXPORT_SYMBOL (c6x_dma_ops);arch/c6x/mm/dma-coherent.c +27
-3@@ -19,10 +19,12 @@#include <linux/bitops.h> #include <linux/module.h> #include <linux/interrupt.h> -#include <linux/dma-mapping.h> +#include <linux/dma-noncoherent.h> #include <linux/memblock.h> +#include <asm/cacheflush.h> #include <asm/page.h> +#include <asm/setup.h> /* * DMA coherent memory management, can be redefined using the memdma= @@ -73,7 +75,7 @@ static void __free_dma_pages(u32 addr, int order)* Allocate DMA coherent memory space and return both the kernel * virtual and DMA address for that space. */ -void *c6x_dma_alloc (struct device *dev,size_t size,dma_addr_t *handle, +void *arch_dma_alloc (struct device *dev,size_t size,dma_addr_t *handle,gfp_t gfp,unsigned long attrs) {u32 paddr;@@ -98,7 +100,7 @@ void *c6x_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,/* * Free DMA coherent memory as defined by the above mapping. */ -void c6x_dma_free (struct device *dev,size_t size,void *vaddr, +void arch_dma_free (struct device *dev,size_t size,void *vaddr,dma_addr_t dma_handle,unsigned long attrs) {int order;@@ -139,3 +141,35 @@ void __init coherent_mem_init(phys_addr_t start, u32 size) dma_bitmap =phys_to_virt (bitmap_phys);memset (dma_bitmap,0 , dma_pages *PAGE_SIZE ); } + +static void c6x_dma_sync (struct device *dev,phys_addr_t paddr,size_t size, +enum dma_data_direction dir) +{ +BUG_ON (!valid_dma_direction (dir)); + +switch (dir) { +case DMA_FROM_DEVICE : +L2_cache_block_invalidate (paddr, paddr + size); +break ; +case DMA_TO_DEVICE : +L2_cache_block_writeback (paddr, paddr + size); +break ; +case DMA_BIDIRECTIONAL : +L2_cache_block_writeback_invalidate (paddr, paddr + size); +break ; +default : +break ; + } +} + +void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
arch/c6x/mm/dma-coherent.c void __init coherent_mem_init(phys_addr_t start, u32 size) · line 175
Quoted 10 lines
arch/c6x/mm/dma-coherent.c +10
-0+ size_t size, enum dma_data_direction dir) +{ +return c6x_dma_sync (dev, paddr, size, dir); +} + +void arch_sync_dma_for_cpu (struct device *dev,phys_addr_t paddr, +size_t size,enum dma_data_direction dir) +{ +return c6x_dma_sync (dev, paddr, size, dir); +}
PATCH 6/20 hexagon: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
This removes the previous sync_single_for_cpu implementation, which looks bogus given that no syncing is happening in the similar but more important unmap_single case.
This adds the previously missing sync_sg_for_device implementation that matches the pre-existing sync_single_for_device implementation.
--- arch/hexagon/Kconfig | 2 + arch/hexagon/include/asm/Kbuild | 1 + arch/hexagon/include/asm/dma-mapping.h | 40 ------- arch/hexagon/kernel/dma.c | 143 ++----------------------- 4 files changed, 11 insertions(+), 175 deletions(-) delete mode 100644 arch/hexagon/include/asm/dma-mapping.h
arch/hexagon/Kconfig +2 -0
@@ -4,6 +4,7 @@ comment "Linux Kernel Configuration for Hexagon" config HEXAGON def_bool y + select ARCH_HAS_SYNC_DMA_FOR_DEVICE select HAVE_OPROFILE # Other pending projects/to-do items. # select HAVE_REGS_AND_STACK_ACCESS_API
@@ -28,6 +29,7 @@ config HEXAGON select GENERIC_CLOCKEVENTS_BROADCAST select MODULES_USE_ELF_RELA select GENERIC_CPU_DEVICES + select DMA_NONCOHERENT_OPS ---help--- Qualcomm Hexagon is a processor architecture designed for high performance and low power across a wide variety of applications.
arch/hexagon/include/asm/Kbuild +1 -0
@@ -5,6 +5,7 @@ generic-y += bugs.h generic-y += current.h generic-y += device.h generic-y += div64.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += extable.h generic-y += fb.h
arch/hexagon/include/asm/dma-mapping.h deleted +0 -40
@@ -1,40 +0,0 @@ -/* -* DMA operations for the Hexagon architecture -* -* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 and -* only version 2 as published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -* 02110-1301, USA. -*/ - -#ifndef _ASM_DMA_MAPPING_H -#define _ASM_DMA_MAPPING_H - -#include <linux/types.h> -#include <linux/cache.h> -#include <linux/mm.h> -#include <linux/scatterlist.h> -#include <linux/dma-debug.h> -#include <asm/io.h> - -struct device ; - -extern const struct dma_map_ops *dma_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -return dma_ops; -} - -#endif
arch/hexagon/kernel/dma.c +8 -135
174 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 7/20 m68k: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
--- arch/m68k/Kconfig | 2 + arch/m68k/include/asm/Kbuild | 1 + arch/m68k/include/asm/dma-mapping.h | 12 ----- arch/m68k/kernel/dma.c | 68 ++++------------------------- 4 files changed, 11 insertions(+), 72 deletions(-) delete mode 100644 arch/m68k/include/asm/dma-mapping.h
arch/m68k/Kconfig +2 -0
@@ -2,6 +2,7 @@ config M68K bool default y + select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA select ARCH_MIGHT_HAVE_PC_PARPORT if ISA select ARCH_NO_COHERENT_DMA_MMAP if !MMU select HAVE_IDE
@@ -24,6 +25,7 @@ config M68K select MODULES_USE_ELF_RELA select OLD_SIGSUSPEND3 select OLD_SIGACTION + select DMA_NONCOHERENT_OPS if HAS_DMA config CPU_BIG_ENDIAN def_bool y
arch/m68k/include/asm/Kbuild +1 -0
@@ -1,5 +1,6 @@ generic-y += barrier.h generic-y += device.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h generic-y += extable.h
arch/m68k/include/asm/dma-mapping.h deleted +0 -12
@@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _M68K_DMA_MAPPING_H -#define _M68K_DMA_MAPPING_H - -extern const struct dma_map_ops m68k_dma_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -return &m68k_dma_ops; -} - -#endif /* _M68K_DMA_MAPPING_H */
arch/m68k/kernel/dma.c +8 -60
107 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 8/20 microblaze: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
This removes the direction-based optimizations in sync_{single,sg}_for_{cpu,device} which were marked untestested and do not match the usually very well tested {un,}map_{single,sg} implementations.
--- arch/microblaze/Kconfig | 4 + arch/microblaze/include/asm/Kbuild | 1 + arch/microblaze/include/asm/dma-mapping.h | 28 ----- arch/microblaze/include/asm/pgtable.h | 2 - arch/microblaze/kernel/dma.c | 144 ++-------------------- arch/microblaze/mm/consistent.c | 9 +- 6 files changed, 22 insertions(+), 166 deletions(-) delete mode 100644 arch/microblaze/include/asm/dma-mapping.h
arch/microblaze/Kconfig +4 -0
@@ -1,6 +1,8 @@ config MICROBLAZE def_bool y select ARCH_HAS_GCOV_PROFILE_ALL + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_NO_COHERENT_DMA_MMAP if !MMU select ARCH_WANT_IPC_PARSE_VERSION
@@ -8,6 +10,8 @@ config MICROBLAZE select TIMER_OF select CLONE_BACKWARDS3 select COMMON_CLK + select DMA_NONCOHERENT_OPS + select DMA_NONCOHERENT_MMAP select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS select GENERIC_CPU_DEVICES
arch/microblaze/include/asm/Kbuild +1 -0
@@ -4,6 +4,7 @@ generic-y += bug.h generic-y += bugs.h generic-y += device.h generic-y += div64.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h generic-y += extable.h
arch/microblaze/include/asm/dma-mapping.h deleted +0 -28
@@ -1,28 +0,0 @@ -/* -* Implements the generic device dma API for microblaze and the pci -* -* Copyright (C) 2009-2010 Michal Simek <[email protected]> -* Copyright (C) 2009-2010 PetaLogix -* -* This file is subject to the terms and conditions of the GNU General -* Public License. See the file COPYING in the main directory of this -* archive for more details. -* -* This file is base on powerpc and x86 dma-mapping.h versions -* Copyright (C) 2004 IBM -*/ - -#ifndef _ASM_MICROBLAZE_DMA_MAPPING_H -#define _ASM_MICROBLAZE_DMA_MAPPING_H - -/* -* Available generic sets of operations -*/ -extern const struct dma_map_ops dma_nommu_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -return &dma_nommu_ops; -} - -#endif /* _ASM_MICROBLAZE_DMA_MAPPING_H */
arch/microblaze/include/asm/pgtable.h +0 -2
@@ -553,8 +553,6 @@ void __init *early_get_page(void);extern unsigned long ioremap_bot, ioremap_base; -void *consistent_alloc (gfp_t gfp,size_t size,dma_addr_t *dma_handle); -void consistent_free (size_t size,void *vaddr);void consistent_sync (void *vaddr,size_t size,int direction);void consistent_sync_page (struct page *page,unsigned long offset,size_t size,int direction);
arch/microblaze/kernel/dma.c +12 -132
171 lines not on this page · raw message
arch/microblaze/mm/consistent.c +5 -4
@@ -33,6 +33,7 @@#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/gfp.h> +#include <linux/dma-noncoherent.h> #include <asm/pgalloc.h> #include <linux/io.h>
@@ -59,7 +60,8 @@* uncached region. This will no doubt cause big problems if memory allocated * here is not also freed properly. -- JW */ -void *consistent_alloc (gfp_t gfp,size_t size,dma_addr_t *dma_handle) +void *arch_dma_alloc (struct device *dev,size_t size,dma_addr_t *dma_handle, +gfp_t gfp,unsigned long attrs) {unsigned long order, vaddr;void *ret;
@@ -154,7 +156,6 @@ void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *dma_handle)return ret; } -EXPORT_SYMBOL (consistent_alloc);#ifdef CONFIG_MMU static pte_t *consistent_virt_to_pte (void *vaddr)
@@ -178,7 +179,8 @@ unsigned long consistent_virt_to_pfn(void *vaddr)/* * free page(s) as defined by the above mapping. */ -void consistent_free (size_t size,void *vaddr) +void arch_dma_free (struct device *dev,size_t size,void *vaddr, +dma_addr_t dma_addr,unsigned long attrs) {struct page *page;
@@ -218,7 +220,6 @@ void consistent_free(size_t size, void *vaddr)flush_tlb_all ();#endif } -EXPORT_SYMBOL (consistent_free);/* * make an area consistent.
Signature · 1 line
2.17.0
PATCH 9/20 microblaze: remove the consistent_sync and consistent_sync_page
In reply to Christoph HellwigBoth unused.
--- arch/microblaze/include/asm/pgtable.h | 3 -- arch/microblaze/mm/consistent.c | 45 --------------------------- 2 files changed, 48 deletions(-)
arch/microblaze/include/asm/pgtable.h +0 -3
@@ -553,9 +553,6 @@ void __init *early_get_page(void);extern unsigned long ioremap_bot, ioremap_base; -void consistent_sync (void *vaddr,size_t size,int direction); -void consistent_sync_page (struct page *page,unsigned long offset, -size_t size,int direction);unsigned long consistent_virt_to_pfn (void *vaddr);void setup_memory (void );
arch/microblaze/mm/consistent.c +0 -45
48 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 10/20 nds32: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
This makes sure the cache_sync routines is called in the unmap_sg case, to match the unmap_single and sync_{single,sg}_to_cpu cases.
Note that this now always uses page_address, as previously done in the non-sg cache sync routines.
--- arch/nds32/Kconfig | 3 + arch/nds32/include/asm/Kbuild | 1 + arch/nds32/include/asm/dma-mapping.h | 14 --- arch/nds32/kernel/dma.c | 182 ++++++--------------------- 4 files changed, 39 insertions(+), 161 deletions(-) delete mode 100644 arch/nds32/include/asm/dma-mapping.h
arch/nds32/Kconfig +3 -0
@@ -5,10 +5,13 @@ config NDS32 def_bool y + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_WANT_FRAME_POINTERS if FTRACE select CLKSRC_MMIO select CLONE_BACKWARDS select COMMON_CLK + select DMA_NONCOHERENT_OPS select GENERIC_ATOMIC64 select GENERIC_CPU_DEVICES select GENERIC_CLOCKEVENTS
arch/nds32/include/asm/Kbuild +1 -0
@@ -13,6 +13,7 @@ generic-y += cputime.h generic-y += device.h generic-y += div64.h generic-y += dma.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += errno.h generic-y += exec.h
arch/nds32/include/asm/dma-mapping.h deleted +0 -14
@@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2005-2017 Andes Technology Corporation - -#ifndef ASMNDS32_DMA_MAPPING_H -#define ASMNDS32_DMA_MAPPING_H - -extern struct dma_map_ops nds32_dma_ops; - -static inline struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -return &nds32_dma_ops; -} - -#endif
arch/nds32/kernel/dma.c +35 -147
226 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 11/20 nios2: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
--- arch/nios2/Kconfig | 3 + arch/nios2/include/asm/Kbuild | 1 + arch/nios2/include/asm/dma-mapping.h | 20 ---- arch/nios2/mm/dma-mapping.c | 139 +++------------------------ 4 files changed, 17 insertions(+), 146 deletions(-) delete mode 100644 arch/nios2/include/asm/dma-mapping.h
arch/nios2/Kconfig +3 -0
@@ -1,6 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 config NIOS2 def_bool y + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE + select DMA_NONCOHERENT_OPS select TIMER_OF select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS
arch/nios2/include/asm/Kbuild +1 -0
@@ -8,6 +8,7 @@ generic-y += current.h generic-y += device.h generic-y += div64.h generic-y += dma.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h generic-y += extable.h
arch/nios2/include/asm/dma-mapping.h deleted +0 -20
@@ -1,20 +0,0 @@ -/* -* Copyright (C) 2011 Tobias Klauser <[email protected]> -* Copyright (C) 2009 Wind River Systems Inc -* -* This file is subject to the terms and conditions of the GNU General -* Public License. See the file COPYING in the main directory of this -* archive for more details. -*/ - -#ifndef _ASM_NIOS2_DMA_MAPPING_H -#define _ASM_NIOS2_DMA_MAPPING_H - -extern const struct dma_map_ops nios2_dma_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -return &nios2_dma_ops; -} - -#endif /* _ASM_NIOS2_DMA_MAPPING_H */
arch/nios2/mm/dma-mapping.c +13 -126
174 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 12/20 openrisc: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
Fix sync_single_for_device to do the same cache coherency operations as the more tested map_single path, as both should transfer ownership to the device.
Remove the sync_single_for_cpu implementation as no cache coherency operations are used in the more commonly used unmap_single case, both of which transfer ownership to the CPU.
Implement the missing sync_sg_for_device operation, matching the cache coherency operations in sync_single_for_device and map_{single,sg}.
--- arch/openrisc/Kconfig | 2 + arch/openrisc/include/asm/Kbuild | 1 + arch/openrisc/include/asm/dma-mapping.h | 35 -------- arch/openrisc/kernel/dma.c | 109 +++--------------------- 4 files changed, 13 insertions(+), 134 deletions(-) delete mode 100644 arch/openrisc/include/asm/dma-mapping.h
arch/openrisc/Kconfig +2 -0
@@ -6,6 +6,8 @@ config OPENRISC def_bool y + select ARCH_HAS_SYNC_DMA_FOR_DEVICE + select DMA_NONCOHERENT_OPS select OF select OF_EARLY_FLATTREE select IRQ_DOMAIN
arch/openrisc/include/asm/Kbuild +1 -0
@@ -6,6 +6,7 @@ generic-y += current.h generic-y += device.h generic-y += div64.h generic-y += dma.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h generic-y += extable.h
arch/openrisc/include/asm/dma-mapping.h deleted +0 -35
@@ -1,35 +0,0 @@ -/* -* OpenRISC Linux -* -* Linux architectural port borrowing liberally from similar works of -* others. All original copyrights apply as per the original source -* declaration. -* -* OpenRISC implementation: -* Copyright (C) 2010-2011 Jonas Bonn <[email protected]> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -*/ - -#ifndef __ASM_OPENRISC_DMA_MAPPING_H -#define __ASM_OPENRISC_DMA_MAPPING_H - -/* -* See Documentation/DMA-API-HOWTO.txt and -* Documentation/DMA-API.txt for documentation. -*/ - -#include <linux/dma-debug.h> -#include <linux/dma-mapping.h> - -extern const struct dma_map_ops or1k_dma_map_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -return &or1k_dma_map_ops; -} - -#endif /* __ASM_OPENRISC_DMA_MAPPING_H */
arch/openrisc/kernel/dma.c +10 -99
139 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 13/20 sh: simplify get_arch_dma_ops
In reply to Christoph HellwigRemove the indirection through the dma_ops variable, and just return nommu_dma_ops directly from get_arch_dma_ops.
--- arch/sh/include/asm/dma-mapping.h | 5 ++--- arch/sh/kernel/dma-nommu.c | 8 +------- arch/sh/mm/consistent.c | 3 --- arch/sh/mm/init.c | 10 ---------- 4 files changed, 3 insertions(+), 23 deletions(-)
arch/sh/include/asm/dma-mapping.h +2 -3
@@ -2,12 +2,11 @@#ifndef __ASM_SH_DMA_MAPPING_H#define __ASM_SH_DMA_MAPPING_H -extern const struct dma_map_ops *dma_ops; -extern void no_iommu_init (void ); +extern const struct dma_map_ops nommu_dma_ops;static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) { -return dma_ops; +return &nommu_dma_ops; } extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
arch/sh/kernel/dma-nommu.c +1 -7
@@ -79,10 +79,4 @@ const struct dma_map_ops nommu_dma_ops = { .sync_sg_for_device = nommu_sync_sg_for_device,#endif }; - -void __init no_iommu_init (void ) -{ -if (dma_ops) -return ; - dma_ops = &nommu_dma_ops; -} +EXPORT_SYMBOL (nommu_dma_ops);
arch/sh/mm/consistent.c +0 -3
@@ -20,9 +20,6 @@#include <asm/cacheflush.h> #include <asm/addrspace.h> -const struct dma_map_ops *dma_ops; -EXPORT_SYMBOL (dma_ops); -void *dma_generic_alloc_coherent (struct device *dev,size_t size,dma_addr_t *dma_handle,gfp_t gfp,unsigned long attrs)
arch/sh/mm/init.c +0 -10
@@ -395,22 +395,12 @@ void __init paging_init(void)free_area_init_nodes (max_zone_pfns); } -/* -* Early initialization for any I/O MMUs we might have. -*/ -static void __init iommu_init (void ) -{ -no_iommu_init (); -} -unsigned int mem_init_done =0 ;void __init mem_init (void ) {pg_data_t *pgdat; -iommu_init (); - high_memory =NULL ;for_each_online_pgdat (pgdat) high_memory = max_t(void *, high_memory,
Signature · 1 line
2.17.0
PATCH 14/20 sh: introduce a sh_cacheop_vaddr helper
In reply to Christoph HellwigAnd use it in the maple bus code to avoid a dma API dependency.
--- arch/sh/include/asm/cacheflush.h | 7 +++++++ arch/sh/mm/consistent.c | 5 +---- drivers/sh/maple/maple.c | 7 ++++--- 3 files changed, 12 insertions(+), 7 deletions(-)
arch/sh/include/asm/cacheflush.h +7 -0
@@ -101,5 +101,12 @@ void kunmap_coherent(void *kvaddr);void cpu_cache_init (void ); +static inline void *sh_cacheop_vaddr (void *vaddr) +{ +if (__in_29bit_mode ()) + vaddr = (void *)CAC_ADDR ((unsigned long )vaddr); +return vaddr; +} +#endif /* __KERNEL__ */ #endif /* __ASM_SH_CACHEFLUSH_H */
arch/sh/mm/consistent.c +1 -4
@@ -69,10 +69,7 @@ void dma_generic_free_coherent(struct device *dev, size_t size,void sh_sync_dma_for_device (void *vaddr,size_t size,enum dma_data_direction direction) { -void *addr; - - addr =__in_29bit_mode () ? - (void *)CAC_ADDR ((unsigned long )vaddr) : vaddr; +void *addr =sh_cacheop_vaddr (vaddr);switch (direction) {case DMA_FROM_DEVICE :/* invalidate only */
drivers/sh/maple/maple.c +4 -3
@@ -300,8 +300,8 @@ static void maple_send(void)mutex_unlock (&maple_wlist_lock);if (maple_packets >0 ) {for (i =0 ; i < (1 <<MAPLE_DMA_PAGES ); i++) -sh_sync_dma_for_device (maple_sendbuf + i *PAGE_SIZE , -PAGE_SIZE ,DMA_BIDIRECTIONAL ); +__flush_purge_region (maple_sendbuf + i *PAGE_SIZE , +PAGE_SIZE ); } finish:
@@ -642,7 +642,8 @@ static void maple_dma_handler(struct work_struct *work)list_for_each_entry_safe (mq, nmq, &maple_sentq, list) { mdev = mq->dev; recvbuf = mq->recvbuf->buf; -sh_sync_dma_for_device (recvbuf,0x400 ,DMA_FROM_DEVICE ); +__flush_invalidate_region (sh_cacheop_vaddr (recvbuf), +0x400 ); code = recvbuf[0 ];kfree (mq->sendbuf);list_del_init (&mq->list);
Signature · 1 line
2.17.0
PATCH 15/20 sh: use dma_direct_ops for the CONFIG_DMA_COHERENT case
In reply to Christoph HellwigThis is a slight change in behavior as we avoid the detour through the virtual mapping for the coherent allocator, but if this CPU really is coherent that should be the right thing to do.
--- arch/sh/Kconfig | 1 + arch/sh/include/asm/dma-mapping.h | 4 ++++ arch/sh/kernel/Makefile | 4 ++-- arch/sh/kernel/dma-nommu.c | 4 ---- 4 files changed, 7 insertions(+), 6 deletions(-)
arch/sh/Kconfig +1 -0
@@ -157,6 +157,7 @@ config SWAP_IO_SPACE bool config DMA_COHERENT + select DMA_DIRECT_OPS bool config DMA_NONCOHERENT
arch/sh/include/asm/dma-mapping.h +4 -0
@@ -6,7 +6,11 @@ extern const struct dma_map_ops nommu_dma_ops;static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) { +#ifdef CONFIG_DMA_NONCOHERENT return &nommu_dma_ops; +#else +return &dma_direct_ops; +#endif } extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
arch/sh/kernel/Makefile +2 -2
@@ -12,7 +12,7 @@ endif CFLAGS_REMOVE_return_address.o = -pg -obj-y := debugtraps.o dma-nommu.o dumpstack.o \ +obj-y := debugtraps.o dumpstack.o \ idle.o io.o irq.o irq_$(BITS).o kdebugfs.o \ machvec.o nmi_debug.o process.o \ process_$(BITS).o ptrace.o ptrace_$(BITS).o \
@@ -45,7 +45,7 @@ obj-$(CONFIG_DUMP_CODE) += disassemble.o obj-$(CONFIG_HIBERNATION) += swsusp.o obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o - +obj-$(CONFIG_DMA_NONCOHERENT) += dma-nommu.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o ccflags-y := -Werror
arch/sh/kernel/dma-nommu.c +0 -4
@@ -51,7 +51,6 @@ static int nommu_map_sg(struct device *dev, struct scatterlist *sg,return nents; } -#ifdef CONFIG_DMA_NONCOHERENT static void nommu_sync_single_for_device (struct device *dev,dma_addr_t addr,size_t size,enum dma_data_direction dir) {
@@ -67,16 +66,13 @@ static void nommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,for_each_sg (sg, s, nelems, i)sh_sync_dma_for_device (sg_virt (s), s->length, dir); } -#endif const struct dma_map_ops nommu_dma_ops = { .alloc = dma_generic_alloc_coherent, .free = dma_generic_free_coherent, .map_page = nommu_map_page, .map_sg = nommu_map_sg, -#ifdef CONFIG_DMA_NONCOHERENT .sync_single_for_device = nommu_sync_single_for_device, .sync_sg_for_device = nommu_sync_sg_for_device, -#endif };EXPORT_SYMBOL (nommu_dma_ops);
Signature · 1 line
2.17.0
PATCH 16/20 mm: split arch/sh/mm/consistent.c
In reply to Christoph HellwigHalf of the file just contains platform device memory setup code which is required for all builds, and half contains helpers for dma coherent allocation, which is only needed if CONFIG_DMA_NONCOHERENT is enabled.
--- arch/sh/kernel/Makefile | 2 +- arch/sh/kernel/dma-coherent.c | 80 +++++++++++++++++++++++++++++++++++ arch/sh/mm/consistent.c | 76 --------------------------------- 3 files changed, 81 insertions(+), 77 deletions(-) create mode 100644 arch/sh/kernel/dma-coherent.c
arch/sh/kernel/Makefile +1 -1
@@ -45,7 +45,7 @@ obj-$(CONFIG_DUMP_CODE) += disassemble.o obj-$(CONFIG_HIBERNATION) += swsusp.o obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o -obj-$(CONFIG_DMA_NONCOHERENT) += dma-nommu.o +obj-$(CONFIG_DMA_NONCOHERENT) += dma-nommu.o dma-coherent.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o ccflags-y := -Werror
arch/sh/kernel/dma-coherent.c new file +80 -0
80 lines not on this page · raw message
arch/sh/mm/consistent.c +0 -76
89 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 17/20 sh: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
--- arch/sh/Kconfig | 3 +- arch/sh/include/asm/Kbuild | 1 + arch/sh/include/asm/dma-mapping.h | 26 ----------- arch/sh/kernel/Makefile | 2 +- arch/sh/kernel/dma-coherent.c | 20 ++++---- arch/sh/kernel/dma-nommu.c | 78 ------------------------------- 6 files changed, 13 insertions(+), 117 deletions(-) delete mode 100644 arch/sh/include/asm/dma-mapping.h delete mode 100644 arch/sh/kernel/dma-nommu.c
arch/sh/Kconfig +2 -1
@@ -49,7 +49,6 @@ config SUPERH select HAVE_ARCH_AUDITSYSCALL select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_NMI - select NEED_DMA_MAP_STATE select NEED_SG_DMA_LENGTH help
@@ -162,6 +161,8 @@ config DMA_COHERENT config DMA_NONCOHERENT def_bool !DMA_COHERENT + select ARCH_HAS_SYNC_DMA_FOR_DEVICE + select DMA_NONCOHERENT_OPS config PGTABLE_LEVELS default 3 if X2TLB
arch/sh/include/asm/Kbuild +1 -0
@@ -1,6 +1,7 @@ generic-y += current.h generic-y += delay.h generic-y += div64.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h generic-y += irq_regs.h
arch/sh/include/asm/dma-mapping.h deleted +0 -26
@@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_SH_DMA_MAPPING_H -#define __ASM_SH_DMA_MAPPING_H - -extern const struct dma_map_ops nommu_dma_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -#ifdef CONFIG_DMA_NONCOHERENT -return &nommu_dma_ops; -#else -return &dma_direct_ops; -#endif -} - -extern void *dma_generic_alloc_coherent (struct device *dev,size_t size, -dma_addr_t *dma_addr,gfp_t flag, -unsigned long attrs); -extern void dma_generic_free_coherent (struct device *dev,size_t size, -void *vaddr,dma_addr_t dma_handle, -unsigned long attrs); - -void sh_sync_dma_for_device (void *vaddr,size_t size, -enum dma_data_direction dir); - -#endif /* __ASM_SH_DMA_MAPPING_H */
arch/sh/kernel/Makefile +1 -1
@@ -45,7 +45,7 @@ obj-$(CONFIG_DUMP_CODE) += disassemble.o obj-$(CONFIG_HIBERNATION) += swsusp.o obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o -obj-$(CONFIG_DMA_NONCOHERENT) += dma-nommu.o dma-coherent.o +obj-$(CONFIG_DMA_NONCOHERENT) += dma-coherent.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o ccflags-y := -Werror
arch/sh/kernel/dma-coherent.c +9 -11
@@ -7,14 +7,13 @@*/ #include <linux/mm.h> #include <linux/init.h> -#include <linux/dma-mapping.h> +#include <linux/dma-noncoherent.h> #include <linux/module.h> #include <asm/cacheflush.h> #include <asm/addrspace.h> -void *dma_generic_alloc_coherent (struct device *dev,size_t size, -dma_addr_t *dma_handle,gfp_t gfp, -unsigned long attrs) +void *arch_dma_alloc (struct device *dev,size_t size,dma_addr_t *dma_handle, +gfp_t gfp,unsigned long attrs) {void *ret, *ret_nocache;int order =get_order (size);
@@ -44,9 +43,8 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,return ret_nocache; } -void dma_generic_free_coherent (struct device *dev,size_t size, -void *vaddr,dma_addr_t dma_handle, -unsigned long attrs) +void arch_dma_free (struct device *dev,size_t size,void *vaddr, +dma_addr_t dma_handle,unsigned long attrs) {int order =get_order (size);unsigned long pfn = (dma_handle >>PAGE_SHIFT ) + dev->dma_pfn_offset;
@@ -58,12 +56,12 @@ void dma_generic_free_coherent(struct device *dev, size_t size,iounmap (vaddr); } -void sh_sync_dma_for_device (void *vaddr,size_t size, -enum dma_data_direction direction) +void arch_sync_dma_for_device (struct device *dev,phys_addr_t paddr, +size_t size,enum dma_data_direction dir) { -void *addr =sh_cacheop_vaddr (vaddr); +void *addr =sh_cacheop_vaddr (phys_to_virt (paddr)); -switch (direction) { +switch (dir) {case DMA_FROM_DEVICE :/* invalidate only */ __flush_invalidate_region (addr, size);break ;
arch/sh/kernel/dma-nommu.c deleted +0 -78
78 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 18/20 xtensa: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
--- arch/xtensa/Kconfig | 3 + arch/xtensa/include/asm/Kbuild | 1 + arch/xtensa/include/asm/dma-mapping.h | 26 ------ arch/xtensa/kernel/pci-dma.c | 130 +++----------------------- 4 files changed, 19 insertions(+), 141 deletions(-) delete mode 100644 arch/xtensa/include/asm/dma-mapping.h
arch/xtensa/Kconfig +3 -0
@@ -5,11 +5,14 @@ config ZONE_DMA config XTENSA def_bool y select ARCH_NO_COHERENT_DMA_MMAP if !MMU + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_IPC_PARSE_VERSION select BUILDTIME_EXTABLE_SORT select CLONE_BACKWARDS select COMMON_CLK + select DMA_NONCOHERENT_OPS select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS select GENERIC_IRQ_SHOW
arch/xtensa/include/asm/Kbuild +1 -0
@@ -2,6 +2,7 @@ generic-y += bug.h generic-y += device.h generic-y += div64.h generic-y += dma-contiguous.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h generic-y += extable.h
arch/xtensa/include/asm/dma-mapping.h deleted +0 -26
@@ -1,26 +0,0 @@ -/* -* This file is subject to the terms and conditions of the GNU General Public -* License. See the file "COPYING" in the main directory of this archive -* for more details. -* -* Copyright (C) 2003 - 2005 Tensilica Inc. -* Copyright (C) 2015 Cadence Design Systems Inc. -*/ - -#ifndef _XTENSA_DMA_MAPPING_H -#define _XTENSA_DMA_MAPPING_H - -#include <asm/cache.h> -#include <asm/io.h> - -#include <linux/mm.h> -#include <linux/scatterlist.h> - -extern const struct dma_map_ops xtensa_dma_map_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus) -{ -return &xtensa_dma_map_ops; -} - -#endif /* _XTENSA_DMA_MAPPING_H */
arch/xtensa/kernel/pci-dma.c +15 -115
190 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 19/20 sparc: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
This removes the previous sync_single_for_device implementation, which looks bogus given that no syncing is happening in the similar but more important map_single case.
--- arch/sparc/Kconfig | 2 + arch/sparc/include/asm/dma-mapping.h | 5 +- arch/sparc/kernel/ioport.c | 151 ++------------------------- 3 files changed, 14 insertions(+), 144 deletions(-)
arch/sparc/Kconfig +2 -0
@@ -48,6 +48,8 @@ config SPARC config SPARC32 def_bool !64BIT + select ARCH_HAS_SYNC_DMA_FOR_CPU + select DMA_NONCOHERENT_OPS select GENERIC_ATOMIC64 select CLZ_TAB select HAVE_UID16
arch/sparc/include/asm/dma-mapping.h +2 -3
@@ -7,7 +7,6 @@#include <linux/dma-debug.h> extern const struct dma_map_ops *dma_ops; -extern const struct dma_map_ops pci32_dma_ops;extern struct bus_type pci_bus_type;
@@ -15,11 +14,11 @@ static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) {#ifdef CONFIG_SPARC_LEON if (sparc_cpu_model == sparc_leon) -return &pci32_dma_ops; +return &dma_noncoherent_ops;#endif #if defined(CONFIG_SPARC32 ) && defined(CONFIG_PCI )if (bus == &pci_bus_type) -return &pci32_dma_ops; +return &dma_noncoherent_ops;#endif return dma_ops; }
arch/sparc/kernel/ioport.c +10 -141
179 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH 20/20 parisc: use generic dma_noncoherent_ops
In reply to Christoph HellwigSwitch to the generic noncoherent direct mapping implementation.
Parisc previously had two different non-coherent dma ops implementation that just different in the way coherent allocations were handled or not handled. The different behavior is not selected at runtime in the arch_dma_alloc and arch_dma_free routines. The non-coherent allocation in the pcx cases now uses the dma_direct helpers that are a little more sophisticated and used by a lot of other architectures.
Fix sync_single_for_cpu to do skip the cache flush unless the transfer is to the device to match the more tested unmap_single path which should have the same cache coherency implications.
This also now consistenly uses flush_kernel_dcache_range for cache flushing while previously some of the SG based operations used flush_kernel_vmap_range instead.
--- arch/parisc/Kconfig | 4 + arch/parisc/include/asm/dma-mapping.h | 5 - arch/parisc/kernel/pci-dma.c | 184 +++----------------------- arch/parisc/kernel/setup.c | 8 +- arch/parisc/mm/init.c | 11 +- 5 files changed, 32 insertions(+), 180 deletions(-)
arch/parisc/Kconfig +4 -0
@@ -188,6 +188,10 @@ config PA20 config PA11 def_bool y depends on PA7000 || PA7100LC || PA7200 || PA7300LC + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE + select DMA_NONCOHERENT_OPS + select DMA_NONCOHERENT_CACHE_SYNC config PREFETCH def_bool y
arch/parisc/include/asm/dma-mapping.h +0 -5
@@ -21,11 +21,6 @@** flush/purge and allocate "regular" cacheable pages for everything. */ -#ifdef CONFIG_PA11 -extern const struct dma_map_ops pcxl_dma_ops; -extern const struct dma_map_ops pcx_dma_ops; -#endif -extern const struct dma_map_ops *hppa_dma_ops;static inline const struct dma_map_ops *get_arch_dma_ops (struct bus_type *bus)
arch/parisc/kernel/pci-dma.c +22 -162
213 lines not on this page · raw message
arch/parisc/kernel/setup.c +3 -5
@@ -97,14 +97,12 @@ void __init dma_ops_init(void)panic ("PA-RISC Linux currently only supports machines that conform to\n" "the PA-RISC 1.1 or 2.0 architecture specification.\n" ); -case pcxs: -case pcxt: - hppa_dma_ops = &pcx_dma_ops; -break ;case pcxl2:pa7300lc_init ();case pcxl:/* falls through */ - hppa_dma_ops = &pcxl_dma_ops; +case pcxs: +case pcxt: + hppa_dma_ops = &dma_noncoherent_ops;break ;default :break ;
arch/parisc/mm/init.c +3 -8
@@ -19,7 +19,6 @@#include <linux/gfp.h> #include <linux/delay.h> #include <linux/init.h> -#include <linux/pci.h> /* for hppa_dma_ops and pcxl_dma_ops */ #include <linux/initrd.h> #include <linux/swap.h> #include <linux/unistd.h>
@@ -616,17 +615,13 @@ void __init mem_init(void)free_all_bootmem ();#ifdef CONFIG_PA11 -if (hppa_dma_ops == &pcxl_dma_ops) { +if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) { pcxl_dma_start = (unsigned long )SET_MAP_OFFSET (MAP_START ); parisc_vmalloc_start =SET_MAP_OFFSET (pcxl_dma_start +PCXL_DMA_MAP_SIZE ); - }else { - pcxl_dma_start =0 ; - parisc_vmalloc_start =SET_MAP_OFFSET (MAP_START ); - } -#else - parisc_vmalloc_start =SET_MAP_OFFSET (MAP_START ); + } else#endif + parisc_vmalloc_start =SET_MAP_OFFSET (MAP_START );mem_init_print_info (NULL );
Signature · 1 line
2.17.0
Helge Deller
maintainerQuoted 23 lines · Christoph Hellwig
this series continues consolidating the dma-mapping code, with a focus on architectures that do not (always) provide cache coherence for DMA. Three architectures (arm, mips and powerpc) are still left to be converted later due to complexity of their dma ops selection.
The dma-noncoherent ops calls the dma-direct ops for the actual translation of streaming mappins and allow the architecture to provide any cache flushing required for cpu to device and/or device to cpu ownership transfers. The dma coherent allocator is for now still left entirely to architecture supplied implementations due the amount of variations. Hopefully we can do some consolidation for them later on as well.
A lot of architectures are currently doing very questionable things in their dma mapping routines, which are documented in the changelogs for each patch. Please review them very careful and correct me on incorrect assumptions.
Because this series sits on top of two previously submitted series a git tree might be useful to actually test it. It is provided here:
git://git.infradead.org/users/hch/misc.gitgeneric-dma-noncoherent
Quoted 7 lines
Gitweb:
http://git.infradead.org/users/hch/misc.git/shortlog/refs/heads/generic-dma-noncoherent
Changes since RFC:
- fix a typo accidentally disabling the device to cpu transfer sync
- fixed a few compile failures
I tested it again on parisc (this time again on top of git head) and it still breaks the same way as I reported in my mail on April 21st: the lasi82956 network driver works unreliable. NIC gets IP, but ping doesn't work.
See drivers/net/ethernet/i825xx/lasi_82596.c, it uses dma*sync() functions.
See comment in James mail from April 21st too:
-> you just made every 32 bit parisc system unnecessarily use non-coherent.
Helge