Skip to content

Commit

Permalink
Merge tag 'dma-mapping-5.3' of git://git.infradead.org/users/hch/dma-…
Browse files Browse the repository at this point in the history
…mapping

Pull dma-mapping updates from Christoph Hellwig:

 - move the USB special case that bounced DMA through a device bar into
   the USB code instead of handling it in the common DMA code (Laurentiu
   Tudor and Fredrik Noring)

 - don't dip into the global CMA pool for single page allocations
   (Nicolin Chen)

 - fix a crash when allocating memory for the atomic pool failed during
   boot (Florian Fainelli)

 - move support for MIPS-style uncached segments to the common code and
   use that for MIPS and nios2 (me)

 - make support for DMA_ATTR_NON_CONSISTENT and
   DMA_ATTR_NO_KERNEL_MAPPING generic (me)

 - convert nds32 to the generic remapping allocator (me)

* tag 'dma-mapping-5.3' of git://git.infradead.org/users/hch/dma-mapping: (29 commits)
  dma-mapping: mark dma_alloc_need_uncached as __always_inline
  MIPS: only select ARCH_HAS_UNCACHED_SEGMENT for non-coherent platforms
  usb: host: Fix excessive alignment restriction for local memory allocations
  lib/genalloc.c: Add algorithm, align and zeroed family of DMA allocators
  nios2: use the generic uncached segment support in dma-direct
  nds32: use the generic remapping allocator for coherent DMA allocations
  arc: use the generic remapping allocator for coherent DMA allocations
  dma-direct: handle DMA_ATTR_NO_KERNEL_MAPPING in common code
  dma-direct: handle DMA_ATTR_NON_CONSISTENT in common code
  dma-mapping: add a dma_alloc_need_uncached helper
  openrisc: remove the partial DMA_ATTR_NON_CONSISTENT support
  arc: remove the partial DMA_ATTR_NON_CONSISTENT support
  arm-nommu: remove the partial DMA_ATTR_NON_CONSISTENT support
  ARM: dma-mapping: allow larger DMA mask than supported
  dma-mapping: truncate dma masks to what dma_addr_t can hold
  iommu/dma: Apply dma_{alloc,free}_contiguous functions
  dma-remap: Avoid de-referencing NULL atomic_pool
  MIPS: use the generic uncached segment support in dma-direct
  dma-direct: provide generic support for uncached kernel segments
  au1100fb: fix DMA API abuse
  ...
  • Loading branch information
torvalds committed Jul 12, 2019
2 parents 9787aed + 15ffe5e commit 9e3a25d
Show file tree
Hide file tree
Showing 41 changed files with 515 additions and 654 deletions.
8 changes: 8 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,14 @@ config ARCH_HAS_SET_MEMORY
config ARCH_HAS_SET_DIRECT_MAP
bool

#
# Select if arch has an uncached kernel segment and provides the
# uncached_kernel_address / cached_kernel_address symbols to use it
#
config ARCH_HAS_UNCACHED_SEGMENT
select ARCH_HAS_DMA_PREP_COHERENT
bool

# Select if arch init_task must go in the __init_task_data section
config ARCH_TASK_STRUCT_ON_STACK
bool
Expand Down
2 changes: 2 additions & 0 deletions arch/arc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ config ARC
def_bool y
select ARC_TIMERS
select ARCH_HAS_DMA_COHERENT_TO_PFN
select ARCH_HAS_DMA_PREP_COHERENT
select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_SETUP_DMA_OPS
select ARCH_HAS_SYNC_DMA_FOR_CPU
Expand All @@ -16,6 +17,7 @@ config ARC
select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS
select COMMON_CLK
select DMA_DIRECT_REMAP
select GENERIC_ATOMIC64 if !ISA_ARCV2 || !(ARC_HAS_LL64 && ARC_HAS_LLSC)
select GENERIC_CLOCKEVENTS
select GENERIC_FIND_FIRST_BIT
Expand Down
71 changes: 10 additions & 61 deletions arch/arc/mm/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,15 @@
#include <asm/cacheflush.h>

