aboutsummaryrefslogtreecommitdiff
path: root/src/bd/txbd.rs
diff options
context:
space:
mode:
authorIan McIntyre <me@mciantyre.dev>2025-07-17 20:50:40 -0400
committerIan McIntyre <me@mciantyre.dev>2025-07-17 20:50:40 -0400
commit6498f85de3078ad7c3206c22c690ecb3d0fa71bb (patch)
treef1d22b0a780cdc1c3fcf151445982c9607174f49 /src/bd/txbd.rs
parent48b00ed3b83db5205b848f152f6e3139f5dea4b9 (diff)
Rewrite descriptors with atomics
The memory ordering ensures that operations to normal memory are synchronized with operations on device memory, at runtime. I've seen this play out in the transmit path: writes to the transmit buffer's flags weren't reaching memory by the time the MAC was checking, resulting in missing packets. Moving the fence works, but it's better to use atomics.
Diffstat (limited to 'src/bd/txbd.rs')
-rw-r--r--src/bd/txbd.rs68
1 files changed, 18 insertions, 50 deletions
diff --git a/src/bd/txbd.rs b/src/bd/txbd.rs
index 9550eff..b8265a6 100644
--- a/src/bd/txbd.rs
+++ b/src/bd/txbd.rs
@@ -1,52 +1,31 @@
//! Enhanced transmit buffer descriptor layout and fields.
-use ral_registers::RWRegister;
+use core::sync::atomic::{AtomicU16, AtomicU32, Ordering};
#[repr(C)]
pub struct TxBD {
- pub data_length: RWRegister<u16>,
- pub flags: RWRegister<u16>,
- pub data_buffer_pointer: RWRegister<u32>,
- pub errors: RWRegister<u16>,
- pub control: RWRegister<u16>,
- pub launch_time: RWRegister<u32>,
+ pub data_length: AtomicU16,
+ pub flags: AtomicU16,
+ pub data_buffer_pointer: AtomicU32,
+ pub errors: AtomicU16,
+ pub control: AtomicU16,
+ pub launch_time: AtomicU32,
_reserved0: [u16; 1],
- pub last_bdu: RWRegister<u16>,
- pub timestamp_1588: RWRegister<u32>,
+ pub last_bdu: AtomicU16,
+ pub timestamp_1588: AtomicU32,
_reserved1: [u16; 4],
}
-bdfields!(flags, u16,
- ready [ offset = 15, bits = 1, ],
- to1 [ offset = 14, bits = 1, ],
- wrap [ offset = 13, bits = 1, ],
- to2 [ offset = 12, bits = 1, ],
- last_in [ offset = 11, bits = 1, ],
- transmit_crc [ offset = 10, bits = 1, ],
-);
+pub const FLAGS_READY: u16 = 1 << 15;
+pub const FLAGS_WRAP: u16 = 1 << 13;
+pub const FLAGS_LAST_IN: u16 = 1 << 11;
+pub const FLAGS_TRANSMIT_CRC: u16 = 1 << 10;
-bdfields!(errors, u16,
- transmit [ offset = 15, bits = 1, ],
- underflow [ offset = 13, bits = 1, ],
- excess_collision [ offset = 12, bits = 1, ],
- frame_error [ offset = 11, bits = 1, ],
- late_collision [ offset = 10, bits = 1, ],
- overflow [ offset = 9, bits = 1, ],
- timestamp [ offset = 8, bits = 1, ],
-);
-
-bdfields!(control, u16,
- interrupt [ offset = 14, bits = 1, ],
- timestamp [ offset = 13, bits = 1, ],
- pins [ offset = 12, bits = 1, ],
- iins [ offset = 11, bits = 1, ],
- utlt [ offset = 8, bits = 1, ],
- ftype [ offset = 4, bits = 4, NON_AVB = 0, AVB_A = 1, AVB_B = 2 ],
-);
-
-bdfields!(last_bdu, u16,
- last_bdu [ offset = 15, bits = 1, ],
-);
+impl TxBD {
+ pub(crate) fn is_ready(&self) -> bool {
+ self.flags.load(Ordering::SeqCst) & FLAGS_READY != 0
+ }
+}
#[cfg(test)]
mod tests {
@@ -77,15 +56,4 @@ mod tests {
addr_of!(txbd.timestamp_1588).cast()
);
}
-
- #[test]
- fn bdfields_enum() {
- let txbd = zeroed();
- ral_registers::modify_reg!(super, &txbd, control, ftype: AVB_B);
- assert_eq!(txbd.control.read(), 0x2 << 4);
- ral_registers::modify_reg!(super, &txbd, control, interrupt: 1);
- assert_eq!(txbd.control.read(), 0x2 << 4 | 1 << 14);
- ral_registers::modify_reg!(super, &txbd, control, ftype: 0);
- assert_eq!(txbd.control.read(), 1 << 14);
- }
}