From d27fb99f62af7b79c542d161aa5155ed57271ddc Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 23 Jul 2018 22:42:48 +0100 Subject: dma-mapping: relax warning for per-device areas The reasons why dma_free_attrs() should not be called from IRQ context are not necessarily obvious and somewhat buried in the development history, so let's start by documenting the warning itself to help anyone who does happen to hit it and wonder what the deal is. However, this check turns out to be slightly over-restrictive for the way that per-device memory has been spliced into the general API, since for that case we know that dma_declare_coherent_memory() has created an appropriate CPU mapping for the entire area and nothing dynamic should be happening. Given that the usage model for per-device memory is often more akin to streaming DMA than 'real' coherent DMA (e.g. allocating and freeing space to copy short-lived packets in and out), it is also somewhat more reasonable for those operations to happen in IRQ handlers for such devices. Therefore, let's move the irqs_disabled() check down past the per-device area hook, so that that gets a chance to resolve the request before we reach definite "you're doing it wrong" territory. Reported-by: Fredrik Noring Tested-by: Fredrik Noring Signed-off-by: Robin Murphy Signed-off-by: Christoph Hellwig --- include/linux/dma-mapping.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index f9cc309507d9..1db6a6b46d0d 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -538,10 +538,17 @@ static inline void dma_free_attrs(struct device *dev, size_t size, const struct dma_map_ops *ops = get_dma_ops(dev); BUG_ON(!ops); - WARN_ON(irqs_disabled()); if (dma_release_from_dev_coherent(dev, get_order(size), cpu_addr)) return; + /* + * On non-coherent platforms which implement DMA-coherent buffers via + * non-cacheable remaps, ops->free() may call vunmap(). Thus getting + * this far in IRQ context is a) at risk of a BUG_ON() or trying to + * sleep on some machines, and b) an indication that the driver is + * probably misusing the coherent API anyway. + */ + WARN_ON(irqs_disabled()); if (!ops->free || !cpu_addr) return; -- cgit v1.2.3-59-g8ed1b From 7d63fb3af87aa67aa7d24466e792f9d7c57d8e79 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 10 Jul 2018 16:22:22 -0700 Subject: swiotlb: clean up reporting This removes needless use of '%p', and refactors the printk calls to use pr_*() helpers instead. Signed-off-by: Kees Cook Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: Christoph Hellwig --- kernel/dma/swiotlb.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 904541055792..4f8a6dbf0b60 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -17,6 +17,8 @@ * 08/12/11 beckyb Add highmem support */ +#define pr_fmt(fmt) "software IO TLB: " fmt + #include #include #include @@ -162,20 +164,16 @@ static bool no_iotlb_memory; void swiotlb_print_info(void) { unsigned long bytes = io_tlb_nslabs << IO_TLB_SHIFT; - unsigned char *vstart, *vend; if (no_iotlb_memory) { - pr_warn("software IO TLB: No low mem\n"); + pr_warn("No low mem\n"); return; } - vstart = phys_to_virt(io_tlb_start); - vend = phys_to_virt(io_tlb_end); - - printk(KERN_INFO "software IO TLB [mem %#010llx-%#010llx] (%luMB) mapped at [%p-%p]\n", + pr_info("mapped [mem %#010llx-%#010llx] (%luMB)\n", (unsigned long long)io_tlb_start, (unsigned long long)io_tlb_end, - bytes >> 20, vstart, vend - 1); + bytes >> 20); } /* @@ -275,7 +273,7 @@ swiotlb_init(int verbose) if (io_tlb_start) memblock_free_early(io_tlb_start, PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT)); - pr_warn("Cannot allocate SWIOTLB buffer"); + pr_warn("Cannot allocate buffer"); no_iotlb_memory = true; } @@ -317,8 +315,8 @@ swiotlb_late_init_with_default_size(size_t default_size) return -ENOMEM; } if (order != get_order(bytes)) { - printk(KERN_WARNING "Warning: only able to allocate %ld MB " - "for software IO TLB\n", (PAGE_SIZE << order) >> 20); + pr_warn("only able to allocate %ld MB\n", + (PAGE_SIZE << order) >> 20); io_tlb_nslabs = SLABS_PER_PAGE << order; } rc = swiotlb_late_init_with_tbl(vstart, io_tlb_nslabs); -- cgit v1.2.3-59-g8ed1b From 25622e045a6aed45c9b12d1977fcb3fc3b349a73 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 16 Apr 2018 19:27:22 +0200 Subject: nios2: use generic dma_noncoherent_ops Switch to the generic noncoherent direct mapping implementation. Signed-off-by: Christoph Hellwig Acked-by: Ley Foon Tan Tested-by: Ley Foon Tan --- 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 diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig index 3d4ec88f1db1..92035042cf62 100644 --- a/arch/nios2/Kconfig +++ b/arch/nios2/Kconfig @@ -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 diff --git a/arch/nios2/include/asm/Kbuild b/arch/nios2/include/asm/Kbuild index 64ed3d656956..8fde4fa2c34f 100644 --- a/arch/nios2/include/asm/Kbuild +++ b/arch/nios2/include/asm/Kbuild @@ -9,6 +9,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 diff --git a/arch/nios2/include/asm/dma-mapping.h b/arch/nios2/include/asm/dma-mapping.h deleted file mode 100644 index 6ceb92251da0..000000000000 --- a/arch/nios2/include/asm/dma-mapping.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2011 Tobias Klauser - * 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 */ diff --git a/arch/nios2/mm/dma-mapping.c b/arch/nios2/mm/dma-mapping.c index 4be815519dd4..4af9e5b5ba1c 100644 --- a/arch/nios2/mm/dma-mapping.c +++ b/arch/nios2/mm/dma-mapping.c @@ -12,18 +12,18 @@ #include #include -#include #include -#include #include #include #include #include -static inline void __dma_sync_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) { - switch (direction) { + void *vaddr = phys_to_virt(paddr); + + switch (dir) { case DMA_FROM_DEVICE: invalidate_dcache_range((unsigned long)vaddr, (unsigned long)(vaddr + size)); @@ -42,10 +42,12 @@ static inline void __dma_sync_for_device(void *vaddr, size_t size, } } -static inline void __dma_sync_for_cpu(void *vaddr, size_t size, - enum dma_data_direction direction) +void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr, + size_t size, enum dma_data_direction dir) { - switch (direction) { + void *vaddr = phys_to_virt(paddr); + + switch (dir) { case DMA_BIDIRECTIONAL: case DMA_FROM_DEVICE: invalidate_dcache_range((unsigned long)vaddr, @@ -58,8 +60,8 @@ static inline void __dma_sync_for_cpu(void *vaddr, size_t size, } } -static void *nios2_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; @@ -80,125 +82,10 @@ static void *nios2_dma_alloc(struct device *dev, size_t size, return ret; } -static void nios2_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) { unsigned long addr = (unsigned long) CAC_ADDR((unsigned long) vaddr); free_pages(addr, get_order(size)); } - -static int nios2_dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction, - unsigned long attrs) -{ - int i; - - for_each_sg(sg, sg, nents, i) { - void *addr = sg_virt(sg); - - if (!addr) - continue; - - sg->dma_address = sg_phys(sg); - - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) - continue; - - __dma_sync_for_device(addr, sg->length, direction); - } - - return nents; -} - -static dma_addr_t nios2_dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction, - unsigned long attrs) -{ - void *addr = page_address(page) + offset; - - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) - __dma_sync_for_device(addr, size, direction); - - return page_to_phys(page) + offset; -} - -static void nios2_dma_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, enum dma_data_direction direction, - unsigned long attrs) -{ - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) - __dma_sync_for_cpu(phys_to_virt(dma_address), size, direction); -} - -static void nios2_dma_unmap_sg(struct device *dev, struct scatterlist *sg, - int nhwentries, enum dma_data_direction direction, - unsigned long attrs) -{ - void *addr; - int i; - - if (direction == DMA_TO_DEVICE) - return; - - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) - return; - - for_each_sg(sg, sg, nhwentries, i) { - addr = sg_virt(sg); - if (addr) - __dma_sync_for_cpu(addr, sg->length, direction); - } -} - -static void nios2_dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - __dma_sync_for_cpu(phys_to_virt(dma_handle), size, direction); -} - -static void nios2_dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - __dma_sync_for_device(phys_to_virt(dma_handle), size, direction); -} - -static void nios2_dma_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - int i; - - /* Make sure that gcc doesn't leave the empty loop body. */ - for_each_sg(sg, sg, nelems, i) - __dma_sync_for_cpu(sg_virt(sg), sg->length, direction); -} - -static void nios2_dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - int i; - - /* Make sure that gcc doesn't leave the empty loop body. */ - for_each_sg(sg, sg, nelems, i) - __dma_sync_for_device(sg_virt(sg), sg->length, direction); - -} - -const struct dma_map_ops nios2_dma_ops = { - .alloc = nios2_dma_alloc, - .free = nios2_dma_free, - .map_page = nios2_dma_map_page, - .unmap_page = nios2_dma_unmap_page, - .map_sg = nios2_dma_map_sg, - .unmap_sg = nios2_dma_unmap_sg, - .sync_single_for_device = nios2_dma_sync_single_for_device, - .sync_single_for_cpu = nios2_dma_sync_single_for_cpu, - .sync_sg_for_cpu = nios2_dma_sync_sg_for_cpu, - .sync_sg_for_device = nios2_dma_sync_sg_for_device, -}; -EXPORT_SYMBOL(nios2_dma_ops); -- cgit v1.2.3-59-g8ed1b From a5516219b10218a87abb3352c82248ce3088e94a Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Fri, 27 Jul 2018 15:14:15 +0100 Subject: of/platform: Initialise default DMA masks When of_dma_configure() was first born in 591c1ee465ce ("of: configure the platform device dma parameters"), everything DMA-related was factored out of of_platform_device_create_pdata() as seemed appropriate at the time. However, now that of_dma_configure() has grown into the generic handler for processing DMA-related properties from DT for all kinds of devices, it is no longer an appropriate place to be doing OF-platform-specific business. Since there are still plenty of platform drivers not setting their own masks and depending on the bus default, let's reinstate that inialisation in the OF-platform code itself, and restore the long-standing status quo from 0589342c2794 ("of: set dma_mask to point to coherent_dma_mask") Signed-off-by: Robin Murphy Acked-by: Rob Herring Signed-off-by: Christoph Hellwig --- drivers/of/platform.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 6925d993e1f0..7ba90c290a42 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -185,6 +185,9 @@ static struct platform_device *of_platform_device_create_pdata( if (!dev) goto err_clear_flag; + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + if (!dev->dev.dma_mask) + dev->dev.dma_mask = &dev->dev.coherent_dma_mask; dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; of_msi_configure(&dev->dev, dev->dev.of_node); -- cgit v1.2.3-59-g8ed1b From 5ac65e8c89410892189ef778f567da4adafb2e2f Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 23 Jul 2018 23:16:06 +0100 Subject: ACPI/IORT: Support address size limit for root complexes IORT revision D allows PCI root complex nodes to specify a memory address size limit equivalently to named components, to help describe straightforward integrations which don't really warrant a full-blown _DMA method. Now that our headers are up-to-date, plumb it in. If both _DMA and an address size limit are present, we would always expect the former to be a more specific subset of the latter (since it makes little sense for a _DMA range to involve bits which IORT says aren't wired up), thus we can save calculating an explicit intersection of the two effective masks and simply use short-circuit logic instead. Reviewed-by: Hanjun Guo Signed-off-by: Robin Murphy Acked-by: Ard Biesheuvel Acked-by: Will Deacon Acked-by: Lorenzo Pieralisi Signed-off-by: Christoph Hellwig --- drivers/acpi/arm64/iort.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 7a3a541046ed..4a66896e2aa3 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -947,6 +947,24 @@ static int nc_dma_get_range(struct device *dev, u64 *size) return 0; } +static int rc_dma_get_range(struct device *dev, u64 *size) +{ + struct acpi_iort_node *node; + struct acpi_iort_root_complex *rc; + + node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX, + iort_match_node_callback, dev); + if (!node || node->revision < 1) + return -ENODEV; + + rc = (struct acpi_iort_root_complex *)node->node_data; + + *size = rc->memory_address_limit >= 64 ? U64_MAX : + 1ULL<memory_address_limit; + + return 0; +} + /** * iort_dma_setup() - Set-up device DMA parameters. * @@ -975,10 +993,13 @@ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); - if (dev_is_pci(dev)) + if (dev_is_pci(dev)) { ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size); - else + if (ret == -ENODEV) + ret = rc_dma_get_range(dev, &size); + } else { ret = nc_dma_get_range(dev, &size); + } if (!ret) { msb = fls64(dmaaddr + size - 1); -- cgit v1.2.3-59-g8ed1b From f07d141fe9430cdf9f8a65a87c4136bd83b8ab2e Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 23 Jul 2018 23:16:07 +0100 Subject: dma-mapping: Generalise dma_32bit_limit flag Whilst the notion of an upstream DMA restriction is most commonly seen in PCI host bridges saddled with a 32-bit native interface, a more general version of the same issue can exist on complex SoCs where a bus or point-to-point interconnect link from a device's DMA master interface to another component along the path to memory (often an IOMMU) may carry fewer address bits than the interfaces at both ends nominally support. In order to properly deal with this, the first step is to expand the dma_32bit_limit flag into an arbitrary mask. To minimise the impact on existing code, we'll make sure to only consider this new mask valid if set. That makes sense anyway, since a mask of zero would represent DMA not being wired up at all, and that would be better handled by not providing valid ops in the first place. Signed-off-by: Robin Murphy Acked-by: Ard Biesheuvel Signed-off-by: Christoph Hellwig --- arch/x86/kernel/pci-dma.c | 2 +- include/linux/device.h | 6 +++--- kernel/dma/direct.c | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index ab5d9dd668d2..80f9fe8d27d0 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -175,7 +175,7 @@ rootfs_initcall(pci_iommu_init); static int via_no_dac_cb(struct pci_dev *pdev, void *data) { - pdev->dev.dma_32bit_limit = true; + pdev->dev.bus_dma_mask = DMA_BIT_MASK(32); return 0; } diff --git a/include/linux/device.h b/include/linux/device.h index 055a69dbcd18..6d3b000be57e 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -886,6 +886,8 @@ struct dev_links_info { * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all * hardware supports 64-bit addresses for consistent allocations * such descriptors. + * @bus_dma_mask: Mask of an upstream bridge or bus which imposes a smaller DMA + * limit than the device itself supports. * @dma_pfn_offset: offset of DMA memory range relatively of RAM * @dma_parms: A low level driver may set these to teach IOMMU code about * segment limitations. @@ -912,8 +914,6 @@ struct dev_links_info { * @offline: Set after successful invocation of bus type's .offline(). * @of_node_reused: Set if the device-tree node is shared with an ancestor * device. - * @dma_32bit_limit: bridge limited to 32bit DMA even if the device itself - * indicates support for a higher limit in the dma_mask field. * * At the lowest level, every device in a Linux system is represented by an * instance of struct device. The device structure contains the information @@ -967,6 +967,7 @@ struct device { not all hardware supports 64 bit addresses for consistent allocations such descriptors. */ + u64 bus_dma_mask; /* upstream dma_mask constraint */ unsigned long dma_pfn_offset; struct device_dma_parameters *dma_parms; @@ -1002,7 +1003,6 @@ struct device { bool offline_disabled:1; bool offline:1; bool of_node_reused:1; - bool dma_32bit_limit:1; }; static inline struct device *kobj_to_dev(struct kobject *kobj) diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index 8be8106270c2..c2860c5a9e96 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -180,10 +180,10 @@ int dma_direct_supported(struct device *dev, u64 mask) return 0; #endif /* - * Various PCI/PCIe bridges have broken support for > 32bit DMA even - * if the device itself might support it. + * Upstream PCI/PCIe bridges or SoC interconnects may not carry + * as many DMA address bits as the device itself supports. */ - if (dev->dma_32bit_limit && mask > DMA_BIT_MASK(32)) + if (dev->bus_dma_mask && mask > dev->bus_dma_mask) return 0; return 1; } -- cgit v1.2.3-59-g8ed1b From d74ea7100b0d065f2008c4e1ddf637483bc3d28c Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 23 Jul 2018 23:16:08 +0100 Subject: ACPI/IORT: Set bus DMA mask as appropriate When an explicit DMA limit is described by firmware, we need to remember it regardless of how drivers might subsequently update their devices' masks. The new bus_dma_mask field does that. Signed-off-by: Robin Murphy Acked-by: Ard Biesheuvel Acked-by: Lorenzo Pieralisi Signed-off-by: Christoph Hellwig --- drivers/acpi/arm64/iort.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 4a66896e2aa3..bc51cff5505e 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -1014,6 +1014,7 @@ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) * Limit coherent and dma mask based on size * retrieved from firmware. */ + dev->bus_dma_mask = mask; dev->coherent_dma_mask = mask; *dev->dma_mask = mask; } -- cgit v1.2.3-59-g8ed1b From 6c2fb2ea76361da9b420a8e23a2a19e7842cbdda Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 23 Jul 2018 23:16:09 +0100 Subject: of/device: Set bus DMA mask as appropriate When an explicit DMA limit is described by firmware, we need to remember it regardless of how drivers might subsequently update their devices' masks. The new bus_dma_mask field does that. Signed-off-by: Robin Murphy Acked-by: Ard Biesheuvel Signed-off-by: Christoph Hellwig --- drivers/of/device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/of/device.c b/drivers/of/device.c index 33d85511d790..0d39633e8545 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -149,6 +149,7 @@ int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma) * set by the driver. */ mask = DMA_BIT_MASK(ilog2(dma_addr + size - 1) + 1); + dev->bus_dma_mask = mask; dev->coherent_dma_mask &= mask; *dev->dma_mask &= mask; -- cgit v1.2.3-59-g8ed1b From 03bfdc31176cbe21e456f889ccbbf67568831149 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 23 Jul 2018 23:16:10 +0100 Subject: iommu/dma: Respect bus DMA limit for IOVAs Take the new bus limit into account (when present) for IOVA allocations, to accommodate those SoCs which integrate off-the-shelf IP blocks with narrower interconnects such that the link between a device output and an IOMMU input can truncate DMA addresses to even fewer bits than the native size of either block's interface would imply. Eventually it might make sense for the DMA core to apply this constraint up-front in dma_set_mask() and friends, but for now this seems like the least risky approach. Signed-off-by: Robin Murphy Acked-by: Ard Biesheuvel Acked-by: Joerg Roedel Signed-off-by: Christoph Hellwig --- drivers/iommu/dma-iommu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index ddcbbdb5d658..511ff9a1d6d9 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -367,6 +367,9 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain, if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) iova_len = roundup_pow_of_two(iova_len); + if (dev->bus_dma_mask) + dma_limit &= dev->bus_dma_mask; + if (domain->geometry.force_aperture) dma_limit = min(dma_limit, domain->geometry.aperture_end); -- cgit v1.2.3-59-g8ed1b From 6757cdae44449dec2af68cd4db0a5f9a30e66b38 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 23 Jul 2018 23:16:11 +0100 Subject: ACPI/IORT: Don't set default coherent DMA mask Now that we can track upstream DMA constraints properly with bus_dma_mask instead of trying (and failing) to maintain it in coherent_dma_mask, it doesn't make much sense for the firmware code to be touching the latter at all. It's merely papering over bugs wherein a driver has failed to call dma_set_coherent_mask() *and* the bus code has not initialised any default value. We don't really want to encourage more drivers coercing dma_mask so we'll continue to fix that up if necessary, but add a warning to help flush out any such buggy bus code that remains. Signed-off-by: Robin Murphy Acked-by: Ard Biesheuvel Acked-by: Lorenzo Pieralisi Signed-off-by: Christoph Hellwig --- drivers/acpi/arm64/iort.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index bc51cff5505e..08f26db2da7e 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -978,20 +978,20 @@ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) int ret, msb; /* - * Set default coherent_dma_mask to 32 bit. Drivers are expected to - * setup the correct supported mask. + * If @dev is expected to be DMA-capable then the bus code that created + * it should have initialised its dma_mask pointer by this point. For + * now, we'll continue the legacy behaviour of coercing it to the + * coherent mask if not, but we'll no longer do so quietly. */ - if (!dev->coherent_dma_mask) - dev->coherent_dma_mask = DMA_BIT_MASK(32); - - /* - * Set it to coherent_dma_mask by default if the architecture - * code has not set it. - */ - if (!dev->dma_mask) + if (!dev->dma_mask) { + dev_warn(dev, "DMA mask not set\n"); dev->dma_mask = &dev->coherent_dma_mask; + } - size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); + if (dev->coherent_dma_mask) + size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); + else + size = 1ULL << 32; if (dev_is_pci(dev)) { ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size); -- cgit v1.2.3-59-g8ed1b From 4d8bde883bfba3e8dd3335f91b640e5a70ec0aa6 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 23 Jul 2018 23:16:12 +0100 Subject: OF: Don't set default coherent DMA mask Now that we can track upstream DMA constraints properly with bus_dma_mask instead of trying (and failing) to maintain it in coherent_dma_mask, it doesn't make much sense for the firmware code to be touching the latter at all. It's merely papering over bugs wherein a driver has failed to call dma_set_coherent_mask() *and* the bus code has not initialised any default value. We don't really want to encourage more drivers coercing dma_mask so we'll continue to fix that up if necessary, but add a warning to help flush out any such buggy bus code that remains. Signed-off-by: Robin Murphy Acked-by: Ard Biesheuvel Signed-off-by: Christoph Hellwig --- drivers/of/device.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/of/device.c b/drivers/of/device.c index 0d39633e8545..5957cd4fa262 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -127,20 +127,20 @@ int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma) } /* - * Set default coherent_dma_mask to 32 bit. Drivers are expected to - * setup the correct supported mask. + * If @dev is expected to be DMA-capable then the bus code that created + * it should have initialised its dma_mask pointer by this point. For + * now, we'll continue the legacy behaviour of coercing it to the + * coherent mask if not, but we'll no longer do so quietly. */ - if (!dev->coherent_dma_mask) - dev->coherent_dma_mask = DMA_BIT_MASK(32); - /* - * Set it to coherent_dma_mask by default if the architecture - * code has not set it. - */ - if (!dev->dma_mask) + if (!dev->dma_mask) { + dev_warn(dev, "DMA mask not set\n"); dev->dma_mask = &dev->coherent_dma_mask; + } - if (!size) + if (!size && dev->coherent_dma_mask) size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); + else if (!size) + size = 1ULL << 32; dev->dma_pfn_offset = offset; -- cgit v1.2.3-59-g8ed1b From b2fcb677d4dd2aac3202365719733452b5512719 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 16 Apr 2018 17:26:38 +0200 Subject: sh: simplify get_arch_dma_ops Remove the indirection through the dma_ops variable, and just return nommu_dma_ops directly from get_arch_dma_ops. Signed-off-by: Christoph Hellwig Acked-by: Yoshinori Sato --- 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(-) diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 41167931e5d9..149e71f95be7 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -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, diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c index 3e3a32fc676e..79a9edafa5b0 100644 --- a/arch/sh/kernel/dma-nommu.c +++ b/arch/sh/kernel/dma-nommu.c @@ -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); diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index fceb2adfcac7..e9d422bd42a5 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c @@ -20,9 +20,6 @@ #include #include -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) diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 4034035fbede..7713c084d040 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -339,22 +339,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, -- cgit v1.2.3-59-g8ed1b From 47fcae0d2a5fc77123fc14b0db9fe0025a1a829a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 18 Apr 2018 08:53:46 +0200 Subject: sh: introduce a sh_cacheop_vaddr helper And use it in the maple bus code to avoid a dma API dependency. Signed-off-by: Christoph Hellwig Acked-by: Yoshinori Sato --- arch/sh/include/asm/cacheflush.h | 7 +++++++ arch/sh/mm/consistent.c | 6 +----- drivers/sh/maple/maple.c | 7 ++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/sh/include/asm/cacheflush.h b/arch/sh/include/asm/cacheflush.h index d103ab5a4e4b..b932e42ef028 100644 --- a/arch/sh/include/asm/cacheflush.h +++ b/arch/sh/include/asm/cacheflush.h @@ -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 */ diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index e9d422bd42a5..1622ae6b9dbd 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c @@ -74,10 +74,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 */ @@ -93,7 +90,6 @@ void sh_sync_dma_for_device(void *vaddr, size_t size, BUG(); } } -EXPORT_SYMBOL(sh_sync_dma_for_device); static int __init memchunk_setup(char *str) { diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index 2e45988d1259..e5d7fb81ad66 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c @@ -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); -- cgit v1.2.3-59-g8ed1b From a602915f5d0d9eff96a1d85b6f81e4921b52edfe Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 17 Apr 2018 22:02:10 +0200 Subject: sh: use dma_direct_ops for the CONFIG_DMA_COHERENT case This 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. Signed-off-by: Christoph Hellwig Acked-by: Yoshinori Sato --- 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(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index dd4f3d3e644f..c9993a0cdc7e 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -159,6 +159,7 @@ config SWAP_IO_SPACE bool config DMA_COHERENT + select DMA_DIRECT_OPS bool config DMA_NONCOHERENT diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 149e71f95be7..1ebc6a4eb1c5 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -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, diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index dc80041f7363..cb5f1bfb52de 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -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 diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c index 79a9edafa5b0..d8689b1cb743 100644 --- a/arch/sh/kernel/dma-nommu.c +++ b/arch/sh/kernel/dma-nommu.c @@ -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); -- cgit v1.2.3-59-g8ed1b From 46bcde94cd02283535cb719666399f1c4cfb8f22 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 18 Jul 2018 06:55:20 -0700 Subject: sh: split arch/sh/mm/consistent.c Half 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. Signed-off-by: Christoph Hellwig Acked-by: Yoshinori Sato --- arch/sh/kernel/Makefile | 2 +- arch/sh/kernel/dma-coherent.c | 84 +++++++++++++++++++++++++++++++++++++++++++ arch/sh/mm/consistent.c | 80 ----------------------------------------- 3 files changed, 85 insertions(+), 81 deletions(-) create mode 100644 arch/sh/kernel/dma-coherent.c diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index cb5f1bfb52de..d5ddb64bfffe 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -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 diff --git a/arch/sh/kernel/dma-coherent.c b/arch/sh/kernel/dma-coherent.c new file mode 100644 index 000000000000..2518065d5d27 --- /dev/null +++ b/arch/sh/kernel/dma-coherent.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2004 - 2007 Paul Mundt + * + * 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. + */ +#include +#include +#include +#include +#include +#include + +void *dma_generic_alloc_coherent(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); + + gfp |= __GFP_ZERO; + + ret = (void *)__get_free_pages(gfp, order); + if (!ret) + return NULL; + + /* + * Pages from the page allocator may have data present in + * cache. So flush the cache before using uncached memory. + */ + sh_sync_dma_for_device(ret, size, DMA_BIDIRECTIONAL); + + ret_nocache = (void __force *)ioremap_nocache(virt_to_phys(ret), size); + if (!ret_nocache) { + free_pages((unsigned long)ret, order); + return NULL; + } + + split_page(pfn_to_page(virt_to_phys(ret) >> PAGE_SHIFT), order); + + *dma_handle = virt_to_phys(ret); + if (!WARN_ON(!dev)) + *dma_handle -= PFN_PHYS(dev->dma_pfn_offset); + + return ret_nocache; +} + +void dma_generic_free_coherent(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); + int k; + + if (!WARN_ON(!dev)) + pfn += dev->dma_pfn_offset; + + for (k = 0; k < (1 << order); k++) + __free_pages(pfn_to_page(pfn + k), 0); + + iounmap(vaddr); +} + +void sh_sync_dma_for_device(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + void *addr = sh_cacheop_vaddr(vaddr); + + switch (direction) { + case DMA_FROM_DEVICE: /* invalidate only */ + __flush_invalidate_region(addr, size); + break; + case DMA_TO_DEVICE: /* writeback only */ + __flush_wback_region(addr, size); + break; + case DMA_BIDIRECTIONAL: /* writeback and invalidate */ + __flush_purge_region(addr, size); + break; + default: + BUG(); + } +} diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index 1622ae6b9dbd..792f36129062 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c @@ -1,10 +1,6 @@ /* - * arch/sh/mm/consistent.c - * * Copyright (C) 2004 - 2007 Paul Mundt * - * Declared coherent memory functions based on arch/x86/kernel/pci-dma_32.c - * * 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. @@ -13,83 +9,7 @@ #include #include #include -#include #include -#include -#include -#include -#include - -void *dma_generic_alloc_coherent(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); - - gfp |= __GFP_ZERO; - - ret = (void *)__get_free_pages(gfp, order); - if (!ret) - return NULL; - - /* - * Pages from the page allocator may have data present in - * cache. So flush the cache before using uncached memory. - */ - sh_sync_dma_for_device(ret, size, DMA_BIDIRECTIONAL); - - ret_nocache = (void __force *)ioremap_nocache(virt_to_phys(ret), size); - if (!ret_nocache) { - free_pages((unsigned long)ret, order); - return NULL; - } - - split_page(pfn_to_page(virt_to_phys(ret) >> PAGE_SHIFT), order); - - *dma_handle = virt_to_phys(ret); - if (!WARN_ON(!dev)) - *dma_handle -= PFN_PHYS(dev->dma_pfn_offset); - - return ret_nocache; -} - -void dma_generic_free_coherent(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; - int k; - - if (!WARN_ON(!dev)) - pfn += dev->dma_pfn_offset; - - for (k = 0; k < (1 << order); k++) - __free_pages(pfn_to_page(pfn + k), 0); - - iounmap(vaddr); -} - -void sh_sync_dma_for_device(void *vaddr, size_t size, - enum dma_data_direction direction) -{ - void *addr = sh_cacheop_vaddr(vaddr); - - switch (direction) { - case DMA_FROM_DEVICE: /* invalidate only */ - __flush_invalidate_region(addr, size); - break; - case DMA_TO_DEVICE: /* writeback only */ - __flush_wback_region(addr, size); - break; - case DMA_BIDIRECTIONAL: /* writeback and invalidate */ - __flush_purge_region(addr, size); - break; - default: - BUG(); - } -} static int __init memchunk_setup(char *str) { -- cgit v1.2.3-59-g8ed1b From 6fa1d28e38cfa0c90f8d64c0cab37769e5337b85 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 11 May 2018 08:36:53 +0200 Subject: sh: use generic dma_noncoherent_ops Switch to the generic noncoherent direct mapping implementation. Signed-off-by: Christoph Hellwig Acked-by: Yoshinori Sato --- 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 | 23 ++++++------ arch/sh/kernel/dma-nommu.c | 78 --------------------------------------- 6 files changed, 15 insertions(+), 118 deletions(-) delete mode 100644 arch/sh/include/asm/dma-mapping.h delete mode 100644 arch/sh/kernel/dma-nommu.c diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index c9993a0cdc7e..da4db4b5359f 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -51,7 +51,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 @@ -164,6 +163,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 diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild index 46dd82ab2c29..6a5609a55965 100644 --- a/arch/sh/include/asm/Kbuild +++ b/arch/sh/include/asm/Kbuild @@ -2,6 +2,7 @@ generic-y += compat.h 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 diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h deleted file mode 100644 index 1ebc6a4eb1c5..000000000000 --- a/arch/sh/include/asm/dma-mapping.h +++ /dev/null @@ -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 */ diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index d5ddb64bfffe..59673f8a3379 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -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 diff --git a/arch/sh/kernel/dma-coherent.c b/arch/sh/kernel/dma-coherent.c index 2518065d5d27..a0021eef956b 100644 --- a/arch/sh/kernel/dma-coherent.c +++ b/arch/sh/kernel/dma-coherent.c @@ -7,14 +7,13 @@ */ #include #include -#include +#include #include #include #include -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); @@ -29,7 +28,8 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size, * Pages from the page allocator may have data present in * cache. So flush the cache before using uncached memory. */ - sh_sync_dma_for_device(ret, size, DMA_BIDIRECTIONAL); + arch_sync_dma_for_device(dev, virt_to_phys(ret), size, + DMA_BIDIRECTIONAL); ret_nocache = (void __force *)ioremap_nocache(virt_to_phys(ret), size); if (!ret_nocache) { @@ -46,9 +46,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); @@ -63,12 +62,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; diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c deleted file mode 100644 index d8689b1cb743..000000000000 --- a/arch/sh/kernel/dma-nommu.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * DMA mapping support for platforms lacking IOMMUs. - * - * Copyright (C) 2009 Paul Mundt - * - * 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. - */ -#include -#include -#include - -static dma_addr_t nommu_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 = page_to_phys(page) + offset - - PFN_PHYS(dev->dma_pfn_offset); - - WARN_ON(size == 0); - - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) - sh_sync_dma_for_device(page_address(page) + offset, size, dir); - - return addr; -} - -static int nommu_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction dir, - unsigned long attrs) -{ - struct scatterlist *s; - int i; - - WARN_ON(nents == 0 || sg[0].length == 0); - - for_each_sg(sg, s, nents, i) { - dma_addr_t offset = PFN_PHYS(dev->dma_pfn_offset); - - BUG_ON(!sg_page(s)); - - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) - sh_sync_dma_for_device(sg_virt(s), s->length, dir); - - s->dma_address = sg_phys(s) - offset; - s->dma_length = s->length; - } - - return nents; -} - -static void nommu_sync_single_for_device(struct device *dev, dma_addr_t addr, - size_t size, enum dma_data_direction dir) -{ - sh_sync_dma_for_device(phys_to_virt(addr), size, dir); -} - -static void nommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg, - int nelems, enum dma_data_direction dir) -{ - struct scatterlist *s; - int i; - - for_each_sg(sg, s, nelems, i) - sh_sync_dma_for_device(sg_virt(s), s->length, dir); -} - -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, - .sync_single_for_device = nommu_sync_single_for_device, - .sync_sg_for_device = nommu_sync_sg_for_device, -}; -EXPORT_SYMBOL(nommu_dma_ops); -- cgit v1.2.3-59-g8ed1b