/*
* ARCH specific callbacks for generic noncoherent DMA ops (dma/noncoherent.c)
* ARCH specific callbacks for generic noncoherent DMA ops
* - hardware IOC not available (or "dma-coherent" not set for device in DT)
* - But still handle both coherent and non-coherent requests from caller
*
* For DMA coherent hardware (IOC) generic code suffices
*/
void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
gfp_t gfp, unsigned long attrs)
{
unsigned long order = get_order(size);
struct page *page;
phys_addr_t paddr;
void *kvaddr;
bool need_coh = !(attrs & DMA_ATTR_NON_CONSISTENT);

/*
* __GFP_HIGHMEM flag is cleared by upper layer functions
* (in include/linux/dma-mapping.h) so we should never get a
* __GFP_HIGHMEM here.
*/
BUG_ON(gfp & __GFP_HIGHMEM);

page = alloc_pages(gfp | __GFP_ZERO, order);
if (!page)
return NULL;

/* This is linear addr (0x8000_0000 based) */
paddr = page_to_phys(page);

*dma_handle = paddr;

/*
* A coherent buffer needs MMU mapping to enforce non-cachability.
* kvaddr is kernel Virtual address (0x7000_0000 based).
*/
if (need_coh) {
kvaddr = ioremap_nocache(paddr, size);
if (kvaddr == NULL) {
__free_pages(page, order);
return NULL;
}
} else {
kvaddr = (void *)(u32)paddr;
}

void arch_dma_prep_coherent(struct page *page, size_t size)
{
/*
* Evict any existing L1 and/or L2 lines for the backing page
* in case it was used earlier as a normal "cached" page.
Expand All @@ -63,28 +27,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
* Currently flush_cache_vmap nukes the L1 cache completely which
* will be optimized as a separate commit
*/
if (need_coh)
dma_cache_wback_inv(paddr, size);

return kvaddr;
}

void arch_dma_free(struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_handle, unsigned long attrs)
{
phys_addr_t paddr = dma_handle;
struct page *page = virt_to_page(paddr);

if (!(attrs & DMA_ATTR_NON_CONSISTENT))
iounmap((void __force __iomem *)vaddr);

__free_pages(page, get_order(size));
}

long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
dma_addr_t dma_addr)
{
return __phys_to_pfn(dma_addr);
dma_cache_wback_inv(page_to_phys(page), size);
}

/*
Expand Down Expand Up @@ -161,3 +104,9 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
dev_info(dev, "use %sncoherent DMA ops\n",
dev->dma_coherent ? "" : "non");
}

static int __init atomic_pool_init(void)
{
return dma_atomic_pool_init(GFP_KERNEL, pgprot_noncached(PAGE_KERNEL));
}
postcore_initcall(atomic_pool_init);
24 changes: 3 additions & 21 deletions arch/arm/mm/dma-mapping-nommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,7 @@ static void *arm_nommu_dma_alloc(struct device *dev, size_t size,
unsigned long attrs)

{
void *ret;

/*
* Try generic allocator first if we are advertised that
* consistency is not required.
*/

if (attrs & DMA_ATTR_NON_CONSISTENT)
return dma_direct_alloc_pages(dev, size, dma_handle, gfp,
attrs);

ret = dma_alloc_from_global_coherent(size, dma_handle);
void *ret = dma_alloc_from_global_coherent(size, dma_handle);

/*
* dma_alloc_from_global_coherent() may fail because:
Expand All @@ -66,16 +55,9 @@ static void arm_nommu_dma_free(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_addr,
unsigned long attrs)
{
if (attrs & DMA_ATTR_NON_CONSISTENT) {
dma_direct_free_pages(dev, size, cpu_addr, dma_addr, attrs);
} else {
int ret = dma_release_from_global_coherent(get_order(size),
cpu_addr);

WARN_ON_ONCE(ret == 0);
}
int ret = dma_release_from_global_coherent(get_order(size), cpu_addr);

return;
WARN_ON_ONCE(ret == 0);
}

static int arm_nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
Expand Down
20 changes: 1 addition & 19 deletions arch/arm/mm/dma-mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,25 +216,7 @@ EXPORT_SYMBOL(arm_coherent_dma_ops);

static int __dma_supported(struct device *dev, u64 mask, bool warn)
{
unsigned long max_dma_pfn;

/*
* If the mask allows for more memory than we can address,
* and we actually have that much memory, then we must
* indicate that DMA to this device is not supported.
*/
if (sizeof(mask) != sizeof(dma_addr_t) &&
mask > (dma_addr_t)~0 &&
dma_to_pfn(dev, ~0) < max_pfn - 1) {
if (warn) {
dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n",
mask);
dev_warn(dev, "Driver did not use or check the return value from dma_set_coherent_mask()?\n");
}
return 0;
}

