Skip to content

Commit

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

 - add debugfs support for dumping dma-debug information (Corentin
   Labbe)

 - Kconfig cleanups (Andy Shevchenko and me)

 - debugfs cleanups (Greg Kroah-Hartman)

 - improve dma_map_resource and use it in the media code

 - arch_setup_dma_ops / arch_teardown_dma_ops cleanups

 - various small cleanups and improvements for the per-device coherent
   allocator

 - make the DMA mask an upper bound and don't fail "too large" dma mask
   in the remaning two architectures - this will allow big driver
   cleanups in the following merge windows

* tag 'dma-mapping-5.1' of git://git.infradead.org/users/hch/dma-mapping: (21 commits)
  Documentation/DMA-API-HOWTO: update dma_mask sections
  sparc64/pci_sun4v: allow large DMA masks
  sparc64/iommu: allow large DMA masks
  sparc64: refactor the ali DMA quirk
  ccio: allow large DMA masks
  dma-mapping: remove the DMA_MEMORY_EXCLUSIVE flag
  dma-mapping: remove dma_mark_declared_memory_occupied
  dma-mapping: move CONFIG_DMA_CMA to kernel/dma/Kconfig
  dma-mapping: improve selection of dma_declare_coherent availability
  dma-mapping: remove an incorrect __iommem annotation
  of: select OF_RESERVED_MEM automatically
  device.h: dma_mem is only needed for HAVE_GENERIC_DMA_COHERENT
  mfd/sm501: depend on HAS_DMA
  dma-mapping: add a kconfig symbol for arch_teardown_dma_ops availability
  dma-mapping: add a kconfig symbol for arch_setup_dma_ops availability
  dma-mapping: move debug configuration options to kernel/dma
  dma-debug: add dumping facility via debugfs
  dma: debug: no need to check return value of debugfs_create functions
  videobuf2: replace a layering violation with dma_map_resource
  dma-mapping: don't BUG when calling dma_map_resource on RAM
  ...
  • Loading branch information
torvalds committed Mar 10, 2019
2 parents 065b6c4 + 9eb9e96 commit b7a7d1c
Show file tree
Hide file tree
Showing 47 changed files with 341 additions and 542 deletions.
121 changes: 41 additions & 80 deletions Documentation/DMA-API-HOWTO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,114 +146,75 @@ What about block I/O and networking buffers? The block I/O and
networking subsystems make sure that the buffers they use are valid
for you to DMA from/to.

DMA addressing limitations
DMA addressing capabilities
==========================

Does your device have any DMA addressing limitations? For example, is
your device only capable of driving the low order 24-bits of address?
If so, you need to inform the kernel of this fact.
By default, the kernel assumes that your device can address 32-bits of DMA
addressing. For a 64-bit capable device, this needs to be increased, and for
a device with limitations, it needs to be decreased.

By default, the kernel assumes that your device can address the full
32-bits. For a 64-bit capable device, this needs to be increased.
And for a device with limitations, as discussed in the previous
paragraph, it needs to be decreased.
Special note about PCI: PCI-X specification requires PCI-X devices to support
64-bit addressing (DAC) for all transactions. And at least one platform (SGI
SN2) requires 64-bit consistent allocations to operate correctly when the IO
bus is in PCI-X mode.

Special note about PCI: PCI-X specification requires PCI-X devices to
support 64-bit addressing (DAC) for all transactions. And at least
one platform (SGI SN2) requires 64-bit consistent allocations to
operate correctly when the IO bus is in PCI-X mode.
For correct operation, you must set the DMA mask to inform the kernel about
your devices DMA addressing capabilities.

For correct operation, you must interrogate the kernel in your device
probe routine to see if the DMA controller on the machine can properly
support the DMA addressing limitation your device has. It is good
style to do this even if your device holds the default setting,
because this shows that you did think about these issues wrt. your
device.

The query is performed via a call to dma_set_mask_and_coherent()::
This is performed via a call to dma_set_mask_and_coherent()::

int dma_set_mask_and_coherent(struct device *dev, u64 mask);

which will query the mask for both streaming and coherent APIs together.
If you have some special requirements, then the following two separate
queries can be used instead:
which will set the mask for both streaming and coherent APIs together. If you
have some special requirements, then the following two separate calls can be
used instead:

