From de7eab301de78869322104ea13e124c936ad3e1f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Apr 2018 17:18:19 +0200 Subject: dma-direct: try reallocation with GFP_DMA32 if possible As the recent swiotlb bug revealed, we seem to have given up the direct DMA allocation too early and felt back to swiotlb allocation. The reason is that swiotlb allocator expected that dma_direct_alloc() would try harder to get pages even below 64bit DMA mask with GFP_DMA32, but the function doesn't do that but only deals with GFP_DMA case. This patch adds a similar fallback reallocation with GFP_DMA32 as we've done with GFP_DMA. The condition is that the coherent mask is smaller than 64bit (i.e. some address limitation), and neither GFP_DMA nor GFP_DMA32 is set beforehand. Signed-off-by: Takashi Iwai Signed-off-by: Christoph Hellwig --- lib/dma-direct.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib/dma-direct.c') diff --git a/lib/dma-direct.c b/lib/dma-direct.c index bbfb229aa067..970d39155618 100644 --- a/lib/dma-direct.c +++ b/lib/dma-direct.c @@ -84,6 +84,13 @@ again: __free_pages(page, page_order); page = NULL; + if (IS_ENABLED(CONFIG_ZONE_DMA32) && + dev->coherent_dma_mask < DMA_BIT_MASK(64) && + !(gfp & (GFP_DMA32 | GFP_DMA))) { + gfp |= GFP_DMA32; + goto again; + } + if (IS_ENABLED(CONFIG_ZONE_DMA) && dev->coherent_dma_mask < DMA_BIT_MASK(32) && !(gfp & GFP_DMA)) { -- cgit From 325ef1857fff8b2049322921e19421b6c5ad74e5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 12 Apr 2018 09:33:30 +0200 Subject: PCI: remove PCI_DMA_BUS_IS_PHYS This was used by the ide, scsi and networking code in the past to determine if they should bounce payloads. Now that the dma mapping always have to support dma to all physical memory (thanks to swiotlb for non-iommu systems) there is no need to this crude hack any more. Signed-off-by: Christoph Hellwig Acked-by: Palmer Dabbelt (for riscv) Reviewed-by: Jens Axboe --- lib/dma-direct.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/dma-direct.c') diff --git a/lib/dma-direct.c b/lib/dma-direct.c index 970d39155618..df9e726e0712 100644 --- a/lib/dma-direct.c +++ b/lib/dma-direct.c @@ -187,6 +187,5 @@ const struct dma_map_ops dma_direct_ops = { .map_sg = dma_direct_map_sg, .dma_supported = dma_direct_supported, .mapping_error = dma_direct_mapping_error, - .is_phys = 1, }; EXPORT_SYMBOL(dma_direct_ops); -- cgit From 782e6769c0df744e773dc2acff71c974b3bba4e9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 16 Apr 2018 15:24:51 +0200 Subject: dma-mapping: provide a generic dma-noncoherent implementation Add 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. Signed-off-by: Christoph Hellwig Tested-by: Alexey Brodkin Acked-by: Vineet Gupta --- lib/dma-direct.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/dma-direct.c') diff --git a/lib/dma-direct.c b/lib/dma-direct.c index df9e726e0712..b824eb218782 100644 --- a/lib/dma-direct.c +++ b/lib/dma-direct.c @@ -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; } -- cgit From f068fe3170bcf06f14fd0a9eec0be12be04ff012 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 27 Apr 2018 09:02:55 +0200 Subject: core, dma-direct: add a flag 32-bit dma limits Various PCI bridges (VIA PCI, Xilinx PCIe) limit DMA to only 32-bits even if the device itself supports more. Add a single bit flag to struct device (to be moved into the dma extension once we get to it) to flag such devices and reject larger DMA to them. Signed-off-by: Christoph Hellwig Reviewed-by: Greg Kroah-Hartman --- lib/dma-direct.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib/dma-direct.c') diff --git a/lib/dma-direct.c b/lib/dma-direct.c index b824eb218782..a48f94eff62e 100644 --- a/lib/dma-direct.c +++ b/lib/dma-direct.c @@ -172,6 +172,12 @@ int dma_direct_supported(struct device *dev, u64 mask) if (mask < DMA_BIT_MASK(32)) return 0; #endif + /* + * Various PCI/PCIe bridges have broken support for > 32bit DMA even + * if the device itself might support it. + */ + if (dev->dma_32bit_limit && mask > DMA_BIT_MASK(32)) + return 0; return 1; } -- cgit From 2550bbfd495227945e17ed1fa1c05bce4753b86b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 29 May 2018 16:15:12 +0200 Subject: dma-direct: don't crash on device without dma_mask Print a useful warning instead. Reported-by: Finn Thain Tested-by: Finn Thain Signed-off-by: Christoph Hellwig --- lib/dma-direct.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib/dma-direct.c') diff --git a/lib/dma-direct.c b/lib/dma-direct.c index a48f94eff62e..8be8106270c2 100644 --- a/lib/dma-direct.c +++ b/lib/dma-direct.c @@ -34,6 +34,13 @@ check_addr(struct device *dev, dma_addr_t dma_addr, size_t size, const char *caller) { if (unlikely(dev && !dma_capable(dev, dma_addr, size))) { + if (!dev->dma_mask) { + dev_err(dev, + "%s: call on device without dma_mask\n", + caller); + return false; + } + if (*dev->dma_mask >= DMA_BIT_MASK(32)) { dev_err(dev, "%s: overflow %pad+%zu of device mask %llx\n", -- cgit