max_dma_pfn = min(max_pfn, arm_dma_pfn_limit);
unsigned long max_dma_pfn = min(max_pfn, arm_dma_pfn_limit);

/*
* Translate the device's DMA mask to a PFN limit. This
Expand Down
1 change: 1 addition & 0 deletions arch/mips/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,7 @@ config DMA_NONCOHERENT
bool
select ARCH_HAS_DMA_MMAP_PGPROT
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select ARCH_HAS_UNCACHED_SEGMENT
select NEED_DMA_MAP_STATE
select ARCH_HAS_DMA_COHERENT_TO_PFN
select DMA_NONCOHERENT_CACHE_SYNC
Expand Down
3 changes: 0 additions & 3 deletions arch/mips/include/asm/page.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,6 @@ extern bool __virt_addr_valid(const volatile void *kaddr);
((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)

#define UNCAC_ADDR(addr) (UNCAC_BASE + __pa(addr))
#define CAC_ADDR(addr) ((unsigned long)__va((addr) - UNCAC_BASE))

#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>

Expand Down
6 changes: 0 additions & 6 deletions arch/mips/jazz/jazzdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,19 +575,13 @@ static void *jazz_dma_alloc(struct device *dev, size_t size,
return NULL;
}

if (!(attrs & DMA_ATTR_NON_CONSISTENT)) {
dma_cache_wback_inv((unsigned long)ret, size);
ret = (void *)UNCAC_ADDR(ret);
}
return ret;
}

static void jazz_dma_free(struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_handle, unsigned long attrs)
{
vdma_free(dma_handle);
if (!(attrs & DMA_ATTR_NON_CONSISTENT))
vaddr = (void *)CAC_ADDR((unsigned long)vaddr);
dma_direct_free_pages(dev, size, vaddr, dma_handle, attrs);
}

Expand Down
2 changes: 0 additions & 2 deletions arch/mips/mm/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size);
void (*_dma_cache_wback)(unsigned long start, unsigned long size);
void (*_dma_cache_inv)(unsigned long start, unsigned long size);

EXPORT_SYMBOL(_dma_cache_wback_inv);

#endif /* CONFIG_DMA_NONCOHERENT */

/*
Expand Down
26 changes: 9 additions & 17 deletions arch/mips/mm/dma-noncoherent.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,33 +44,25 @@ static inline bool cpu_needs_post_dma_flush(struct device *dev)
}
}

void *arch_dma_alloc(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
void arch_dma_prep_coherent(struct page *page, size_t size)
{
void *ret;

ret = dma_direct_alloc_pages(dev, size, dma_handle, gfp, attrs);
if (ret && !(attrs & DMA_ATTR_NON_CONSISTENT)) {
dma_cache_wback_inv((unsigned long) ret, size);
ret = (void *)UNCAC_ADDR(ret);
}
dma_cache_wback_inv((unsigned long)page_address(page), size);
}

return ret;
void *uncached_kernel_address(void *addr)
{
return (void *)(__pa(addr) + UNCAC_BASE);
}

void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t dma_addr, unsigned long attrs)
void *cached_kernel_address(void *addr)
{
if (!(attrs & DMA_ATTR_NON_CONSISTENT))
cpu_addr = (void *)CAC_ADDR((unsigned long)cpu_addr);
dma_direct_free_pages(dev, size, cpu_addr, dma_addr, attrs);
return __va(addr) - UNCAC_BASE;
}

long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
dma_addr_t dma_addr)
{
unsigned long addr = CAC_ADDR((unsigned long)cpu_addr);
return page_to_pfn(virt_to_page((void *)addr));
return page_to_pfn(virt_to_page(cached_kernel_address(cpu_addr)));
}

pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
Expand Down
2 changes: 2 additions & 0 deletions arch/nds32/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
config NDS32
def_bool y
select ARCH_32BIT_OFF_T
select ARCH_HAS_DMA_PREP_COHERENT
select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select ARCH_WANT_FRAME_POINTERS if FTRACE
select CLKSRC_MMIO
select CLONE_BACKWARDS
select COMMON_CLK
select DMA_DIRECT_REMAP
select GENERIC_ATOMIC64
select GENERIC_CPU_DEVICES
select GENERIC_CLOCKEVENTS
Expand Down
Loading

0 comments on commit 9e3a25d

Please sign in to comment.