Write-Combining Device Memory Can Merge CPU Stores Before I/O
A sequence of CPU stores to device memory does not necessarily become an identical sequence of bus transactions. With a write-combining mapping, the processor may collect adjacent stores and emit a larger transfer later. That behavior suits framebuffer-like regions and other device buffers built for bulk writes, but it changes the ordering and transaction assumptions a driver can safely make.
Linux exposes this mapping class through interfaces such as ioremap_wc(). It is distinct from the default ioremap() mapping used for ordinary control registers.
Write combining changes the memory-side contract
A normal ioremap() mapping is intended for device registers. Linux documents it as uncached, non-speculative, non-repeating, and non-write-combining from the driver’s portable point of view. Individual I/O operations remain discrete rather than being merged into larger writes by the CPU mapping semantics.
ioremap_wc() deliberately relaxes that contract. Stores may be combined, operations may be reordered within the permitted memory model, and the processor can delay propagation while gathering writes. The resulting bus activity can therefore differ from the store sequence visible in source code.
CPU store 0 ----\
CPU store 1 -----+--> write-combining buffer --> device transaction
CPU store 2 -----+
CPU store 3 ----/The diagram describes a permitted pattern, not a guaranteed transaction size. A processor can flush a partially filled combining buffer, so device logic must not depend on every group becoming one full-width transfer.
Bulk data regions and control registers need different semantics
Write combining is useful when the destination behaves like memory: a framebuffer, aperture, or device-owned buffer can accept independent writes across a region without assigning a side effect to every store. Combining several stores can reduce the number of transactions needed to move a block of data.
Control registers have a different contract. A register write may acknowledge an interrupt, advance a queue, start an engine, or select state for a later operation. Merging, repeating, or reordering those accesses can change device behavior. Such registers belong behind the normal device-I/O mapping and accessor rules unless the hardware specification explicitly defines another safe model.
For PCI resources, Linux also ties write-combining suitability to resource attributes. The kernel documentation states that ioremap_wc() is generally safe for PCI MMIO regions marked IORESOURCE_PREFETCH; drivers cannot assume that an arbitrary BAR region is suitable.
Store order does not define transaction order
Source order alone is not an I/O ordering primitive for write-combining memory. A CPU can retain stores in combining buffers and propagate them later. Separate buffered regions can also become visible in an order that is weaker than ordinary device-register mappings provide.
This becomes significant when software fills a device buffer and then writes a control register that tells the device to consume it:
write-combining buffer writes
|
v
required ordering boundary
|
v
MMIO doorbell or control writeThe boundary is part of the device protocol. Linux provides architecture-aware I/O and memory-barrier interfaces for these cases; the correct primitive depends on the mapping and the ordering relationship required by the driver. A plain compiler barrier is not a substitute for a hardware I/O ordering operation.
Linux also provides io_stop_wc() for a narrower purpose: it prevents write-combining accesses before the call from being merged with write-combining accesses after it. That operation addresses combining boundaries, not every possible ordering requirement between memory, MMIO, and DMA.
Partial flushes are part of the interface reality
Combining buffers are finite microarchitectural resources. Their exact count, eviction policy, and emitted transaction shape are processor-specific details rather than portable driver guarantees. Interrupts, context changes, competing stores, or other implementation conditions can contribute to a buffer being flushed before software has filled the region it expected to combine.
A device exposed through write-combining memory must therefore tolerate legal partial writes for the interface it advertises. Software can arrange aligned, contiguous stores to encourage efficient transfers, but it cannot promote a common observed packet shape into an architectural guarantee.
This distinction matters during performance work. A trace showing large transactions on one processor demonstrates measured behavior for that platform and workload. It does not establish the same transaction boundaries for another CPU generation or interconnect implementation.
Mapping type is a correctness decision
Write combining is often discussed as a throughput optimization, but selecting it also selects weaker access semantics. The device region has to support those semantics before performance enters the decision.
The safe split is architectural: bulk regions designed to absorb memory-like writes can use a write-combining mapping when the platform and resource attributes permit it; side-effecting registers retain device-I/O mappings and accessors. Explicit ordering operations then connect the data path to control operations at points required by the hardware protocol.
That separation keeps transaction merging an implementation freedom instead of an accidental dependency in the device interface.