Difference between revisions of "Dmaengine overview"

[quality revision] [quality revision]
m
(Merge articles)
 
Applicable for STM32MP13x lines, STM32MP15x lines

This article provides basic information about the DMA engine and how STM32 DMA, DMAMUX and MDMA drivers are plugged into it.

1 Framework purpose[edit]

This article provides basic information about the DMA framework. However it is worth browsing For additional information, browse the Kernel documentation related to DMA concept[1].

The direct memory access (DMA) is a feature that allows some hardware subsystems to access memory independently from the central processing unit (CPU).
The DMA can transfer data between peripherals and memory or between memory and memory.

2 System overview[edit]

Peripheral DMA client drivers Peripheral DMA client drivers Virtual DMA channel support DMA Engine DMAMUX Driver DMA Driver MDMA Driver DMAMUX DMA MDMA Peripheral clients Memories Peripheral clients Memories
DMA Engine

2.1 Component description[edit]

  • Peripheral DMA client drivers:

DMA clients are drivers that are mapped on the DMA API[2].

  • DMA engine:

The DMA engine is the engine core on which all clients rely.
Refer to DMA provider[1] for useful information on DMA internal behaviourbehavior.

  • Virtual DMA channel support:

The virtual DMA channel support manages virtual DMA channels and DMA requests queues. This layer is no used by DMA clients.

  • STM32 xDMA driver:

The STM32 xDMA driver is used to develop the DMA engine API.

  • STM32 DMAMUX driver:

The STM32 DMAMUX driver request multiplexer allows routing DMA request lines between the device peripherals and the DMA controllers.

  • DMAMUX, DMA and MDMA IP controller:

This is the STM32 DMA controller that handles data transfers between peripherals and memories or memory and memory connected to the same bus.

DMAMUX (DMA request router): DMAMUX internal peripheral
DMA: DMA internal peripheral
MDMA : MDMA internal peripheral

  • Peripheral clients:

Peripheral clients are peripherals where at least one DMA request line is mapped on DMAMUX.

  • Memories:

Memories can be either internal (e.g. such as SRAM, RETRAM or BCKRAMbackup RAM) or external (DDR memories).

2.2 APIs API description[edit]

Please refer Refer to DMA Engine API Guide[3] for a clear description of the DMA framework API.

In addition, going through Dynamic API[4] provides insight on the DMA memory allocation API. The client has to rely on this API to properly allocate DMA buffers so that they are processed by the DMA engine without any trouble.

The document Dynamic DMA mapping Guide[5]presents some examples and usecases.
It can be read in conjunction with the previous one. It presents some examples and usecases.

3 Configuration[edit]

3.1 Kernel Configurationconfiguration[edit]

The DMA engine and driver are enabled throughout menu config (see Menuconfig or how to configure kernel):

For DMA:

Device Driversdrivers -> 
    [*] DMA Engineengine support ->
        [*] STMicroelectronics STM32 DMA support

For DMAMUX:

Device Driversdrivers -> 
    [*] DMA Engineengine support ->
        [*] STMicroelectronics STM32 dmaDMA multiplexer support

For MDMA

Device Driversdrivers -> 
    [*] DMA Engineengine support ->
        [*] STMicroelectronics STM32 master dmaDMA support

3.2 Device Tree tree configuration[edit]

The device tree (DT) configuration can be done using the STM32CubeMX.

Refer to the following articles for a description of the DT configuration:

4 How to use the framework[edit]

Refer to the DMA Engine API Guide[3] for an exhautive description of the DMA engine client API.

4.1 Request a DMA channel[edit]

Device Tree configuration at STM32 level (arch/arm/boot/dts/stm32mp131.dtsi for STM32MP13x lines Warning.png, arch/arm/boot/dts/stm32mp151.dtsi for STM32MP15x lines More info.png) contains the "dmas" and "dma-names" properties in peripheral nodes having request line mapped.

The peripheral drivers just have to request one or more DMA channels. This is generally done during probe.

#include <linux/dmaengine.h>
struct dma_chan *dma_request_chan(struct device *dev, const char *name);

Thanks to the name, the dmaengine finds a channel that matches the configuration specified in the dmas property.

struct dma_chan *chan_rx, *chan_tx;

chan_rx =  dma_request_chan(&pdev->dev, "rx");
chan_tx = dma_request_chan(&pdev->dev, "tx");

The returned channel can be null if there are no more available channels or none of them fits the requested configuration. In this case, the peripheral must check the returned channel and switch to Interrupt mode.

4.2 Configure the DMA channel[edit]

A part of channel configuration comes from the dmas property in the peripheral device tree node. Refer to the description in DMA controller device tree bindings. dma_slave_config structure is also used to set up the channel. Refer to the dma_slave_config structure definition in include/linux/dmaengine.h for an exhaustive description.

struct dma_slave_config {
	enum dma_transfer_direction direction;
	phys_addr_t src_addr;
	phys_addr_t dst_addr;
	enum dma_slave_buswidth src_addr_width;
	enum dma_slave_buswidth dst_addr_width;
	u32 src_maxburst;
	u32 dst_maxburst;
	u32 src_port_window_size;
	u32 dst_port_window_size;
	bool device_fc;
	unsigned int slave_id;
};

Source/Destination addresses, Source/Destination address width, Source/Destination maximum burst are used by the DMA controller driver to configure the channel. The user must use dmaengine_slave_config() to set this dma_slave_config structure in the DMA controller driver.

struct dma_slave_config config;

/* In case of memory to device (TX) */
memset(&config, 0, sizeof(config));
config.dst_addr = phy_addr + txdr_offset;
config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
config.dst_maxburst = 1;
config.direction = DMA_MEM_TO_DEV;

/* In case of device to memory (RX/Capture) */
memset(&config, 0, sizeof(config));
config.src_addr = phy_addr + rxdr_offset;
config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
config.src_maxburst = 1;
config.direction = DMA_DEV_TO_MEM;

int dmaengine_slave_config(struct dma_chan *chan, struct dma_slave_config *config);

4.3 Configure the DMA transfer[edit]

The DMA engine transfer API must be used to prepare the DMA transfer. Three modes are supported by STM32 DMA controller drivers:

  • slave_sg: prepares a transfer of a list of scatter-gather buffer from/to a peripheral
  • dma_cyclic: prepares a cyclic operation from/to a peripheral until the operation is stopped by the user
  • dma_memcpy: prepares a memcpy operation (seldom used except by dmatest)
struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
           struct dma_chan *chan, struct scatterlist *sgl,
           unsigned int sg_len, enum dma_data_direction direction,
           unsigned long flags);

struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
           struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
           size_t period_len, enum dma_data_direction direction);

struct dma_async_tx_descriptor *dmaengine_prep_dma_memcpy(
           struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
           size_t len, unsigned long flags);

A peripheral driver completion callback can be set up using the callback* fields of the dma_async_tx_descriptor returned by the dmaengine_prep* function.

struct dma_async_tx_descriptor *txdesc;

txdesc = dmaengine_prep_...
txdesc->callback = peripheral_driver_dma_callback;
txdesc->callback_param = peripheral_dev;

