Skip to content

Day 100 - DMA Controller and DMA Channel

Today's Goal

Continue learning the Linux DMA Engine Framework by focusing on DMA controller drivers and DMA channel management.

The objective of Day100 is to understand how a hardware-specific DMA controller is represented inside the DMA Engine Framework, how its channels are registered and managed, and how a client driver obtains the correct channel through Device Tree.


What I Learned

Today focused on the relationship between DMA controller drivers, the DMA Engine Framework, and client drivers.

Why Linux Needs DMA Controller Drivers

Different SoCs provide different DMA controller hardware.

The hardware may differ in:

  • Register layout
  • Channel organization
  • Descriptor format
  • DMA request routing
  • Interrupt handling
  • Supported transaction types
  • Hardware limitations

Without a common framework, every client driver would need controller-specific code and would become tightly coupled to a particular SoC.

Linux separates the DMA subsystem into the following layers:

Client Driver
DMA Engine Framework
DMA Controller Driver
DMA Controller Hardware

The client driver describes the transfer it needs, while the DMA controller driver handles hardware-specific operations.


DMA Engine Framework and Controller Driver

The DMA Engine Framework provides a generic interface between DMA clients and hardware-specific controller drivers.

The responsibility of each layer is:

Layer Responsibility
Client Driver Requests DMA resources and prepares DMA transfers without accessing controller registers.
DMA Engine Framework Manages DMA controllers and channels and provides common DMA APIs.
DMA Controller Driver Implements controller-specific operations and controls the hardware.
DMA Controller Hardware Performs the actual data transfer.

The framework does not understand the register layout of a particular controller. Instead, it invokes operation callbacks supplied by the DMA controller driver.

This follows the same Linux framework pattern used by VFS, gpiolib, and other kernel subsystems:

Generic Framework
Operation Callbacks
Hardware-Specific Driver
Hardware

struct dma_device

A DMA controller driver represents one DMA controller using:

struct dma_device

The object describes the controller to the DMA Engine Framework.

Its major responsibilities include:

  • Identifying the underlying Linux device
  • Advertising supported DMA capabilities
  • Maintaining the controller's DMA channel list
  • Providing controller-specific operation callbacks
  • Linking the controller into the framework's global device list

A useful first-level classification of its members is:

Category Purpose
Identity Associates the DMA controller with the Linux Device Model.
Capabilities Describes the transaction types supported by the controller.
Channels Maintains the channels provided by the controller.
Operations Provides hardware-specific callback implementations.
Framework linkage Connects the controller to the DMA Engine global device list.

A DMA controller driver normally initializes this object during its probe() function and registers it using the DMA Engine registration interface.


Controller and Channel Lists

Two list members in struct dma_device operate at different hierarchy levels:

Member Purpose
channels List head for all struct dma_chan objects owned by this controller.
global_node Node used to link this struct dma_device into the framework's global DMA device list.

This creates two levels of linked lists:

DMA Engine Global Device List
├── dma_device A
│       └── Local Channel List
│               ├── dma_chan 0
│               └── dma_chan 1
└── dma_device B
└── Local Channel List
├── dma_chan 0
└── dma_chan 1

The framework uses the global list to manage registered DMA controllers, while each controller uses its local channel list to manage its own resources.


Advanced DMA Capabilities

Some members of struct dma_device are intended for specialized DMA hardware rather than ordinary peripheral DMA.

Examples include:

Member Purpose
max_xor Maximum number of source buffers supported by a hardware XOR operation.
max_pq Maximum number of source buffers supported when generating RAID6 P/Q parity.

These capabilities are primarily used by storage and RAID acceleration hardware.

They are normally unrelated to common UART, SPI, I2S, or other peripheral DMA transfers.


struct dma_chan

A DMA controller normally provides one or more DMA channels.

Each channel is represented by:

struct dma_chan

The relationship is:

struct dma_device
├── struct dma_chan
├── struct dma_chan
└── struct dma_chan

struct dma_chan represents a DMA resource that can be assigned to a client driver.

Important conceptual responsibilities include:

  • Identifying the parent struct dma_device
  • Representing one controller-provided channel
  • Maintaining channel allocation or reference state
  • Providing the object used by client-facing DMA APIs

The client driver normally stores a pointer such as:

struct dma_chan *rx_chan;
struct dma_chan *tx_chan;

The client does not create these channel objects. They are created and initialized by the DMA controller driver and later assigned through the DMA Engine Framework.


DMA Controller Registration Lifecycle

The DMA controller is normally initialized during kernel boot when its driver is probed.

A simplified lifecycle is:

Kernel Boot
DMA Controller Driver Probe
Initialize Hardware Resources
Initialize struct dma_device
Initialize struct dma_chan Objects
Register with DMA Engine Framework
Controller and Channels Become Available

The probe function commonly performs operations such as:

  • Mapping controller registers
  • Requesting interrupts
  • Initializing controller-private state
  • Configuring struct dma_device
  • Creating and linking DMA channels
  • Registering the DMA controller with the framework

