eth: prepare link change detection

This commit is contained in:
Astro 2019-09-29 02:30:03 +02:00
parent 378755a0ce
commit 0f6bc68d1f
3 changed files with 53 additions and 25 deletions

View File

@ -4,6 +4,7 @@ use crate::println;
use crate::clocks::CpuClocks; use crate::clocks::CpuClocks;
pub mod phy; pub mod phy;
use phy::{Phy, PhyAccess};
mod regs; mod regs;
pub mod rx; pub mod rx;
pub mod tx; pub mod tx;
@ -19,6 +20,9 @@ pub struct Eth<'r, RX, TX> {
regs: &'r mut regs::RegisterBlock, regs: &'r mut regs::RegisterBlock,
rx: RX, rx: RX,
tx: TX, tx: TX,
link: bool,
// TODO: no Option
phy: Option<Phy>,
} }
impl<'r> Eth<'r, (), ()> { impl<'r> Eth<'r, (), ()> {
@ -172,8 +176,13 @@ impl<'r> Eth<'r, (), ()> {
regs, regs,
rx: (), rx: (),
tx: (), tx: (),
}.init(); link: false,
phy: None,
};
eth.init();
eth.configure(macaddr); eth.configure(macaddr);
eth.phy = Phy::find(&mut eth);
eth.reset_phy();
eth 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. // Clear the Network Control register.
self.regs.net_ctrl.write(regs::NetCtrl::zeroed()); self.regs.net_ctrl.write(regs::NetCtrl::zeroed());
self.regs.net_ctrl.write(regs::NetCtrl::zeroed().clear_stat_regs(true)); 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( self.regs.tx_qbar.write(
regs::TxQbar::zeroed() regs::TxQbar::zeroed()
); );
self
} }
fn configure(&mut self, macaddr: [u8; 6]) { fn configure(&mut self, macaddr: [u8; 6]) {
@ -354,6 +361,8 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
regs: self.regs, regs: self.regs,
rx: rx::DescList::new(rx_list, rx_buffers), rx: rx::DescList::new(rx_list, rx_buffers),
tx: self.tx, tx: self.tx,
link: self.link,
phy: self.phy,
}; };
let list_addr = new_self.rx.list_addr(); let list_addr = new_self.rx.list_addr();
assert!(list_addr & 0b11 == 0); assert!(list_addr & 0b11 == 0);
@ -372,6 +381,8 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
regs: self.regs, regs: self.regs,
rx: self.rx, rx: self.rx,
tx: tx::DescList::new(tx_list, tx_buffers), tx: tx::DescList::new(tx_list, tx_buffers),
link: self.link,
phy: self.phy,
}; };
let list_addr = &new_self.tx.list_addr(); let list_addr = &new_self.tx.list_addr();
assert!(list_addr & 0b11 == 0); assert!(list_addr & 0b11 == 0);
@ -389,10 +400,9 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
while !self.regs.net_status.read().phy_mgmt_idle() {} while !self.regs.net_status.read().phy_mgmt_idle() {}
} }
pub fn reset_phy(&mut self) -> bool { pub fn reset_phy(&mut self) {
match phy::Phy::find(self) { let phy = self.phy.clone().expect("phy");
Some(phy) => { println!("eth: Reset PHY at {}: {}", phy.addr, phy.name());
println!("eth: Found PHY at {}: {}", phy.addr, phy.name());
phy.modify_control(self, |control| phy.modify_control(self, |control|
control.set_reset(true) control.set_reset(true)
); );
@ -403,15 +413,29 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
control.set_autoneg_enable(true) control.set_autoneg_enable(true)
.set_restart_autoneg(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 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);
} }
None => false (true, false) => {
println!("eth: link lost");
phy.modify_control(self, |control|
control.set_autoneg_enable(true)
.set_restart_autoneg(true)
);
} }
_ => {}
}
self.link = link;
} }
} }
@ -457,6 +481,7 @@ impl<'r, 'rx, TX> Eth<'r, rx::DescList<'rx>, TX> {
} }
result result
} else { } else {
self.check_link_change();
Ok(None) 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 { fn read_phy(&mut self, addr: u8, reg: u8) -> u16 {
self.wait_phy_idle(); self.wait_phy_idle();
self.regs.phy_maint.write( 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)) Some((pktref, tx_token))
} }
Ok(None) => Ok(None) => {
None, // TODO: self.check_link_change();
None
}
Err(e) => { Err(e) => {
println!("eth recv error: {:?}", e); println!("eth recv error: {:?}", e);
None None

View File

@ -10,11 +10,13 @@ pub trait PhyAccess {
fn write_phy(&mut self, addr: u8, reg: u8, data: u16); fn write_phy(&mut self, addr: u8, reg: u8, data: u16);
} }
#[derive(Clone)]
pub struct Phy { pub struct Phy {
pub addr: u8, pub addr: u8,
device: PhyDevice, device: PhyDevice,
} }
#[derive(Clone, Copy)]
pub enum PhyDevice { pub enum PhyDevice {
Marvel88E1116R, Marvel88E1116R,
Rtl8211E, Rtl8211E,

View File

@ -90,7 +90,6 @@ fn main() {
let mut eth = eth::Eth::default(HWADDR.clone()); let mut eth = eth::Eth::default(HWADDR.clone());
println!("Eth on"); println!("Eth on");
eth.reset_phy();
const RX_LEN: usize = 2; const RX_LEN: usize = 2;
let mut rx_descs: [eth::rx::DescEntry; RX_LEN] = unsafe { uninitialized() }; let mut rx_descs: [eth::rx::DescEntry; RX_LEN] = unsafe { uninitialized() };