4.4 Submit the DMA transfer[edit]

Once the transfer is prepared, it can be submitted for execution. It is added to the pending queue using dmaengine_submit() used as parameter of dma_submit_error() to digest the returned value.

dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
static inline int dma_submit_error(dma_cookie_t cookie)

ret = dma_submit_error(dmaengine_submit(desc));

The transfer can then be started using dma_async_issue_pending(). If the channel is idle, the first transfer in the queue is started.

void dma_async_issue_pending(struct dma_chan *chan);

On completion of each DMA transfer, a DMA interrupt is raised, then the next transfer in the queue is started and a tasklet is triggered. When scheduled, this tasklet calls the peripheral driver completion callback, provided it is set.

4.5 Terminate the DMA transfer[edit]

Two variants are available to force the DMA channel to stop an ongoing transfer. No completion callback is called for an incomplete transfer and the data in DMA controller FIFO may be lost. Refer to the DMA Engine API Guide[3] for more details.

  • dmaengine_terminate_async(): this function can be called from atomic context or from within a completion callback;
  • dmaengine_terminate_sync(): this function must not be called from atomic context or from within a completion callback.
int dmaengine_terminate_sync(struct dma_chan *chan)
int dmaengine_terminate_async(struct dma_chan *chan)

dmaengine_synchronize() must be used after dmaengine_terminate_async() and outside atomic context or completion callback, to synchronize the termination of the DMA channel with the current context. The function waits for the completion of the ongoing transfer and any callback before returning.

void dma_release_channel(struct dma_chan *chan)

4.6 Release the DMA channel[edit]

The peripheral driver can ask for new transfers or simply release the channel if it is no more needed. It is typically done by calling the peripheral driver remove() function.

void dma_release_channel(struct dma_chan *chan)

5 How to trace and debug the framework[edit]

45.1 How to trace[edit]

Through menuconfig, enable DMA engine debugging and DMA engine verbose debugging (including STM32 drivers):

Device Drivers -> 
    [*] DMA Engine support ->
        [*] DMA Engine debugging
        [*]   DMA Engine verbose debugging (NEW)

45.2 How to debug[edit]

45.2.1 devfs[edit]

sysfs entry can be used to browse for available DMA channels.

More information can be found in sysfs.

The following command lists all the registered DMA channels:

Board $> ls /sys/class/dma/
dma0chan0   dma0chan13  dma0chan18  dma0chan22  dma0chan27  dma0chan31  dma0chan8  dma1chan3  dma2chan0  dma2chan5
dma0chan1   dma0chan14  dma0chan19  dma0chan23  dma0chan28  dma0chan4   dma0chan9  dma1chan4  dma2chan1  dma2chan6
dma0chan10  dma0chan15  dma0chan2   dma0chan24  dma0chan29  dma0chan5   dma1chan0  dma1chan5  dma2chan2  dma2chan7
dma0chan11  dma0chan16  dma0chan20  dma0chan25  dma0chan3   dma0chan6   dma1chan1  dma1chan6  dma2chan3
dma0chan12  dma0chan17  dma0chan21  dma0chan26  dma0chan30  dma0chan7   dma1chan2  dma1chan7  dma2chan4

Each channel is expanded as follows:

Board $> ls -la /sys/class/dma/dma0chan0/
total 0
drwxr-xr-x  3 root root    0 Jun  7 21:22 .
drwxr-xr-x 34 root root    0 Jun  7 21:22 ..
-r--r--r--  1 root root 4096 Jun  9 13:11 bytes_transferred
lrwxrwxrwx  1 root root    0 Jun  9 13:11 device -> ../../../58000000.dma
-r--r--r--  1 root root 4096 Jun  9 13:11 in_use
-r--r--r--  1 root root 4096 Jun  9 13:11 memcpy_count
drwxr-xr-x  2 root root    0 Jun  9 13:11 power
lrwxrwxrwx  1 root root    0 Jun  9 13:11 subsystem -> ../../../../../../class/dma
-rw-r--r--  1 root root 4096 Jun  7 21:22 uevent

device indicates which DMA driver manages the channel.

echoing in_use indicates whether the channel has been allocated or not.

Board $> cat /sys/class/dma/dma0chan0/in_use                                               
1

45.2.2 Debugfs[edit]

debugfs entries are available. The user can get information about the DMA devices and the used channels through the /sys/kernel/debug/dmaengine .

root@stm32mp1:~# cat /sys/kernel/debug/dmaengine/summary 
dma0 (58000000.dma-controller): number of channels: 32
 dma0chan0    | 48000000.dma-controller:ch0
 dma0chan1    | 48000000.dma-controller:ch1
 dma0chan2    | 48000000.dma-controller:ch2
 dma0chan3    | 48000000.dma-controller:ch3
 dma0chan4    | 48000000.dma-controller:ch4
 dma0chan5    | 48000000.dma-controller:ch5
 dma0chan6    | 48000000.dma-controller:ch6
 dma0chan7    | 48000000.dma-controller:ch7
 dma0chan8    | 48001000.dma-controller:ch0
 dma0chan9    | 48001000.dma-controller:ch1
 dma0chan10   | 48001000.dma-controller:ch2
 dma0chan11   | 48001000.dma-controller:ch3
 dma0chan12   | 48001000.dma-controller:ch4
 dma0chan13   | 48001000.dma-controller:ch5
 dma0chan14   | 48001000.dma-controller:ch6
 dma0chan15   | 48001000.dma-controller:ch7
 dma0chan16   | 54002000.hash:in

dma1 (48000000.dma-controller): number of channels: 8
 dma1chan0    | 4000e000.serial:rx (via router: 48002000.dma-router)
 dma1chan1    | 4000e000.serial:tx (via router: 48002000.dma-router)
 dma1chan2    | 4000b000.audio-controller:tx (via router: 48002000.dma-router)
 dma1chan3    | 4000b000.audio-controller:rx (via router: 48002000.dma-router)
 dma1chan4    | 4400b004.audio-controller:tx (via router: 48002000.dma-router)
 dma1chan5    | 4400b024.audio-controller:rx (via router: 48002000.dma-router)

dma2 (48001000.dma-controller): number of channels: 8

Other DMA debugfs entries are available when the Linux® kernel is compiled using "Enable debugging of DMA-API usage" configuration. They are documented in Part III - Debug drivers use of the DMA-API[4].

45.2.3 dmatest[edit]

dmatest can be used to validate or debug DMA engine and driver without using client devices. This module is more a test than a debug module. It performs a memory-to-memory copy using the standard DMA engine API.

For details on how to use this kernel module, refer to [6].

5 6 Source code location[edit]

DMA: drivers/dma/stm32-dma.c
MDMA: drivers/dma/stm32-mdma.c
DMAMUX: drivers/dma/stm32-dmamux.c

DMA engine:

6 7 To go further[edit]

Very useful documentation can be found at https://www.kernel.org/doc/html/v4.19/driver-api/dmaengine/index.html.

7

DMAEngine documentation

8 References[edit]



