A driver fills a buffer with a packet and tells the network card to send it. The card reads the buffer from memory with DMA. But the packet's last few bytes are still in the processor's cache, dirty, not yet written to memory. The card reads stale bytes from memory and sends a corrupted packet. The processor's caches are coherent with each other; the card was never part of that agreement.
How do devices that access memory directly stay consistent with processor caches?
The obvious answer is that DMA goes to memory, so it sees memory's contents. But memory is not the latest value when a processor cache holds the line dirty, and a processor that cached a line before a device wrote it keeps reading its stale copy afterwards. A device outside the coherence protocol sees the same problem as an uncoordinated cache (lesson 13.1), in both directions.
Approach | How | Cost |
|---|---|---|
I/O coherent device | The device's reads and writes are snooped against processor caches: a read gets dirty data from a cache, a write invalidates cached copies. The device itself caches nothing. | Snoop traffic and latency on every device access; interconnect support |
Fully coherent device | The device has its own cache that takes part in the protocol like a core's | Most hardware; for accelerators that reuse data |
Non-coherent device with cache maintenance | Software cleans (writes back) lines before the device reads them and invalidates lines before the CPU reads what the device wrote | Software complexity; maintenance time per transfer; easy to get wrong |
Buffers that share a line with other data: invalidating the buffer discards the neighbouring data's dirty bytes. DMA buffers must be aligned to and sized in whole cache lines.
Speculative prefetch: the CPU may bring buffer lines back into the cache while the device is writing them; invalidate after the DMA too, not only before.
Missing barriers: the maintenance must complete before the device is started, and before the CPU reads the result.
Wrong point of coherence: cleaning only to an inner cache level does not make the data visible to a device that reads memory.
Protocol | I/O coherence |
|---|---|
AMBA ACE-Lite | No snoop channels of its own: its reads and writes are coherent with caches without the device caching anything (fact A23) |
AMBA ACE and CHI | Fully coherent agents with caches (fact A23) |
PCI Express | DMA is normally snooped by the host's coherence logic; a request may set the No Snoop attribute when software has made sure no snoop is needed (fact P21) |
Arm processors | Cache maintenance instructions to the Point of Coherency (DC CVAC clean, DC IVAC invalidate, DC CIVAC both) for non-coherent devices (fact A26) |
A camera driver (illustrative) allocated a frame buffer that was not line-aligned; its last line shared a cache line with a driver status word. After each frame, the driver invalidated the buffer's lines, discarding a recent status update that had not been written back. The status word reverted to an old value now and then. Aligning and padding DMA buffers to whole lines fixed it.
Clean the buffer's lines to the point of coherency, then a barrier, then start the device.
Invalidating a line that also holds other data discards that data's unwritten changes.
Devices outside the coherence protocol see stale data in both directions.
I/O coherent interconnects snoop device accesses; otherwise software cleans and invalidates around each transfer.
Maintenance needs line-aligned buffers, barriers, and invalidation after DMA as well as before.