Day 106 — DMA Slave Configuration and dma_slave_config¶
Today's Goal¶
Understand how a DMA client configures the peripheral side of a slave DMA channel and how that configuration is later consumed by a DMA controller driver.
The main focus is the relationship between:
struct dma_slave_configdmaengine_slave_config()- DMA transfer direction
- Peripheral FIFO/register addresses
- Transfer width and burst configuration
- DMA transaction descriptors
- DMA controller-specific hardware descriptors
1. DMA Slave Configuration¶
Slave DMA transfers move data between memory and a peripheral endpoint.
Typical examples include:
Unlike memory-to-memory DMA, the DMA controller must know how to access the peripheral side of the transaction.
Linux represents this information with:
and applies it with:
2. struct dma_slave_config¶
Important fields studied today include:
The source or destination fields used for a transaction depend on the DMA transfer direction.
For DMA_MEM_TO_DEV:
The peripheral-side configuration normally uses:
For DMA_DEV_TO_MEM:
The peripheral-side configuration normally uses:
3. Peripheral Address¶
The peripheral address normally identifies a DMA-accessible FIFO or register.
Examples include:
This address is different from the memory DMA address supplied when preparing a DMA transaction.
Conceptually:
4. CPU MMIO vs DMA Addressing¶
A peripheral driver may maintain different address representations for CPU and DMA access.
The BCM2835 SPI driver provides a useful example.
In bcm2835_spi_probe():
This separates:
bs->regs
│
└── CPU virtual MMIO mapping
bs->phys_addr
│
└── Peripheral resource address used when building DMA configuration
The CPU accesses peripheral registers through an MMIO mapping.
DMA hardware does not use the CPU virtual address.
On platforms with more complex interconnects, the DMA controller may also require additional address translation before programming the hardware descriptor.
5. BCM2835 SPI DMA Client Example¶
The following source was studied:
Relevant functions:
The driver requests TX and RX DMA channels:
The TX channel is configured with the SPI FIFO as its peripheral destination:
slave_config.dst_addr = bs->phys_addr + BCM2835_SPI_FIFO;
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
ret = dmaengine_slave_config(ctlr->dma_tx, &slave_config);
The RX configuration contains both source and destination peripheral addresses:
slave_config.src_addr = bs->phys_addr + BCM2835_SPI_FIFO;
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_config.dst_addr = bs->phys_addr + BCM2835_SPI_CS;
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
This is because the RX DMA channel is used bidirectionally by this driver.
For normal RX:
For a TX-only transfer, the driver can use the channel to cyclically write a precalculated value to the SPI CS register to clear the RX FIFO.
This demonstrates an important rule:
A DMA channel name such as
"rx"does not itself determine the transaction direction.
The descriptor direction determines which side of dma_slave_config is used.
6. Peripheral Transfer Width¶
Fields such as:
describe the peripheral-side transfer beat width.
For example:
means that the peripheral endpoint is accessed using 4-byte transfer beats.
It does not describe:
- DMA address width.
- Total buffer size.
- Total transaction length.
7. Burst Configuration¶
The fields:
describe the requested peripheral-side burst behavior.
The DMA client expresses the requirement through the generic DMA Engine interface.
The DMA controller driver later translates that value into controller-specific hardware encoding.
8. Slave Configuration vs Descriptor¶
One of today's most important distinctions is:
dma_slave_config
│
▼
Peripheral-Side Channel Configuration
DMA Descriptor
│
▼
Individual DMA Transaction
Slave configuration may contain:
A transaction descriptor may contain:
The DMA controller driver eventually combines both sets of information when preparing the hardware transaction.
9. Raspberry Pi 5 RP1 DMA Topology¶
The Raspberry Pi 5 Device Tree was inspected to understand a real DMA provider relationship.
An RP1 SPI node contains entries such as:
This connects the DMA client to the RP1 DMA provider.
Conceptually:
The DMA request specifier identifies the DMA request/resource relationship.
It does not replace src_addr or dst_addr.
10. RP1 DMA Provider¶
The RP1 DMA controller node contains:
The controller provides eight DMA channels and multiple DMA request targets.
This allowed the source trace to continue into the Synopsys AXI DMA controller driver.
11. dmaengine_slave_config() Provider Path¶
The Synopsys AXI DMA driver registers:
The callback implementation stores the configuration:
static int dw_axi_dma_chan_slave_config(struct dma_chan *dchan,
struct dma_slave_config *config)
{
struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan);
memcpy(&chan->config, config, sizeof(*config));
return 0;
}
This demonstrates that:
dmaengine_slave_config()does not necessarily program the DMA hardware immediately.
In this implementation:
The configuration is saved in controller-specific channel state.
12. Hardware Descriptor Preparation¶
The saved configuration is later consumed by:
The function combines:
to construct the controller-specific hardware descriptor.
For DMA_MEM_TO_DEV, the driver uses:
For DMA_DEV_TO_MEM, it uses:
13. DMA-Visible Peripheral Address¶
The AXI DMA driver performs address translation before programming the hardware descriptor:
This reinforces the distinction between:
These addresses may refer to the same hardware endpoint but are not necessarily numerically identical.
14. Hardware Descriptor Fields¶
The controller driver converts the generic DMA Engine configuration into hardware-specific fields.
The studied AXI DMA implementation derives information including:
For DMA_MEM_TO_DEV:
For DMA_DEV_TO_MEM:
A peripheral FIFO normally remains at a fixed register address while the memory address advances through the DMA buffer.
15. Complete Source Trace¶
Today's source trace can be summarized as:
DMA Client Driver
│
│ fill struct dma_slave_config
▼
dmaengine_slave_config()
│
▼
struct dma_device::device_config()
│
▼
dw_axi_dma_chan_slave_config()
│
│ memcpy()
▼
chan->config
│
│ later
▼
Descriptor Preparation
│
▼
dw_axi_dma_set_hw_desc()
│
├── saved slave configuration
├── memory DMA address
├── length
└── direction
│
▼
Hardware Descriptor / LLI
│
├── SAR / DAR
├── Width
├── Burst
├── INC / NOINC
└── Transfer Count
16. Reusable Diagram¶
A reusable diagram was created to show the relationship between peripheral configuration, transaction information, controller channel state, and hardware descriptor preparation.
The diagram intentionally uses a generic DMA client/provider model rather than tying the architecture to BCM2835 SPI, RP1, or Synopsys AXI DMA.
Key Takeaways¶
- Slave DMA transfers data between memory and a peripheral endpoint.
struct dma_slave_configdescribes the peripheral side of the DMA channel.DMA_MEM_TO_DEVnormally uses thedst_*configuration fields.DMA_DEV_TO_MEMnormally uses thesrc_*configuration fields.src_addr_widthanddst_addr_widthdescribe peripheral transfer beat width, not address width.src_maxburstanddst_maxburstexpress requested peripheral burst behavior.- The DMA channel name does not by itself determine transaction direction.
- CPU MMIO virtual addresses must not be used as DMA addresses.
- DMA-visible addressing may require platform-specific translation.
dmaengine_slave_config()may save configuration without immediately programming DMA hardware.- The controller driver later combines slave configuration with transaction-specific information.
- Peripheral FIFO addresses are normally fixed while memory addresses increment through the DMA buffer.
- Generic DMA Engine configuration is translated into controller-specific hardware descriptor fields.
Related Topics¶
- DMA Slave Configuration
- Linux DMA Engine Framework
- DMA Controller Driver and DMA Channel
- DMA Descriptor
- DMA Cyclic