Skip to content

Commit 4cb10d9

Browse files
committed
Optimize ringbuffer interactions in smoltcp device
We want to directly copy the packet instead of first changing its shape manually
1 parent 3c5a17c commit 4cb10d9

1 file changed

Lines changed: 31 additions & 48 deletions

File tree

firmware-support/bittide-sys/src/smoltcp/ringbuffer.rs

Lines changed: 31 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,11 @@ impl Device for RingbufferDevice {
121121
let mut header_buf: [[u8; 8]; 1] = [[0u8; 8]; 1];
122122
self.rx_buffer.read_slice(&mut header_buf, 0);
123123

124-
// Extract CRC, sequence number, and length from header
125-
let _stored_crc = u32::from_le_bytes([
126-
header_buf[0][0],
127-
header_buf[0][1],
128-
header_buf[0][2],
129-
header_buf[0][3],
130-
]);
131-
let seq_num = u16::from_le_bytes([header_buf[0][4], header_buf[0][5]]);
132-
let packet_len = u16::from_le_bytes([header_buf[0][6], header_buf[0][7]]) as usize;
124+
// Extract CRC, sequence number, and length from header using direct pointer reads
125+
let header_ptr = header_buf[0].as_ptr();
126+
let _stored_crc = unsafe { (header_ptr as *const u32).read_unaligned() };
127+
let seq_num = unsafe { (header_ptr.add(4) as *const u16).read_unaligned() };
128+
let packet_len = unsafe { (header_ptr.add(6) as *const u16).read_unaligned() } as usize;
133129

134130
// Check if this is the same packet we saw before (based on sequence number)
135131
if seq_num == self.last_rx_seq {
@@ -151,29 +147,19 @@ impl Device for RingbufferDevice {
151147
// Calculate total packet size: header + payload
152148
let total_len = PACKET_HEADER_SIZE + packet_len;
153149
let num_words = total_len.div_ceil(8);
154-
let mut buffer = [[0u8; 8]; ScatterUnit::SCATTER_MEMORY_LEN];
155-
let words = &mut buffer[..num_words];
156150

157-
// Copy entire packet from ringbuffer (header + payload)
158-
self.rx_buffer.read_slice(words, 0);
159-
160-
// Convert to contiguous byte buffer
151+
// Allocate aligned buffer for reading from ringbuffer
152+
// Use a flat byte buffer and cast it to [[u8; 8]] for the API
161153
let mut packet_buffer = [0u8; ScatterUnit::SCATTER_MEMORY_LEN * 8];
162-
let mut idx = 0;
163-
for word in words.iter() {
164-
for &byte in word.iter() {
165-
packet_buffer[idx] = byte;
166-
idx += 1;
167-
if idx >= total_len {
168-
break;
169-
}
170-
}
171-
if idx >= total_len {
172-
break;
173-
}
174-
}
175154

176-
// Validate CRC
155+
let word_slice = unsafe {
156+
core::slice::from_raw_parts_mut(packet_buffer.as_mut_ptr() as *mut [u8; 8], num_words)
157+
};
158+
159+
// Copy entire packet from ringbuffer (header + payload)
160+
self.rx_buffer.read_slice(word_slice, 0);
161+
162+
// Validate CRC (packet_buffer is already in the right format)
177163
if !is_valid(&packet_buffer[..total_len]) {
178164
trace!("CRC validation failed for packet seq {}", seq_num);
179165
return None;
@@ -253,36 +239,33 @@ impl phy::TxToken for TxToken<'_> {
253239
// Prepare buffer: header + payload
254240
let mut buffer = [0u8; GatherUnit::GATHER_MEMORY_LEN * 8];
255241

242+
// Write header fields using direct pointer writes
256243
// Header format: CRC32 (4 bytes) + sequence (2 bytes) + length (2 bytes)
257-
// Checksum added later
258-
buffer[4..6].copy_from_slice(&(self.seq_num.to_le_bytes()));
259-
buffer[6..8].copy_from_slice(&(len as u16).to_le_bytes());
244+
let header_ptr = buffer.as_mut_ptr();
245+
unsafe {
246+
// Write sequence and length (CRC written later after payload)
247+
(header_ptr.add(4) as *mut u16).write_unaligned(self.seq_num.to_le());
248+
(header_ptr.add(6) as *mut u16).write_unaligned((len as u16).to_le());
249+
}
260250

261251
// Let smoltcp fill the packet data
262252
let result = f(&mut buffer[PACKET_HEADER_SIZE..PACKET_HEADER_SIZE + len]);
253+
263254
// Calculate total length and seal packet with CRC in header
264255
let total_len = PACKET_HEADER_SIZE + len;
265-
266256
let crc = CRC.checksum(&buffer[4..total_len]);
267-
buffer[0..4].copy_from_slice(&(crc.to_le_bytes()));
257+
unsafe {
258+
(header_ptr as *mut u32).write_unaligned(crc.to_le());
259+
}
268260

269-
// Convert to word array for ringbuffer
261+
// Convert to word array for ringbuffer using pointer cast
270262
let num_words = total_len.div_ceil(8);
271-
let max_words = GatherUnit::GATHER_MEMORY_LEN;
272-
let mut word_buffer = [[0u8; 8]; GatherUnit::GATHER_MEMORY_LEN];
273-
274-
for (i, chunk) in buffer[..total_len].chunks(8).enumerate() {
275-
if i >= max_words {
276-
break;
277-
}
278-
for (j, &byte) in chunk.iter().enumerate() {
279-
word_buffer[i][j] = byte;
280-
}
281-
}
263+
// The buffer is correctly sized and alignment is maintained.
264+
let word_slice =
265+
unsafe { core::slice::from_raw_parts(buffer.as_ptr() as *const [u8; 8], num_words) };
282266

283267
// Write to ringbuffer starting at offset 0
284-
let words = &word_buffer[..num_words.min(max_words)];
285-
self.tx_buffer.write_slice(words, 0);
268+
self.tx_buffer.write_slice(word_slice, 0);
286269

287270
trace!(
288271
"Transmitted packet: checksum {}, seq {}, total length {}",

0 commit comments

Comments
 (0)