Hello, On Thursday, March 22, 2012 2:45 PM Subash Patel wrote: > I have found out an issue with dma_mmap_writecombine() and coherent devices. > > On 02/29/2012 08:34 PM, Marek Szyprowski wrote: > > This patch converts dma_alloc/free/mmap_{coherent,writecombine} > > functions to use generic alloc/free/mmap methods from dma_map_ops > > structure. A new DMA_ATTR_WRITE_COMBINE DMA attribute have been > > introduced to implement writecombine methods. > > > > Signed-off-by: Marek Szyprowski<m.szyprowski@xxxxxxxxxxx> > > Signed-off-by: Kyungmin Park<kyungmin.park@xxxxxxxxxxx> > > --- > > arch/arm/common/dmabounce.c | 3 + > > arch/arm/include/asm/dma-mapping.h | 107 ++++++++++++++++++++++++++---------- > > arch/arm/mm/dma-mapping.c | 53 ++++++------------ > > 3 files changed, 98 insertions(+), 65 deletions(-) > > > > diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c > > index 119f487..dbae5ad 100644 > > --- a/arch/arm/common/dmabounce.c > > +++ b/arch/arm/common/dmabounce.c > > @@ -449,6 +449,9 @@ static int dmabounce_set_mask(struct device *dev, u64 dma_mask) > > } > > > > static struct dma_map_ops dmabounce_ops = { > > + .alloc = arm_dma_alloc, > > + .free = arm_dma_free, > > + .mmap = arm_dma_mmap, > > .map_page = dmabounce_map_page, > > .unmap_page = dmabounce_unmap_page, > > .sync_single_for_cpu = dmabounce_sync_for_cpu, > > diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h > > index 266cba6..4342b75 100644 > > --- a/arch/arm/include/asm/dma-mapping.h > > +++ b/arch/arm/include/asm/dma-mapping.h > > @@ -5,6 +5,7 @@ > > > > #include<linux/mm_types.h> > > #include<linux/scatterlist.h> > > +#include<linux/dma-attrs.h> > > #include<linux/dma-debug.h> > > > > #include<asm-generic/dma-coherent.h> > > @@ -110,68 +111,115 @@ static inline void dma_free_noncoherent(struct device *dev, size_t > size, > > extern int dma_supported(struct device *dev, u64 mask); > > > > /** > > - * dma_alloc_coherent - allocate consistent memory for DMA > > + * arm_dma_alloc - allocate consistent memory for DMA > > * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices > > * @size: required memory size > > * @handle: bus-specific DMA address > > + * @attrs: optinal attributes that specific mapping properties > > * > > - * Allocate some uncached, unbuffered memory for a device for > > - * performing DMA. This function allocates pages, and will > > - * return the CPU-viewed address, and sets @handle to be the > > - * device-viewed address. > > + * Allocate some memory for a device for performing DMA. This function > > + * allocates pages, and will return the CPU-viewed address, and sets @handle > > + * to be the device-viewed address. > > */ > > -extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t); > > +extern void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, > > + gfp_t gfp, struct dma_attrs *attrs); > > + > > +#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) > > + > > +static inline void *dma_alloc_attrs(struct device *dev, size_t size, > > + dma_addr_t *dma_handle, gfp_t flag, > > + struct dma_attrs *attrs) > > +{ > > + struct dma_map_ops *ops = get_dma_ops(dev); > > + void *cpu_addr; > > + BUG_ON(!ops); > > + > > + cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs); > > + debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); > > + return cpu_addr; > > +} > > > > /** > > - * dma_free_coherent - free memory allocated by dma_alloc_coherent > > + * arm_dma_free - free memory allocated by arm_dma_alloc > > * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices > > * @size: size of memory originally requested in dma_alloc_coherent > > * @cpu_addr: CPU-view address returned from dma_alloc_coherent > > * @handle: device-view address returned from dma_alloc_coherent > > + * @attrs: optinal attributes that specific mapping properties > > * > > * Free (and unmap) a DMA buffer previously allocated by > > - * dma_alloc_coherent(). > > + * arm_dma_alloc(). > > * > > * References to memory and mappings associated with cpu_addr/handle > > * during and after this call executing are illegal. > > */ > > -extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t); > > +extern void arm_dma_free(struct device *dev, size_t size, void *cpu_addr, > > + dma_addr_t handle, struct dma_attrs *attrs); > > + > > +#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) > > + > > +static inline void dma_free_attrs(struct device *dev, size_t size, > > + void *cpu_addr, dma_addr_t dma_handle, > > + struct dma_attrs *attrs) > > +{ > > + struct dma_map_ops *ops = get_dma_ops(dev); > > + BUG_ON(!ops); > > + > > + debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); > > + ops->free(dev, size, cpu_addr, dma_handle, attrs); > > +} > > > > /** > > - * dma_mmap_coherent - map a coherent DMA allocation into user space > > + * arm_dma_mmap - map a coherent DMA allocation into user space > > * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices > > * @vma: vm_area_struct describing requested user mapping > > * @cpu_addr: kernel CPU-view address returned from dma_alloc_coherent > > * @handle: device-view address returned from dma_alloc_coherent > > * @size: size of memory originally requested in dma_alloc_coherent > > + * @attrs: optinal attributes that specific mapping properties > > * > > * Map a coherent DMA buffer previously allocated by dma_alloc_coherent > > * into user space. The coherent DMA buffer must not be freed by the > > * driver until the user space mapping has been released. > > */ > > -int dma_mmap_coherent(struct device *, struct vm_area_struct *, > > - void *, dma_addr_t, size_t); > > +extern int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, > > + void *cpu_addr, dma_addr_t dma_addr, size_t size, > > + struct dma_attrs *attrs); > > > > +#define dma_mmap_coherent(d,v,c,h,s) dma_mmap_attrs(d,v,c,h,s,NULL) > > > > -/** > > - * dma_alloc_writecombine - allocate writecombining memory for DMA > > - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices > > - * @size: required memory size > > - * @handle: bus-specific DMA address > > - * > > - * Allocate some uncached, buffered memory for a device for > > - * performing DMA. This function allocates pages, and will > > - * return the CPU-viewed address, and sets @handle to be the > > - * device-viewed address. > > - */ > > -extern void *dma_alloc_writecombine(struct device *, size_t, dma_addr_t *, > > - gfp_t); > > +static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, > > + void *cpu_addr, dma_addr_t dma_addr, > > + size_t size, struct dma_attrs *attrs) > > +{ > > + struct dma_map_ops *ops = get_dma_ops(dev); > > + BUG_ON(!ops); > > + return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); > > +} > > > > -#define dma_free_writecombine(dev,size,cpu_addr,handle) \ > > - dma_free_coherent(dev,size,cpu_addr,handle) > > +static inline void *dma_alloc_writecombine(struct device *dev, size_t size, > > + dma_addr_t *dma_handle, gfp_t flag) > > +{ > > + DEFINE_DMA_ATTRS(attrs); > > + dma_set_attr(DMA_ATTR_WRITE_COMBINE,&attrs); > > + return dma_alloc_attrs(dev, size, dma_handle, flag,&attrs); > > +} > > > > -int dma_mmap_writecombine(struct device *, struct vm_area_struct *, > > - void *, dma_addr_t, size_t); > > +static inline void dma_free_writecombine(struct device *dev, size_t size, > > + void *cpu_addr, dma_addr_t dma_handle) > > +{ > > + DEFINE_DMA_ATTRS(attrs); > > + dma_set_attr(DMA_ATTR_WRITE_COMBINE,&attrs); > > + return dma_free_attrs(dev, size, cpu_addr, dma_handle,&attrs); > > +} > > + > > +static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma, > > + void *cpu_addr, dma_addr_t dma_addr, size_t size) > > +{ > > + DEFINE_DMA_ATTRS(attrs); > > + dma_set_attr(DMA_ATTR_WRITE_COMBINE,&attrs); > > + return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size,&attrs); > > +} > > > For devices, which do not have a coherent/reserved pool, then the > allocation in function __dma_alloc() happens, and the memory will be > remapped by calling __dma_alloc_remap(). In the above function, > arm_vmregion_find() will be called, and it succeeds to get the map and > it will be mapped to used. > > This has issues with devices with coherent memory. If we have any device > which has declared coherent memory, then the allocation happens from > per-device coherent area. Eg: Exynos MFC which declares: > s5p_mfc_reserve_mem(). In that case, dma_mmap_writecombine() fails, and > hence vb2_dc_mmap() fails as well. Right, I missed that case. Now I prepared a fix, I will send the patches in a minute. Please check if it works for you. Best regards -- Marek Szyprowski Samsung Poland R&D Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>