The query for streaming mappings is performed via a call to
The setup for streaming mappings is performed via a call to
dma_set_mask()::

int dma_set_mask(struct device *dev, u64 mask);

The query for consistent allocations is performed via a call
The setup for consistent allocations is performed via a call
to dma_set_coherent_mask()::

int dma_set_coherent_mask(struct device *dev, u64 mask);

Here, dev is a pointer to the device struct of your device, and mask
is a bit mask describing which bits of an address your device
supports. It returns zero if your card can perform DMA properly on
the machine given the address mask you provided. In general, the
device struct of your device is embedded in the bus-specific device
struct of your device. For example, &pdev->dev is a pointer to the
device struct of a PCI device (pdev is a pointer to the PCI device
struct of your device).
Here, dev is a pointer to the device struct of your device, and mask is a bit
mask describing which bits of an address your device supports. Often the
device struct of your device is embedded in the bus-specific device struct of
your device. For example, &pdev->dev is a pointer to the device struct of a
PCI device (pdev is a pointer to the PCI device struct of your device).

If it returns non-zero, your device cannot perform DMA properly on
this platform, and attempting to do so will result in undefined
behavior. You must either use a different mask, or not use DMA.
These calls usually return zero to indicated your device can perform DMA
properly on the machine given the address mask you provided, but they might
return an error if the mask is too small to be supportable on the given
system. If it returns non-zero, your device cannot perform DMA properly on
this platform, and attempting to do so will result in undefined behavior.
You must not use DMA on this device unless the dma_set_mask family of
functions has returned success.

This means that in the failure case, you have three options:
This means that in the failure case, you have two options:

1) Use another DMA mask, if possible (see below).
2) Use some non-DMA mode for data transfer, if possible.
3) Ignore this device and do not initialize it.
1) Use some non-DMA mode for data transfer, if possible.
2) Ignore this device and do not initialize it.

It is recommended that your driver print a kernel KERN_WARNING message
when you end up performing either #2 or #3. In this manner, if a user
of your driver reports that performance is bad or that the device is not
even detected, you can ask them for the kernel messages to find out
exactly why.
It is recommended that your driver print a kernel KERN_WARNING message when
setting the DMA mask fails. In this manner, if a user of your driver reports
that performance is bad or that the device is not even detected, you can ask
them for the kernel messages to find out exactly why.

The standard 32-bit addressing device would do something like this::
The standard 64-bit addressing device would do something like this::

if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
dev_warn(dev, "mydev: No suitable DMA available\n");
goto ignore_this_device;
}

Another common scenario is a 64-bit capable device. The approach here
is to try for 64-bit addressing, but back down to a 32-bit mask that
should not fail. The kernel may fail the 64-bit mask not because the
platform is not capable of 64-bit addressing. Rather, it may fail in
this case simply because 32-bit addressing is done more efficiently
than 64-bit addressing. For example, Sparc64 PCI SAC addressing is
more efficient than DAC addressing.

Here is how you would handle a 64-bit capable device which can drive
all 64-bits when accessing streaming DMA::

int using_dac;
If the device only supports 32-bit addressing for descriptors in the
coherent allocations, but supports full 64-bits for streaming mappings
it would look like this:

if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
using_dac = 1;
} else if (!dma_set_mask(dev, DMA_BIT_MASK(32))) {
using_dac = 0;
} else {
dev_warn(dev, "mydev: No suitable DMA available\n");
goto ignore_this_device;
}

If a card is capable of using 64-bit consistent allocations as well,
the case would look like this::

int using_dac, consistent_using_dac;

if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
using_dac = 1;
consistent_using_dac = 1;
} else if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
using_dac = 0;
consistent_using_dac = 0;
} else {
if (dma_set_mask(dev, DMA_BIT_MASK(64))) {
dev_warn(dev, "mydev: No suitable DMA available\n");
goto ignore_this_device;
}
Expand Down
29 changes: 4 additions & 25 deletions Documentation/DMA-API.txt
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,7 @@ 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, int
flags)
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.
Expand All @@ -581,12 +580,6 @@ dma_addr_t in dma_alloc_coherent()).

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

