Cyclic DMA¶
Cyclic DMA is a DMA Engine transfer mode designed for continuous data streams that repeatedly traverse the same DMA buffer.
Unlike a one-shot DMA transaction, a cyclic transaction does not normally finish after reaching the end of the buffer. The DMA controller wraps back to the beginning and continues transferring data until the client stops the transaction.
Typical use cases include continuous audio, serial data streams, and other producer/consumer workloads that repeatedly reuse a fixed DMA buffer.
Mental Model¶
A cyclic DMA buffer is divided into multiple periods.
For example:
Cyclic Buffer
┌──────────────┬──────────────┬──────────────┬──────────────┐
│ Period 0 │ Period 1 │ Period 2 │ Period 3 │
└──────────────┴──────────────┴──────────────┴──────────────┘
↑ │
└─────────────────────────────────────────────┘
wrap
The entire buffer belongs to one long-running DMA transaction.
The individual periods are not separate DMA transactions.
The client prepares and submits the cyclic descriptor once. The DMA controller then repeatedly traverses the buffer until the transaction is terminated.
Cyclic DMA vs Repeated One-Shot DMA¶
Cyclic DMA should not be modeled as repeatedly completing and resubmitting the same descriptor.
Incorrect model:
Cyclic DMA instead keeps the same long-running transaction active:
Therefore:
The mechanism that implements the wrap is provided by the DMA controller driver and hardware.
Preparing a Cyclic Transaction¶
DMA clients prepare cyclic transfers using:
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_transfer_direction dir,
unsigned long flags);
The important buffer parameters are:
| Parameter | Description |
|---|---|
buf_addr |
DMA address of the cyclic buffer. |
buf_len |
Total length of the cyclic buffer. |
period_len |
Length of each notification period. |
dir |
DMA transfer direction. |
flags |
DMA descriptor preparation flags. |
For example:
buf_len = 4096
period_len = 1024
┌──────────┬──────────┬──────────┬──────────┐
│ P0 │ P1 │ P2 │ P3 │
└──────────┴──────────┴──────────┴──────────┘
1024 1024 1024 1024
In this example, one cyclic transaction contains four periods.
The exact hardware representation is controller-specific.
DMA Engine and Controller Responsibilities¶
The DMA Engine framework provides a generic cyclic DMA interface.
DMA Client
↓
dmaengine_prep_dma_cyclic()
↓
DMA Engine Framework
↓
device_prep_dma_cyclic()
↓
DMA Controller Driver
↓
DMA Hardware
The controller driver translates the generic request into whatever mechanism its DMA controller supports.
One controller might build a hardware descriptor ring:
Another controller may provide native circular-buffer or cyclic hardware support.
DMA Engine therefore defines the cyclic transaction semantics, but does not require every controller to implement cyclic execution in the same way.
Periods¶
A period is a progress and notification unit within the cyclic buffer.
It is not an independent DMA transaction.
One Cyclic Transaction
┌─────────────────────────────────────────────┐
│ │
│ P0 → P1 → P2 → P3 → P0 → P1 → ... │
│ │
└─────────────────────────────────────────────┘
The periods do not receive independent DMA cookies and are not separately submitted through dmaengine_submit().
Therefore:
Period Callbacks¶
A client can associate a callback with the cyclic descriptor before submission.
Conceptually:
desc = dmaengine_prep_dma_cyclic(chan,
dma_addr,
buf_len,
period_len,
direction,
flags);
if (!desc)
return -EIO;
desc->callback = period_callback;
desc->callback_param = context;
cookie = dmaengine_submit(desc);
if (dma_submit_error(cookie))
return dma_submit_error(cookie);
dma_async_issue_pending(chan);
The same callback can then be invoked repeatedly as DMA crosses period boundaries.
The callback reports progress inside the cyclic transaction.
It does not normally indicate that the entire transaction has completed.
Period Completion vs Transaction Completion¶
This distinction is fundamental to cyclic DMA.
For a normal one-shot transaction:
For a cyclic transaction:
Therefore:
A period boundary does not normally retire the cyclic descriptor.
Cyclic Descriptor and Cookie Lifetime¶
The cyclic descriptor receives one cookie when it is submitted.
For example:
These callbacks still belong to the same transaction and descriptor.
The cookie is not replaced for every period.
Therefore:
Cookie completion bookkeeping should not be interpreted as a per-period counter.
virt-dma Cyclic Callback Path¶
The virt-dma infrastructure explicitly distinguishes cyclic period callbacks from normal descriptor completion.
A virt-dma-based controller may report a cyclic period event using:
Normal descriptor completion instead uses:
Conceptually:
Controller Event
↓
Is Descriptor Cyclic?
│
├── Yes
│ ↓
│ vchan_cyclic_callback()
│ ↓
│ Period Callback
│ ↓
│ Descriptor Remains Active
│
└── No
↓
vchan_cookie_complete()
↓
Normal Transaction Completion
The important distinction is:
Although cyclic callback processing can reach the virt-dma deferred processing function named vchan_complete(), this does not mean the cyclic transaction has completed.
vchan_complete() participates in both normal completion processing and cyclic callback processing.
DMA and Callback Execution¶
DMA hardware does not normally need to wait for the client callback before continuing into the next period.
For an RX stream:
There can be latency between:
Therefore, by the time the callback executes, DMA hardware may already have progressed into the next period.
A period callback indicates that a boundary occurred. It does not imply that DMA hardware is currently stopped at that boundary.
Cyclic DMA Lifecycle¶
The complete cyclic DMA lifecycle is shown below.
The important property is that period callbacks occur inside the lifetime of the same cyclic descriptor and transaction.
The transaction continues until the client begins the stop sequence.
Producer and Consumer Model¶
Cyclic DMA naturally creates a producer/consumer relationship between DMA hardware and software.
Peripheral to Memory¶
For DMA_DEV_TO_MEM:
The roles can be modeled as:
| Role | Component |
|---|---|
| Producer | DMA hardware |
| Consumer | CPU / DMA client |
After DMA completes one period and advances to the next, software can process the completed region according to the client or subsystem protocol.
Memory to Peripheral¶
For DMA_MEM_TO_DEV:
The roles are reversed:
| Role | Component |
|---|---|
| Producer | CPU / DMA client |
| Consumer | DMA hardware |
After DMA consumes a region, software can prepare it for future reuse according to the client or subsystem protocol.
Buffer Processing Window¶
Consider a four-period RX buffer:
After P0 completes, software has the time during which DMA traverses the remaining periods before DMA eventually returns to P0.
Conceptually:
CPU:
Process P0
└─────────────────────────────┐
│
DMA: │
P1 → P2 → P3 ─────────────────┘
↓
Return to P0
The number and size of periods therefore affect the buffering window between producer and consumer.
Overrun and Underrun¶
Cyclic DMA does not provide unlimited buffering.
For RX, DMA may eventually return to a region that software has not finished consuming:
For TX, DMA may reach a region that software has not prepared in time.
These conditions can result in overrun, underrun, stale data, or other subsystem-specific behavior.
DMA Engine does not automatically solve this producer/consumer synchronization problem.
The client and subsystem must ensure that software keeps up with the required data rate.
Period Callbacks Are Progress Notifications¶
Period callbacks should not be treated as unlimited historical event storage.
A safer model is:
Even if software records callback history, the cyclic buffer itself continues to be reused.
Old data may already have been overwritten when DMA wraps.
Therefore:
Callback backlog does not imply that historical buffer contents are still available.
DMA Residue and Position¶
DMA clients can query transaction state using:
The returned struct dma_tx_state can contain residue information.
For controllers that provide suitable cyclic residue reporting, software may be able to infer the current position inside the buffer.
A common conceptual relationship is:
However, residue reporting is controller-dependent.
The DMA controller's residue granularity determines how accurately progress can be reported.
Therefore, generic client code must not assume that residue always provides a byte-accurate hardware position.
It is useful to keep three concepts separate:
| Mechanism | Meaning |
|---|---|
| Cookie | Transaction lifecycle and status |
| Residue | Transfer progress or position information |
| Period callback | Period progress notification |
Stopping a Cyclic Transaction¶
A cyclic transaction normally continues until the client explicitly stops it.
Typical stop conditions include:
- A requested number of periods has been processed.
- A requested streaming duration has elapsed.
- Userspace requests the stream to stop.
- Device shutdown or removal begins.
- An error requires the stream to stop.
A client-defined finite duration does not prevent cyclic DMA from being appropriate.
For example:
or:
The important property is that DMA remains continuous while the stream is active.
Cyclic DMA vs Periodically Triggered DMA¶
Cyclic DMA should be distinguished from periodically starting independent DMA transactions.
Cyclic streaming:
Periodically triggered one-shot DMA:
The second pattern is generally better modeled using a timer, delayed work, thread, or another scheduling mechanism that periodically starts a one-shot DMA transaction.
A useful decision question is:
Should DMA continuously stream between two samples, or should DMA actually be idle?
Continuous streaming with repeated buffer traversal is a strong cyclic DMA use case.
Long idle intervals between independent transfers usually are not.
Termination and Synchronization¶
The standard DMA Engine termination model applies to cyclic DMA.
A safe client-side shutdown sequence is:
RUNNING
↓
STOPPING
↓
Prevent New Client Work
↓
dmaengine_terminate_async()
↓
dmaengine_synchronize()
↓
Safe Cleanup
↓
STOPPED
When synchronous waiting is allowed, the client may use:
instead.
Termination should not be confused with normal transaction completion.
The exact controller-side handling of the active cyclic descriptor and its cookie is provider-specific.
Callback Lifetime During Shutdown¶
Stopping DMA hardware does not automatically prove that all previously scheduled period callback activity has finished.
A race can look like:
Therefore:
Synchronization establishes the boundary after which the client can safely release resources that DMA-related asynchronous activity might reference.
This includes:
- Callback context.
- DMA buffer metadata.
- Driver state referenced by callbacks.
- Other client resources tied to the DMA stream.
Typical Client Workflow¶
A complete cyclic DMA client workflow can be modeled as:
Allocate / Map DMA Buffer
↓
Request and Configure DMA Channel
↓
dmaengine_prep_dma_cyclic()
↓
Set Callback and Callback Parameter
↓
dmaengine_submit()
↓
Cookie Assigned
↓
dma_async_issue_pending()
↓
┌─────────────────────────────┐
│ CYCLIC RUNNING │
│ │
│ P0 → callback │
│ P1 → callback │
│ P2 → callback │
│ P3 → callback │
│ P0 → callback │
│ ... │
└─────────────────────────────┘
↓
Stop Condition
↓
Prevent New Client Work
↓
Terminate
↓
Synchronize
↓
Release Resources
The callback context and DMA-related resources must remain valid for the required lifetime of the cyclic transaction and any asynchronous callback activity.
Key Takeaways¶
- Cyclic DMA is one long-running DMA transaction.
- A cyclic descriptor is prepared and submitted once.
- Periods are notification units, not independent DMA transactions.
- Period callbacks do not normally complete the cyclic transaction.
- The same descriptor and cookie remain associated with multiple period callbacks.
vchan_cyclic_callback()is different from normalvchan_cookie_complete().- DMA hardware can continue transferring while software processes a period callback.
- Cyclic DMA creates a producer/consumer relationship between DMA and software.
- Software must keep up with the stream before the DMA buffer wraps.
- Residue can provide progress information, but its precision is controller-dependent.
- Finite count or duration can still be valid cyclic DMA use cases.
- Periodically triggered one-shot DMA is different from cyclic DMA.
- Cyclic DMA normally ends through explicit termination.
- Termination does not by itself guarantee callback quiescence.
- Synchronization is required before releasing resources that asynchronous DMA activity may still reference.