DMA Termination and Synchronization¶
DMA termination stops outstanding DMA transactions, while synchronization ensures that asynchronous completion activity has reached a safe quiescent point before client resources are released.
These are separate lifecycle operations.
Stopping DMA hardware alone is not sufficient for safe cleanup because completion processing, deferred callbacks, or other provider-specific activity may still be pending or running after the hardware transfer has stopped.
Termination and Synchronization Lifecycle¶
The complete shutdown lifecycle separates client shutdown, DMA termination, synchronization, and resource cleanup.
The key boundary is between termination and synchronization:
Terminate DMA
↓
Outstanding DMA Work Stopped or Retired
↓
Completion Processing May Still Exist
↓
Synchronize
↓
DMA-Related Activity Quiescent
↓
Safe Client Cleanup
Termination stops the DMA transaction lifecycle.
Synchronization closes the remaining asynchronous execution lifetime before client resources are reclaimed.
Why Stopping DMA Hardware Is Not Enough¶
DMA hardware execution and software completion processing have separate lifetimes.
A transaction may progress through:
DMA Hardware Completion
↓
Cookie Completion
↓
Deferred Completion Processing
↓
Callback Execution
↓
Descriptor Finalization
When termination occurs, stopping or aborting the DMA controller prevents outstanding hardware activity from continuing.
However, software completion activity may already have been scheduled.
For example:
If the callback references a DMA buffer or client context, releasing those resources immediately after hardware termination can cause use-after-free or other lifetime violations.
Safe cleanup therefore requires both:
- Termination of outstanding DMA activity.
- Synchronization of remaining completion activity.
Client API Model¶
The DMA Engine framework exposes three related client APIs:
| API | Terminates DMA | Synchronizes Completion Activity | Safe Cleanup Boundary |
|---|---|---|---|
dmaengine_terminate_async() |
Yes | No | No |
dmaengine_synchronize() |
No | Yes | After the corresponding termination |
dmaengine_terminate_sync() |
Yes | Yes | Yes |
The exact termination and synchronization mechanisms are implemented by the DMA controller driver.
dmaengine_terminate_async()¶
dmaengine_terminate_async() requests termination of outstanding DMA activity.
Conceptually:
DMA Client
↓
dmaengine_terminate_async()
↓
device_terminate_all()
↓
Controller-Specific Termination
↓
return
The controller driver may need to:
- Stop or abort an active hardware transfer.
- Prevent queued transactions from becoming active.
- Retire outstanding descriptors.
- Update controller-specific software state.
- Perform termination-side descriptor bookkeeping.
A successful return means that the controller termination operation returned successfully.
It does not guarantee that:
- Deferred completion processing has quiesced.
- A pending callback has executed.
- A running callback has returned.
- Client resources referenced by old DMA activity are safe to release.
Therefore:
dmaengine_synchronize()¶
dmaengine_synchronize() establishes the synchronization boundary after termination.
Conceptually:
Depending on the provider implementation, synchronization may include:
- Waiting for required hardware quiescence.
- Synchronizing interrupt processing.
- Synchronizing deferred completion processing.
- Waiting for running callbacks.
- Preventing pending deferred callbacks from executing.
- Reclaiming terminated descriptors.
These operations do not imply a generic fixed ordering.
The controller driver determines how its hardware and completion mechanisms reach the required quiescent state.
dmaengine_terminate_sync()¶
dmaengine_terminate_sync() combines termination and synchronization.
Conceptually:
dmaengine_terminate_sync()
│
├── dmaengine_terminate_async()
│
└── dmaengine_synchronize()
│
▼
Safe Cleanup Boundary
This is appropriate when the caller can complete both operations in the current execution context.
When termination must occur separately from synchronization, the client can instead use:
ret = dmaengine_terminate_async(chan);
if (ret)
return ret;
/*
* Perform synchronization later from an execution context
* suitable for the provider's synchronization requirements.
*/
dmaengine_synchronize(chan);
The client must follow the calling-context requirements of the DMA Engine API and the synchronization mechanisms used by the provider.
Controller Driver Operations¶
The corresponding provider operations are part of struct dma_device.
Conceptually:
DMA Engine Client API Controller Driver Operation
dmaengine_terminate_async()
│
└───────────────────────► device_terminate_all()
dmaengine_synchronize()
│
└───────────────────────► device_synchronize()
dmaengine_terminate_sync()
│
├── terminate_async()
└── synchronize()
There is no separate controller operation corresponding directly to dmaengine_terminate_sync().
The synchronous client API composes termination and synchronization.
Descriptor State During Termination¶
Termination may occur while descriptors are at different lifecycle stages.
| Descriptor State | Main Termination Concern |
|---|---|
| Submitted | Retire queued work before it can be issued. |
| Issued | Prevent queued work from becoming active later. |
| Active | Stop or abort hardware execution and retire the transaction. |
| Completed / callback pending | Hardware execution may already be complete, but completion processing may still require synchronization. |
The exact descriptor states and queues are provider-specific.
DMA Engine does not require every controller driver to use the same internal descriptor lists.
Submitted Descriptor¶
A submitted descriptor may not yet have reached hardware execution.
Termination must prevent it from later progressing into the active state.
No hardware abort may be necessary for that descriptor, but its software lifecycle still needs to be handled correctly.
Issued Descriptor¶
An issued descriptor may be waiting behind another active transaction.
Termination must prevent it from becoming active after the current hardware transfer is stopped.
Stopping only the current hardware transfer without retiring queued work could allow another descriptor to start afterward.
Active Descriptor¶
An active descriptor may require controller-specific hardware termination.
The transfer may have completed only partially when termination occurs.
Termination must not be treated as equivalent to normal successful completion.
Completed Descriptor with Pending Callback¶
A descriptor may already have completed at the hardware and cookie levels while its deferred callback is still pending.
Termination cannot undo an already recorded completion.
The remaining concern is the lifetime of deferred completion processing and resources referenced by the callback.
Completion and Termination Races¶
DMA completion and termination may occur concurrently.
For example:
Termination Path Completion Path
terminate
│
│ Hardware Completion
│ │
└──────────── race ────────────────┘
The controller driver must serialize descriptor state transitions so that a descriptor is not incorrectly processed through conflicting completion and termination paths.
Depending on the implementation, locking may protect:
- Descriptor ownership.
- Queue membership.
- Active descriptor identity.
- Completion decisions.
- Termination decisions.
Conceptually:
ACTIVE
│
┌──────────┴──────────┐
│ │
Completion Path Termination Path
│ │
└──── serialized ─────┘
│
┌──────────┴──────────┐
▼ ▼
Completed Terminated
The exact locking and state transitions remain controller-specific.
Locking Does Not Replace Synchronization¶
Locking protects software state consistency.
Synchronization protects asynchronous execution lifetime.
These are different responsibilities:
Lock
↓
Serialize Descriptor State Transitions
Synchronize
↓
Wait Until Relevant Asynchronous
Execution Has Quiesced
A completion callback may execute outside the controller descriptor lock.
Therefore, successfully acquiring the lock during termination does not prove that an already scheduled or running callback has finished.
Callback Synchronization¶
A callback can be in different states when synchronization begins:
Callback Pending
↓
May Be Prevented from Executing
Callback Running
↓
Must Finish
↓
Synchronization Returns
The exact behavior depends on the provider's deferred completion implementation.
For example, a virt-dma implementation using tasklets can synchronize tasklet execution so that pending or running completion activity no longer exists when synchronization returns.
The important guarantee is quiescence, not that every previously scheduled callback must execute.
Client Operational State¶
DMA Engine transaction state does not represent the operational state of the DMA client.
A client that resubmits DMA from its callback must prevent new transactions before beginning termination.
A useful client lifecycle is:
The client state answers:
Is this driver still allowed to create new DMA work?
Transaction status answers a different question:
What happened to a particular DMA transaction?
Therefore, APIs such as dmaengine_tx_status() should not be used as a replacement for client shutdown state.
Callback-Driven Resubmission¶
Consider a client callback that submits another DMA transaction:
static void dma_callback(void *arg)
{
struct my_device *dev = arg;
if (READ_ONCE(dev->dma_state) != MY_DMA_RUNNING)
return;
my_dma_submit_next(dev);
}
The shutdown path must first prevent callback-driven resubmission:
Set Client State to STOPPING
↓
Prevent New DMA Work
↓
Terminate Outstanding DMA
↓
Synchronize
↓
Release Resources
The exact synchronization primitive used to protect the client state depends on the driver's concurrency model.
A plain state variable should not be assumed to provide sufficient synchronization without considering the execution contexts that access it.
Client Resource Lifetime¶
DMA shutdown is fundamentally a resource-lifetime problem.
A descriptor may reference:
Different execution paths may still access these resources:
DMA Hardware ───────────────┐
│
IRQ / Completion Processing ├──► Client Resources
│
Deferred Callback ──────────┘
Before releasing a resource, every asynchronous execution path that may reference it must have quiesced.
A typical cleanup sequence is:
Stop New DMA Submissions
↓
Terminate Outstanding DMA
↓
Synchronize
↓
Release DMA Buffers
↓
Release Callback / Client State
↓
Release DMA Channel
The exact resource cleanup order is driver-specific, but the lifetime requirement remains the same.
Descriptor Object Lifetime¶
Transaction termination does not imply immediate descriptor destruction.
These concepts must remain separate:
A provider may retire a transaction while retaining the descriptor object for later reclamation.
Therefore:
DMA clients must follow the DMA Engine ownership model and must not assume they can manually free a submitted provider descriptor.
virt-dma Termination Model¶
virt-dma provides reusable helpers for DMA controller drivers.
Relevant termination and synchronization helpers include:
vchan_next_desc()vchan_terminate_vdesc()vchan_get_all_descriptors()vchan_synchronize()
A virt-dma controller may move descriptors into:
and reclaim them later during synchronization.
Conceptually:
Outstanding Descriptor
↓
Termination
↓
desc_terminated
↓
vchan_synchronize()
↓
Descriptor Reclamation
This is an implementation model provided by virt-dma and is not mandatory for every DMA controller.
Controller Implementation Example¶
A virt-dma-based controller may need to treat the descriptor associated with current hardware execution differently from descriptors that are only queued.
One implementation pattern can look like:
Stop / Abort Hardware
↓
Handle Current Descriptor
↓
Collect Remaining Descriptors
↓
Move Descriptors into
Termination-Side State
↓
Return from Termination
↓
Synchronize Later
↓
Reclaim Descriptor Objects
Some controller implementations may update DMA cookie bookkeeping while retiring a descriptor.
This does not mean that termination is equivalent to normal successful completion.
Cookie accounting, transaction outcome, callback execution, and descriptor lifetime are separate concepts.
Common Misconceptions¶
Termination Means the Callback Cannot Run¶
Not necessarily.
Completion processing may already be pending or running when termination occurs.
Synchronization is required to establish the callback quiescence boundary.
Hardware Stopped Means Resources Are Safe to Free¶
Not necessarily.
A deferred callback may still reference the DMA buffer or client context.
Cookie Complete Means Successful DMA Completion¶
Not necessarily.
Cookie bookkeeping records transaction progress for DMA Engine status tracking.
It does not by itself describe the complete transaction result or descriptor lifetime.
Termination Immediately Frees the Descriptor¶
Not necessarily.
Provider implementations may retain terminated descriptor objects until later reclamation.
Holding the Descriptor Lock Makes Cleanup Safe¶
Not necessarily.
The lock may protect descriptor state while callbacks execute outside that lock.
Synchronization Stops New Client DMA Submissions¶
No.
The DMA client is responsible for preventing its own callbacks, workers, IRQ paths, or threads from producing new DMA transactions during shutdown.
Summary¶
DMA termination and synchronization form two distinct shutdown phases.
Client STOPPING
↓
Prevent New DMA Work
↓
Termination
↓
Outstanding DMA Transactions Retired
↓
Synchronization
↓
DMA-Related Asynchronous Activity Quiescent
↓
Safe Client Cleanup
The most important rules are:
- Termination stops or retires outstanding DMA transactions.
- Synchronization establishes the quiescent boundary required for safe cleanup.
- Hardware termination does not automatically stop already pending software completion processing.
- Completion and termination may race and must be serialized by the controller implementation.
- Locking protects state consistency but does not replace execution synchronization.
- DMA clients must prevent new DMA work before beginning shutdown.
- Client resources must remain valid until every DMA-related asynchronous execution path that may reference them has quiesced.
- virt-dma provides one implementation model but does not define mandatory behavior for every DMA controller.
Related Topics¶
- Linux DMA Engine Framework
- DMA Controller and Channel
- DMA Descriptor
- DMA Completion and Transaction Status