flags can be ORed together and are:

- DMA_MEMORY_EXCLUSIVE - only allocate memory from the declared regions.
Do not allow dma_alloc_coherent() to fall back to system memory when
it's out of memory in the declared region.

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

Expand All @@ -605,23 +598,6 @@ unconditionally having removed all the required structures. It is the
driver's job to ensure that no parts of this memory region are
currently in use.

::

void *
dma_mark_declared_memory_occupied(struct device *dev,
dma_addr_t device_addr, size_t size)

This is used to occupy specific regions of the declared space
(dma_alloc_coherent() will hand out the first free region it finds).

device_addr is the *device* address of the region requested.

size is the size (and should be a page-sized multiple).

The return value will be either a pointer to the processor virtual
address of the memory, or an error (via PTR_ERR()) if any part of the
region is occupied.

Part III - Debug drivers use of the DMA-API
-------------------------------------------

Expand Down Expand Up @@ -696,6 +672,9 @@ dma-api/disabled This read-only file contains the character 'Y'
happen when it runs out of memory or if it was
disabled at boot time

dma-api/dump This read-only file contains current DMA
mappings.

dma-api/error_count This file is read-only and shows the total
numbers of errors found.

Expand Down
3 changes: 1 addition & 2 deletions arch/arc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ config ARC
select ARC_TIMERS
select ARCH_HAS_DMA_COHERENT_TO_PFN
select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_SETUP_DMA_OPS
select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC
Expand All @@ -31,7 +32,6 @@ config ARC
select HAVE_ARCH_TRACEHOOK
select HAVE_DEBUG_STACKOVERFLOW
select HAVE_FUTEX_CMPXCHG if FUTEX
select HAVE_GENERIC_DMA_COHERENT
select HAVE_IOREMAP_PROT
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZMA
Expand All @@ -45,7 +45,6 @@ config ARC
select MODULES_USE_ELF_RELA
select OF
select OF_EARLY_FLATTREE
select OF_RESERVED_MEM
select PCI_SYSCALL if PCI
select PERF_USE_VMALLOC if ARC_CACHE_VIPT_ALIASING

Expand Down
1 change: 1 addition & 0 deletions arch/arc/include/asm/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ generic-y += bugs.h
generic-y += compat.h
generic-y += device.h
generic-y += div64.h
generic-y += dma-mapping.h
generic-y += emergency-restart.h
generic-y += extable.h
generic-y += ftrace.h
Expand Down
13 changes: 0 additions & 13 deletions arch/arc/include/asm/dma-mapping.h

This file was deleted.

5 changes: 3 additions & 2 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ config ARM
select ARCH_HAS_MEMBARRIER_SYNC_CORE
select ARCH_HAS_PTE_SPECIAL if ARM_LPAE
select ARCH_HAS_PHYS_TO_DMA
select ARCH_HAS_SETUP_DMA_OPS
select ARCH_HAS_SET_MEMORY
select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL
select ARCH_HAS_STRICT_MODULE_RWX if MMU
select ARCH_HAS_TEARDOWN_DMA_OPS if MMU
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_HAVE_CUSTOM_GPIO_H
select ARCH_HAS_GCOV_PROFILE_ALL
Expand All @@ -31,6 +33,7 @@ config ARM
select CLONE_BACKWARDS
select CPU_PM if SUSPEND || CPU_IDLE
select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS
select DMA_DECLARE_COHERENT
select DMA_REMAP if MMU
select EDAC_SUPPORT
select EDAC_ATOMIC_SCRUB
Expand Down Expand Up @@ -73,7 +76,6 @@ config ARM
select HAVE_FUNCTION_GRAPH_TRACER if !THUMB2_KERNEL
select HAVE_FUNCTION_TRACER if !XIP_KERNEL
select HAVE_GCC_PLUGINS
select HAVE_GENERIC_DMA_COHERENT
select HAVE_HW_BREAKPOINT if PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)
select HAVE_IDE if PCI || ISA || PCMCIA
select HAVE_IRQ_TIME_ACCOUNTING
Expand Down Expand Up @@ -102,7 +104,6 @@ config ARM
select MODULES_USE_ELF_REL
select NEED_DMA_MAP_STATE
select OF_EARLY_FLATTREE if OF
select OF_RESERVED_MEM if OF
select OLD_SIGACTION
select OLD_SIGSUSPEND3
select PCI_SYSCALL if PCI
Expand Down
9 changes: 0 additions & 9 deletions arch/arm/include/asm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,6 @@ static inline unsigned long dma_max_pfn(struct device *dev)
}
#define dma_max_pfn(dev) dma_max_pfn(dev)

