Skip to content

Commit

Permalink
Merge tag 'dma-mapping-5.10' 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:

 - rework the non-coherent DMA allocator

 - move private definitions out of <linux/dma-mapping.h>

 - lower CMA_ALIGNMENT (Paul Cercueil)

 - remove the omap1 dma address translation in favor of the common code

 - make dma-direct aware of multiple dma offset ranges (Jim Quinlan)

 - support per-node DMA CMA areas (Barry Song)

 - increase the default seg boundary limit (Nicolin Chen)

 - misc fixes (Robin Murphy, Thomas Tai, Xu Wang)

 - various cleanups

* tag 'dma-mapping-5.10' of git://git.infradead.org/users/hch/dma-mapping: (63 commits)
  ARM/ixp4xx: add a missing include of dma-map-ops.h
  dma-direct: simplify the DMA_ATTR_NO_KERNEL_MAPPING handling
  dma-direct: factor out a dma_direct_alloc_from_pool helper
  dma-direct check for highmem pages in dma_direct_alloc_pages
  dma-mapping: merge <linux/dma-noncoherent.h> into <linux/dma-map-ops.h>
  dma-mapping: move large parts of <linux/dma-direct.h> to kernel/dma
  dma-mapping: move dma-debug.h to kernel/dma/
  dma-mapping: remove <asm/dma-contiguous.h>
  dma-mapping: merge <linux/dma-contiguous.h> into <linux/dma-map-ops.h>
  dma-contiguous: remove dma_contiguous_set_default
  dma-contiguous: remove dev_set_cma_area
  dma-contiguous: remove dma_declare_contiguous
  dma-mapping: split <linux/dma-mapping.h>
  cma: decrease CMA_ALIGNMENT lower limit to 2
  firewire-ohci: use dma_alloc_pages
  dma-iommu: implement ->alloc_noncoherent
  dma-mapping: add new {alloc,free}_noncoherent dma_map_ops methods
  dma-mapping: add a new dma_alloc_pages API
  dma-mapping: remove dma_cache_sync
  53c700: convert to dma_alloc_noncoherent
  ...
  • Loading branch information
torvalds committed Oct 15, 2020
2 parents f065199 + 2a410d0 commit 5a32c34
Show file tree
Hide file tree
Showing 170 changed files with 1,921 additions and 1,699 deletions.
13 changes: 12 additions & 1 deletion Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,18 @@
placement constraint by the physical address range of
memory allocations. A value of 0 disables CMA
altogether. For more information, see
include/linux/dma-contiguous.h
kernel/dma/contiguous.c

cma_pernuma=nn[MG]
[ARM64,KNL]
Sets the size of kernel per-numa memory area for
contiguous memory allocations. A value of 0 disables
per-numa CMA altogether. And If this option is not
specificed, the default value is 0.
With per-numa CMA enabled, DMA users on node nid will
first try to allocate buffer from the pernuma area
which is located in node nid, if the allocation fails,
they will fallback to the global default memory area.

cmo_free_hint= [PPC] Format: { yes | no }
Specify whether pages are marked as being inactive
Expand Down
99 changes: 36 additions & 63 deletions Documentation/core-api/dma-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -516,48 +516,56 @@ routines, e.g.:::
}


Part II - Advanced dma usage
----------------------------
Part II - Non-coherent DMA allocations
--------------------------------------

Warning: These pieces of the DMA API should not be used in the
majority of cases, since they cater for unlikely corner cases that
don't belong in usual drivers.
These APIs allow to allocate pages in the kernel direct mapping that are
guaranteed to be DMA addressable. This means that unlike dma_alloc_coherent,
virt_to_page can be called on the resulting address, and the resulting
struct page can be used for everything a struct page is suitable for.

If you don't understand how cache line coherency works between a
processor and an I/O device, you should not be using this part of the
API at all.
If you don't understand how cache line coherency works between a processor and
an I/O device, you should not be using this part of the API.

::

void *
dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
gfp_t flag, unsigned long attrs)
dma_alloc_noncoherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, enum dma_data_direction dir,
gfp_t gfp)

Identical to dma_alloc_coherent() except that when the
DMA_ATTR_NON_CONSISTENT flags is passed in the attrs argument, the
platform will choose to return either consistent or non-consistent memory
as it sees fit. By using this API, you are guaranteeing to the platform
that you have all the correct and necessary sync points for this memory
in the driver should it choose to return non-consistent memory.
This routine allocates a region of <size> bytes of consistent memory. It
returns a pointer to the allocated region (in the processor's virtual address
space) or NULL if the allocation failed. The returned memory may or may not
be in the kernels direct mapping. Drivers must not call virt_to_page on
the returned memory region.

