Skip to content

Commit

Permalink
Implement RCTL strip CRC flag and use its buffer size instead of cons…
Browse files Browse the repository at this point in the history
…tant
  • Loading branch information
FlorianFreudiger committed Oct 15, 2023
1 parent ede4e9d commit 486e002
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 11 deletions.
1 change: 0 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ fn main() {
.with_crate(crate_dir)
.with_pragma_once(true)
.with_include_version(true)
.exclude_item("DESCRIPTOR_BUFFER_SIZE")
.generate()
.expect("Unable to generate bindings")
.write_to_file(bindings_path);
Expand Down
1 change: 0 additions & 1 deletion src/e1000/descriptors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::NicContext;

// Each descriptor is 16 bytes long, 8 for buffer address, rest for status, length, etc...
const DESCRIPTOR_LENGTH: usize = 16;
pub const DESCRIPTOR_BUFFER_SIZE: usize = 1920; // Default size linux kernel driver uses

#[derive(Debug)]
pub struct DescriptorRing {
Expand Down
33 changes: 24 additions & 9 deletions src/e1000/receive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,34 @@ impl<C: NicContext> E1000<C> {

let mut descriptor: ReceiveDescriptor = rx_ring.read_head(&mut self.nic_ctx)?;

let mut buffer = [0u8; DESCRIPTOR_BUFFER_SIZE];
buffer[..received.len()].copy_from_slice(received);

// Packets are cut short by 4 bytes because a Frame Check Sequence (FCS) is expected
// to be present at end and already checked by nic,
// Unless SECRC (Strip Ethernet CRC) is set,
// a Frame Check Sequence (FCS) is expected to be present at end and already checked by nic,
// but because we receive just the frame, assume it's ok and increase length to compensate
descriptor.length = received.len() as u16 + 4;
// otherwise packets would just be cut short by 4 bytes
let mut received_length = received.len();
if !self.regs.rctl.SECRC {
received_length += 4;
}

descriptor.length = received_length as u16;
descriptor.status_eop = true;
descriptor.status_dd = true;

self.nic_ctx
.dma_prepare(descriptor.buffer as usize, buffer.len());
self.nic_ctx.dma_write(descriptor.buffer as usize, &buffer, 0);
let buffer_size = self.regs.rctl.get_buffer_size();
if received_length > buffer_size {
todo!(
"Multiple RX descriptors per packet not yet supported, buffer size={}B, packet={}B",
buffer_size,
received_length,
);
}

let address = descriptor.buffer as usize;
if address == 0 {
todo!("RX Descriptor null padding not yet supported");
}
self.nic_ctx.dma_prepare(address, buffer_size);
self.nic_ctx.dma_write(address, &received, 0);

trace!("Put RX descriptor: {:?}", descriptor);
rx_ring.write_and_advance_head(descriptor, &mut self.nic_ctx)?;
Expand Down
26 changes: 26 additions & 0 deletions src/e1000/registers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,32 @@ impl InterruptDelay {
pub struct ReceiveControl {
#[packed_field(bits = "1")]
pub EN: bool, // Receiver Enable

#[packed_field(bits = "16:17")]
BSIZE: u8, // Receive Buffer Size

#[packed_field(bits = "25")]
BSEX: bool, // Buffer Size Extension

#[packed_field(bits = "26")]
pub SECRC: bool, // Strip Ethernet CRC from incoming packet
}

impl ReceiveControl {
pub fn get_buffer_size(&self) -> usize {
let mut size = match self.BSIZE {
0b00 => 2048,
0b01 => 1024,
0b10 => 512,
0b11 => 256,
_ => unreachable!("Invalid RCTL BSIZE"),
};
if self.BSEX {
// BSEX is normally only supported for BSIZE values != 00, but support it anyway
size *= 16;
}
size
}
}

#[derive(PackedStruct, Clone, Default, Debug)]
Expand Down

0 comments on commit 486e002

Please sign in to comment.