From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:47:47
Hi all,
various architectures have used exact memory allocations for dma
allocations for a long time, but x86 and thus the common code based
on it kept using our normal power of two allocator, which tends to
waste a lot of memory for certain allocations.
Switching to a slightly cleaned up alloc_pages_exact is pretty easy,
but it turns out that because we didn't filter valid gfp_t flags
on the DMA allocator, a bunch of drivers were passing __GFP_COMP
to it, which is rather bogus in too many ways to explain. Arm has
been filtering it for a while, but this series instead tries to fix
the drivers and warn when __GFP_COMP is passed, which makes it much
larger than just adding the functionality.
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:47:45
dma_alloc_coherent does not return a physical address, but a DMA
address, which might be remapped or have an offset. Passing this
DMA address to vm_iomap_memory is completely bogus. Use the proper
dma_mmap_coherent helper instead, and stop passing __GFP_COMP
to dma_alloc_coherent, as the memory management inside the DMA
allocator is hidden from the callers.
Fixes: a8f3c203e19b ("[media] videobuf-dma-contig: add cache support")
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/media/v4l2-core/videobuf-dma-contig.c | 23 +++++++------------
1 file changed, 8 insertions(+), 15 deletions(-)
@@ -260,8 +260,7 @@ static int __videobuf_iolock(struct videobuf_queue *q,returnvideobuf_dma_contig_user_get(mem,vb);/* allocate memory for the read() method */-if(__videobuf_dc_alloc(q->dev,mem,PAGE_ALIGN(vb->size),-GFP_KERNEL))+if(__videobuf_dc_alloc(q->dev,mem,PAGE_ALIGN(vb->size)))return-ENOMEM;break;caseV4L2_MEMORY_OVERLAY:
@@ -280,7 +279,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,structvideobuf_dma_contig_memory*mem;structvideobuf_mapping*map;intretval;-unsignedlongsize;dev_dbg(q->dev,"%s\n",__func__);
@@ -298,23 +296,18 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,BUG_ON(!mem);MAGIC_CHECK(mem->magic,MAGIC_DC_MEM);-if(__videobuf_dc_alloc(q->dev,mem,PAGE_ALIGN(buf->bsize),-GFP_KERNEL|__GFP_COMP))+if(__videobuf_dc_alloc(q->dev,mem,PAGE_ALIGN(buf->bsize)))gotoerror;-/* Try to remap memory */-size=vma->vm_end-vma->vm_start;-vma->vm_page_prot=pgprot_noncached(vma->vm_page_prot);-/* the "vm_pgoff" is just used in v4l2 to find the*correspondingbufferdatastructurewhichisallocated*earlieranditdoesnotmeantheoffsetfromthephysical*bufferstartaddressasusual.Sosetitto0topass-*thesanitycheckinvm_iomap_memory().+*thesanitycheckindma_mmap_coherent().*/vma->vm_pgoff=0;--retval=vm_iomap_memory(vma,mem->dma_handle,size);+retval=dma_mmap_coherent(q->dev,vma,mem->vaddr,mem->dma_handle,+vma->vm_end-vma->vm_start);if(retval){dev_err(q->dev,"mmap: remap failed with error %d. ",retval);
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:47:52
Remove usage of the legacy drm PCI DMA wrappers, and with that the
incorrect usage cocktail of __GFP_COMP, virt_to_page on DMA allocation
and SetPageReserved.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/gpu/drm/ati_pcigart.c | 27 +++++++++++----------------
include/drm/ati_pcigart.h | 5 ++++-
2 files changed, 15 insertions(+), 17 deletions(-)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:48:01
These functions are rather broken in that they try to pass __GFP_COMP
to dma_alloc_coherent, call virt_to_page on the return value and
mess with PageReserved. And not actually used by any modern driver.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/gpu/drm/drm_bufs.c | 85 ++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/drm_pci.c | 89 --------------------------------------
2 files changed, 85 insertions(+), 89 deletions(-)
@@ -38,6 +38,91 @@#include<linux/nospec.h>+/**+*drm_pci_alloc-AllocateaPCIconsistentmemoryblock,forDMA.+*@dev:DRMdevice+*@size:sizeofblocktoallocate+*@align:alignmentofblock+*+*FIXME:ThisisaneedlessabstractionoftheLinuxdma-apiandshouldbe+*removed.+*+*Return:AhandletotheallocatedmemoryblockonsuccessorNULLon+*failure.+*/+drm_dma_handle_t*drm_pci_alloc(structdrm_device*dev,size_tsize,size_talign)+{+drm_dma_handle_t*dmah;+unsignedlongaddr;+size_tsz;++/* pci_alloc_consistent only guarantees alignment to the smallest+*PAGE_SIZEorderwhichisgreaterthanorequaltotherequestedsize.+*ReturnNULLherefornowtomakesurenobodytriesforlargeralignment+*/+if(align>size)+returnNULL;++dmah=kmalloc(sizeof(drm_dma_handle_t),GFP_KERNEL);+if(!dmah)+returnNULL;++dmah->size=size;+dmah->vaddr=dma_alloc_coherent(&dev->pdev->dev,size,+&dmah->busaddr,+GFP_KERNEL|__GFP_COMP);++if(dmah->vaddr==NULL){+kfree(dmah);+returnNULL;+}++/* XXX - Is virt_to_page() legal for consistent mem? */+/* Reserve */+for(addr=(unsignedlong)dmah->vaddr,sz=size;+sz>0;addr+=PAGE_SIZE,sz-=PAGE_SIZE){+SetPageReserved(virt_to_page((void*)addr));+}++returndmah;+}++/*+*FreeaPCIconsistentmemoryblockwithoutfreeingitsdescriptor.+*+*ThisfunctionisforinternaluseintheLinux-specificDRMcorecode.+*/+void__drm_legacy_pci_free(structdrm_device*dev,drm_dma_handle_t*dmah)+{+unsignedlongaddr;+size_tsz;++if(dmah->vaddr){+/* XXX - Is virt_to_page() legal for consistent mem? */+/* Unreserve */+for(addr=(unsignedlong)dmah->vaddr,sz=dmah->size;+sz>0;addr+=PAGE_SIZE,sz-=PAGE_SIZE){+ClearPageReserved(virt_to_page((void*)addr));+}+dma_free_coherent(&dev->pdev->dev,dmah->size,dmah->vaddr,+dmah->busaddr);+}+}++/**+*drm_pci_free-FreeaPCIconsistentmemoryblock+*@dev:DRMdevice+*@dmah:handletomemoryblock+*+*FIXME:ThisisaneedlessabstractionoftheLinuxdma-apiandshouldbe+*removed.+*/+voiddrm_pci_free(structdrm_device*dev,drm_dma_handle_t*dmah)+{+__drm_legacy_pci_free(dev,dmah);+kfree(dmah);+}+staticstructdrm_map_list*drm_find_matching_map(structdrm_device*dev,structdrm_local_map*map){
@@ -31,95 +31,6 @@#include"drm_internal.h"#include"drm_legacy.h"-/**-*drm_pci_alloc-AllocateaPCIconsistentmemoryblock,forDMA.-*@dev:DRMdevice-*@size:sizeofblocktoallocate-*@align:alignmentofblock-*-*FIXME:ThisisaneedlessabstractionoftheLinuxdma-apiandshouldbe-*removed.-*-*Return:AhandletotheallocatedmemoryblockonsuccessorNULLon-*failure.-*/-drm_dma_handle_t*drm_pci_alloc(structdrm_device*dev,size_tsize,size_talign)-{-drm_dma_handle_t*dmah;-unsignedlongaddr;-size_tsz;--/* pci_alloc_consistent only guarantees alignment to the smallest-*PAGE_SIZEorderwhichisgreaterthanorequaltotherequestedsize.-*ReturnNULLherefornowtomakesurenobodytriesforlargeralignment-*/-if(align>size)-returnNULL;--dmah=kmalloc(sizeof(drm_dma_handle_t),GFP_KERNEL);-if(!dmah)-returnNULL;--dmah->size=size;-dmah->vaddr=dma_alloc_coherent(&dev->pdev->dev,size,-&dmah->busaddr,-GFP_KERNEL|__GFP_COMP);--if(dmah->vaddr==NULL){-kfree(dmah);-returnNULL;-}--/* XXX - Is virt_to_page() legal for consistent mem? */-/* Reserve */-for(addr=(unsignedlong)dmah->vaddr,sz=size;-sz>0;addr+=PAGE_SIZE,sz-=PAGE_SIZE){-SetPageReserved(virt_to_page((void*)addr));-}--returndmah;-}--EXPORT_SYMBOL(drm_pci_alloc);--/*-*FreeaPCIconsistentmemoryblockwithoutfreeingitsdescriptor.-*-*ThisfunctionisforinternaluseintheLinux-specificDRMcorecode.-*/-void__drm_legacy_pci_free(structdrm_device*dev,drm_dma_handle_t*dmah)-{-unsignedlongaddr;-size_tsz;--if(dmah->vaddr){-/* XXX - Is virt_to_page() legal for consistent mem? */-/* Unreserve */-for(addr=(unsignedlong)dmah->vaddr,sz=dmah->size;-sz>0;addr+=PAGE_SIZE,sz-=PAGE_SIZE){-ClearPageReserved(virt_to_page((void*)addr));-}-dma_free_coherent(&dev->pdev->dev,dmah->size,dmah->vaddr,-dmah->busaddr);-}-}--/**-*drm_pci_free-FreeaPCIconsistentmemoryblock-*@dev:DRMdevice-*@dmah:handletomemoryblock-*-*FIXME:ThisisaneedlessabstractionoftheLinuxdma-apiandshouldbe-*removed.-*/-voiddrm_pci_free(structdrm_device*dev,drm_dma_handle_t*dmah)-{-__drm_legacy_pci_free(dev,dmah);-kfree(dmah);-}--EXPORT_SYMBOL(drm_pci_free);-#ifdef CONFIG_PCIstaticintdrm_get_pci_domain(structdrm_device*dev)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:48:08
The memory returned from dma_alloc_coherent is opaqueue to the user,
thus the exact way of page refcounting shall not matter either.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/gpu/drm/drm_bufs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:48:16
dma_alloc_coherent is not just the page allocator. The only valid
arguments to pass are either GFP_ATOMIC or GFP_ATOMIC with possible
modifiers of __GFP_NORETRY or __GFP_NOWARN.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/infiniband/hw/qib/qib_iba6120.c | 2 +-
drivers/infiniband/hw/qib/qib_init.c | 20 +++-----------------
2 files changed, 4 insertions(+), 18 deletions(-)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:48:19
dma_alloc_coherent is not just the page allocator. The only valid
arguments to pass are either GFP_ATOMIC or GFP_ATOMIC with possible
modifiers of __GFP_NORETRY or __GFP_NOWARN.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/infiniband/hw/hfi1/init.c | 22 +++-------------------
1 file changed, 3 insertions(+), 19 deletions(-)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:48:22
dma_alloc_coherent is not just the page allocator. The only valid
arguments to pass are either GFP_ATOMIC or GFP_ATOMIC with possible
modifiers of __GFP_NORETRY or __GFP_NOWARN.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 3 +--
drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:48:46
Many architectures (e.g. arm, m68 and sh) have always used exact
allocation in their dma coherent allocator, which avoids a lot of
memory waste especially for larger allocations. Lift this behavior
into the generic allocator so that dma-direct and the generic IOMMU
code benefit from this behavior as well.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
include/linux/dma-contiguous.h | 8 +++++---
kernel/dma/contiguous.c | 17 +++++++++++------
2 files changed, 16 insertions(+), 9 deletions(-)
@@ -243,14 +242,20 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)/* CMA can be used only in the context which permits sleeping */if(cma&&gfpflags_allow_blocking(gfp)){+size_talign=get_order(PAGE_ALIGN(size));+structpage*page;+align=min_t(size_t,align,CONFIG_CMA_ALIGNMENT);page=cma_alloc(cma,count,align,gfp&__GFP_NOWARN);+if(page)+returnpage;}/* Fallback allocation of normal pages */-if(!page)-page=alloc_pages_node(node,gfp,align);-returnpage;+cpu_addr=alloc_pages_exact_node(node,size,gfp);+if(!cpu_addr)+returnNULL;+returnvirt_to_page(cpu_addr);}/**
From: David Laight <hidden> Date: 2019-06-14 14:15:50
From: Christoph Hellwig
quoted hunk
Sent: 14 June 2019 14:47
Many architectures (e.g. arm, m68 and sh) have always used exact
allocation in their dma coherent allocator, which avoids a lot of
memory waste especially for larger allocations. Lift this behavior
into the generic allocator so that dma-direct and the generic IOMMU
code benefit from this behavior as well.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
include/linux/dma-contiguous.h | 8 +++++---
kernel/dma/contiguous.c | 17 +++++++++++------
2 files changed, 16 insertions(+), 9 deletions(-)
Does this still guarantee that requests for 16k will not cross a 16k boundary?
It looks like you are losing the alignment parameter.
There may be drivers and hardware that also require 12k allocates
to not cross 16k boundaries (etc).
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
From: David Laight <hidden> Date: 2019-06-14 15:01:33
From: 'Christoph Hellwig'
Sent: 14 June 2019 15:50
To: David Laight
On Fri, Jun 14, 2019 at 02:15:44PM +0000, David Laight wrote:
quoted
Does this still guarantee that requests for 16k will not cross a 16k boundary?
It looks like you are losing the alignment parameter.
The DMA API never gave you alignment guarantees to start with,
and you can get not naturally aligned memory from many of our
current implementations.
Hmmm...
I thought that was even documented.
I'm pretty sure there is a lot of code out there that makes that assumption.
Without it many drivers will have to allocate almost double the
amount of memory they actually need in order to get the required alignment.
So instead of saving memory you'll actually make more be used.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
On Fri, Jun 14, 2019 at 03:01:22PM +0000, David Laight wrote:
I'm pretty sure there is a lot of code out there that makes that assumption.
Without it many drivers will have to allocate almost double the
amount of memory they actually need in order to get the required alignment.
So instead of saving memory you'll actually make more be used.
That code would already be broken on a lot of Linux platforms.
From: Robin Murphy <robin.murphy@arm.com> Date: 2019-06-14 15:05:40
On 14/06/2019 15:50, 'Christoph Hellwig' wrote:
On Fri, Jun 14, 2019 at 02:15:44PM +0000, David Laight wrote:
quoted
Does this still guarantee that requests for 16k will not cross a 16k boundary?
It looks like you are losing the alignment parameter.
The DMA API never gave you alignment guarantees to start with,
and you can get not naturally aligned memory from many of our
current implementations.
Well, apart from the bit in DMA-API-HOWTO which has said this since
forever (well, before Git history, at least):
"The CPU virtual address and the DMA address are both
guaranteed to be aligned to the smallest PAGE_SIZE order which
is greater than or equal to the requested size. This invariant
exists (for example) to guarantee that if you allocate a chunk
which is smaller than or equal to 64 kilobytes, the extent of the
buffer you receive will not cross a 64K boundary."
That said, I don't believe this particular patch should make any
appreciable difference - alloc_pages_exact() is still going to give back
the same base address as the rounded up over-allocation would, and
PAGE_ALIGN()ing the size passed to get_order() already seemed to be
pointless.
Robin.
On Fri, Jun 14, 2019 at 04:05:33PM +0100, Robin Murphy wrote:
That said, I don't believe this particular patch should make any
appreciable difference - alloc_pages_exact() is still going to give back
the same base address as the rounded up over-allocation would, and
PAGE_ALIGN()ing the size passed to get_order() already seemed to be
pointless.
True, we actually do get the right alignment just about anywhere.
Not 100% sure about the various static pool implementations, but we
can make sure if any didn't we'll do that right thing once those
get consolidated.
From: David Laight <hidden> Date: 2019-06-14 15:16:49
From: Robin Murphy
Sent: 14 June 2019 16:06
...
Well, apart from the bit in DMA-API-HOWTO which has said this since
forever (well, before Git history, at least):
"The CPU virtual address and the DMA address are both
guaranteed to be aligned to the smallest PAGE_SIZE order which
is greater than or equal to the requested size. This invariant
exists (for example) to guarantee that if you allocate a chunk
which is smaller than or equal to 64 kilobytes, the extent of the
buffer you receive will not cross a 64K boundary."
I knew it was somewhere :-)
Interestingly that also implies that the address returned for a size
of (say) 128 will also be page aligned.
In that case 128 byte alignment should probably be ok - but it is still
an API change that could have horrid consequences.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:48:50
comedi_buf.c abuse the DMA API in gravely broken ways, as it assumes it
can call virt_to_page on the result, and the just remap it as uncached
using vmap. Disable the driver until this API abuse has been fixed.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/staging/comedi/Kconfig | 1 +
1 file changed, 1 insertion(+)
On Fri, Jun 14, 2019 at 03:47:22PM +0200, Christoph Hellwig wrote:
quoted hunk
comedi_buf.c abuse the DMA API in gravely broken ways, as it assumes it
can call virt_to_page on the result, and the just remap it as uncached
using vmap. Disable the driver until this API abuse has been fixed.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/staging/comedi/Kconfig | 1 +
1 file changed, 1 insertion(+)
@@ -1,6 +1,7 @@# SPDX-License-Identifier: GPL-2.0configCOMEDItristate"Data acquisition support (comedi)"+depends onBROKEN
Um, that's a huge sledgehammer.
Perhaps a hint as to how we can fix this up? This is the first time
I've heard of the comedi code not handling dma properly.
thanks,
greg k-h
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 14:49:30
On Fri, Jun 14, 2019 at 04:02:39PM +0200, Greg KH wrote:
Perhaps a hint as to how we can fix this up? This is the first time
I've heard of the comedi code not handling dma properly.
It can be fixed by:
a) never calling virt_to_page (or vmalloc_to_page for that matter)
on dma allocation
b) never remapping dma allocation with conflicting cache modes
(no remapping should be doable after a) anyway).
On Fri, Jun 14, 2019 at 04:48:57PM +0200, Christoph Hellwig wrote:
On Fri, Jun 14, 2019 at 04:02:39PM +0200, Greg KH wrote:
quoted
Perhaps a hint as to how we can fix this up? This is the first time
I've heard of the comedi code not handling dma properly.
It can be fixed by:
a) never calling virt_to_page (or vmalloc_to_page for that matter)
on dma allocation
b) never remapping dma allocation with conflicting cache modes
(no remapping should be doable after a) anyway).
Ok, fair enough, have any pointers of drivers/core code that does this
correctly? I can put it on my todo list, but might take a week or so...
Ian, want to look into doing this sooner?
thanks,
greg k-h
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 15:35:02
On Fri, Jun 14, 2019 at 05:30:32PM +0200, Greg KH wrote:
On Fri, Jun 14, 2019 at 04:48:57PM +0200, Christoph Hellwig wrote:
quoted
On Fri, Jun 14, 2019 at 04:02:39PM +0200, Greg KH wrote:
quoted
Perhaps a hint as to how we can fix this up? This is the first time
I've heard of the comedi code not handling dma properly.
It can be fixed by:
a) never calling virt_to_page (or vmalloc_to_page for that matter)
on dma allocation
b) never remapping dma allocation with conflicting cache modes
(no remapping should be doable after a) anyway).
Ok, fair enough, have any pointers of drivers/core code that does this
correctly? I can put it on my todo list, but might take a week or so...
Just about everyone else. They just need to remove the vmap and
either do one large allocation, or live with the fact that they need
helpers to access multiple array elements instead of one net vmap,
which most of the users already seem to do anyway, with just a few
using the vmap (which might explain why we didn't see blowups yet).
From: Ian Abbott <abbotti@mev.co.uk> Date: 2019-06-17 13:21:50
On 14/06/2019 16:34, Christoph Hellwig wrote:
On Fri, Jun 14, 2019 at 05:30:32PM +0200, Greg KH wrote:
quoted
On Fri, Jun 14, 2019 at 04:48:57PM +0200, Christoph Hellwig wrote:
quoted
On Fri, Jun 14, 2019 at 04:02:39PM +0200, Greg KH wrote:
quoted
Perhaps a hint as to how we can fix this up? This is the first time
I've heard of the comedi code not handling dma properly.
It can be fixed by:
a) never calling virt_to_page (or vmalloc_to_page for that matter)
on dma allocation
b) never remapping dma allocation with conflicting cache modes
(no remapping should be doable after a) anyway).
Ok, fair enough, have any pointers of drivers/core code that does this
correctly? I can put it on my todo list, but might take a week or so...
Just about everyone else. They just need to remove the vmap and
either do one large allocation, or live with the fact that they need
helpers to access multiple array elements instead of one net vmap,
which most of the users already seem to do anyway, with just a few
using the vmap (which might explain why we didn't see blowups yet).
Avoiding the vmap in comedi should be do-able as it already has other
means to get at the buffer pages.
When comedi makes the buffer from DMA coherent memory, it currently
allocates it as a series of page-sized chunks. That cannot be mmap'ed
in one go with dma_mmap_coherent(), so I see the following solutions.
1. Change the buffer allocation to allocate a single chunk of DMA
coherent memory and use dma_mmap_coherent() to mmap it.
2. Call dma_mmap_coherent() in a loop, adjusting vma->vm_start and
vma->vm_end for each iteration (vma->vm_pgoff will be 0), and restoring
the vma->vm_start and vma->vm_end at the end.
I'm not sure if 2 is a legal option.
--
-=( Ian Abbott [off-list ref] || Web: www.mev.co.uk )=-
-=( MEV Ltd. is a company registered in England & Wales. )=-
-=( Registered number: 02862268. Registered address: )=-
-=( 15 West Park Road, Bramhall, STOCKPORT, SK7 3JZ, UK. )=-
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:48:57
No need to duplicate the logic over two functions that are almost the
same.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
include/linux/gfp.h | 5 +++--
mm/page_alloc.c | 39 +++++++--------------------------------
2 files changed, 10 insertions(+), 34 deletions(-)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:48:59
Lift the code to clear __GFP_COMP from arm into the common DMA
allocator path. For one this fixes the various other patches that
call alloc_pages_exact or split_page in case a bogus driver passes
the argument, and it also prepares for doing exact allocation in
the generic dma-direct allocator.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/arm/mm/dma-mapping.c | 17 -----------------
kernel/dma/mapping.c | 9 +++++++++
2 files changed, 9 insertions(+), 17 deletions(-)
@@ -252,6 +252,15 @@ void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,/* let the implementation decide on the zone to allocate from: */flag&=~(__GFP_DMA|__GFP_DMA32|__GFP_HIGHMEM);+/*+*__GFP_COMPinteractsbadlywithsplittingupalargerorder+*allocation.Butasourallocationsmightnotevencomefromthe+*pageallocator,thecallerscan'trelyonthefactthatthey+*evengetpages,nevermindwhichkind.+*/+if(WARN_ON_ONCE(flag&__GFP_COMP))+flag&=~__GFP_COMP;+if(dma_is_direct(ops))cpu_addr=dma_direct_alloc(dev,size,dma_handle,flag,attrs);elseif(ops->alloc)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:49:13
This fits in with the naming scheme used by alloc_pages_node.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
include/linux/gfp.h | 2 +-
mm/page_alloc.c | 4 ++--
mm/page_ext.c | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:49:27
dma_alloc_coherent is not just the page allocator. The only valid
arguments to pass are either GFP_ATOMIC or GFP_ATOMIC with possible
modifiers of __GFP_NORETRY or __GFP_NOWARN.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/s390/net/ism_drv.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:49:43
dma_alloc_coherent is not just the page allocator. The only valid
arguments to pass are either GFP_ATOMIC or GFP_ATOMIC with possible
modifiers of __GFP_NORETRY or __GFP_NOWARN.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/net/ethernet/broadcom/cnic.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:50:01
We are not allowed to call virt_to_page on pages returned from
dma_alloc_coherent, as in many cases the virtual address returned
is aactually a kernel direct mapping. Also there generally is no
need to mark dma memory as reserved.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/gpu/drm/drm_bufs.c | 16 +---------------
1 file changed, 1 insertion(+), 15 deletions(-)
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-14 13:50:26
Remove usage of the legacy drm PCI DMA wrappers, and with that the
incorrect usage cocktail of __GFP_COMP, virt_to_page on DMA allocation
and SetPageReserved.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/gpu/drm/i915/i915_gem.c | 30 +++++++++++++-------------
drivers/gpu/drm/i915/i915_gem_object.h | 3 ++-
drivers/gpu/drm/i915/intel_display.c | 2 +-
3 files changed, 18 insertions(+), 17 deletions(-)
@@ -603,7 +603,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,structdrm_i915_gem_pwrite*args,structdrm_file*file){-void*vaddr=obj->phys_handle->vaddr+args->offset;+void*vaddr=obj->phys_vaddr+args->offset;char__user*user_data=u64_to_user_ptr(args->data_ptr);/* We manually control the domain here and pretend that it
From: Ville Syrjälä <hidden> Date: 2019-06-14 16:45:59
On Fri, Jun 14, 2019 at 03:47:13PM +0200, Christoph Hellwig wrote:
quoted hunk
Remove usage of the legacy drm PCI DMA wrappers, and with that the
incorrect usage cocktail of __GFP_COMP, virt_to_page on DMA allocation
and SetPageReserved.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/gpu/drm/i915/i915_gem.c | 30 +++++++++++++-------------
drivers/gpu/drm/i915/i915_gem_object.h | 3 ++-
drivers/gpu/drm/i915/intel_display.c | 2 +-
3 files changed, 18 insertions(+), 17 deletions(-)
This one is fine I think since the object remains a phys obj once
turned into one. At least the current code isn't clearing
phys_handle here. But my memory is a bit hazy on the details. Chris?
Also maybe s/phys_handle/phys_busaddr/ all over?
quoted hunk
}
static void
@@ -603,7 +603,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file) {- void *vaddr = obj->phys_handle->vaddr + args->offset;+ void *vaddr = obj->phys_vaddr + args->offset; char __user *user_data = u64_to_user_ptr(args->data_ptr); /* We manually control the domain here and pretend that it
@@ -1431,7 +1431,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, ret = i915_gem_gtt_pwrite_fast(obj, args); if (ret == -EFAULT || ret == -ENOSPC) {- if (obj->phys_handle)+ if (obj->phys_vaddr) ret = i915_gem_phys_pwrite(obj, args, file); else ret = i915_gem_shmem_pwrite(obj, args);
From: Dan Carpenter <hidden> Date: 2019-06-17 08:22:56
I once wrote a Smatch check based on a commit message that said we can't
pass dma_alloc_coherent() pointers to virt_to_phys(). But then I never
felt like I understood the rules enough to actually report the warnings
as bugs.
drivers/platform/x86/dcdbas.c:108 smi_data_buf_realloc() error: 'buf' came from dma_alloc_coherent() so we can't do virt_to_phys()
drivers/net/caif/caif_virtio.c:414 cfv_create_genpool() error: 'cfv->alloc_addr' came from dma_alloc_coherent() so we can't do virt_to_phys()
drivers/infiniband/hw/cxgb4/qp.c:135 alloc_host_sq() error: 'sq->queue' came from dma_alloc_coherent() so we can't do virt_to_phys()
drivers/infiniband/hw/cxgb4/qp.c:272 create_qp() error: 'wq->rq.queue' came from dma_alloc_coherent() so we can't do virt_to_phys()
drivers/infiniband/hw/cxgb4/qp.c:2628 alloc_srq_queue() error: 'wq->queue' came from dma_alloc_coherent() so we can't do virt_to_phys()
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c:494 ocrdma_alloc_ucontext() error: 'ctx->ah_tbl.va' came from dma_alloc_coherent() so we can't do virt_to_phys()
drivers/infiniband/hw/cxgb4/qp.c
129 static int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
130 {
131 sq->queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), sq->memsize,
132 &(sq->dma_addr), GFP_KERNEL);
133 if (!sq->queue)
134 return -ENOMEM;
135 sq->phys_addr = virt_to_phys(sq->queue);
136 dma_unmap_addr_set(sq, mapping, sq->dma_addr);
137 return 0;
138 }
Is this a bug?
regards,
dan carpenter
From: Jason Gunthorpe <jgg@ziepe.ca> Date: 2019-06-19 16:29:07
On Mon, Jun 17, 2019 at 10:33:42AM +0200, Christoph Hellwig wrote:
quoted
drivers/infiniband/hw/cxgb4/qp.c
129 static int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
130 {
131 sq->queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), sq->memsize,
132 &(sq->dma_addr), GFP_KERNEL);
133 if (!sq->queue)
134 return -ENOMEM;
135 sq->phys_addr = virt_to_phys(sq->queue);
136 dma_unmap_addr_set(sq, mapping, sq->dma_addr);
137 return 0;
138 }
Is this a bug?
Yes. This will blow up badly on many platforms, as sq->queue
might be vmapped, ioremapped, come from a pool without page backing.
Gah, this addr gets fed into io_remap_pfn_range/remap_pfn_range too..
Potnuri, you should fix this..
You probably need to use dma_mmap_from_dev_coherent() in the mmap ?
Jason
From: Christoph Hellwig <hch@lst.de> Date: 2019-06-20 10:51:58
On Wed, Jun 19, 2019 at 01:29:03PM -0300, Jason Gunthorpe wrote:
quoted
Yes. This will blow up badly on many platforms, as sq->queue
might be vmapped, ioremapped, come from a pool without page backing.
Gah, this addr gets fed into io_remap_pfn_range/remap_pfn_range too..
Potnuri, you should fix this..
You probably need to use dma_mmap_from_dev_coherent() in the mmap ?
The function to use is dma_mmap_coherent, dma_mmap_from_dev_coherent is
just an internal helper.
That beiŋ said the drivers/infiniband code has a lot of
*remap_pfn_range, and a lot of them look like they might be for
DMA memory.
From: Christoph Hellwig <hch@lst.de> Date: 2019-07-01 08:48:38
On Fri, Jun 14, 2019 at 03:47:10PM +0200, Christoph Hellwig wrote:
Switching to a slightly cleaned up alloc_pages_exact is pretty easy,
but it turns out that because we didn't filter valid gfp_t flags
on the DMA allocator, a bunch of drivers were passing __GFP_COMP
to it, which is rather bogus in too many ways to explain. Arm has
been filtering it for a while, but this series instead tries to fix
the drivers and warn when __GFP_COMP is passed, which makes it much
larger than just adding the functionality.
Dear driver maintainers,
can you look over the patches touching your drivers, please? I'd
like to get as much as possible of the driver patches into this
merge window, so that it can you through your maintainer trees.
From: Arend Van Spriel <arend.vanspriel@broadcom.com> Date: 2019-07-02 09:48:52
On 7/1/2019 10:48 AM, Christoph Hellwig wrote:
On Fri, Jun 14, 2019 at 03:47:10PM +0200, Christoph Hellwig wrote:
quoted
Switching to a slightly cleaned up alloc_pages_exact is pretty easy,
but it turns out that because we didn't filter valid gfp_t flags
on the DMA allocator, a bunch of drivers were passing __GFP_COMP
to it, which is rather bogus in too many ways to explain. Arm has
been filtering it for a while, but this series instead tries to fix
the drivers and warn when __GFP_COMP is passed, which makes it much
larger than just adding the functionality.
Dear driver maintainers,
can you look over the patches touching your drivers, please? I'd
like to get as much as possible of the driver patches into this
merge window, so that it can you through your maintainer trees.
You made me look ;-) Actually not touching my drivers so I'm off the
hook. However, I was wondering if drivers could know so I decided to
look into the DMA-API.txt documentation which currently states:
"""
The flag parameter (dma_alloc_coherent() only) allows the caller to
specify the ``GFP_`` flags (see kmalloc()) for the allocation (the
implementation may choose to ignore flags that affect the location of
the returned memory, like GFP_DMA).
"""
I do expect you are going to change that description as well now that
you are going to issue a warning on __GFP_COMP. Maybe include that in
patch 15/16 where you introduce that warning.
Regards,
Arend
From: Christoph Hellwig <hch@lst.de> Date: 2019-07-08 18:43:56
On Tue, Jul 02, 2019 at 11:48:44AM +0200, Arend Van Spriel wrote:
You made me look ;-) Actually not touching my drivers so I'm off the hook.
However, I was wondering if drivers could know so I decided to look into
the DMA-API.txt documentation which currently states:
"""
The flag parameter (dma_alloc_coherent() only) allows the caller to
specify the ``GFP_`` flags (see kmalloc()) for the allocation (the
implementation may choose to ignore flags that affect the location of
the returned memory, like GFP_DMA).
"""
I do expect you are going to change that description as well now that you
are going to issue a warning on __GFP_COMP. Maybe include that in patch
15/16 where you introduce that warning.
Yes, that description needs an updated, even without this series.
I'll make sure it is more clear.