diff --git a/src/eth/mod.rs b/src/eth/mod.rs index bf955c62..59b3e192 100644 --- a/src/eth/mod.rs +++ b/src/eth/mod.rs @@ -4,6 +4,7 @@ use crate::println; use crate::clocks::CpuClocks; pub mod phy; +use phy::{Phy, PhyAccess}; mod regs; pub mod rx; pub mod tx; @@ -19,6 +20,9 @@ pub struct Eth<'r, RX, TX> { regs: &'r mut regs::RegisterBlock, rx: RX, tx: TX, + link: bool, + // TODO: no Option + phy: Option, } impl<'r> Eth<'r, (), ()> { @@ -172,8 +176,13 @@ impl<'r> Eth<'r, (), ()> { regs, rx: (), tx: (), - }.init(); + link: false, + phy: None, + }; + eth.init(); eth.configure(macaddr); + eth.phy = Phy::find(&mut eth); + eth.reset_phy(); eth } } @@ -225,7 +234,7 @@ impl<'r, RX, TX> Eth<'r, RX, TX> { }); } - fn init(self) -> Self { + fn init(&mut self) { // Clear the Network Control register. self.regs.net_ctrl.write(regs::NetCtrl::zeroed()); self.regs.net_ctrl.write(regs::NetCtrl::zeroed().clear_stat_regs(true)); @@ -287,8 +296,6 @@ impl<'r, RX, TX> Eth<'r, RX, TX> { self.regs.tx_qbar.write( regs::TxQbar::zeroed() ); - - self } fn configure(&mut self, macaddr: [u8; 6]) { @@ -354,6 +361,8 @@ impl<'r, RX, TX> Eth<'r, RX, TX> { regs: self.regs, rx: rx::DescList::new(rx_list, rx_buffers), tx: self.tx, + link: self.link, + phy: self.phy, }; let list_addr = new_self.rx.list_addr(); assert!(list_addr & 0b11 == 0); @@ -372,6 +381,8 @@ impl<'r, RX, TX> Eth<'r, RX, TX> { regs: self.regs, rx: self.rx, tx: tx::DescList::new(tx_list, tx_buffers), + link: self.link, + phy: self.phy, }; let list_addr = &new_self.tx.list_addr(); assert!(list_addr & 0b11 == 0); @@ -389,29 +400,42 @@ impl<'r, RX, TX> Eth<'r, RX, TX> { while !self.regs.net_status.read().phy_mgmt_idle() {} } - pub fn reset_phy(&mut self) -> bool { - match phy::Phy::find(self) { - Some(phy) => { - println!("eth: Found PHY at {}: {}", phy.addr, phy.name()); - phy.modify_control(self, |control| - control.set_reset(true) - ); - while phy.get_control(self).reset() { - println!("eth: Wait for PHY reset"); - } + pub fn reset_phy(&mut self) { + let phy = self.phy.clone().expect("phy"); + println!("eth: Reset PHY at {}: {}", phy.addr, phy.name()); + phy.modify_control(self, |control| + control.set_reset(true) + ); + while phy.get_control(self).reset() { + println!("eth: Wait for PHY reset"); + } + phy.modify_control(self, |control| + control.set_autoneg_enable(true) + .set_restart_autoneg(true) + ); + } + + fn check_link_change(&mut self) { + let phy = self.phy.clone().expect("phy"); + let link = phy.get_status(self).link_status(); + + // Check link state transition + match (self.link, link) { + (false, true) => { + println!("eth: got link, setting clock for gigabit"); + Self::setup_gem0_clock(TX_1000); + } + (true, false) => { + println!("eth: link lost"); phy.modify_control(self, |control| control.set_autoneg_enable(true) .set_restart_autoneg(true) ); - println!("eth: Wait for link"); - while !phy.get_status(self).link_status() {} - println!("eth: Got link, setting clock for gigabit"); - Self::setup_gem0_clock(TX_1000); - - true } - None => false + _ => {} } + + self.link = link; } } @@ -457,6 +481,7 @@ impl<'r, 'rx, TX> Eth<'r, rx::DescList<'rx>, TX> { } result } else { + self.check_link_change(); Ok(None) } } @@ -468,7 +493,7 @@ impl<'r, 'tx, RX> Eth<'r, RX, tx::DescList<'tx>> { } } -impl<'r, RX, TX> phy::PhyAccess for Eth<'r, RX, TX> { +impl<'r, RX, TX> PhyAccess for Eth<'r, RX, TX> { fn read_phy(&mut self, addr: u8, reg: u8) -> u16 { self.wait_phy_idle(); self.regs.phy_maint.write( @@ -517,8 +542,10 @@ impl<'r, 'rx, 'tx: 'a, 'a> smoltcp::phy::Device<'a> for &mut Eth<'r, rx::DescLis }; Some((pktref, tx_token)) } - Ok(None) => - None, + Ok(None) => { + // TODO: self.check_link_change(); + None + } Err(e) => { println!("eth recv error: {:?}", e); None diff --git a/src/eth/phy/mod.rs b/src/eth/phy/mod.rs index 191d8cf5..f09aaf22 100644 --- a/src/eth/phy/mod.rs +++ b/src/eth/phy/mod.rs @@ -10,11 +10,13 @@ pub trait PhyAccess { fn write_phy(&mut self, addr: u8, reg: u8, data: u16); } +#[derive(Clone)] pub struct Phy { pub addr: u8, device: PhyDevice, } +#[derive(Clone, Copy)] pub enum PhyDevice { Marvel88E1116R, Rtl8211E, diff --git a/src/main.rs b/src/main.rs index 783af930..9e1e0e9f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -90,7 +90,6 @@ fn main() { let mut eth = eth::Eth::default(HWADDR.clone()); println!("Eth on"); - eth.reset_phy(); const RX_LEN: usize = 2; let mut rx_descs: [eth::rx::DescEntry; RX_LEN] = unsafe { uninitialized() };