Note: where the platform can return consistent memory, it will
guarantee that the sync points become nops.
It also returns a <dma_handle> which may be cast to an unsigned integer the
same width as the bus and given to the device as the DMA address base of
the region.

The dir parameter specified if data is read and/or written by the device,
see dma_map_single() for details.

The gfp parameter allows the caller to specify the ``GFP_`` flags (see
kmalloc()) for the allocation, but rejects flags used to specify a memory
zone such as GFP_DMA or GFP_HIGHMEM.

Warning: Handling non-consistent memory is a real pain. You should
only use this API if you positively know your driver will be
required to work on one of the rare (usually non-PCI) architectures
that simply cannot make consistent memory.
Before giving the memory to the device, dma_sync_single_for_device() needs
to be called, and before reading memory written by the device,
dma_sync_single_for_cpu(), just like for streaming DMA mappings that are
reused.

::

void
dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t dma_handle, unsigned long attrs)
dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t dma_handle, enum dma_data_direction dir)

Free memory allocated by the dma_alloc_attrs(). All common
parameters must be identical to those otherwise passed to dma_free_coherent,
and the attrs argument must be identical to the attrs passed to
dma_alloc_attrs().
Free a region of memory previously allocated using dma_alloc_noncoherent().
dev, size and dma_handle and dir must all be the same as those passed into
dma_alloc_noncoherent(). cpu_addr must be the virtual address returned by
the dma_alloc_noncoherent().

::

Expand All @@ -575,41 +583,6 @@ memory or doing partial flushes.
into the width returned by this call. It will also always be a power
of two for easy alignment.

::

void
dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction)

Do a partial sync of memory that was allocated by dma_alloc_attrs() with
the DMA_ATTR_NON_CONSISTENT flag starting at virtual address vaddr and
continuing on for size. Again, you *must* observe the cache line
boundaries when doing this.

::

int
dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
dma_addr_t device_addr, size_t size);

Declare region of memory to be handed out by dma_alloc_coherent() when
it's asked for coherent memory for this device.

phys_addr is the CPU physical address to which the memory is currently
assigned (this will be ioremapped so the CPU can access the region).

device_addr is the DMA address the device needs to be programmed
with to actually address this memory (this will be handed out as the
dma_addr_t in dma_alloc_coherent()).

size is the size of the area (must be multiples of PAGE_SIZE).

As a simplification for the platforms, only *one* such region of
memory may be declared per device.

For reasons of efficiency, most platforms choose to track the declared
region only at the granularity of a page. For smaller allocations,
you should use the dma_pool() API.

Part III - Debug drivers use of the DMA-API
-------------------------------------------
Expand Down
8 changes: 0 additions & 8 deletions Documentation/core-api/dma-attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,6 @@ Since it is optional for platforms to implement DMA_ATTR_WRITE_COMBINE,
those that do not will simply ignore the attribute and exhibit default
behavior.

DMA_ATTR_NON_CONSISTENT
-----------------------

DMA_ATTR_NON_CONSISTENT lets the platform to choose to return either
consistent or non-consistent memory as it sees fit. By using this API,
you are guaranteeing to the platform that you have all the correct and
necessary sync points for this memory in the driver.

DMA_ATTR_NO_KERNEL_MAPPING
--------------------------

Expand Down
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -5216,7 +5216,7 @@ T: git git://git.infradead.org/users/hch/dma-mapping.git
F: include/asm-generic/dma-mapping.h
F: include/linux/dma-direct.h
F: include/linux/dma-mapping.h
F: include/linux/dma-noncoherent.h
F: include/linux/dma-map-ops.h
F: kernel/dma/

DMA-BUF HEAPS FRAMEWORK
Expand Down
11 changes: 4 additions & 7 deletions arch/alpha/kernel/pci_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <linux/export.h>
#include <linux/scatterlist.h>
#include <linux/log2.h>
#include <linux/dma-mapping.h>
#include <linux/dma-map-ops.h>
#include <linux/iommu-helper.h>

