Compare commits

..

2 Commits

5 changed files with 61 additions and 40 deletions

1
Cargo.lock generated
View File

@ -89,6 +89,7 @@ version = "0.0.0"
dependencies = [
"bit_field",
"embedded-hal",
"libasync",
"libcortex_a9",
"libregister",
"log",

View File

@ -7,13 +7,19 @@ use smoltcp::{
iface::EthernetInterface,
phy::Device,
socket::SocketSet,
time::Instant,
time::{Duration, Instant},
};
use crate::task;
mod tcp_stream;
pub use tcp_stream::TcpStream;
pub trait LinkCheck {
type Link;
fn is_idle(&self) -> bool;
fn check_link_change(&mut self) -> Option<Self::Link>;
}
static mut SOCKETS: Option<Sockets> = None;
pub struct Sockets {
@ -41,14 +47,24 @@ impl Sockets {
/// Block and run executor indefinitely while polling the smoltcp
/// iface
pub fn run<'b, 'c, 'e, D: for<'d> Device<'d>>(
pub fn run<'b, 'c, 'e, D: for<'d> Device<'d> + LinkCheck>(
iface: &mut EthernetInterface<'b, 'c, 'e, D>,
mut get_time: impl FnMut() -> Instant,
) -> ! {
task::block_on(async {
let mut last_link_check = Instant::from_millis(0);
const LINK_CHECK_INTERVAL: u64 = 500;
loop {
let instant = get_time();
Self::instance().poll(iface, instant);
let dev = iface.device_mut();
if dev.is_idle() && instant >= last_link_check + Duration::from_millis(LINK_CHECK_INTERVAL) {
dev.check_link_change();
last_link_check = instant;
}
task::r#yield().await;
}
})

View File

@ -21,6 +21,7 @@ void = { version = "1", default-features = false }
log = "0.4"
libregister = { path = "../libregister" }
libcortex_a9 = { path = "../libcortex_a9" }
libasync = { path = "../libasync" }
[dependencies.smoltcp]
version = "0.6"

View File

@ -145,6 +145,8 @@ pub struct Eth<GEM: Gem, RX, TX> {
tx: TX,
inner: EthInner<GEM>,
phy: Phy,
/// keep track of RX path occupation to avoid needless `check_link_change()`
idle: bool,
}
impl Eth<Gem0, (), ()> {
@ -314,6 +316,7 @@ impl<GEM: Gem> Eth<GEM, (), ()> {
tx: (),
inner,
phy,
idle: true,
}
}
}
@ -325,6 +328,7 @@ impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
tx: self.tx,
inner: self.inner,
phy: self.phy,
idle: self.idle,
};
let list_addr = new_self.rx.list_addr();
assert!(list_addr & 0b11 == 0);
@ -344,6 +348,7 @@ impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
tx: tx::DescList::new(tx_size),
inner: self.inner,
phy: self.phy,
idle: self.idle,
};
let list_addr = &new_self.tx.list_addr();
assert!(list_addr & 0b11 == 0);
@ -395,17 +400,31 @@ impl<GEM: Gem, TX> Eth<GEM, rx::DescList, TX> {
regs::RxStatus::zeroed()
.frame_recd(true)
);
self.idle = true;
}
_ => {}
_ =>
self.idle = false,
}
result
} else {
self.inner.check_link_change(&self.phy);
self.idle = true;
Ok(None)
}
}
}
impl<GEM: Gem, TX> libasync::smoltcp::LinkCheck for &mut Eth<GEM, rx::DescList, TX> {
type Link = Option<phy::Link>;
fn check_link_change(&mut self) -> Option<Self::Link> {
self.inner.check_link_change(&self.phy)
}
fn is_idle(&self) -> bool {
self.idle
}
}
impl<GEM: Gem, RX> Eth<GEM, RX, tx::DescList> {
pub fn send<'s: 'p, 'p>(&'s mut self, length: usize) -> Option<tx::PktRef<'p>> {
self.tx.send(GEM::regs(), length)
@ -439,10 +458,11 @@ impl<'a, GEM: Gem> smoltcp::phy::Device<'a> for &mut Eth<GEM, rx::DescList, tx::
regs: GEM::regs(),
desc_list: &mut self.tx,
};
self.idle = false;
Some((pktref, tx_token))
}
Ok(None) => {
self.inner.check_link_change(&self.phy);
self.idle = true;
None
}
Err(e) => {
@ -602,13 +622,7 @@ impl<GEM: Gem> EthInner<GEM> {
}
fn check_link_change(&mut self, phy: &Phy) {
// As the PHY access takes some time, exit early if there was
// already a link. TODO: check once per second.
if self.link.is_some() {
return
}
fn check_link_change(&mut self, phy: &Phy) -> Option<Option<phy::Link>> {
let link = phy.get_link(self);
// Check link state transition
@ -640,6 +654,9 @@ impl<GEM: Gem> EthInner<GEM> {
}
self.link = link;
Some(link)
} else {
None
}
}
}

View File

@ -7,7 +7,7 @@ pub use control::Control;
mod pssr;
pub use pssr::PSSR;
#[derive(Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Link {
pub speed: LinkSpeed,
pub duplex: LinkDuplex,
@ -34,15 +34,6 @@ pub trait PhyAccess {
#[derive(Clone)]
pub struct Phy {
pub addr: u8,
device: PhyDevice,
}
#[derive(Clone, Copy)]
pub enum PhyDevice {
Marvell88E1116R,
Marvell88E1512,
Rtl8211E,
PEF7071
}
const OUI_MARVELL: u32 = 0x005043;
@ -52,40 +43,35 @@ const OUI_LANTIQ : u32 = 0x355969;
impl Phy {
/// Probe all addresses on MDIO for a known PHY
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
(1..32).filter_map(|addr| {
match identify_phy(pa, addr) {
(1..32).find(|addr| {
match identify_phy(pa, *addr) {
Some(PhyIdentifier {
oui: OUI_MARVELL,
// Marvell 88E1116R
model: 36,
..
}) => Some(PhyDevice::Marvell88E1116R),
}) => true,
Some(PhyIdentifier {
oui: OUI_MARVELL,
// Marvell 88E1512
model: 29,
..
}) => Some(PhyDevice::Marvell88E1512),
}) => true,
Some(PhyIdentifier {
oui: OUI_REALTEK,
// RTL 8211E
model: 0b010001,
rev: 0b0101,
}) => Some(PhyDevice::Rtl8211E),
}) => true,
Some(PhyIdentifier {
oui: OUI_LANTIQ,
// Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6
model: 0,
..
}) => Some(PhyDevice::PEF7071),
_ => None,
}.map(|device| Phy { addr, device })
}).next()
}
pub fn name(&self) -> &'static str {
match self.device {
PhyDevice::Marvell88E1116R => &"Marvell 88E1116R",
PhyDevice::Marvell88E1512 => &"Marvell 88E1512",
PhyDevice::Rtl8211E => &"RTL8211E",
PhyDevice::PEF7071 => &"Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6"
}) => true,
_ => false,
}
}).map(|addr| Phy { addr })
}
pub fn read_reg<PA, PR>(&self, pa: &mut PA) -> PR