Build1 distinct publisher3 min readUpdated
A dev.to walkthrough of the Linux DMA API names the three sources of most DMA corruption on ARM boards: broken streaming ownership, memory that was never DMA-able, and shared cache lines.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
A walkthrough of the Linux DMA API published on dev.to sets out the contract a driver has to honour, and names the three ways it usually gets broken: the ownership rule of streaming mappings, DMA to memory that is not DMA-able, and cache-line sharing between a DMA buffer and CPU-written fields [1]. The reason to care is the failure signature the piece describes: a driver that looks correct, passes a quick test, and corrupts data months later on a different board [2].
The API exists because the address a device puts on the bus is not the address the CPU uses, and because on most embedded SoCs the CPU cache is not kept in step with device accesses [16]. There are three addresses in play: the CPU virtual address from kmalloc() or ioremap(), the CPU physical address as phys_addr_t, and the dma_addr_t that the device sees, which an IOMMU or host bridge may translate into something completely different [3]. On a simple SoC those last two are often the same value, which is precisely why a broken driver runs fine on one board and fails on the next one with an IOMMU or a bus offset [4].
The two mapping styles are not interchangeable. dma_alloc_coherent() hands back a CPU pointer and a dma_addr_t for memory both sides can touch without explicit cache maintenance, intended for small long-lived structures allocated at probe [5]; the kernel documentation's examples are ring descriptors, adapter mailboxes, and device firmware executed out of main memory, where flushing on every access would be unreasonable [7]. Streaming mappings, dma_map_single() and dma_map_sg(), lend an existing buffer to the device for one transfer, with the kernel performing the clean or invalidate at map, sync and unmap time [6].
That list of maintenance points is the ownership rule. If cache maintenance happens only at map, sync and unmap, then any CPU read or write in between has no corresponding clean or invalidate behind it, and the two views of the buffer diverge silently [14].
The second failure is decided before any transfer starts. Page allocator memory, kmalloc() and kmem_cache_alloc() are DMA-able; vmalloc(), kernel and module image addresses, stack addresses and the return of kmap() are not [8]. A DMA buffer on the stack is the classic case: it can appear to work on a coherent x86 test machine and then corrupt neighbouring stack data on an ARM board with non-coherent caches [9]. The remedy given is kmalloc(), or embedding the buffer in a device structure with the cache-line isolation the kernel provides [10]. Two of the three named causes, non-DMA-able memory and cache-line sharing, are settled at allocation time, before there is any sync call to get wrong [15].
Two smaller traps. Declare addressing capability up front, for example dma_set_mask_and_coherent() with DMA_BIT_MASK(32), since the default assumption is 32-bit [11]; the documentation notes the call does not fail for masks larger than 32 bits, so "try 64, fall back to 32" is not the recommended pattern and the mask should come from what the hardware actually does [12]. And coherent does not mean ordered: the CPU can still reorder stores to coherent memory, with the article's example being a device that must see word0 before word1 is marked valid [13].
What to watch in your own tree: buffers on the stack or from vmalloc() passed to a map call [8], masks copied from another driver rather than derived from the datasheet [12], and CPU touches of a streaming buffer between map and unmap [14]. Validation on identity-mapped SoCs will not surface any of it [4].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
Most DMA corruption on ARM boards comes from breaking the ownership rule of streaming mappings, from DMA to memory that is not DMA-able, or from cache-line sharing between a DMA buffer and CPU-written fields.
A driver that uses the DMA API can look correct, pass a quick test, and then corrupt data months later on a different board.
The kernel documentation identifies three kinds of address: the CPU virtual address returned by kmalloc() or ioremap() and translated by the MMU, the CPU physical address (phys_addr_t, as seen in /proc/iomem), and the DMA bus address (dma_addr_t) that the device puts on the bus, which an IOMMU or host bridge may translate to something completely different from the physical address.
On a simple SoC the DMA address often equals the physical address, which is exactly why a broken driver can work on one board and fail on the next one that has an IOMMU or a bus offset.
dma_alloc_coherent() returns a CPU virtual address and a dma_addr_t for memory both CPU and device can access without explicit cache maintenance; it is meant for small, long-lived structures such as descriptor rings, is usually allocated at probe, and is released with dma_free_coherent().
Streaming mappings (dma_map_single(), dma_map_sg()) hand an existing buffer to the device for one transfer, and the kernel performs the cache clean or invalidate at map, sync and unmap time.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Documentation-grounded but single-sourced
The technical assertions are specific, code-backed and repeatedly attributed to Linux kernel documentation (address kinds, DMA-able memory rules, coherent-memory use cases, mask behaviour), which makes them checkable in principle. But the cluster contains exactly one item from one publisher, the body is truncated before the streaming ownership rules and debugging material it promises, and the headline three-cause taxonomy is unquantified editorial framing with no bug data behind it.
No adoption signal in sources
The supplied source is an explainer with no release, deployment, benchmark, incident, pricing or usage disclosure. Its only usage-adjacent statement is the unquantified remark that almost every data-moving driver uses the DMA API, which is background rather than an observable adoption event. Nothing here supports a score.
Broadly aligned, one unquantified superlative
Claims sit close to the evidence: the guidance is conservative, tracks kernel documentation, and explicitly warns against shortcuts (uncached bulk buffers, try-64-fall-back masks) rather than overselling anything. The small positive reading comes from the framing claim that these three causes account for 'most' DMA corruption on ARM boards, which is stated as fact without incidence data, and from a promised debugging payoff the supplied text never delivers.
Author audience-building, no commercial stake visible
The piece is a self-published developer-platform post that cross-promotes at least two of the same author's companion articles, so there is a discoverability and audience-building incentive. There is no vendor, product, funding or licensing interest visible in the source, and the subject is an in-tree kernel API the author does not own or sell, which keeps the incentive pressure low.
Moderate: verifiable content, thin sourcing
Confidence is limited by one publisher, one item and a truncated body, which prevents any cross-publisher check and leaves two named topics (streaming ownership sequencing, cache-line sharing) undeveloped. It is raised by the concreteness and documentation-attribution of the claims that are present, and by adoption being reported as insufficient rather than inferred.
build
The balance check that runs before the debit is CWE-367, not a guardrail1 distinct publisher
build
Your slow box already reports runqueue wait per thread. Do not turn it into a percentage1 distinct publisher
build
Six MariaDB versions, one real difference: the only reason to leave 10.6 is the July 2026 clock1 distinct publisher
build
Force the tool call, then hand Lightsail a long-lived key1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 21, 2026