If a client driver probes before its DMA provider is ready, channel acquisition may return -EPROBE_DEFER, allowing the client probe to be retried later.


DMA Channel Allocation

A client driver obtains a DMA channel using a logical name:

struct dma_chan *dma_request_chan(struct device *dev,
const char *name);

For example:

rx_chan = dma_request_chan(dev, "rx");

The string "rx" is a logical channel name rather than a hardware channel number.

The name is matched against the client's firmware description, commonly through Device Tree.


Device Tree DMA Description

A peripheral node can describe its DMA connections using dmas and dma-names.

Example:

uart0 {
dmas = <&dma0 5>,
<&dma0 6>;
dma-names = "rx", "tx";
};

The entries correspond by index:

Index dma-names dmas
0 "rx" <&dma0 5>
1 "tx" <&dma0 6>

When the client requests "rx", the framework locates index 0 and retrieves the corresponding DMA specifier.

The cells following the DMA controller phandle form a controller-specific DMA specifier. Their meaning is defined by the DMA controller binding and interpreted by the controller driver.

They may describe information such as:

  • DMA request line
  • Physical channel or stream
  • DMA multiplexer selection
  • Transfer configuration flags
  • Priority or routing information

The specifier must not be assumed to match dma_chan->chan_id.


dma_request_chan() Lookup Flow

The conceptual lookup flow is:

Client Driver
│ dma_request_chan(dev, "rx")
DMA Engine Framework
Find "rx" in dma-names
Read the Corresponding dmas Entry
Locate the DMA Controller Provider
Perform Controller-Specific Translation
Return struct dma_chan *

The framework coordinates the lookup, but the DMA controller provider interprets the controller-specific DMA specifier.

Therefore, dma_request_chan() does not create a new channel and does not simply choose a random unused channel from every registered controller.

It resolves the DMA connection described for the requesting device and returns an existing channel managed by the selected provider.


Operation Callbacks

Many callback members in struct dma_device use names beginning with device_, such as:

  • device_alloc_chan_resources
  • device_free_chan_resources
  • device_prep_dma_memcpy
  • device_prep_slave_sg
  • device_issue_pending
  • device_tx_status

These are controller-driver callbacks rather than the normal public APIs called directly by client drivers.

The typical call path is:

Client Driver
Public DMA Engine API
DMA Engine Framework
dma_device Operation Callback
DMA Controller Driver
DMA Hardware

This separates generic client-facing APIs from hardware-specific controller implementations.


Linux Source Tour

Important source locations studied today include:

Location Purpose
include/linux/dmaengine.h Defines the public DMA Engine objects, capabilities, and interfaces.
drivers/dma/dmaengine.c Implements the DMA Engine core and generic framework behavior.
drivers/dma/of-dma.c Provides Device Tree DMA provider and lookup support.
drivers/dma/virt-dma.c Provides reusable virtual-channel and descriptor queue helpers.
drivers/dma/ Contains hardware-specific DMA controller drivers.

The source tree contains both framework code and controller-specific drivers. These responsibilities must be distinguished when reading the implementation.


Important Observations

Several important distinctions were clarified today:

  • The DMA Engine Framework is not a DMA controller.
  • One struct dma_device normally represents one DMA controller.
  • One struct dma_device may own multiple struct dma_chan objects.
  • The controller driver creates and registers the controller and channel objects.
  • The client driver obtains an existing channel rather than creating one.
  • dma-names provides logical names used by client drivers.
  • dmas provides controller references and controller-specific specifiers.
  • A DMA specifier is not necessarily a Linux channel ID.
  • Framework APIs and struct dma_device operation callbacks belong to different abstraction layers.
  • No actual DMA transaction has occurred at the channel-allocation stage.

A concise mental model is:

Client drivers use struct dma_chan, the DMA Engine Framework manages struct dma_device, and DMA controller drivers implement struct dma_device.


Summary

Day100 established how Linux represents and manages DMA controllers and DMA channels.

A DMA controller driver initializes a struct dma_device, creates its struct dma_chan objects, provides hardware-specific operation callbacks, and registers the controller with the DMA Engine Framework.

A client driver later calls dma_request_chan() with a logical name. The framework uses the client's firmware description, including dmas and dma-names, to locate the correct DMA provider and obtain a suitable channel.

This completes the resource-management portion of the DMA Engine mental model.

No DMA transfer has started yet. The next stage is to understand how a client uses an acquired struct dma_chan to prepare, submit, start, and complete a DMA transaction.


Next Plan

Continue with Day101 - DMA Transaction and Descriptor Lifecycle, including:

  • DMA transaction model
  • struct dma_async_tx_descriptor
  • Descriptor preparation
  • device_prep_*() callbacks
  • dmaengine_submit()
  • dma_async_issue_pending()
  • DMA cookies
  • Completion interrupts and callbacks