#include <asm/io.h>
Expand Down Expand Up @@ -141,12 +141,7 @@ iommu_arena_find_pages(struct device *dev, struct pci_iommu_arena *arena,
unsigned long boundary_size;

base = arena->dma_base >> PAGE_SHIFT;
if (dev) {
boundary_size = dma_get_seg_boundary(dev) + 1;
boundary_size >>= PAGE_SHIFT;
} else {
boundary_size = 1UL << (32 - PAGE_SHIFT);
}
boundary_size = dma_get_seg_boundary_nr_pages(dev, PAGE_SHIFT);

/* Search forward for the first mask-aligned sequence of N free ptes */
ptes = arena->ptes;
Expand Down Expand Up @@ -957,5 +952,7 @@ const struct dma_map_ops alpha_pci_ops = {
.dma_supported = alpha_pci_supported,
.mmap = dma_common_mmap,
.get_sgtable = dma_common_get_sgtable,
.alloc_pages = dma_common_alloc_pages,
.free_pages = dma_common_free_pages,
};
EXPORT_SYMBOL(alpha_pci_ops);
2 changes: 1 addition & 1 deletion arch/arc/mm/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*/

#include <linux/dma-noncoherent.h>
#include <linux/dma-map-ops.h>
#include <asm/cache.h>
#include <asm/cacheflush.h>

Expand Down
3 changes: 2 additions & 1 deletion arch/arm/common/dmabounce.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
#include <linux/slab.h>
#include <linux/page-flags.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/dma-direct.h>
#include <linux/dma-map-ops.h>
#include <linux/dmapool.h>
#include <linux/list.h>
#include <linux/scatterlist.h>
Expand Down
15 changes: 0 additions & 15 deletions arch/arm/include/asm/dma-contiguous.h

This file was deleted.

35 changes: 33 additions & 2 deletions arch/arm/include/asm/dma-direct.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,44 @@
#ifndef ASM_ARM_DMA_DIRECT_H
#define ASM_ARM_DMA_DIRECT_H 1

static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
#include <asm/memory.h>

/*
* dma_to_pfn/pfn_to_dma/virt_to_dma are architecture private
* functions used internally by the DMA-mapping API to provide DMA
* addresses. They must not be used by drivers.
*/
static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn)
{
if (dev && dev->dma_range_map)
pfn = PFN_DOWN(translate_phys_to_dma(dev, PFN_PHYS(pfn)));
return (dma_addr_t)__pfn_to_bus(pfn);
}

static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr)
{
unsigned long pfn = __bus_to_pfn(addr);

if (dev && dev->dma_range_map)
pfn = PFN_DOWN(translate_dma_to_phys(dev, PFN_PHYS(pfn)));
return pfn;
}

static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
{
if (dev)
return pfn_to_dma(dev, virt_to_pfn(addr));

return (dma_addr_t)__virt_to_bus((unsigned long)(addr));
}

static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
{
unsigned int offset = paddr & ~PAGE_MASK;
return pfn_to_dma(dev, __phys_to_pfn(paddr)) + offset;
}

static inline phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dev_addr)
static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
{
unsigned int offset = dev_addr & ~PAGE_MASK;
return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset;
Expand Down
1 change: 0 additions & 1 deletion arch/arm/include/asm/dma-iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

#include <linux/mm_types.h>
#include <linux/scatterlist.h>
#include <linux/dma-debug.h>
#include <linux/kref.h>

struct dma_iommu_mapping {
Expand Down
71 changes: 0 additions & 71 deletions arch/arm/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@

#include <linux/mm_types.h>
#include <linux/scatterlist.h>
#include <linux/dma-debug.h>

#include <asm/memory.h>

#include <xen/xen.h>
#include <asm/xen/hypervisor.h>
Expand All @@ -23,74 +20,6 @@ static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
return NULL;
}

#ifdef __arch_page_to_dma
#error Please update to __arch_pfn_to_dma
#endif

/*
* dma_to_pfn/pfn_to_dma/dma_to_virt/virt_to_dma are architecture private
* functions used internally by the DMA-mapping API to provide DMA
* addresses. They must not be used by drivers.
*/
#ifndef __arch_pfn_to_dma
static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn)
{
if (dev)
pfn -= dev->dma_pfn_offset;
return (dma_addr_t)__pfn_to_bus(pfn);
}

static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr)
{
unsigned long pfn = __bus_to_pfn(addr);

if (dev)
pfn += dev->dma_pfn_offset;

return pfn;
}

static inline void *dma_to_virt(struct device *dev, dma_addr_t addr)
{
if (dev) {
unsigned long pfn = dma_to_pfn(dev, addr);

return phys_to_virt(__pfn_to_phys(pfn));
}

return (void *)__bus_to_virt((unsigned long)addr);
}

static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
{
if (dev)
return pfn_to_dma(dev, virt_to_pfn(addr));

return (dma_addr_t)__virt_to_bus((unsigned long)(addr));
}

#else
static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn)
{
return __arch_pfn_to_dma(dev, pfn);
}

static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr)
{
return __arch_dma_to_pfn(dev, addr);
}

static inline void *dma_to_virt(struct device *dev, dma_addr_t addr)
{
return __arch_dma_to_virt(dev, addr);
}

static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
{
return __arch_virt_to_dma(dev, addr);
}
#endif

/**
* arm_dma_alloc - allocate consistent memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
Expand Down
Loading

0 comments on commit 5a32c34

Please sign in to comment.