From c71e5183910673cd7b6362aa8e381baf9b736b53 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Sun, 26 Jul 2026 20:19:29 +0900 Subject: [PATCH] rtl8139d: DMA barriers on CAPR doorbell and TSD doorbell Apply the same release/acquire fence pattern as e1000d and rtl8168d: - acquire fence before reading the RX status / length / data bytes, so the compiler does not reorder the buffer reads past the rxsts observation on weakly-ordered architectures. - release fence before the CAPR write (RX doorbell) so the device sees the buffer reads before the doorbell signals the consumer is done with the ring. - release fence before the TSD write (TX doorbell) so the device sees the buffer writes before claiming ownership of the descriptor. The 8139 is a legacy 100 Mb/s chip with a 64 KB ring rather than a 16-entry descriptor table, but the same hand-off semantics apply: ownership bit is cleared on read, set on write, and the device accesses buffer memory after the doorbell. The fences are the same compiler-level ordering the Linux 8139too driver places around its MMIO writes; the 8139 chip itself does not need anything more. --- drivers/net/rtl8139d/src/device.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/rtl8139d/src/device.rs b/drivers/net/rtl8139d/src/device.rs index d742813296..7e19e7b651 100644 --- a/drivers/net/rtl8139d/src/device.rs +++ b/drivers/net/rtl8139d/src/device.rs @@ -138,6 +138,11 @@ impl NetworkAdapter for Rtl8139 { fn read_packet(&mut self, buf: &mut [u8]) -> Result> { if !self.regs.cr.readf(CR_BUFE) { + // Acquire fence pairs the device's write of rxsts / size / + // data with our subsequent reads on weakly-ordered + // architectures. + core::sync::atomic::fence(core::sync::atomic::Ordering::Acquire); + let rxsts = (self.rx(0) as u16) | (self.rx(1) as u16) << 8; let size_with_crc = (self.rx(2) as usize) | (self.rx(3) as usize) << 8; @@ -158,6 +163,10 @@ impl NetworkAdapter for Rtl8139 { self.receive_i = (self.receive_i + 4 + size_with_crc).next_multiple_of(4) % RX_BUFFER_SIZE; let capr = self.receive_i.wrapping_sub(16) as u16; + // Release fence ensures the buffer reads above are + // visible to the device before the CAPR doorbell is + // observed. + core::sync::atomic::fence(core::sync::atomic::Ordering::Release); self.regs.capr.write(capr); res @@ -189,6 +198,11 @@ impl NetworkAdapter for Rtl8139 { assert_eq!(i as u32, i as u32 & TSD_SIZE_MASK); self.regs.tsd[self.transmit_i].write(i as u32 & TSD_SIZE_MASK); + // Release fence ensures the buffer writes above are + // visible to the device before the TSD doorbell is + // observed. + core::sync::atomic::fence(core::sync::atomic::Ordering::Release); + //TODO: wait for TSD_TOK or error self.transmit_i += 1;