stmmac: move to softirq approach
This commit is contained in:
parent
57d46ed070
commit
6253ab282e
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2770,6 +2770,7 @@ dependencies = [
|
||||
"bytemuck",
|
||||
"device-api",
|
||||
"device-tree",
|
||||
"futures-util",
|
||||
"libk",
|
||||
"libk-mm",
|
||||
"libk-util",
|
||||
|
@ -15,3 +15,4 @@ ygg_driver_net_core.path = "../core"
|
||||
tock-registers.workspace = true
|
||||
log.workspace = true
|
||||
bytemuck.workspace = true
|
||||
futures-util.workspace = true
|
||||
|
@ -10,9 +10,10 @@ use device_api::{
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, util::read_mac_address, Node, ProbeContext};
|
||||
use libk::{device::external_interrupt_controller, dma::DmaBuffer, error::Error};
|
||||
use futures_util::task::AtomicWaker;
|
||||
use libk::{device::external_interrupt_controller, dma::DmaBuffer, error::Error, task::runtime};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use libk_util::{event::BitmapEvent, sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use regs::{
|
||||
dma::{DMACiCR, DMACiIER, DMACiSR, DMACiTXCR, DMAC0RXCR, DMAMR, DMASBMR},
|
||||
mac::{
|
||||
@ -28,7 +29,7 @@ use ygg_driver_net_core::{
|
||||
RxPacket,
|
||||
};
|
||||
use yggdrasil_abi::net::{
|
||||
link::{EthernetLinkState, LinkState},
|
||||
link::{Duplex, EthernetLinkState, EthernetSpeed, LinkState},
|
||||
MacAddress,
|
||||
};
|
||||
|
||||
@ -51,12 +52,29 @@ struct Stmmac {
|
||||
resets: Vec<ResetHandle>,
|
||||
clocks: Vec<ClockHandle>,
|
||||
irq: FullIrq,
|
||||
softirq_events: BitmapEvent<AtomicWaker>,
|
||||
|
||||
inner: OneTimeInit<Inner>,
|
||||
iface_id: OneTimeInit<u32>,
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
fn link_state(&self) -> LinkState {
|
||||
// TODO read the link state properly, i.e., read from PHY's registers, I guess? I didn't
|
||||
// find a nice way to read the link state from the MAC itself, it only seems to report
|
||||
// the MAC<->PHY link state (which is always up, obviously)
|
||||
LinkState::Ethernet(EthernetLinkState::Up(
|
||||
EthernetSpeed::Unknown,
|
||||
Duplex::Unknown,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Stmmac {
|
||||
const SOFTIRQ_GMII_STATUS: u64 = 1 << 0;
|
||||
const SOFTIRQ_TX_STATUS: u64 = 1 << 1;
|
||||
const SOFTIRQ_RX_STATUS: u64 = 1 << 2;
|
||||
|
||||
pub fn start_xmit(&self, frame: DmaBuffer<[u8]>) -> Result<(), Error> {
|
||||
let inner = self.inner.get();
|
||||
let regs = inner.regs.lock();
|
||||
@ -73,6 +91,35 @@ impl Stmmac {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn softirq(&self) {
|
||||
let inner = self.inner.get();
|
||||
let dma = self.dma.get();
|
||||
let iface = *self.iface_id.get();
|
||||
|
||||
loop {
|
||||
let events = self.softirq_events.wait().await;
|
||||
|
||||
if events & Self::SOFTIRQ_GMII_STATUS != 0 {
|
||||
let link_status = inner.link_state();
|
||||
log::info!("stmmac: link is {link_status}");
|
||||
}
|
||||
|
||||
if events & Self::SOFTIRQ_TX_STATUS != 0 {
|
||||
inner.tx_ring.lock().consume().ok();
|
||||
}
|
||||
|
||||
if events & Self::SOFTIRQ_RX_STATUS != 0 {
|
||||
let mut rx_ring = inner.rx_ring.lock();
|
||||
rx_ring
|
||||
.consume(dma.as_ref(), |packet| {
|
||||
let packet = RxPacket::new(packet, 0, iface);
|
||||
ygg_driver_net_core::receive_packet(packet).ok();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptHandler for Stmmac {
|
||||
@ -83,36 +130,17 @@ impl InterruptHandler for Stmmac {
|
||||
let dma0_sr = regs.DMA.DMAC0SR.extract();
|
||||
|
||||
if mac_isr.matches_all(MACISR::RGSMIIIS::SET) {
|
||||
let macphycsr = regs.MAC.MACPHYCSR.extract();
|
||||
let state = if macphycsr.matches_all(MACPHYCSR::LNKSTS::Up) {
|
||||
"up"
|
||||
} else {
|
||||
"down"
|
||||
};
|
||||
let mode = if macphycsr.matches_all(MACPHYCSR::LNKMOD::FullDuplex) {
|
||||
"full-duplex"
|
||||
} else {
|
||||
"half-duplex"
|
||||
};
|
||||
log::info!("RGMII link status update");
|
||||
log::info!("Link state: link={state}, mode={mode}");
|
||||
let _ = regs.MAC.MACPHYCSR.get();
|
||||
self.softirq_events.signal(Self::SOFTIRQ_GMII_STATUS);
|
||||
}
|
||||
|
||||
if dma0_sr.matches_all(DMACiSR::TI::SET) {
|
||||
regs.DMA.DMAC0SR.modify(DMACiSR::TI::SET);
|
||||
inner.tx_ring.lock().consume().ok();
|
||||
self.softirq_events.signal(Self::SOFTIRQ_TX_STATUS);
|
||||
}
|
||||
if dma0_sr.matches_all(DMACiSR::RI::SET) {
|
||||
let dma = self.dma.get();
|
||||
regs.DMA.DMAC0SR.modify(DMACiSR::RI::SET);
|
||||
let iface = *self.iface_id.get();
|
||||
let mut rx_ring = inner.rx_ring.lock();
|
||||
rx_ring
|
||||
.consume(dma.as_ref(), |packet| {
|
||||
let packet = RxPacket::new(packet, 0, iface);
|
||||
ygg_driver_net_core::receive_packet(packet).ok();
|
||||
})
|
||||
.ok();
|
||||
self.softirq_events.signal(Self::SOFTIRQ_RX_STATUS);
|
||||
}
|
||||
|
||||
true
|
||||
@ -285,6 +313,9 @@ impl Device for Stmmac {
|
||||
|
||||
intc.enable_irq(self.irq.irq)?;
|
||||
|
||||
let p = self.clone();
|
||||
runtime::spawn(async move { p.softirq().await })?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -311,8 +342,7 @@ impl NetworkDevice for Stmmac {
|
||||
}
|
||||
|
||||
fn link_state(&self) -> LinkState {
|
||||
// TODO
|
||||
LinkState::Ethernet(EthernetLinkState::Down)
|
||||
self.inner.get().link_state()
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,6 +364,8 @@ device_tree_driver! {
|
||||
mac,
|
||||
irq,
|
||||
|
||||
softirq_events: BitmapEvent::new(AtomicWaker::new()),
|
||||
|
||||
dma: OneTimeInit::new(),
|
||||
inner: OneTimeInit::new(),
|
||||
iface_id: OneTimeInit::new(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user