Day 107 — DMA Slave Transfer and dmaengine_prep_slave_single()¶
Today's Goal¶
Understand how a DMA client prepares and executes a one-shot slave DMA transaction after the peripheral-side channel configuration has been completed.
The main focus is the relationship between:
- DMA buffer mapping
dmaengine_prep_slave_single()dmaengine_prep_slave_sg()- DMA mapping direction
- DMA Engine transfer direction
- Descriptor submission and issue
- Completion callbacks
- Buffer lifetime
- DMA cleanup and termination
- Slave configuration from Day106
The implementation goal is to begin building a practical sequence for writing DMA client drivers instead of studying DMA Engine APIs only as isolated concepts.
1. One-Shot Slave DMA Lifecycle¶
A typical one-shot slave DMA transfer has two different lifetimes.
Driver initialization prepares long-lived DMA resources:
Each individual transaction then follows a separate lifecycle:
CPU buffer
│
▼
DMA mapping
│
▼
Prepare descriptor
│
▼
Set callback
│
▼
Submit
│
▼
Issue pending
│
▼
DMA execution
│
▼
Completion
│
▼
Unmap
This separates:
2. DMA Mapping Before Descriptor Preparation¶
For a simple streaming DMA buffer, the CPU buffer must first be mapped for DMA.
For TX:
For RX:
The returned:
represents the DMA-visible memory address that should be supplied to the DMA Engine transaction preparation API.
The CPU virtual address must not simply be cast to dma_addr_t.
3. DMA Mapping Direction vs DMA Engine Direction¶
Two different direction enums participate in a slave DMA transaction.
For TX:
| Layer | Direction |
|---|---|
| DMA Mapping API | DMA_TO_DEVICE |
| DMA Engine API | DMA_MEM_TO_DEV |
For RX:
| Layer | Direction |
|---|---|
| DMA Mapping API | DMA_FROM_DEVICE |
| DMA Engine API | DMA_DEV_TO_MEM |
These enums describe different abstractions.
DMA mapping direction describes how the device accesses memory and is relevant to DMA mapping, cache maintenance, and ownership semantics.
DMA Engine direction describes the transaction topology between memory and the peripheral endpoint.
4. dmaengine_prep_slave_single()¶
A one-shot single-buffer transaction can be prepared with:
Conceptually:
A typical TX preparation uses:
desc = dmaengine_prep_slave_single(chan,
dma_addr,
len,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
The DMA address supplied to this API must already be DMA mapped.
5. dmaengine_prep_slave_single() Is an SG Helper¶
The implementation in:
shows that dmaengine_prep_slave_single() creates a one-entry scatterlist representation and forwards the request through the provider's slave SG preparation callback.
Conceptually:
Therefore, single does not mean:
- One physical page.
- One hardware descriptor.
- One hardware transfer block.
It means that the DMA client describes the memory side using one DMA address range.
The DMA controller driver may still split that range into multiple hardware descriptors.
6. dmaengine_prep_slave_sg()¶
When memory is represented by multiple DMA segments, a client can use:
Conceptually:
Mapped SG entries
│
▼
dmaengine_prep_slave_sg()
│
▼
DMA controller driver
│
▼
One or more hardware descriptors
A scatterlist entry is a software memory representation and is not the same object as a DMA controller hardware descriptor or LLI.
The provider may further split an SG entry according to hardware limits.
7. vmalloc() and Scatter-Gather DMA¶
A vmalloc() buffer is virtually contiguous but its backing physical pages are not guaranteed to be physically contiguous.
Conceptually:
vmalloc() buffer
│
▼
virtually contiguous range
│
▼
physically scattered backing pages
│
▼
SG representation
│
▼
DMA mapping
│
▼
DMA-visible segments
Therefore, vmalloc() memory is not simply equivalent to "DMA cannot be used."
A suitable subsystem or driver may represent the backing memory using scatter-gather DMA.
The exact mapping mechanism and hardware restrictions still depend on the subsystem and device.
8. BCM2835 SPI DMA Transfer Path¶
The following source was studied:
The normal DMA transfer path uses:
The BCM2835 SPI driver uses:
rather than directly using dmaengine_prep_slave_single() for its normal SPI transfer buffers.
The driver receives DMA-mapped scatter-gather information through the SPI subsystem.
Conceptually:
SPI transfer buffer
│
▼
SPI Core
│
│ DMA mapping / SG preparation
▼
tx_sg / rx_sg
│
▼
BCM2835 SPI Driver
│
▼
dmaengine_prep_slave_sg()
This demonstrates that a DMA client driver does not always perform DMA mapping directly.
When a subsystem framework already manages mapping, the hardware driver consumes the mapped representation supplied by that framework.
9. Framework Responsibility Boundary¶
The source trace demonstrated an important responsibility boundary.
The SPI Core handles generic SPI transfer and DMA mapping concerns.
The BCM2835 SPI controller driver handles controller-specific behavior such as:
- FIFO behavior.
- DMA interaction.
- Transfer alignment restrictions.
- Completion handling.
The DMA Engine provides the generic DMA transaction abstraction.
The DMA controller driver translates the generic transaction into controller-specific hardware descriptors.
Conceptually:
SPI Core
│
│ generic mapping
▼
SPI Controller Driver
│
│ peripheral-specific behavior
▼
DMA Engine
│
│ generic DMA transaction
▼
DMA Controller Driver
│
│ controller-specific programming
▼
DMA Hardware
10. DMA Completion vs Peripheral Completion¶
A DMA completion does not necessarily mean that the peripheral operation has physically completed.
For example:
DMA completion may indicate that the memory data has reached the SPI FIFO while the SPI controller is still shifting the final data onto the wire.
Therefore, a DMA client driver may need to verify peripheral-specific completion after receiving DMA completion.
This responsibility belongs to the peripheral driver rather than the DMA Engine framework.
11. Synopsys AXI DMA Slave SG Preparation¶
The provider-side source trace continued into the Synopsys AXI DMA driver.
The provider registers a slave SG preparation callback that eventually reaches:
The function consumes transaction information such as:
while Day106 established that peripheral-side configuration is stored in:
The two sources of information meet during hardware descriptor preparation.
Day106 Day107
chan->config mapped memory
Peripheral address DMA address
Peripheral width length
Burst direction
│ │
└────────────┬───────────────┘
▼
DMA Controller Driver
│
▼
Hardware Descriptor
12. Hardware Descriptor Construction¶
The AXI DMA provider may split one SG entry into multiple hardware descriptors according to controller block-size limitations.
Therefore:
For DMA_MEM_TO_DEV:
For DMA_DEV_TO_MEM:
This connects the transaction information studied today with the slave configuration studied on Day106.
13. Submit and Issue¶
After preparing a descriptor, the client configures completion handling:
The descriptor is then submitted:
cookie = dmaengine_submit(desc);
ret = dma_submit_error(cookie);
if (ret)
/* Handle submission failure. */
and issued:
The lifecycle is:
Preparing or constructing hardware descriptors does not itself mean that DMA execution has started.
14. Callback Context Lifetime¶
DMA completion is asynchronous.
Therefore, callback context must remain valid until the completion path can no longer reference it.
The following pattern is unsafe:
struct my_dma_request req;
desc->callback_param = &req;
dmaengine_submit(desc);
dma_async_issue_pending(chan);
return 0;
if req is a stack object and the function returns before the callback executes.
The general rule is:
Callback context lifetime must cover the entire period in which the callback may execute.
The same lifetime reasoning applies to the DMA buffer and DMA mapping.
15. Buffer Ownership vs DMA Mapping Ownership¶
Buffer allocation ownership and DMA mapping ownership are separate concepts.
For example:
The code that calls:
normally owns the corresponding:
but that does not automatically mean it owns the allocation and may call:
Ownership must be defined independently.
16. Error Path Before DMA Issue¶
If DMA mapping succeeds but descriptor preparation fails:
There is no active DMA transaction to terminate.
Similarly, a failed descriptor submission must release resources that remain owned by the client, including the streaming DMA mapping.
The cleanup path should reflect which resources have actually been acquired.
17. Timeout After DMA Issue¶
Once:
has been called, DMA hardware may already be accessing the mapped buffer.
A timeout path must not immediately unmap or free the transaction resources.
The safe sequence studied today is:
DMA issued
│
▼
wait_for_completion_timeout()
│
▼
Timeout
│
▼
dmaengine_terminate_sync()
│
▼
DMA / completion activity synchronized
│
▼
dma_unmap_single()
The important safety question is not the cookie number.
The important question is:
Can DMA hardware or completion activity still access this transaction's resources?
18. Blocking One-Shot TX Implementation¶
A guided TX implementation used:
dma_map_single(..., DMA_TO_DEVICE)
↓
dmaengine_prep_slave_single(..., DMA_MEM_TO_DEV)
↓
set callback
↓
dmaengine_submit()
↓
dma_async_issue_pending()
↓
wait_for_completion_timeout()
↓
completion
↓
dma_unmap_single(..., DMA_TO_DEVICE)
On timeout:
This exercise established the basic implementation sequence without requiring the complete API prototypes to be memorized.
19. Blocking One-Shot RX Implementation¶
The RX exercise used the corresponding directions:
The lifecycle is:
RX buffer
↓
dma_map_single(..., DMA_FROM_DEVICE)
↓
dmaengine_prep_slave_single(..., DMA_DEV_TO_MEM)
↓
submit
↓
issue
↓
DMA writes buffer
↓
completion
↓
dma_unmap_single(..., DMA_FROM_DEVICE)
↓
CPU accesses received data
For this one-shot streaming mapping, an additional dma_sync_single_for_cpu() is not required after the mapping has been unmapped.
20. Cyclic DMA and DMA Synchronization¶
A related question was examined for a persistent cyclic DMA buffer.
For example:
4096-byte cyclic buffer
+----------+----------+----------+----------+
| Period 0 | Period 1 | Period 2 | Period 3 |
+----------+----------+----------+----------+
DMA may continuously move through:
In this model, dma_sync_*_for_cpu() does not pause cyclic DMA.
Synchronization addresses memory/cache visibility and ownership. It does not stop the DMA controller.
The CPU must process a completed period before DMA wraps around and reuses that region.
This introduces a producer/consumer problem:
If the CPU cannot keep up, the result is a ring-buffer overrun rather than a problem that dma_sync_*() alone can solve.
The exact synchronization strategy depends on whether the driver uses coherent memory, persistent streaming mappings, or subsystem-specific DMA handling.
21. Reusable Diagram¶
A reusable diagram was created to summarize the one-shot slave DMA lifecycle.
The diagram separates the normal transaction flow from cleanup after DMA has already been issued.
It also emphasizes the relationship between DMA mapping, descriptor preparation, completion, termination, and mapping lifetime.
22. Implementation Mental Model¶
The practical sequence established today can be reduced to a small set of operations.
Driver initialization:
Per-transfer path:
Error or removal path:
The goal is not to memorize every DMA Engine prototype.
The important implementation skill is understanding operation order, ownership, and resource lifetime.
Key Takeaways¶
dmaengine_slave_config()prepares persistent peripheral-side channel configuration, while descriptor preparation describes an individual transaction.- Streaming DMA buffers must be mapped before their DMA addresses are passed to DMA Engine preparation APIs.
DMA_TO_DEVICE/DMA_FROM_DEVICEbelong to the DMA mapping API.DMA_MEM_TO_DEV/DMA_DEV_TO_MEMbelong to the DMA Engine transaction API.dmaengine_prep_slave_single()represents one DMA address range and internally uses the slave SG provider path.- A single client-side DMA range may become multiple controller-specific hardware descriptors.
dmaengine_prep_slave_sg()consumes DMA-mapped SG information.- SG entries and hardware LLIs are different abstraction layers.
- A DMA client may delegate buffer mapping to its subsystem framework.
vmalloc()memory may participate in DMA through a suitable SG-based mapping path; physical continuity must not be assumed.- DMA completion and peripheral operation completion are not necessarily the same event.
- Callback context and DMA buffer lifetime must extend until asynchronous access has ended.
- Buffer allocation ownership and DMA mapping ownership must be tracked independently.
- A failure before DMA is issued normally requires resource cleanup but not active-DMA termination.
- After DMA is issued, timeout or removal paths must synchronize termination before unmapping or freeing transaction resources.
dma_unmap_single()completes a one-shot streaming mapping before the CPU reuses an RX buffer.dma_sync_*()is relevant when a mapping remains active while CPU and device access alternate; it does not pause cyclic DMA.- The practical DMA client sequence is Request → Configure → Map → Prepare → Submit → Issue → Complete → Unmap.
Related Topics¶
- DMA Slave Configuration
- Linux DMA Engine Framework
- DMA Controller Driver and DMA Channel
- DMA Descriptor
- DMA Completion and Transaction Status
- DMA Termination and Synchronization
- DMA Cyclic
Related API Reference¶
Next Plan¶
Continue from one-shot slave DMA transfers toward the next stage of practical DMA client implementation, with emphasis on reusable transfer handling, synchronization, and preparation for a future hardware-backed DMA lab.