eth rx: error handling

This commit is contained in:
Astro 2019-06-22 01:20:18 +02:00
parent 98947961c6
commit 6757ceb76c
3 changed files with 94 additions and 13 deletions

View File

@ -265,8 +265,12 @@ impl<RX, TX> Eth<RX, TX> {
.speed(true) .speed(true)
.no_broadcast(false) .no_broadcast(false)
.multi_hash_en(true) .multi_hash_en(true)
// Promiscuous mode // Promiscuous mode (TODO?)
.copy_all(true) .copy_all(true)
// Remove 4-byte Frame CheckSum
.fcs_remove(true)
// One of the slower speeds
// TODO: calculate properly
.mdc_clk_div(0b110) .mdc_clk_div(0b110)
); );
@ -327,14 +331,73 @@ impl<RX, TX> Eth<RX, TX> {
new_self new_self
} }
// pub fn start_tx<'tx>(self, tx_buffers: [&'tx [u8]; tx::DESCS]) -> Eth<RX, tx::DescList<'tx>> {
// let new_self = Eth {
// regs: self.regs,
// rx: self.rx,
// tx: tx::DescList::new(tx_buffers),
// };
// let list_addr = &new_self.tx as *const _ as u32;
// assert!(list_addr & 0b11 == 0);
// new_self.regs.tx_qbar.write(
// regs::TxQbar::zeroed()
// .tx_q_baseaddr(list_addr >> 2)
// );
// new_self.regs.net_ctrl.modify(|_, w|
// w.tx_en(true)
// );
// new_self
// }
fn wait_phy_idle(&self) { fn wait_phy_idle(&self) {
while !self.regs.net_status.read().phy_mgmt_idle() {} while !self.regs.net_status.read().phy_mgmt_idle() {}
} }
} }
impl<'rx, TX> Eth<rx::DescList<'rx>, TX> { impl<'rx, TX> Eth<rx::DescList<'rx>, TX> {
pub fn recv_next(&mut self) -> Option<rx::PktRef> { pub fn recv_next(&mut self) -> Result<Option<rx::PktRef>, rx::Error> {
self.rx.recv_next() let status = self.regs.rx_status.read();
if status.hresp_not_ok() {
// Clear
self.regs.rx_status.write(
regs::RxStatus::zeroed()
.hresp_not_ok(true)
);
return Err(rx::Error::HrespNotOk);
}
if status.rx_overrun() {
// Clear
self.regs.rx_status.write(
regs::RxStatus::zeroed()
.rx_overrun(true)
);
return Err(rx::Error::RxOverrun);
}
if status.buffer_not_avail() {
// Clear
self.regs.rx_status.write(
regs::RxStatus::zeroed()
.buffer_not_avail(true)
);
return Err(rx::Error::BufferNotAvail);
}
if status.frame_recd() {
let result = self.rx.recv_next();
match result {
Ok(None) => {
// No packet, clear status bit
self.regs.rx_status.write(
regs::RxStatus::zeroed()
.frame_recd(true)
);
}
_ => {}
}
result
} else {
Ok(None)
}
} }
} }

View File

@ -1,6 +1,14 @@
use core::ops::Deref; use core::ops::Deref;
use crate::{register, register_bit, register_bits, register_bits_typed, regs::*}; use crate::{register, register_bit, register_bits, register_bits_typed, regs::*};
#[derive(Debug)]
pub enum Error {
HrespNotOk,
RxOverrun,
BufferNotAvail,
Truncated,
}
/// Descriptor entry /// Descriptor entry
#[repr(C)] #[repr(C)]
pub struct DescEntry { pub struct DescEntry {
@ -44,7 +52,6 @@ impl<'a> DescList<'a> {
let last = list.len().min(buffers.len()) - 1; let last = list.len().min(buffers.len()) - 1;
for (i, (entry, buffer)) in list.iter_mut().zip(buffers.iter_mut()).enumerate() { for (i, (entry, buffer)) in list.iter_mut().zip(buffers.iter_mut()).enumerate() {
let is_last = i == last; let is_last = i == last;
assert!(buffer.len() >= 1536);
let buffer_addr = &mut buffer[0] as *mut _ as u32; let buffer_addr = &mut buffer[0] as *mut _ as u32;
assert!(buffer_addr & 0b11 == 0); assert!(buffer_addr & 0b11 == 0);
entry.word0.write( entry.word0.write(
@ -69,13 +76,12 @@ impl<'a> DescList<'a> {
&self.list[0] as *const _ as u32 &self.list[0] as *const _ as u32
} }
pub fn recv_next<'s: 'p, 'p>(&'s mut self) -> Option<PktRef<'p>> { pub fn recv_next<'s: 'p, 'p>(&'s mut self) -> Result<Option<PktRef<'p>>, Error> {
let list_len = self.list.len(); let list_len = self.list.len();
let entry = &mut self.list[self.next]; let entry = &mut self.list[self.next];
if entry.word0.read().used() { if entry.word0.read().used() {
let len = entry.word1.read() let word1 = entry.word1.read();
.frame_length_lsbs().into(); let len = word1.frame_length_lsbs().into();
// TODO: check no split pkt across multiple buffers
let buffer = &self.buffers[self.next][0..len]; let buffer = &self.buffers[self.next][0..len];
self.next += 1; self.next += 1;
@ -83,9 +89,14 @@ impl<'a> DescList<'a> {
self.next = 0; self.next = 0;
} }
Some(PktRef { entry, buffer }) let pkt = PktRef { entry, buffer };
if word1.start_of_frame() && word1.end_of_frame() {
Ok(Some(pkt))
} else { } else {
None Err(Error::Truncated)
}
} else {
Ok(None)
} }
} }
} }

View File

@ -98,9 +98,16 @@ fn main() {
loop { loop {
match eth.recv_next() { match eth.recv_next() {
None => {} Ok(Some(pkt)) => {
Some(pkt) => { print!("eth: rx {} bytes", pkt.len());
println!("eth: received {} bytes", pkt.len()); for b in pkt.iter() {
print!(" {:02X}", b);
}
println!("");
}
Ok(None) => {}
Err(e) => {
println!("eth rx error: {:?}", e);
} }
} }
} }