stmmac: move to softirq approach

This commit is contained in:
Mark Poliakov 2025-02-14 00:18:08 +02:00
parent 57d46ed070
commit 6253ab282e
3 changed files with 62 additions and 28 deletions

1
Cargo.lock generated
View File

@ -2770,6 +2770,7 @@ dependencies = [
"bytemuck",
"device-api",
"device-tree",
"futures-util",
"libk",
"libk-mm",
"libk-util",

View File

@ -15,3 +15,4 @@ ygg_driver_net_core.path = "../core"
tock-registers.workspace = true
log.workspace = true
bytemuck.workspace = true
futures-util.workspace = true

View File

@ -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(),