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",
|
"bytemuck",
|
||||||
"device-api",
|
"device-api",
|
||||||
"device-tree",
|
"device-tree",
|
||||||
|
"futures-util",
|
||||||
"libk",
|
"libk",
|
||||||
"libk-mm",
|
"libk-mm",
|
||||||
"libk-util",
|
"libk-util",
|
||||||
|
@ -15,3 +15,4 @@ ygg_driver_net_core.path = "../core"
|
|||||||
tock-registers.workspace = true
|
tock-registers.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
bytemuck.workspace = true
|
bytemuck.workspace = true
|
||||||
|
futures-util.workspace = true
|
||||||
|
@ -10,9 +10,10 @@ use device_api::{
|
|||||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||||
};
|
};
|
||||||
use device_tree::driver::{device_tree_driver, util::read_mac_address, Node, ProbeContext};
|
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_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
use libk_util::{event::BitmapEvent, sync::IrqSafeSpinlock, OneTimeInit};
|
||||||
use regs::{
|
use regs::{
|
||||||
dma::{DMACiCR, DMACiIER, DMACiSR, DMACiTXCR, DMAC0RXCR, DMAMR, DMASBMR},
|
dma::{DMACiCR, DMACiIER, DMACiSR, DMACiTXCR, DMAC0RXCR, DMAMR, DMASBMR},
|
||||||
mac::{
|
mac::{
|
||||||
@ -28,7 +29,7 @@ use ygg_driver_net_core::{
|
|||||||
RxPacket,
|
RxPacket,
|
||||||
};
|
};
|
||||||
use yggdrasil_abi::net::{
|
use yggdrasil_abi::net::{
|
||||||
link::{EthernetLinkState, LinkState},
|
link::{Duplex, EthernetLinkState, EthernetSpeed, LinkState},
|
||||||
MacAddress,
|
MacAddress,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -51,12 +52,29 @@ struct Stmmac {
|
|||||||
resets: Vec<ResetHandle>,
|
resets: Vec<ResetHandle>,
|
||||||
clocks: Vec<ClockHandle>,
|
clocks: Vec<ClockHandle>,
|
||||||
irq: FullIrq,
|
irq: FullIrq,
|
||||||
|
softirq_events: BitmapEvent<AtomicWaker>,
|
||||||
|
|
||||||
inner: OneTimeInit<Inner>,
|
inner: OneTimeInit<Inner>,
|
||||||
iface_id: OneTimeInit<u32>,
|
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 {
|
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> {
|
pub fn start_xmit(&self, frame: DmaBuffer<[u8]>) -> Result<(), Error> {
|
||||||
let inner = self.inner.get();
|
let inner = self.inner.get();
|
||||||
let regs = inner.regs.lock();
|
let regs = inner.regs.lock();
|
||||||
@ -73,6 +91,35 @@ impl Stmmac {
|
|||||||
|
|
||||||
Ok(())
|
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 {
|
impl InterruptHandler for Stmmac {
|
||||||
@ -83,36 +130,17 @@ impl InterruptHandler for Stmmac {
|
|||||||
let dma0_sr = regs.DMA.DMAC0SR.extract();
|
let dma0_sr = regs.DMA.DMAC0SR.extract();
|
||||||
|
|
||||||
if mac_isr.matches_all(MACISR::RGSMIIIS::SET) {
|
if mac_isr.matches_all(MACISR::RGSMIIIS::SET) {
|
||||||
let macphycsr = regs.MAC.MACPHYCSR.extract();
|
let _ = regs.MAC.MACPHYCSR.get();
|
||||||
let state = if macphycsr.matches_all(MACPHYCSR::LNKSTS::Up) {
|
self.softirq_events.signal(Self::SOFTIRQ_GMII_STATUS);
|
||||||
"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}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if dma0_sr.matches_all(DMACiSR::TI::SET) {
|
if dma0_sr.matches_all(DMACiSR::TI::SET) {
|
||||||
regs.DMA.DMAC0SR.modify(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) {
|
if dma0_sr.matches_all(DMACiSR::RI::SET) {
|
||||||
let dma = self.dma.get();
|
|
||||||
regs.DMA.DMAC0SR.modify(DMACiSR::RI::SET);
|
regs.DMA.DMAC0SR.modify(DMACiSR::RI::SET);
|
||||||
let iface = *self.iface_id.get();
|
self.softirq_events.signal(Self::SOFTIRQ_RX_STATUS);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
@ -285,6 +313,9 @@ impl Device for Stmmac {
|
|||||||
|
|
||||||
intc.enable_irq(self.irq.irq)?;
|
intc.enable_irq(self.irq.irq)?;
|
||||||
|
|
||||||
|
let p = self.clone();
|
||||||
|
runtime::spawn(async move { p.softirq().await })?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,8 +342,7 @@ impl NetworkDevice for Stmmac {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn link_state(&self) -> LinkState {
|
fn link_state(&self) -> LinkState {
|
||||||
// TODO
|
self.inner.get().link_state()
|
||||||
LinkState::Ethernet(EthernetLinkState::Down)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,6 +364,8 @@ device_tree_driver! {
|
|||||||
mac,
|
mac,
|
||||||
irq,
|
irq,
|
||||||
|
|
||||||
|
softirq_events: BitmapEvent::new(AtomicWaker::new()),
|
||||||
|
|
||||||
dma: OneTimeInit::new(),
|
dma: OneTimeInit::new(),
|
||||||
inner: OneTimeInit::new(),
|
inner: OneTimeInit::new(),
|
||||||
iface_id: OneTimeInit::new(),
|
iface_id: OneTimeInit::new(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user