use core::ops::{Deref, DerefMut};
use super::*;
use crate::{
DError,
descriptor::{AdvRxDesc, AdvRxDescRead},
};
use alloc::sync::Arc;
use log::{error, trace};
struct RingInner {
base: Ring<AdvRxDesc>,
}
impl RingInner {
fn new(ring: Ring<AdvRxDesc>) -> Result<Self, DError> {
Ok(Self { base: ring })
}
fn init(&mut self) -> Result<(), DError> {
let bus_addr = self.bus_addr();
let size_bytes = self.size_bytes();
self.reg_write(RDBAL, (bus_addr & 0xFFFFFFFF) as u32);
self.reg_write(RDBAH, (bus_addr >> 32) as u32);
self.reg_write(RDLEN, size_bytes as u32);
let pkt_size_kb = self.pkt_size / 1024;
self.reg_write(
SRRCTL,
(SRRCTL::DESCTYPE::AdvancedOneBuffer + SRRCTL::BSIZEPACKET.val(pkt_size_kb as _)).value,
);
self.reg_write(RDH, 0);
self.reg_write(RDT, 0);
self.enable_queue();
wait_for(
|| self.reg_read(RXDCTL) & RXDCTL::ENABLE::Enabled.value > 0,
Duration::from_millis(1),
Some(1000),
)?;
Ok(())
}
pub fn enable_queue(&mut self) {
self.reg_write(
RXDCTL,
(RXDCTL::PTHRESH.val(8)
+ RXDCTL::HTHRESH.val(8)
+ RXDCTL::WTHRESH.val(1)
+ RXDCTL::ENABLE::Enabled)
.value,
);
}
pub fn disable_queue(&mut self) {
self.reg_write(
RXDCTL,
(RXDCTL::PTHRESH.val(8)
+ RXDCTL::HTHRESH.val(8)
+ RXDCTL::WTHRESH.val(1)
+ RXDCTL::ENABLE::Disabled)
.value,
);
}
pub fn get_head(&self) -> u32 {
self.reg_read(RDH)
}
pub fn get_tail(&self) -> u32 {
self.reg_read(RDT)
}
pub fn update_tail(&mut self, mut tail: usize) {
if tail == self.descriptors.len() {
tail = 0;
}
self.reg_write(RDT, tail as u32);
}
}
impl Deref for RingInner {
type Target = super::Ring<AdvRxDesc>;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for RingInner {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
pub struct RxRing(Arc<UnsafeCell<RingInner>>);
unsafe impl Send for RxRing {}
impl RxRing {
#[allow(clippy::arc_with_non_send_sync)]
pub(crate) fn new(idx: usize, mmio_base: NonNull<u8>, size: usize) -> Result<Self, DError> {
let base = Ring::new(idx, mmio_base, size, PACKET_SIZE as usize)?;
let mut ring_inner = RingInner::new(base)?;
ring_inner.init()?;
let ring = Arc::new(UnsafeCell::new(ring_inner));
Ok(Self(ring))
}
fn this(&self) -> &RingInner {
unsafe { &*self.0.get() }
}
fn this_mut(&mut self) -> &mut RingInner {
unsafe { &mut *self.0.get() }
}
pub fn packet_size(&self) -> usize {
self.this().pkt_size
}
pub fn next_pkt(&mut self) -> Option<RxPacket<'_>> {
let index = self.next_index();
let head = self.this().get_head() as usize;
if head == index {
return None; }
let len;
unsafe {
let desc = &self.this().descriptors[index];
if !desc.write.is_done() {
trace!("RxRing: next_pkt descriptor not done at index: {index}");
return None; }
len = desc.write.packet_length() as usize;
}
trace!("RxRing: next_pkt index: {index}");
let request = self.this_mut().meta_ls[index]
.request
.take()
.expect("Request should be set");
Some(RxPacket {
ring: self,
request,
len,
})
}
pub fn submit(&mut self, request: Request) -> Result<(), DError> {
let index = self.this_mut().get_tail() as usize;
let ring = self.this_mut();
if index + 1 == ring.get_head() as usize {
error!("RxRing: submit no available buffer at index: {index}");
return Err(DError::NoMemory); }
let desc = AdvRxDesc {
read: AdvRxDescRead::new(request.bus_addr(), 0, false),
};
ring.descriptors.set(index, desc);
ring.meta_ls[index].request = Some(request);
ring.update_tail(index + 1);
Ok(())
}
fn next_index(&self) -> usize {
let ring = self.this();
(ring.get_tail() as usize + 1) % ring.count()
}
pub fn request_max_count(&self) -> usize {
self.this().count() - 1
}
}
impl Drop for RxRing {
fn drop(&mut self) {
self.this_mut().disable_queue();
}
}
pub struct RxPacket<'a> {
pub request: Request,
ring: &'a mut RxRing,
len: usize,
}
impl<'a> RxPacket<'a> {
pub fn re_submit(self) -> Result<(), DError> {
self.ring.submit(self.request)
}
}
impl Deref for RxPacket<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.request.deref()[..self.len]
}
}