<noinclude>{{ApplicableFor
|MPUs list=STM32MP13x, STM32MP15x
|MPUs checklist=STM32MP13x,STM32MP15x
}}</noinclude>
This article provides basic information about the DMA engine and how STM32 DMA, DMAMUX and MDMA drivers are plugged into it.

== Framework purpose ==

This article provides basic information about the DMA framework.However it is worth browsing For additional information, browse the Kernel documentation related to '''DMA concept'''<ref name="DMA provider">[https://www.kernel.org/doc/html/latest/{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/provider.html | text=DMA provider]}}</ref>.

The direct memory access (DMA) is a feature that allows some hardware subsystems to access memory independently from the central processing unit (CPU). <br>The DMA can transfer data between peripherals and memory or between memory and memory.

==System overview==
{{ImageMap|
Image: DMA schemas.png {{!}} frame {{!}} center {{!}} DMA Engine
rect 213 212 336 262176 186 299 236 [[#Peripheral_DMA_client_drivers| Peripheral DMA client drivers ]]
rect 759 212 882 262722 186 845 236 [[#Peripheral_DMA_client_drivers| Peripheral DMA client drivers ]]
rect 348 272 476 324311 246 439 298 [[#Virtual_DMA_channel_support | Virtual DMA channel support ]]
rect 476 272 602 324439 246 565 298 [[#DMA_Engine | DMA Engine ]]
rect 128 385 253 43891 359 216 412 [[#STM32_DMAMUX_driver| DMAMUX Driver]]
rect 296 385 420 438259 359 383 412 [[#STM32_xDMA_driver| DMA Driver ]]
rect 655 385 779 438618 359 742 412 [[#STM32_xDMA_driver| MDMA Driver]]
rect 128 495 253 54691 469 216 520 [[#DMAMUX, DMA and MDMA IPs controller | DMAMUX]]
rect 296 495 420 546259 469 383 520 [[#DMAMUX, DMA and MDMA IPs controller | DMA]]
rect 655 495 779 546618 469 742 520 [[#DMAMUX, DMA and MDMA IPs controller  | MDMA]]
rect 213 562 336 609176 536 299 583 [[#Peripheral_clients | Peripheral clients]]
rect 478 562 602 609441 536 565 583 [[#Memories | Memories ]]
rect 759 562 881 609722 539 844 583 [[#Peripheral_clients | Peripheral clients]]
rect 478 643 602 694441 617 565 668 [[#Memories | Memories ]]
}}

===Component description===

* '''<span id="Peripheral DMA client drivers">Peripheral DMA client drivers</span>''': 
DMA clients are drivers that are mapped on the '''DMA API'''<ref name="DMA API">[https://www.kernel.org/doc/html/latest/{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/client.html | text=DMA API]}}</ref>.

* '''<span id="DMA engine">DMA engine</span>''': 
The DMA engine is the engine core on which all clients rely.<br>

Refer to '''DMA provider'''<ref name="DMA provider">[https://www.kernel.org/doc/html/latest/{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/provider.html | text=DMA provider]}}</ref> for useful information on DMA internal behaviourbehavior.

* '''<span id="Virtual DMA channel support">Virtual DMA channel support</span>''':
The virtual DMA channel support manages virtual DMA channels and DMA requests queues.
This layer is no used by DMA clients.

* '''<span id="STM32 xDMA driver">STM32 xDMA driver</span>''':
The STM32 xDMA driver is used to develop the DMA engine API.

* '''<span id="STM32 DMAMUX driver">STM32 DMAMUX driver</span>''':
The STM32 DMAMUX driver request multiplexer allows routing DMA request lines between the device peripherals and the DMA controllers.

* '''<span id="DMAMUX, DMA and MDMA IPs controller">DMAMUX, DMA and MDMA IP controller</span>''':
This is the STM32 DMA controller that handles data transfers between peripherals and memories or memory and memory connected to the same bus.

DMAMUX (DMA request router): [[DMAMUX internal peripheral]] <br>

DMA: [[DMA internal peripheral]] <br>

MDMA : [[MDMA internal peripheral]] <br>


* '''<span id="Peripheral clients">Peripheral clients</span>''':
Peripheral clients are peripherals where at least one DMA request line is mapped on DMAMUX.

* '''<span id="Memories">Memories</span>''':
Memories can be either internal (e.g. such as SRAM, RETRAM or BCKRAMbackup RAM) or external (DDR).

===APIs description===
Please refer  memories).

===API description===
Refer to '''DMA Engine API Guide'''<ref name="DMA Engine API Guide">[https://www.kernel.org/doc/html/latest/{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/client.html | text=DMA Engine API Guide]}}</ref> for a clear description of the DMA framework API.

In addition, going through '''Dynamic API'''<ref name="DocumentationDynamic API">{{CodeSource | Linux kernel | Documentation/DMA-API.txt}} DocSource | domain=Linux kernel | path=core-api/dma-api.html | text=Dynamic DMA mapping using the generic device}}</ref> provides insight on the DMA memory allocation API. The client has to rely on this API to properly allocate DMA buffers so that they are processed by the DMA engine without any trouble.

The document '''Dynamic DMA mapping Guide'''<ref name="DMA mapping Guide">{{CodeSource | Linux kernel | Documentation/DMA-API-HOWTO.txt}} DocSource | domain=Linux kernel | path=core-api/dma-api-howto.html | text=Dynamic DMA mapping Guide}}</ref> presents some examples and usecases.<br> It can be read in conjunction with the previous one.<br> It presents some examples and usecases.

==Configuration ==

===Kernel Configuration


==Configuration ==

===Kernel configuration===
The DMA engine and driver are enabled throughout menu config (see [[Menuconfig or how to configure kernel]]):

For DMA:
 Device Driversdrivers -> 
     [*] DMA Engineengine support ->
         [*] STMicroelectronics STM32 DMA support

For DMAMUX:
 Device Driversdrivers -> 
     [*] DMA Engineengine support ->
         [*] STMicroelectronics STM32 dmaDMA multiplexer support

For MDMA
 Device Driversdrivers -> 
     [*] DMA Engineengine support ->
         [*] STMicroelectronics STM32 master dmaDMA support

===Device Treetree configuration===

The device tree (DT) configuration can be done using the [[STM32CubeMX]].

Refer to the following articles for a description of the DT configuration: 
* For DMA: [[DMA_device_tree_configuration | DMA device tree configuration]]
* For DMAMUX: [[DMAMUX_device_tree_configuration | DMAMUX device tree configuration]]
* For MDMA: [[MDMA_device_tree_configuration | MDMA device tree configuration]]

==How to use the framework==

Refer to the '''DMA Engine API Guide'''<ref name="DMA Engine API Guide">{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/client.html | text=DMA Engine API Guide}}</ref> for an exhautive description of the DMA engine client API.

=== Request a DMA channel ===

Device Tree configuration at STM32 level ({{CodeSource | Linux kernel | arch/arm/boot/dts/stm32mp131.dtsi}} for {{MicroprocessorDevice | device=13}}, {{CodeSource | Linux kernel | arch/arm/boot/dts/stm32mp151.dtsi}} for {{MicroprocessorDevice | device=15}}) contains the "dmas" and "dma-names" properties in peripheral nodes having request line mapped.

The peripheral drivers just have to request one or more DMA channels. This is generally done during probe.<syntaxhighlight lang="c">

#include <linux/dmaengine.h>

struct dma_chan *dma_request_chan(struct device *dev, const char *name);</syntaxhighlight>

Thanks to the name, the dmaengine finds a channel that matches the configuration specified in the dmas property.<syntaxhighlight lang="c">

struct dma_chan *chan_rx, *chan_tx;

chan_rx =  dma_request_chan(&pdev->dev, "rx");
chan_tx = dma_request_chan(&pdev->dev, "tx");</syntaxhighlight>

The returned channel can be null if there are no more available channels or none of them fits the requested configuration. In this case, the peripheral must check the returned channel and switch to Interrupt mode.

=== Configure the DMA channel ===

A part of channel configuration comes from the dmas property in the peripheral device tree node. Refer to the description in DMA controller device tree bindings.
dma_slave_config structure is also used to set up the channel. Refer to the dma_slave_config structure definition in {{CodeSource | Linux kernel | include/linux/dmaengine.h}} for an exhaustive description.<syntaxhighlight lang="c">

struct dma_slave_config {
	enum dma_transfer_direction direction;
	phys_addr_t src_addr;
	phys_addr_t dst_addr;
	enum dma_slave_buswidth src_addr_width;
	enum dma_slave_buswidth dst_addr_width;
	u32 src_maxburst;
	u32 dst_maxburst;
	u32 src_port_window_size;
	u32 dst_port_window_size;
	bool device_fc;
	unsigned int slave_id;
};</syntaxhighlight>

Source/Destination addresses, Source/Destination address width, Source/Destination maximum burst are used by the DMA controller driver to configure the channel.
The user must use dmaengine_slave_config() to set this dma_slave_config structure in the DMA controller driver.<syntaxhighlight lang="c">

struct dma_slave_config config;

/* In case of memory to device (TX) */
memset(&config, 0, sizeof(config));
config.dst_addr = phy_addr + txdr_offset;
config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
config.dst_maxburst = 1;
config.direction = DMA_MEM_TO_DEV;

/* In case of device to memory (RX/Capture) */
memset(&config, 0, sizeof(config));
config.src_addr = phy_addr + rxdr_offset;
config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
config.src_maxburst = 1;
config.direction = DMA_DEV_TO_MEM;

int dmaengine_slave_config(struct dma_chan *chan, struct dma_slave_config *config);</syntaxhighlight>


=== Configure the DMA transfer ===

The DMA engine transfer API must be used to prepare the DMA transfer. Three modes are supported by STM32 DMA controller drivers:
* slave_sg: prepares a transfer of a list of scatter-gather buffer from/to a peripheral
* dma_cyclic: prepares a cyclic operation from/to a peripheral until the operation is stopped by the user
* dma_memcpy: prepares a memcpy operation (seldom used except by dmatest)<syntaxhighlight lang="c">

struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
           struct dma_chan *chan, struct scatterlist *sgl,
           unsigned int sg_len, enum dma_data_direction direction,
           unsigned long flags);

struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
           struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
           size_t period_len, enum dma_data_direction direction);

struct dma_async_tx_descriptor *dmaengine_prep_dma_memcpy(
           struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
           size_t len, unsigned long flags);</syntaxhighlight>

A peripheral driver completion callback can be set up using the callback* fields of the dma_async_tx_descriptor returned by the dmaengine_prep* function.<syntaxhighlight lang="c">

struct dma_async_tx_descriptor *txdesc;

txdesc = dmaengine_prep_...
txdesc->callback = peripheral_driver_dma_callback;
txdesc->callback_param = peripheral_dev;</syntaxhighlight>


=== Submit the DMA transfer ===

Once the transfer is prepared, it can be submitted for execution. It is added to the pending queue using dmaengine_submit() used as parameter of dma_submit_error() to digest the returned value.<syntaxhighlight lang="c">

dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
static inline int dma_submit_error(dma_cookie_t cookie)

ret = dma_submit_error(dmaengine_submit(desc));</syntaxhighlight>

The transfer can then be started using dma_async_issue_pending(). If the channel is idle, the first transfer in the queue is started.<syntaxhighlight lang="c">

void dma_async_issue_pending(struct dma_chan *chan);</syntaxhighlight>

On completion of each DMA transfer, a DMA interrupt is raised, then the next transfer in the queue is started and a tasklet is triggered. When scheduled, this tasklet calls the peripheral driver completion callback, provided it is set.

=== Terminate the DMA transfer ===

Two variants are available to force the DMA channel to stop an ongoing transfer. No completion callback is called for an incomplete transfer and the data in DMA controller FIFO may be lost. Refer to the '''DMA Engine API Guide'''<ref name="DMA Engine API Guide">{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/client.html | text=DMA Engine API Guide}}</ref> for more details.
* dmaengine_terminate_async(): this function can be called from atomic context or from within a completion callback;
* dmaengine_terminate_sync(): this function must not be called from atomic context or from within a completion callback.<syntaxhighlight lang="c">

int dmaengine_terminate_sync(struct dma_chan *chan)
int dmaengine_terminate_async(struct dma_chan *chan)</syntaxhighlight>

dmaengine_synchronize() must be used after dmaengine_terminate_async() and outside atomic context or completion callback, to synchronize the termination of the DMA channel with the current context. The function waits for the completion of the ongoing transfer and any callback before returning.<syntaxhighlight lang="c">

void dma_release_channel(struct dma_chan *chan)</syntaxhighlight>


=== Release the DMA channel ===
The peripheral driver can ask for new transfers or simply release the channel if it is no more needed. It is typically done by calling the peripheral driver remove() function.<syntaxhighlight lang="c">

void dma_release_channel(struct dma_chan *chan)</syntaxhighlight>


==How to trace and debug the framework==

=== How to trace ===
Through menuconfig, enable DMA engine debugging and DMA engine verbose debugging (including STM32 drivers):

 Device Drivers -> 
     [*] DMA Engine support ->
         [*] DMA Engine debugging
         [*]   DMA Engine verbose debugging (NEW)

=== How to debug ===
==== devfs ====
'''sysfs''' entry can be used to browse for available DMA channels.

More information can be found in [http://intranet.lme.st.com:8000/php-bin/ug_mcdmpu/index.php/Virtual_File_System_(VFS)#.2Fsys_.28sysfs.29_-_System_filesystem  sysfs][Pseudo_filesystem#sysfs_-28-2Fsys-29_-_System_filesystem|sysfs]].

The following command lists all the registered DMA channels: 
 '''Board $>''' ls /sys/class/dma/
 dma0chan0   dma0chan13  dma0chan18  dma0chan22  dma0chan27  dma0chan31  dma0chan8  dma1chan3  dma2chan0  dma2chan5
 dma0chan1   dma0chan14  dma0chan19  dma0chan23  dma0chan28  dma0chan4   dma0chan9  dma1chan4  dma2chan1  dma2chan6
 dma0chan10  dma0chan15  dma0chan2   dma0chan24  dma0chan29  dma0chan5   dma1chan0  dma1chan5  dma2chan2  dma2chan7
 dma0chan11  dma0chan16  dma0chan20  dma0chan25  dma0chan3   dma0chan6   dma1chan1  dma1chan6  dma2chan3
 dma0chan12  dma0chan17  dma0chan21  dma0chan26  dma0chan30  dma0chan7   dma1chan2  dma1chan7  dma2chan4

Each channel is expanded as follows:
 '''Board $>''' ls -la /sys/class/dma/dma0chan0/
 total 0
 drwxr-xr-x  3 root root    0 Jun  7 21:22 .
 drwxr-xr-x 34 root root    0 Jun  7 21:22 ..
 -r--r--r--  1 root root 4096 Jun  9 13:11 bytes_transferred
 lrwxrwxrwx  1 root root    0 Jun  9 13:11 {{Red|'''device -> ../../../58000000.dma'''}}
 -r--r--r--  1 root root 4096 Jun  9 13:11 {{Red|'''in_use'''}}
 -r--r--r--  1 root root 4096 Jun  9 13:11 memcpy_count
 drwxr-xr-x  2 root root    0 Jun  9 13:11 power
 lrwxrwxrwx  1 root root    0 Jun  9 13:11 subsystem -> ../../../../../../class/dma
 -rw-r--r--  1 root root 4096 Jun  7 21:22 uevent

{{Red|'''device}} indicates which DMA driver manages the channel.

echoing {{Red|'''in_use'''}} indicates whether the channel has been allocated or not.
 '''Board $>''' cat /sys/class/dma/dma0chan0/in_use                                               
 1

==== Debugfs ====
[[Debugfs | debugfs]] entries are available.The user can get information about the DMA devices and the used channels through the /sys/kernel/debug/dmaengine .
 root@stm32mp1:~# cat /sys/kernel/debug/dmaengine/summary 
 dma0 (58000000.dma-controller): number of channels: 32
  dma0chan0    | 48000000.dma-controller:ch0
  dma0chan1    | 48000000.dma-controller:ch1
  dma0chan2    | 48000000.dma-controller:ch2
  dma0chan3    | 48000000.dma-controller:ch3
  dma0chan4    | 48000000.dma-controller:ch4
  dma0chan5    | 48000000.dma-controller:ch5
  dma0chan6    | 48000000.dma-controller:ch6
  dma0chan7    | 48000000.dma-controller:ch7
  dma0chan8    | 48001000.dma-controller:ch0
  dma0chan9    | 48001000.dma-controller:ch1
  dma0chan10   | 48001000.dma-controller:ch2
  dma0chan11   | 48001000.dma-controller:ch3
  dma0chan12   | 48001000.dma-controller:ch4
  dma0chan13   | 48001000.dma-controller:ch5
  dma0chan14   | 48001000.dma-controller:ch6
  dma0chan15   | 48001000.dma-controller:ch7
  dma0chan16   | 54002000.hash:in

 dma1 (48000000.dma-controller): number of channels: 8
  dma1chan0    | 4000e000.serial:rx (via router: 48002000.dma-router)
  dma1chan1    | 4000e000.serial:tx (via router: 48002000.dma-router)
  dma1chan2    | 4000b000.audio-controller:tx (via router: 48002000.dma-router)
  dma1chan3    | 4000b000.audio-controller:rx (via router: 48002000.dma-router)
  dma1chan4    | 4400b004.audio-controller:tx (via router: 48002000.dma-router)
  dma1chan5    | 4400b024.audio-controller:rx (via router: 48002000.dma-router)

 dma2 (48001000.dma-controller): number of channels: 8

Other DMA [[Debugfs | debugfs]] entries are available when the Linux<sup>&reg;</sup> kernel is compiled using "Enable debugging of DMA-API usage" configuration. They are documented in ''Part III - Debug drivers use of the DMA-API''<ref name="DocumentationDynamic API">{{CodeSource | Linux kernel | Documentation/DMA-API.txt}} DocSource | domain=Linux kernel | path=core-api/dma-api.html | text=Dynamic DMA mapping using the generic device}}</ref>.

==== dmatest ====
dmatest can be used to validate or debug DMA engine and driver without using client devices. This module is more a test than a debug module.
It performs a memory-to-memory copy using the standard DMA engine API.

For details on how to use this kernel module, refer to <ref name=dmatest>[https://www.kernel.org/doc/html/latest/{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/dmatest.html | text=driver-api/dmaengine/dmatest.html]}}</ref>.

==Source code location==
DMA: {{CodeSource | Linux kernel | drivers/dma/stm32-dma.c}}<br/>

MDMA: {{CodeSource | Linux kernel | drivers/dma/stm32-mdma.c}}<br/>

DMAMUX: {{CodeSource | Linux kernel | drivers/dma/stm32-dmamux.c}}<br/>


DMA engine: <br/>

* Engine: {{CodeSource | Linux kernel |drivers/dma/dmaengine.c}}<br>

* Virtual channel support: {{CodeSource | Linux kernel | drivers/dma/virt-dma.c}}

==To go further==
Very useful documentation can be found at https://www.kernel.org/doc/html/v4.19/{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/index.html.

==References==<references />

<noinclude>

{{PublicationRequestId | 9635 | 2018-11-13 | text=DMAEngine documentation}}

==References==<references />

<noinclude>

{{ArticleBasedOnModel | Framework overview article model}}
{{PublicationRequestId | 21052| 2021-09-07 | AnneJ}} 
[[Category:DMA]]</noinclude>
(20 intermediate revisions by 4 users not shown)
Line 1: Line 1:
  +
<noinclude>{{ApplicableFor
  +
|MPUs list=STM32MP13x, STM32MP15x
  +
|MPUs checklist=STM32MP13x,STM32MP15x
  +
}}</noinclude>
 
This article provides basic information about the DMA engine and how STM32 DMA, DMAMUX and MDMA drivers are plugged into it.
 
This article provides basic information about the DMA engine and how STM32 DMA, DMAMUX and MDMA drivers are plugged into it.
   
Line 4: Line 8:
   
 
This article provides basic information about the DMA framework.
 
This article provides basic information about the DMA framework.
However it is worth browsing the Kernel documentation related to '''DMA concept'''<ref name="DMA provider">[https://www.kernel.org/doc/html/latest/driver-api/dmaengine/provider.html DMA provider]</ref>.
+
For additional information, browse the Kernel documentation related to '''DMA concept'''<ref name="DMA provider">{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/provider.html | text=DMA provider}}</ref>.
   
 
The direct memory access (DMA) is a feature that allows some hardware subsystems to access memory independently from the central processing unit (CPU). <br>The DMA can transfer data between peripherals and memory or between memory and memory.
 
The direct memory access (DMA) is a feature that allows some hardware subsystems to access memory independently from the central processing unit (CPU). <br>The DMA can transfer data between peripherals and memory or between memory and memory.
Line 11: Line 15:
 
{{ImageMap|
 
{{ImageMap|
 
Image: DMA schemas.png {{!}} frame {{!}} center {{!}} DMA Engine
 
Image: DMA schemas.png {{!}} frame {{!}} center {{!}} DMA Engine
rect 213 212 336 262 [[#Peripheral_DMA_client_drivers| Peripheral DMA client drivers ]]
+
rect 176 186 299 236 [[#Peripheral_DMA_client_drivers| Peripheral DMA client drivers ]]
rect 759 212 882 262 [[#Peripheral_DMA_client_drivers| Peripheral DMA client drivers ]]
+
rect 722 186 845 236 [[#Peripheral_DMA_client_drivers| Peripheral DMA client drivers ]]
rect 348 272 476 324 [[#Virtual_DMA_channel_support | Virtual DMA channel support ]]
+
rect 311 246 439 298 [[#Virtual_DMA_channel_support | Virtual DMA channel support ]]
rect 476 272 602 324 [[#DMA_Engine | DMA Engine ]]
+
rect 439 246 565 298 [[#DMA_Engine | DMA Engine ]]
rect 128 385 253 438 [[#STM32_DMAMUX_driver| DMAMUX Driver]]
+
rect 91 359 216 412 [[#STM32_DMAMUX_driver| DMAMUX Driver]]
rect 296 385 420 438 [[#STM32_xDMA_driver| DMA Driver ]]
+
rect 259 359 383 412 [[#STM32_xDMA_driver| DMA Driver ]]
rect 655 385 779 438 [[#STM32_xDMA_driver| MDMA Driver]]
+
rect 618 359 742 412 [[#STM32_xDMA_driver| MDMA Driver]]
rect 128 495 253 546 [[#DMAMUX, DMA and MDMA IPs controller | DMAMUX]]
+
rect 91 469 216 520 [[#DMAMUX, DMA and MDMA IPs controller | DMAMUX]]
rect 296 495 420 546 [[#DMAMUX, DMA and MDMA IPs controller | DMA]]
+
rect 259 469 383 520 [[#DMAMUX, DMA and MDMA IPs controller | DMA]]
rect 655 495 779 546 [[#DMAMUX, DMA and MDMA IPs controller  | MDMA]]
+
rect 618 469 742 520 [[#DMAMUX, DMA and MDMA IPs controller  | MDMA]]
rect 213 562 336 609 [[#Peripheral_clients | Peripheral clients]]
+
rect 176 536 299 583 [[#Peripheral_clients | Peripheral clients]]
rect 478 562 602 609 [[#Memories | Memories ]]
+
rect 441 536 565 583 [[#Memories | Memories ]]
rect 759 562 881 609 [[#Peripheral_clients | Peripheral clients]]
+
rect 722 539 844 583 [[#Peripheral_clients | Peripheral clients]]
rect 478 643 602 694 [[#Memories | Memories ]]
+
rect 441 617 565 668 [[#Memories | Memories ]]
 
}}
 
}}
   
Line 30: Line 34:
   
 
* '''<span id="Peripheral DMA client drivers">Peripheral DMA client drivers</span>''':  
 
* '''<span id="Peripheral DMA client drivers">Peripheral DMA client drivers</span>''':  
DMA clients are drivers that are mapped on the '''DMA API'''<ref name="DMA API">[https://www.kernel.org/doc/html/latest/driver-api/dmaengine/client.html DMA API]</ref>.
+
DMA clients are drivers that are mapped on the '''DMA API'''<ref name="DMA API">{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/client.html | text=DMA API}}</ref>.
   
 
* '''<span id="DMA engine">DMA engine</span>''':  
 
* '''<span id="DMA engine">DMA engine</span>''':  
 
The DMA engine is the engine core on which all clients rely.<br>
 
The DMA engine is the engine core on which all clients rely.<br>
Refer to '''DMA provider'''<ref name="DMA provider">[https://www.kernel.org/doc/html/latest/driver-api/dmaengine/provider.html DMA provider]</ref> for useful information on DMA internal behaviour.
+
Refer to '''DMA provider'''<ref name="DMA provider">{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/provider.html | text=DMA provider}}</ref> for useful information on DMA internal behavior.
   
 
* '''<span id="Virtual DMA channel support">Virtual DMA channel support</span>''':
 
* '''<span id="Virtual DMA channel support">Virtual DMA channel support</span>''':
Line 57: Line 61:
   
 
* '''<span id="Memories">Memories</span>''':
 
* '''<span id="Memories">Memories</span>''':
Memories can be either internal (e.g. SRAM, RETRAM or BCKRAM) or external (DDR).
+
Memories can be either internal (such as SRAM, RETRAM or backup RAM) or external (DDR memories).
   
===APIs description===
+
===API description===
Please refer to '''DMA Engine API Guide'''<ref name="DMA Engine API Guide">[https://www.kernel.org/doc/html/latest/driver-api/dmaengine/client.html DMA Engine API Guide]</ref> for a clear description of the DMA framework API.
+
Refer to '''DMA Engine API Guide'''<ref name="DMA Engine API Guide">{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/client.html | text=DMA Engine API Guide}}</ref> for a clear description of the DMA framework API.
   
In addition, going through '''Dynamic API'''<ref name="Documentation API">{{CodeSource | Linux kernel | Documentation/DMA-API.txt}} Dynamic DMA mapping using the generic device</ref> provides insight on the DMA memory allocation API. The client has to rely on this API to properly allocate DMA buffers so that they are processed by the DMA engine without any trouble.
+
In addition, going through '''Dynamic API'''<ref name="Dynamic API">{{DocSource | domain=Linux kernel | path=core-api/dma-api.html | text=Dynamic DMA mapping using the generic device}}</ref> provides insight on the DMA memory allocation API. The client has to rely on this API to properly allocate DMA buffers so that they are processed by the DMA engine without any trouble.
   
The document '''Dynamic DMA mapping Guide'''<ref name="DMA mapping Guide">{{CodeSource | Linux kernel | Documentation/DMA-API-HOWTO.txt}} Dynamic DMA mapping Guide</ref> can be read in conjunction with the previous one.<br> It presents some examples and usecases.
+
The document '''Dynamic DMA mapping Guide'''<ref name="DMA mapping Guide">{{DocSource | domain=Linux kernel | path=core-api/dma-api-howto.html | text=Dynamic DMA mapping Guide}}</ref> presents some examples and usecases.<br> It can be read in conjunction with the previous one.
   
 
==Configuration ==
 
==Configuration ==
   
   
===Kernel Configuration===
+
===Kernel configuration===
 
The DMA engine and driver are enabled throughout menu config (see [[Menuconfig or how to configure kernel]]):
 
The DMA engine and driver are enabled throughout menu config (see [[Menuconfig or how to configure kernel]]):
   
 
For DMA:
 
For DMA:
  Device Drivers ->  
+
  Device drivers ->  
     [*] DMA Engine support ->
+
     [*] DMA engine support ->
 
         [*] STMicroelectronics STM32 DMA support
 
         [*] STMicroelectronics STM32 DMA support
   
 
For DMAMUX:
 
For DMAMUX:
  Device Drivers ->  
+
  Device drivers ->  
     [*] DMA Engine support ->
+
     [*] DMA engine support ->
         [*] STMicroelectronics STM32 dma multiplexer support
+
         [*] STMicroelectronics STM32 DMA multiplexer support
   
 
For MDMA
 
For MDMA
  Device Drivers ->  
+
  Device drivers ->  
     [*] DMA Engine support ->
+
     [*] DMA engine support ->
         [*] STMicroelectronics STM32 master dma support
+
         [*] STMicroelectronics STM32 master DMA support
   
===Device Tree configuration===
+
===Device tree configuration===
   
The DT configuration can be done using the [[STM32CubeMX]].
+
The device tree (DT) configuration can be done using the [[STM32CubeMX]].
   
 
Refer to the following articles for a description of the DT configuration:  
 
Refer to the following articles for a description of the DT configuration:  
Line 95: Line 99:
 
* For DMAMUX: [[DMAMUX_device_tree_configuration | DMAMUX device tree configuration]]
 
* For DMAMUX: [[DMAMUX_device_tree_configuration | DMAMUX device tree configuration]]
 
* For MDMA: [[MDMA_device_tree_configuration | MDMA device tree configuration]]
 
* For MDMA: [[MDMA_device_tree_configuration | MDMA device tree configuration]]
  +
  +
==How to use the framework==
  +
  +
Refer to the '''DMA Engine API Guide'''<ref name="DMA Engine API Guide">{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/client.html | text=DMA Engine API Guide}}</ref> for an exhautive description of the DMA engine client API.
  +
  +
=== Request a DMA channel ===
  +
  +
Device Tree configuration at STM32 level ({{CodeSource | Linux kernel | arch/arm/boot/dts/stm32mp131.dtsi}} for {{MicroprocessorDevice | device=13}}, {{CodeSource | Linux kernel | arch/arm/boot/dts/stm32mp151.dtsi}} for {{MicroprocessorDevice | device=15}}) contains the "dmas" and "dma-names" properties in peripheral nodes having request line mapped.
  +
  +
The peripheral drivers just have to request one or more DMA channels. This is generally done during probe.
  +
<syntaxhighlight lang="c">
  +
#include <linux/dmaengine.h>
  +
struct dma_chan *dma_request_chan(struct device *dev, const char *name);
  +
</syntaxhighlight>
  +
Thanks to the name, the dmaengine finds a channel that matches the configuration specified in the dmas property.
  +
<syntaxhighlight lang="c">
  +
struct dma_chan *chan_rx, *chan_tx;
  +
  +
chan_rx =  dma_request_chan(&pdev->dev, "rx");
  +
chan_tx = dma_request_chan(&pdev->dev, "tx");
  +
</syntaxhighlight>
  +
The returned channel can be null if there are no more available channels or none of them fits the requested configuration. In this case, the peripheral must check the returned channel and switch to Interrupt mode.
  +
  +
=== Configure the DMA channel ===
  +
  +
A part of channel configuration comes from the dmas property in the peripheral device tree node. Refer to the description in DMA controller device tree bindings.
  +
dma_slave_config structure is also used to set up the channel. Refer to the dma_slave_config structure definition in {{CodeSource | Linux kernel | include/linux/dmaengine.h}} for an exhaustive description.
  +
<syntaxhighlight lang="c">
  +
struct dma_slave_config {
  +
enum dma_transfer_direction direction;
  +
phys_addr_t src_addr;
  +
phys_addr_t dst_addr;
  +
enum dma_slave_buswidth src_addr_width;
  +
enum dma_slave_buswidth dst_addr_width;
  +
u32 src_maxburst;
  +
u32 dst_maxburst;
  +
u32 src_port_window_size;
  +
u32 dst_port_window_size;
  +
bool device_fc;
  +
unsigned int slave_id;
  +
};
  +
</syntaxhighlight>
  +
Source/Destination addresses, Source/Destination address width, Source/Destination maximum burst are used by the DMA controller driver to configure the channel.
  +
The user must use dmaengine_slave_config() to set this dma_slave_config structure in the DMA controller driver.
  +
<syntaxhighlight lang="c">
  +
struct dma_slave_config config;
  +
  +
/* In case of memory to device (TX) */
  +
memset(&config, 0, sizeof(config));
  +
config.dst_addr = phy_addr + txdr_offset;
  +
config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
  +
config.dst_maxburst = 1;
  +
config.direction = DMA_MEM_TO_DEV;
  +
  +
/* In case of device to memory (RX/Capture) */
  +
memset(&config, 0, sizeof(config));
  +
config.src_addr = phy_addr + rxdr_offset;
  +
config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
  +
config.src_maxburst = 1;
  +
config.direction = DMA_DEV_TO_MEM;
  +
  +
int dmaengine_slave_config(struct dma_chan *chan, struct dma_slave_config *config);
  +
</syntaxhighlight>
  +
  +
=== Configure the DMA transfer ===
  +
  +
The DMA engine transfer API must be used to prepare the DMA transfer. Three modes are supported by STM32 DMA controller drivers:
  +
* slave_sg: prepares a transfer of a list of scatter-gather buffer from/to a peripheral
  +
* dma_cyclic: prepares a cyclic operation from/to a peripheral until the operation is stopped by the user
  +
* dma_memcpy: prepares a memcpy operation (seldom used except by dmatest)
  +
<syntaxhighlight lang="c">
  +
struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
  +
          struct dma_chan *chan, struct scatterlist *sgl,
  +
          unsigned int sg_len, enum dma_data_direction direction,
  +
          unsigned long flags);
  +
  +
struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
  +
          struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
  +
          size_t period_len, enum dma_data_direction direction);
  +
  +
struct dma_async_tx_descriptor *dmaengine_prep_dma_memcpy(
  +
          struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
  +
          size_t len, unsigned long flags);
  +
</syntaxhighlight>
  +
A peripheral driver completion callback can be set up using the callback* fields of the dma_async_tx_descriptor returned by the dmaengine_prep* function.
  +
<syntaxhighlight lang="c">
  +
struct dma_async_tx_descriptor *txdesc;
  +
  +
txdesc = dmaengine_prep_...
  +
txdesc->callback = peripheral_driver_dma_callback;
  +
txdesc->callback_param = peripheral_dev;
  +
</syntaxhighlight>
  +
  +
=== Submit the DMA transfer ===
  +
  +
Once the transfer is prepared, it can be submitted for execution. It is added to the pending queue using dmaengine_submit() used as parameter of dma_submit_error() to digest the returned value.
  +
<syntaxhighlight lang="c">
  +
dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
  +
static inline int dma_submit_error(dma_cookie_t cookie)
  +
  +
ret = dma_submit_error(dmaengine_submit(desc));
  +
</syntaxhighlight>
  +
The transfer can then be started using dma_async_issue_pending(). If the channel is idle, the first transfer in the queue is started.
  +
<syntaxhighlight lang="c">
  +
void dma_async_issue_pending(struct dma_chan *chan);
  +
</syntaxhighlight>
  +
On completion of each DMA transfer, a DMA interrupt is raised, then the next transfer in the queue is started and a tasklet is triggered. When scheduled, this tasklet calls the peripheral driver completion callback, provided it is set.
  +
  +
=== Terminate the DMA transfer ===
  +
  +
Two variants are available to force the DMA channel to stop an ongoing transfer. No completion callback is called for an incomplete transfer and the data in DMA controller FIFO may be lost. Refer to the '''DMA Engine API Guide'''<ref name="DMA Engine API Guide">{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/client.html | text=DMA Engine API Guide}}</ref> for more details.
  +
* dmaengine_terminate_async(): this function can be called from atomic context or from within a completion callback;
  +
* dmaengine_terminate_sync(): this function must not be called from atomic context or from within a completion callback.
  +
<syntaxhighlight lang="c">
  +
int dmaengine_terminate_sync(struct dma_chan *chan)
  +
int dmaengine_terminate_async(struct dma_chan *chan)
  +
</syntaxhighlight>
  +
dmaengine_synchronize() must be used after dmaengine_terminate_async() and outside atomic context or completion callback, to synchronize the termination of the DMA channel with the current context. The function waits for the completion of the ongoing transfer and any callback before returning.
  +
<syntaxhighlight lang="c">
  +
void dma_release_channel(struct dma_chan *chan)
  +
</syntaxhighlight>
  +
  +
=== Release the DMA channel ===
  +
The peripheral driver can ask for new transfers or simply release the channel if it is no more needed. It is typically done by calling the peripheral driver remove() function.
  +
<syntaxhighlight lang="c">
  +
void dma_release_channel(struct dma_chan *chan)
  +
</syntaxhighlight>
   
 
==How to trace and debug the framework==
 
==How to trace and debug the framework==
 
   
 
=== How to trace ===
 
=== How to trace ===
Line 111: Line 241:
 
'''sysfs''' entry can be used to browse for available DMA channels.
 
'''sysfs''' entry can be used to browse for available DMA channels.
   
More information can be found in [http://intranet.lme.st.com:8000/php-bin/ug_mcdmpu/index.php/Virtual_File_System_(VFS)#.2Fsys_.28sysfs.29_-_System_filesystem sysfs].
+
More information can be found in [[Pseudo_filesystem#sysfs_-28-2Fsys-29_-_System_filesystem|sysfs]].
   
 
The following command lists all the registered DMA channels:  
 
The following command lists all the registered DMA channels:  
Line 141: Line 271:
   
 
==== Debugfs ====
 
==== Debugfs ====
[[Debugfs | debugfs]] entries are available. They are documented in ''Part III - Debug drivers use of the DMA-API''<ref name="Documentation API">{{CodeSource | Linux kernel | Documentation/DMA-API.txt}} Dynamic DMA mapping using the generic device</ref>.
+
[[Debugfs | debugfs]] entries are available.
  +
The user can get information about the DMA devices and the used channels through the /sys/kernel/debug/dmaengine .
  +
root@stm32mp1:~# cat /sys/kernel/debug/dmaengine/summary
  +
dma0 (58000000.dma-controller): number of channels: 32
  +
  dma0chan0    | 48000000.dma-controller:ch0
  +
  dma0chan1    | 48000000.dma-controller:ch1
  +
  dma0chan2    | 48000000.dma-controller:ch2
  +
  dma0chan3    | 48000000.dma-controller:ch3
  +
  dma0chan4    | 48000000.dma-controller:ch4
  +
  dma0chan5    | 48000000.dma-controller:ch5
  +
  dma0chan6    | 48000000.dma-controller:ch6
  +
  dma0chan7    | 48000000.dma-controller:ch7
  +
  dma0chan8    | 48001000.dma-controller:ch0
  +
  dma0chan9    | 48001000.dma-controller:ch1
  +
  dma0chan10  | 48001000.dma-controller:ch2
  +
  dma0chan11  | 48001000.dma-controller:ch3
  +
  dma0chan12  | 48001000.dma-controller:ch4
  +
  dma0chan13  | 48001000.dma-controller:ch5
  +
  dma0chan14  | 48001000.dma-controller:ch6
  +
  dma0chan15  | 48001000.dma-controller:ch7
  +
  dma0chan16  | 54002000.hash:in
  +
  +
dma1 (48000000.dma-controller): number of channels: 8
  +
  dma1chan0    | 4000e000.serial:rx (via router: 48002000.dma-router)
  +
  dma1chan1    | 4000e000.serial:tx (via router: 48002000.dma-router)
  +
  dma1chan2    | 4000b000.audio-controller:tx (via router: 48002000.dma-router)
  +
  dma1chan3    | 4000b000.audio-controller:rx (via router: 48002000.dma-router)
  +
  dma1chan4    | 4400b004.audio-controller:tx (via router: 48002000.dma-router)
  +
  dma1chan5    | 4400b024.audio-controller:rx (via router: 48002000.dma-router)
  +
  +
dma2 (48001000.dma-controller): number of channels: 8
  +
 
  +
Other DMA [[Debugfs | debugfs]] entries are available when the Linux<sup>&reg;</sup> kernel is compiled using "Enable debugging of DMA-API usage" configuration. They are documented in ''Part III - Debug drivers use of the DMA-API''<ref name="Dynamic API">{{DocSource | domain=Linux kernel | path=core-api/dma-api.html | text=Dynamic DMA mapping using the generic device}}</ref>.
   
 
==== dmatest ====
 
==== dmatest ====
dmatest can be used to validate or debug DMA engine and driver without using client devices. This module is more a test than a debug module.
+
dmatest can be used to validate or debug DMA engine and driver without using client devices. This is more a test than a debug module.
It performs a memory-to-memory copy using standard DMA engine API.
+
It performs a memory-to-memory copy using the standard DMA engine API.
   
For details on how to use this kernel module, refer to <ref name=dmatest>[https://www.kernel.org/doc/html/latest/driver-api/dmaengine/dmatest.html driver-api/dmaengine/dmatest.html]</ref>.
+
For details on how to use this kernel module, refer to <ref name=dmatest>{{DocSource | domain=Linux kernel | path=driver-api/dmaengine/dmatest.html | text=driver-api/dmaengine/dmatest.html}}</ref>.
   
 
==Source code location==
 
==Source code location==
Line 159: Line 321:
   
 
==To go further==
 
==To go further==
Very useful documentation can be found at https://www.kernel.org/doc/html/v4.19/driver-api/dmaengine/index.html.
+
Very useful documentation can be found at {{DocSource | domain=Linux kernel | path=driver-api/dmaengine/index.html | text=DMAEngine documentation}}
   
 
==References==
 
==References==
Line 165: Line 327:
   
 
<noinclude>
 
<noinclude>
{{PublicationRequestId | 9635 | 2018-11-13 | AnneJ}}  
+
{{ArticleBasedOnModel | Framework overview article model}}
  +
{{PublicationRequestId | 21052| 2021-09-07 | AnneJ}}  
 
[[Category:DMA]]
 
[[Category:DMA]]
 
</noinclude>
 
</noinclude>