DMA and cache
The S31 device tree declares SoC DMA non-coherent. Linux supplies cache writeback and invalidation through vendor SBI calls, so drivers must transfer ownership of PSRAM buffers between the CPU and DMA through the DMA API. Device-tree declaration; cache operations.
This page is for driver development. Applications using interfaces such as SPI and ALSA normally let those subsystems manage their DMA buffers.
Descriptors and data buffers
The AHB and AXI GDMA drivers allocate hardware descriptors from reserved internal SRAM. Client drivers provide the transfer data buffers through their subsystem or DMA allocation and mapping APIs. A DMAengine client requests a prepared transfer descriptor; it does not allocate or modify the GDMA hardware descriptor pool directly. See Memory map for the reservations and the AHB and AXI pool initialization.
Keep the CPU pointer and the returned dma_addr_t separate. Give the DMA address
to DMAengine. For a streaming DMAengine mapping, obtain the mapping device with
dmaengine_get_dma_device(chan) and use that same device for mapping, checking
errors, synchronization and unmapping.
DMAengine client contract.
Streaming buffer ownership
The mapping API and DMAengine use different direction constants:
Transfer |
DMA mapping direction |
DMAengine direction |
|---|---|---|
Memory to peripheral |
|
|
Peripheral to memory |
|
|
For a receive buffer, the mapping fragment is:
struct device *dma_dev = dmaengine_get_dma_device(chan);
dma_addr_t dma_addr;
dma_addr = dma_map_single(dma_dev, buffer, len, DMA_FROM_DEVICE);
if (dma_mapping_error(dma_dev, dma_addr))
return -EIO;
Here buffer is a DMA-suitable kernel buffer, and chan is an acquired and
configured receive channel. After mapping, prepare and submit a descriptor with
DMA_DEV_TO_MEM, check submission errors, then issue the pending transfer. Keep
the buffer mapped and leave it untouched by the CPU while DMA owns it. Once the
transfer has finished, unmap it before the CPU reads or reuses the buffer:
dma_unmap_single(dma_dev, dma_addr, len, DMA_FROM_DEVICE);
If the buffer stays mapped between transfers, use
dma_sync_single_for_cpu() after completion and before CPU access, then
dma_sync_single_for_device() after CPU access and before handing it back to
DMA. Preserve the mapping device, size and direction. An error before a transfer
starts still needs to release a successful mapping; an error after submission
also needs the termination sequence below.
DMA mapping and unmapping;
reusing a streaming mapping.
Stop a transfer before releasing its resources
First stop new peripheral DMA requests and prevent new submissions on the channel.
In a context that may sleep, call dmaengine_terminate_sync() and check its return
value before unmapping or freeing buffers and callback state. This call waits for
the transfer and running completion callbacks; it must not run in atomic context
or in a completion callback on the same channel.
If termination begins in atomic context or a completion callback, use
dmaengine_terminate_async(), check its result, and arrange for a worker or other
sleepable context to call dmaengine_synchronize(). Release resources only after
synchronization. Do not call dma_async_issue_pending() between termination and
synchronization. These rules apply to timeout, removal and suspend paths as well
as ordinary transfer cleanup.
Termination API and lifetime rules.
Examples in the port
The SPI driver
allocates private TX and RX buffers with dma_alloc_noncoherent(). Its target
transfer path synchronizes those buffers explicitly, rounds RX DMA length to a
multiple of four bytes, and terminates both channels during cleanup.
Transfer setup;
completion and cleanup.
The I2S driver
selects SNDRV_DMA_TYPE_NONCOHERENT; ALSA’s allocation layer
provides the corresponding synchronization.
Sv32 has no uncached page-table attribute for these buffers. This is a page-table limitation: the AXI GDMA driver separately maps a direct PSRAM alias for its own recovery copies. Client drivers should follow their DMA API’s ownership rules. Sv32 page-table definitions; AXI alias use.