From 6253ab282ef1282234074a7f257c56781b7ada42 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 14 Feb 2025 00:18:08 +0200 Subject: [PATCH] stmmac: move to softirq approach --- Cargo.lock | 1 + kernel/driver/net/stmmac/Cargo.toml | 1 + kernel/driver/net/stmmac/src/lib.rs | 88 ++++++++++++++++++++--------- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 512671c6..c8c02f28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2770,6 +2770,7 @@ dependencies = [ "bytemuck", "device-api", "device-tree", + "futures-util", "libk", "libk-mm", "libk-util", diff --git a/kernel/driver/net/stmmac/Cargo.toml b/kernel/driver/net/stmmac/Cargo.toml index 7bc316eb..540c6e4c 100644 --- a/kernel/driver/net/stmmac/Cargo.toml +++ b/kernel/driver/net/stmmac/Cargo.toml @@ -15,3 +15,4 @@ ygg_driver_net_core.path = "../core" tock-registers.workspace = true log.workspace = true bytemuck.workspace = true +futures-util.workspace = true diff --git a/kernel/driver/net/stmmac/src/lib.rs b/kernel/driver/net/stmmac/src/lib.rs index 99c805c2..12205d41 100644 --- a/kernel/driver/net/stmmac/src/lib.rs +++ b/kernel/driver/net/stmmac/src/lib.rs @@ -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, clocks: Vec, irq: FullIrq, + softirq_events: BitmapEvent, inner: OneTimeInit, iface_id: OneTimeInit, } +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(),