net/stmmac: use GenericQueue
This commit is contained in:
@@ -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)?;
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user