#define arch_setup_dma_ops arch_setup_dma_ops
extern void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *iommu, bool coherent);

#ifdef CONFIG_MMU
#define arch_teardown_dma_ops arch_teardown_dma_ops
extern void arch_teardown_dma_ops(struct device *dev);
#endif

/* do not use this function in a driver */
static inline bool is_device_dma_coherent(struct device *dev)
{
Expand Down
12 changes: 4 additions & 8 deletions arch/arm/mach-imx/mach-imx27_visstrim_m10.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,7 @@ static void __init visstrim_analog_camera_init(void)
return;

dma_declare_coherent_memory(&pdev->dev, mx2_camera_base,
mx2_camera_base, MX2_CAMERA_BUF_SIZE,
DMA_MEMORY_EXCLUSIVE);
mx2_camera_base, MX2_CAMERA_BUF_SIZE);
}

static void __init visstrim_reserve(void)
Expand Down Expand Up @@ -445,8 +444,7 @@ static void __init visstrim_coda_init(void)
dma_declare_coherent_memory(&pdev->dev,
mx2_camera_base + MX2_CAMERA_BUF_SIZE,
mx2_camera_base + MX2_CAMERA_BUF_SIZE,
MX2_CAMERA_BUF_SIZE,
DMA_MEMORY_EXCLUSIVE);
MX2_CAMERA_BUF_SIZE);
}

/* DMA deinterlace */
Expand All @@ -465,8 +463,7 @@ static void __init visstrim_deinterlace_init(void)
dma_declare_coherent_memory(&pdev->dev,
mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE,
mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE,
MX2_CAMERA_BUF_SIZE,
DMA_MEMORY_EXCLUSIVE);
MX2_CAMERA_BUF_SIZE);
}

/* Emma-PrP for format conversion */
Expand All @@ -485,8 +482,7 @@ static void __init visstrim_emmaprp_init(void)
*/
ret = dma_declare_coherent_memory(&pdev->dev,
mx2_camera_base, mx2_camera_base,
MX2_CAMERA_BUF_SIZE,
DMA_MEMORY_EXCLUSIVE);
MX2_CAMERA_BUF_SIZE);
if (ret)
pr_err("Failed to declare memory for emmaprp\n");
}
Expand Down
3 changes: 1 addition & 2 deletions arch/arm/mach-imx/mach-mx31moboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,7 @@ static int __init mx31moboard_init_cam(void)

ret = dma_declare_coherent_memory(&pdev->dev,
mx3_camera_base, mx3_camera_base,
MX3_CAMERA_BUF_SIZE,
DMA_MEMORY_EXCLUSIVE);
MX3_CAMERA_BUF_SIZE);
if (ret)
goto err;

Expand Down
2 changes: 2 additions & 0 deletions arch/arm/mm/dma-mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ const struct dma_map_ops arm_dma_ops = {
.unmap_page = arm_dma_unmap_page,
.map_sg = arm_dma_map_sg,
.unmap_sg = arm_dma_unmap_sg,
.map_resource = dma_direct_map_resource,
.sync_single_for_cpu = arm_dma_sync_single_for_cpu,
.sync_single_for_device = arm_dma_sync_single_for_device,
.sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
Expand All @@ -211,6 +212,7 @@ const struct dma_map_ops arm_coherent_dma_ops = {
.get_sgtable = arm_dma_get_sgtable,
.map_page = arm_coherent_dma_map_page,
.map_sg = arm_dma_map_sg,
.map_resource = dma_direct_map_resource,
.dma_supported = arm_dma_supported,
};
EXPORT_SYMBOL(arm_coherent_dma_ops);
Expand Down
Loading

0 comments on commit b7a7d1c

Please sign in to comment.