net/stmmac: use GenericQueue

This commit is contained in:
2026-02-07 15:47:40 +02:00
parent 7f46da9ebd
commit a6a6dba155
3 changed files with 61 additions and 222 deletions
-1
View File
@@ -158,7 +158,6 @@ impl<T: GenericTxDescriptor> GenericTxRing<T> {
let buffer_len = frame.len();
let index = inner.wr % self.capacity;
assert!(inner.in_flight[index].is_none());
frame.cache_flush_all(true);
inner.entries[index].setup_tx(buffer_address, buffer_len, index, self.capacity)?;
+18 -21
View File
@@ -29,12 +29,13 @@ use regs::{
},
mtl::{MTLOMR, MTLRXQiOMR, MTLTXQiOMR},
};
use ring::{RxDescriptor, RxRing, TxDescriptor, TxRing};
use ring::{RxDescriptor, TxDescriptor};
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
use ygg_driver_net_core::{
RxPacket,
ephy::{GBESR, PhyAccess},
interface::{NetworkDevice, NetworkInterfaceType},
util::GenericQueue,
};
use yggdrasil_abi::net::{
MacAddress,
@@ -48,9 +49,7 @@ pub mod ring;
struct Inner {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
tx_ring: IrqSafeSpinlock<TxRing>,
rx_ring: IrqSafeSpinlock<RxRing>,
queue: GenericQueue<TxDescriptor, RxDescriptor>,
}
struct Stmmac {
@@ -105,12 +104,12 @@ impl Stmmac {
pub fn start_xmit(&self, frame: DmaBuffer<[u8]>) -> Result<(), Error> {
let inner = self.inner.get();
let regs = inner.regs.lock();
let index = inner.queue.try_push_xmit(frame)?;
let mut tx_ring = inner.tx_ring.lock();
let index = tx_ring.push_xmit(frame)?;
let ring_pos = tx_ring
.buffer_base()
let regs = inner.regs.lock();
let ring_pos = inner
.queue
.tx_buffer_base()
.add(size_of::<TxDescriptor>() * index)
.try_into_u32()
.unwrap();
@@ -134,17 +133,17 @@ impl Stmmac {
}
if events & Self::SOFTIRQ_TX_STATUS != 0 {
inner.tx_ring.lock().consume().ok();
inner.queue.consume_tx().ok();
}
if events & Self::SOFTIRQ_RX_STATUS != 0 {
let mut rx_ring = inner.rx_ring.lock();
rx_ring
.consume(dma.as_ref(), |packet| {
inner
.queue
.consume_rx(dma.as_ref(), None, |packet, _| {
let packet = RxPacket::new(packet, 0, iface);
ygg_driver_net_core::receive_packet(packet).ok();
})
.ok();
.expect("Rx failed");
}
}
}
@@ -230,10 +229,10 @@ impl Device for Stmmac {
);
// Setup DMA Tx/Rx rings
let tx_ring = TxRing::with_capacity(dma.as_ref(), tx_ring_capacity)?;
let rx_ring = RxRing::with_capacity(dma.as_ref(), rx_ring_capacity)?;
let tx_ring_base = tx_ring.buffer_base().try_into_u32().unwrap();
let rx_ring_base = rx_ring.buffer_base().try_into_u32().unwrap();
let queue =
GenericQueue::with_capacity(dma.as_ref(), tx_ring_capacity, rx_ring_capacity, 4096)?;
let tx_ring_base = queue.tx_buffer_base().try_into_u32()?;
let rx_ring_base = queue.rx_buffer_base().try_into_u32()?;
regs.DMA.DMAC0TXRLR.set(tx_ring_capacity as u32 - 1);
regs.DMA.DMAC0TXDLAR.set(tx_ring_base);
@@ -338,9 +337,7 @@ impl Device for Stmmac {
self.inner.init(Inner {
regs: IrqSafeSpinlock::new(regs),
tx_ring: IrqSafeSpinlock::new(tx_ring),
rx_ring: IrqSafeSpinlock::new(rx_ring),
queue,
});
let iface =
+43 -200
View File
@@ -1,26 +1,5 @@
use core::mem::{self, MaybeUninit};
use alloc::vec::Vec;
use device_api::dma::DmaAllocator;
use libk::{
dma::{BusAddress, DmaBuffer},
error::Error,
};
pub struct TxRing {
entries: DmaBuffer<[TxDescriptor]>,
buffers: Vec<Option<DmaBuffer<[u8]>>>,
wr: usize,
rd: usize,
}
pub struct RxRing {
entries: DmaBuffer<[RxDescriptor]>,
buffers: Vec<DmaBuffer<[MaybeUninit<u8>]>>,
rd: usize,
}
use libk::{dma::BusAddress, error::Error};
use ygg_driver_net_core::util::{GenericRxDescriptor, GenericTxDescriptor};
#[derive(Clone, Copy, Debug)]
#[repr(C)]
@@ -40,215 +19,79 @@ pub struct RxDescriptor {
rdes3: u32,
}
impl TxRing {
pub fn with_capacity(dma: &dyn DmaAllocator, capacity: usize) -> Result<Self, Error> {
let entries = DmaBuffer::new_slice(dma, TxDescriptor::empty(), capacity)?;
let buffers = (0..capacity).map(|_| None).collect();
Ok(Self {
entries,
buffers,
wr: 0,
rd: 0,
})
}
pub fn buffer_base(&self) -> BusAddress {
self.entries.bus_address()
}
pub fn capacity(&self) -> usize {
self.entries.len()
}
pub fn can_xmit(&self) -> bool {
self.wr.wrapping_add(1) != self.rd
}
pub fn outstanding_tx(&self) -> bool {
self.wr != self.rd
}
pub fn push_xmit(&mut self, frame: DmaBuffer<[u8]>) -> Result<usize, Error> {
if !self.can_xmit() {
return Err(Error::WouldBlock);
}
let address = frame.bus_address();
let frame_len = frame.len();
let capacity = self.entries.len();
let index = self.wr % capacity;
assert!(self.buffers[index].is_none());
frame.cache_flush_all(true);
self.entries[index].setup_tx(address, frame_len, true)?;
self.entries.cache_flush_element(index, true);
self.buffers[index] = Some(frame);
self.wr = self.wr.wrapping_add(1);
Ok(self.wr % self.capacity())
}
pub fn consume(&mut self) -> Result<usize, Error> {
let mut count = 0;
loop {
let index = self.rd % self.entries.len();
let entry = &self.entries[index];
if self.rd == self.wr {
break;
}
if let Some(status) = entry.tx_status() {
if status != 0 {
log::warn!("tx_ring[{index}] error: {status:#x}");
}
let _ = self.buffers[index].take().unwrap();
self.rd = self.rd.wrapping_add(1);
count += 1;
} else {
break;
}
}
Ok(count)
}
}
impl TxDescriptor {
const TDES3_OWN: u32 = 1 << 31;
const TDES3_FD: u32 = 1 << 29;
const TDES3_LD: u32 = 1 << 28;
const TDES2_IOC: u32 = 1 << 31;
}
pub const fn empty() -> Self {
Self {
tdes0: 0,
tdes1: 0,
tdes2: 0,
tdes3: 0,
}
}
impl GenericTxDescriptor for TxDescriptor {
const EMPTY: Self = Self {
tdes0: 0,
tdes1: 0,
tdes2: 0,
tdes3: 0,
};
pub fn tx_status(&self) -> Option<u32> {
fn consume(&mut self) -> Option<Result<(), Error>> {
if self.tdes3 & Self::TDES3_OWN == 0 {
Some(self.tdes3 & !(0xFFFF << 16))
// Some(self.tdes3 & !(0xFFFF << 16))
Some(Ok(()))
} else {
None
}
}
pub fn setup_tx(
fn setup_tx(
&mut self,
frame: BusAddress,
frame_len: usize,
ioc: bool,
buffer_address: BusAddress,
size: usize,
_index: usize,
_capacity: usize,
) -> Result<(), Error> {
let tdes0 = frame.try_into_u32().map_err(|_| Error::InvalidArgument)?;
if frame_len & !0x3FFF != 0 {
if size & !0x3FFF != 0 {
return Err(Error::InvalidArgument);
}
let mut tdes2 = frame_len as u32;
if ioc {
tdes2 |= Self::TDES2_IOC;
}
let tdes3 = Self::TDES3_OWN | Self::TDES3_FD | Self::TDES3_LD;
self.tdes0 = tdes0;
// TODO ioc only on quarter buffer
self.tdes0 = buffer_address.try_into_u32()?;
self.tdes1 = 0;
self.tdes2 = tdes2;
self.tdes3 = tdes3;
self.tdes2 = size as u32 | Self::TDES2_IOC;
self.tdes3 = Self::TDES3_OWN | Self::TDES3_LD | Self::TDES3_FD;
Ok(())
}
}
impl RxRing {
pub fn with_capacity(dma: &dyn DmaAllocator, capacity: usize) -> Result<Self, Error> {
let mut entries = DmaBuffer::new_slice(dma, RxDescriptor::empty(), capacity)?;
let buffers = (0..capacity)
.map(|_| DmaBuffer::new_uninit_slice(dma, 4096))
.collect::<Result<Vec<_>, _>>()?;
for i in 0..capacity {
entries[i].setup_rx(buffers[i].bus_address(), true)?;
}
Ok(Self {
buffers,
entries,
rd: 0,
})
}
pub fn buffer_base(&self) -> BusAddress {
self.entries.bus_address()
}
pub fn consume<F: Fn(DmaBuffer<[u8]>)>(
&mut self,
dma: &dyn DmaAllocator,
packet_handler: F,
) -> Result<usize, Error> {
let mut count = 0;
loop {
let index = self.rd % self.entries.len();
let entry = &mut self.entries[index];
if entry.rx_completed().is_some() {
// Grab the current buffer (the one just written to by the DMA), replace it
// with the newly allocated one, and mark the descriptor as DMA-owned again
let new_buffer = DmaBuffer::new_uninit_slice(dma, 4096)?;
let new_buffer_address = new_buffer.bus_address();
let buffer = mem::replace(&mut self.buffers[index], new_buffer);
let buffer = unsafe { DmaBuffer::assume_init_slice(buffer) };
// TODO packet size hint
packet_handler(buffer);
entry.setup_rx(new_buffer_address, true)?;
self.rd = self.rd.wrapping_add(1);
count += 1;
} else {
break;
}
}
Ok(count)
}
}
impl RxDescriptor {
const RDES3_OWN: u32 = 1 << 31;
const RDES3_IOC: u32 = 1 << 30;
const RDES3_BUF1V: u32 = 1 << 24;
}
pub const fn empty() -> Self {
Self {
rdes0: 0,
rdes1: 0,
rdes2: 0,
rdes3: 0,
}
}
pub fn rx_completed(&self) -> Option<usize> {
impl GenericRxDescriptor for RxDescriptor {
fn consume(&mut self) -> Option<Result<usize, Error>> {
if self.rdes3 & Self::RDES3_OWN == 0 {
Some((self.rdes3 & 0x7FFF) as usize)
Some(Ok((self.rdes3 & 0x7FFF) as usize))
} else {
None
}
}
pub fn setup_rx(&mut self, buffer: BusAddress, ioc: bool) -> Result<(), Error> {
self.rdes0 = buffer.try_into_u32().map_err(|_| Error::InvalidArgument)?;
self.rdes1 = 0;
self.rdes2 = 0;
self.rdes3 = Self::RDES3_BUF1V;
if ioc {
self.rdes3 |= Self::RDES3_IOC;
}
self.rdes3 |= Self::RDES3_OWN;
Ok(())
fn setup_rx(
buffer_address: BusAddress,
_buffer_size: usize,
_last: bool,
) -> Result<Self, Error> {
let rdes0 = buffer_address.try_into_u32()?;
let rdes1 = 0;
let rdes2 = 0;
// TODO ioc
let rdes3 = Self::RDES3_BUF1V | Self::RDES3_IOC | Self::RDES3_OWN;
Ok(Self {
rdes0,
rdes1,
rdes2,
rdes3,
})
}
}