DMA Completion and Transaction Status¶
Overview¶
DMA completion is not a single event.
When DMA hardware finishes transferring data, several software-visible events may follow:
- The DMA controller reports hardware completion.
- DMA Engine records the transaction cookie as completed.
- A client may observe the transaction through a status query.
- Deferred completion processing may be scheduled.
- The client callback may execute later.
- The descriptor may finally be released or prepared for reuse.
These events are related, but they do not necessarily occur at the same time.
Understanding this separation is important when working with asynchronous DMA because a transaction may already report DMA_COMPLETE before its callback executes.
This page explains:
- Hardware completion and cookie completion
- DMA transaction status queries
- DMA cookie completion tracking and wrap-around
struct dma_tx_state- DMA residue reporting
- Completion callbacks and result-aware callbacks
virt-dmacompletion processing- Callback execution context and descriptor finalization
Completion Is Not a Single Event¶
A useful completion model separates five different concepts:
Hardware Completion
|
v
Cookie Completion
|
v
Transaction Status
|
v
Deferred Completion Processing
|
v
Callback Execution
These concepts describe different aspects of the same DMA transaction.
| Concept | Meaning |
|---|---|
| Hardware completion | The DMA controller has finished or stopped the hardware transfer. |
| Cookie completion | DMA Engine records the submitted transaction as completed. |
| Transaction status | A client queries the current state of a previously submitted transaction. |
| Deferred completion processing | Software processes completed descriptors outside the immediate hardware-completion path. |
| Callback execution | The client receives asynchronous notification of a completion event. |
The ordering between these events matters.
For example, cookie completion may already be visible to a status query while the client callback is still pending.
Completion and Status Architecture¶
DMA completion information crosses several layers:
Client Driver
|
| dmaengine_tx_status()
| callback / callback_result
v
DMA Engine Framework
|
| cookie bookkeeping
| generic callback abstraction
v
DMA Controller Driver
|
| hardware completion handling
| controller-specific status
| residue calculation
v
DMA Hardware
Each layer has a different responsibility.
DMA Hardware¶
The DMA hardware performs the actual data transfer.
Depending on the controller, hardware may expose information such as:
- Transfer-complete interrupts
- Error conditions
- Current descriptor state
- Remaining transfer count
- Current segment or burst position
The available information is hardware-specific.
DMA Controller Driver¶
The controller driver translates hardware state into DMA Engine semantics.
Typical responsibilities include:
- Handling DMA completion interrupts
- Tracking the active descriptor
- Recording transaction completion
- Reporting controller-specific transaction status
- Calculating residue when supported
- Preparing completion result information
DMA Engine Framework¶
DMA Engine provides generic transaction abstractions such as:
- DMA cookies
- Completion tracking
- Status-query interfaces
- Callback interfaces
- Common descriptor-management helpers
The framework cannot infer detailed hardware progress by itself.
Client Driver¶
The client driver consumes the DMA Engine interfaces.
It may:
- Save the cookie returned by
dmaengine_submit() - Query the transaction with
dmaengine_tx_status() - Receive asynchronous completion callbacks
- Use residue information when supported
Transaction Status Query¶
A submitted DMA transaction can be queried through:
Conceptually:
Client Driver
|
| dmaengine_tx_status()
v
DMA Engine
|
| device_tx_status()
v
Controller Driver
|
+--> generic cookie status
|
+--> controller-specific progress
|
v
enum dma_status
struct dma_tx_state
dmaengine_tx_status() does not control DMA execution.
It observes the transaction state exposed by the DMA controller driver.
A status query may therefore report information that is less precise than the hardware's actual instantaneous progress.
dmaengine_tx_status()¶
dmaengine_tx_status() is the client-facing DMA Engine interface for querying a transaction.
The client provides:
- The DMA channel
- The cookie returned when the transaction was submitted
- An optional
struct dma_tx_state
The framework dispatches the request to the DMA controller driver's device_tx_status() operation.
Conceptually:
The returned enum dma_status describes the current transaction state.
Common states include:
DMA_COMPLETEDMA_IN_PROGRESSDMA_PAUSEDDMA_ERROR
The exact status information available depends on the controller driver.
device_tx_status()¶
device_tx_status() is a DMA controller operation exposed through struct dma_device.
It is implemented by the controller driver rather than by the DMA client.
A common implementation pattern is:
device_tx_status()
|
+--> dma_cookie_status()
|
+--> inspect controller state
|
+--> inspect hardware progress
|
+--> calculate residue
|
v
return enum dma_status
The generic cookie state can determine whether the transaction has crossed the completion boundary.
More detailed progress information, however, normally requires controller-specific state or hardware registers.
Therefore:
Cookie tracking provides generic transaction completion information, while detailed progress reporting is controller-specific.
DMA Cookie Completion Tracking¶
DMA cookies identify submitted transactions.
A DMA channel maintains cookie bookkeeping that allows the framework to distinguish completed transactions from transactions that are still outstanding.
Two important channel values are conceptually:
chan->cookie tracks the most recently assigned transaction cookie.
chan->completed_cookie tracks the completion boundary.
When a descriptor is submitted, dma_cookie_assign() assigns the next transaction cookie.
When the transaction completes, dma_cookie_complete() updates the channel's completion state.
Conceptually:
Submit transaction
|
v
dma_cookie_assign()
|
v
cookie = N
|
| hardware eventually completes
v
dma_cookie_complete()
|
v
completed_cookie = N
Cookie completion is independent from callback execution.
Cookie Values¶
DMA cookies use positive values for valid submitted transactions.
Conceptually:
cookie < 0
|
+--> submission error
cookie = 0
|
+--> no valid submitted transaction cookie
cookie > 0
|
+--> valid transaction cookie
Valid transaction cookies begin at DMA_MIN_COOKIE.
A descriptor that has not yet received a valid submitted transaction cookie may therefore use zero as the absence of a valid transaction cookie.
Submission errors are handled separately through the DMA submission error mechanism.
Status helpers assume that callers provide cookies obtained from valid submitted transactions rather than arbitrary integer values.
Cookie Wrap-Around¶
DMA cookies are finite integer values, so the sequence eventually wraps.
DMA Engine does not maintain a separate generation number or wrap counter for transaction-status comparison.
Instead, completion is determined from the relative positions of:
The generic helper divides the sequence into two cases.
No Wrap in the Outstanding Window¶
When:
the outstanding range is:
Conceptually:
A queried cookie inside this interval is still in progress.
Cookies outside the interval are considered complete relative to the current cookie window.
Outstanding Window Crosses Wrap-Around¶
When:
the outstanding range crosses the cookie wrap boundary.
Conceptually:
wrap
|
v
... last_complete | ... MAX ... MIN ... | last_used ...
\_____________________/
outstanding
The same comparison can therefore determine completion without maintaining an additional ring-generation counter.
The relevant helper is:
Its responsibility is ordering and completion-range calculation, not cookie validity checking.
dma_cookie_status()¶
dma_cookie_status() uses the channel cookie bookkeeping to determine generic transaction completion state.
Conceptually:
dma_cookie_status()
|
+--> requested cookie
+--> completed_cookie
+--> last assigned cookie
|
v
dma_async_is_complete()
|
v
DMA_COMPLETE
or
DMA_IN_PROGRESS
This helper does not know detailed hardware progress.
For example, it cannot determine by itself:
- How many bytes have already transferred
- Which scatter-gather segment is active
- Whether the hardware is partway through a burst
Those details must come from the controller driver when available.
struct dma_tx_state¶
struct dma_tx_state carries additional transaction-state information returned through the status-query path.
The most important information for normal DMA progress reporting is the residue.
Conceptually:
The structure represents query-time state.
It should not be confused with struct dmaengine_result, which represents completion-result information delivered through a result-aware callback.
A useful distinction is:
struct dma_tx_state
|
+--> What is the transaction state now?
struct dmaengine_result
|
+--> How did the completion event finish?
DMA Residue¶
DMA residue represents the amount of transfer data that has not yet been completed according to the progress information available to the controller driver.
For example:
However, the numerical value is not necessarily an exact byte-by-byte view of current hardware progress.
The accuracy depends on what the DMA controller and its driver can observe.
Residue Granularity¶
DMA Engine describes residue-reporting capability through several granularity levels.
| Granularity | Meaning |
|---|---|
DMA_RESIDUE_GRANULARITY_DESCRIPTOR |
Progress can only be distinguished at descriptor level. |
DMA_RESIDUE_GRANULARITY_SEGMENT |
Progress can be distinguished at transfer-segment boundaries. |
DMA_RESIDUE_GRANULARITY_BURST |
Progress can be reported with burst-level precision. |
Descriptor Granularity¶
With descriptor-level granularity, the controller may only know whether the entire descriptor is still active or has completed.
For a 4096-byte transaction:
The driver may not be able to report the exact number of bytes already transferred.
Segment Granularity¶
For a scatter-gather transaction:
the controller may know which segment is active without knowing the exact byte position inside that segment.
The reported residue therefore reflects segment-level progress.
Burst Granularity¶
Some controllers expose finer transfer counters.
If hardware progress can be observed at burst boundaries, the controller driver can provide more precise residue information.
The important distinction is:
Residue is expressed as a remaining data amount, but its actual accuracy is limited by the controller's residue-reporting capability.
Status Reporting Does Not Control DMA Execution¶
Transaction-status reporting is an observation path.
For example:
A controller with segment-level reporting may still expose progress corresponding to the most recently known segment boundary.
Meanwhile, the hardware continues transferring data independently.
Conceptually:
DMA Execution Path
Hardware continues transfer
|
v
Hardware progress changes
|
v
Driver updates progress when supported
Status Query Path
dmaengine_tx_status()
|
v
Read current driver/hardware state
|
v
return dma_tx_state
A less precise or slightly delayed status report does not by itself stop or delay DMA execution.
Callback Completion¶
DMA Engine supports asynchronous client notification through descriptor callbacks.
Two callback forms are relevant:
The basic callback provides completion notification.
The result-aware callback additionally receives a struct dmaengine_result.
Conceptually:
The callback interface is associated with the DMA transaction descriptor.
struct dmaengine_result¶
struct dmaengine_result describes the outcome associated with a completion callback.
It contains information such as:
- Transaction result
- Completion residue
This is different from struct dma_tx_state.
The distinction is:
| Object | Purpose |
|---|---|
struct dma_tx_state |
Query-time transaction state and progress |
struct dmaengine_result |
Completion-time result information |
For a successful transaction, a result-aware callback may observe a successful result with zero residue.
For an aborted or failed transfer, the result may describe the failure while residue reports the amount that remained when the transaction ended.
The exact result information depends on the DMA controller and completion path.
Transaction Status vs Completion Result¶
enum dma_status and enum dmaengine_tx_result answer different questions.
Transaction Status¶
enum dma_status answers:
What state is the transaction in?
Examples include:
Completion Result¶
enum dmaengine_tx_result answers:
What was the outcome associated with the completion event?
Examples include:
These two interfaces should not be treated as direct one-to-one mappings.
For example, a transaction may no longer be executing because it was aborted, but that does not mean the requested transfer completed successfully.
Callback-Based Completion vs Status Polling¶
Callbacks and status queries are two different ways for a DMA client to observe transaction progress.
Callback-Based Completion¶
Callback notification is event-driven:
The client does not need to repeatedly query whether the transaction has completed.
Status Polling¶
Status polling is query-driven:
It is also useful when the client needs current progress information such as residue.
They Are Not Mutually Exclusive¶
A transaction may use a callback while still being queried through its cookie.
For example:
Transaction running
|
+--> tx_status()
| |
| +--> DMA_IN_PROGRESS
|
v
Cookie completed
|
+--> tx_status()
| |
| +--> DMA_COMPLETE
|
v
Callback executes later
Therefore:
Callback notification and transaction-status queries are independent observation mechanisms.
DMA Completion and Status Timeline¶
The following timeline shows the relationship between descriptor state, hardware execution, cookie completion, status queries, and deferred callback execution.
The important ordering is:
Hardware Complete
|
v
Cookie Complete
|
| dmaengine_tx_status()
| may already return DMA_COMPLETE
v
Deferred Callback
|
v
Descriptor Finalization
Hardware completion, cookie completion, callback execution, and descriptor finalization should therefore not be treated as the same event.
virt-dma Completion Processing¶
virt-dma provides common descriptor-management infrastructure used by many DMA controller drivers.
It is an implementation helper, not a requirement for every DMA controller driver.
For a normal non-cyclic descriptor, a typical completion path begins with:
Conceptually:
Controller completion path
|
v
vchan_cookie_complete()
|
+--> dma_cookie_complete()
|
+--> desc_completed
|
+--> tasklet_schedule()
dma_cookie_complete() records generic transaction completion.
The descriptor is then queued for deferred completion processing.
The callback does not execute synchronously inside vchan_cookie_complete().
vchan_complete()¶
The virt-dma tasklet later processes completed descriptors through vchan_complete().
A simplified normal-descriptor path is:
vchan_complete()
|
v
lock vc->lock
|
v
move desc_completed to local list
|
v
unlock vc->lock
|
v
iterate local completed descriptors
|
v
obtain callback information
|
v
invoke callback
|
v
finalize descriptor
Moving a descriptor out of desc_completed does not destroy the descriptor object.
It only changes its list membership.
The descriptor remains valid until its finalization path releases it or prepares it for reuse.
Shared List vs Descriptor Lifetime¶
Linux list membership and object lifetime are separate concepts.
Conceptually:
vchan_complete() can detach these descriptors into a local list:
Descriptors A, B, and C still exist.
They can therefore still provide:
- Callback information
- Completion result information
- Controller-specific descriptor state
Only the later descriptor-finalization step determines whether the object is released or reused.
Descriptor Finalization and Reuse¶
After callback processing, virt-dma finalizes the descriptor.
Conceptually:
Completed descriptor
|
v
Callback processing
|
v
Descriptor finalization
|
+--> release descriptor
|
+--> return reusable descriptor
to an allocated state
A reusable descriptor object may later represent another DMA transaction.
If it is submitted again, the new transaction receives a new cookie.
Therefore:
A cookie identifies one submitted transaction, not the permanent lifetime of a descriptor object.
Callback Information Inside DMA Engine¶
DMA client drivers normally use the public DMA Engine declarations from:
During internal completion processing, DMA Engine also uses private helper abstractions under drivers/dma/.
For example, internal completion code can snapshot callback information before invoking client code.
Conceptually:
This internal abstraction allows DMA Engine completion code to separate descriptor bookkeeping from callback invocation.
These helpers are DMA Engine implementation details and are not APIs that normal DMA client drivers should include directly.
Callback Locking¶
Client callback code should not execute while the controller's internal virtual-channel lock is held.
A typical virt-dma pattern is:
This keeps the critical section short and avoids executing arbitrary client code while holding DMA Engine internal state locks.
A callback may interact with other kernel mechanisms or initiate additional DMA operations, so invoking it outside the original completion critical section reduces locking and re-entrancy problems.
Callback Execution Context¶
For the virt-dma completion path described here, callbacks are dispatched through tasklet-based deferred processing.
Conceptually:
DMA Hardware
|
v
Completion IRQ
|
v
vchan_cookie_complete()
|
v
tasklet_schedule()
|
v
Tasklet / softirq context
|
v
Client callback
Tasklet context is not Process Context.
Code running in this path must therefore respect atomic-context restrictions and must not perform operations that may sleep.
If completion requires sleepable or longer-running processing, the callback can defer that work again to an appropriate mechanism such as a workqueue.
The exact callback execution mechanism may differ for DMA controller implementations that do not use this virt-dma completion path.
Cyclic DMA Note¶
vchan_complete() also contains handling for cyclic DMA period callbacks.
A cyclic period callback does not mean that the entire cyclic DMA transaction has completed.
Conceptually:
Cyclic DMA transaction
|
+--> Period 0 complete
| |
| +--> callback
|
+--> Period 1 complete
| |
| +--> callback
|
+--> Period 2 complete
|
+--> callback
The descriptor remains active while the cyclic transfer continues.
Cyclic DMA has a different completion model and is outside the scope of this page.
Complete Mental Model¶
A normal asynchronous DMA transaction can now be viewed through several independent state dimensions:
DMA Hardware
|
+--> running
+--> hardware complete
DMA Descriptor
|
+--> active
+--> completed queue
+--> deferred processing
+--> released / reused
DMA Cookie
|
+--> assigned
+--> outstanding
+--> complete
Status Query
|
+--> DMA_IN_PROGRESS
+--> optional residue
+--> DMA_COMPLETE
Callback
|
+--> pending
+--> deferred execution
+--> client notification
These dimensions are related but not synchronized to one identical completion point.
A particularly important ordering is:
Hardware completes
|
v
Cookie is marked complete
|
v
dmaengine_tx_status()
can report DMA_COMPLETE
|
v
Callback executes later
|
v
Descriptor is finalized
This separation allows DMA hardware scheduling, generic transaction bookkeeping, client observation, and software completion processing to operate asynchronously.
Kernel Source¶
Important source locations include:
| Location | Purpose |
|---|---|
include/linux/dmaengine.h |
Public DMA Engine structures, status interfaces, callback types, and client-facing helpers |
drivers/dma/dmaengine.c |
DMA Engine core implementation |
drivers/dma/dmaengine.h |
DMA Engine internal helper interfaces |
drivers/dma/virt-dma.h |
Common virtual DMA channel and descriptor infrastructure |
drivers/dma/virt-dma.c |
Deferred virt-dma completion processing |
drivers/dma/ |
Hardware-specific DMA controller drivers |
Useful symbols to trace include:
dmaengine_tx_status()
device_tx_status()
dma_cookie_status()
dma_async_is_complete()
dma_cookie_complete()
vchan_cookie_complete()
vchan_complete()
When tracing source, keep the interface boundary clear:
include/linux/dmaengine.h
|
+--> kernel-facing DMA Engine interface
drivers/dma/dmaengine.h
drivers/dma/virt-dma.[ch]
|
+--> DMA Engine / virt-dma implementation internals
Related Labs¶
Day100 through Day103 primarily extend the architecture and kernel-source model around DMA controller, descriptor, submission, completion, and transaction status. A separate lab is not required when the learning work does not introduce a meaningful reproducible implementation or experiment.
Related Topics¶
- Linux DMA Engine Framework
- DMA Controller and DMA Channel
- DMA Descriptor
- DMA Termination and Synchronization
Related API Reference¶
Summary¶
DMA completion is a sequence of related events rather than one synchronous operation.
The DMA hardware first finishes or stops the transfer. The controller driver interprets the hardware state and updates DMA Engine bookkeeping. Cookie completion then allows transaction-status queries to observe the transaction as complete, while deferred completion processing and callback execution may occur later.
The key distinctions are:
- Hardware completion is not callback execution.
- Cookie completion is independent from callback execution.
dmaengine_tx_status()observes transaction state rather than controlling DMA execution.struct dma_tx_staterepresents query-time state.struct dmaengine_resultrepresents completion-result information.- Residue accuracy depends on controller capabilities.
- Cookie wrap-around is handled through circular range comparison rather than a separate generation counter.
virt-dmaprovides one common completion implementation, but it is not mandatory for every DMA controller.- Descriptor list membership and descriptor object lifetime are separate concepts.
- A transaction may report
DMA_COMPLETEbefore its callback executes.
The resulting mental model is: