use core::sync::atomic::{Ordering, compiler_fence, fence};
use stm32_metapac::eth::vals::{Rpd, Rps};
use vcell::VolatileCell;
use crate::eth::RX_BUFFER_SIZE;
use crate::pac::ETH;
mod rx_consts {
pub const RXDESC_0_OWN: u32 = 1 << 31;
pub const RXDESC_0_FS: u32 = 1 << 9;
pub const RXDESC_0_LS: u32 = 1 << 8;
pub const RXDESC_0_ES: u32 = 1 << 15;
pub const RXDESC_0_FL_MASK: u32 = 0x3FFF;
pub const RXDESC_0_FL_SHIFT: usize = 16;
pub const RXDESC_1_RBS_MASK: u32 = 0x0fff;
pub const RXDESC_1_RCH: u32 = 1 << 14;
pub const RXDESC_1_RER: u32 = 1 << 15;
}
use rx_consts::*;
use super::Packet;
#[repr(C)]
pub(crate) struct RDes {
rdes0: VolatileCell<u32>,
rdes1: VolatileCell<u32>,
rdes2: VolatileCell<u32>,
rdes3: VolatileCell<u32>,
}
impl RDes {
pub const fn new() -> Self {
Self {
rdes0: VolatileCell::new(0),
rdes1: VolatileCell::new(0),
rdes2: VolatileCell::new(0),
rdes3: VolatileCell::new(0),
}
}
#[inline(always)]
fn valid(&self) -> bool {
(self.rdes0.get() & (RXDESC_0_ES | RXDESC_0_FS | RXDESC_0_LS)) == (RXDESC_0_FS | RXDESC_0_LS)
}
#[inline(always)]
fn available(&self) -> bool {
self.rdes0.get() & RXDESC_0_OWN == 0 }
#[inline(always)]
fn set_ready(&self, buf: *mut u8) {
self.rdes1
.set(self.rdes1.get() | (RX_BUFFER_SIZE as u32) & RXDESC_1_RBS_MASK);
self.rdes2.set(buf as u32);
fence(Ordering::Release);
compiler_fence(Ordering::Release);
self.rdes0.set(self.rdes0.get() | RXDESC_0_OWN);
fence(Ordering::SeqCst);
}
#[inline(always)]
fn set_buffer2(&self, buffer: *const u8) {
self.rdes3.set(buffer as u32);
}
#[inline(always)]
fn set_end_of_ring(&self) {
self.rdes1.set(self.rdes1.get() | RXDESC_1_RER);
}
#[inline(always)]
fn packet_len(&self) -> usize {
((self.rdes0.get() >> RXDESC_0_FL_SHIFT) & RXDESC_0_FL_MASK) as usize
}
fn setup(&self, next: Option<&Self>, buf: *mut u8) {
self.rdes1.set(self.rdes1.get() | RXDESC_1_RCH);
match next {
Some(next) => self.set_buffer2(next as *const _ as *const u8),
None => {
self.set_buffer2(0 as *const u8);
self.set_end_of_ring();
}
}
self.set_ready(buf);
}
}
#[derive(PartialEq, Eq, Debug)]
pub enum RunningState {
Unknown,
Stopped,
Running,
}
pub(crate) struct RDesRing<'a> {
descriptors: &'a mut [RDes],
buffers: &'a mut [Packet<RX_BUFFER_SIZE>],
index: usize,
}
impl<'a> RDesRing<'a> {
pub(crate) fn new(descriptors: &'a mut [RDes], buffers: &'a mut [Packet<RX_BUFFER_SIZE>]) -> Self {
assert!(descriptors.len() > 1);
assert!(descriptors.len() == buffers.len());
for (i, entry) in descriptors.iter().enumerate() {
entry.setup(descriptors.get(i + 1), buffers[i].0.as_mut_ptr());
}
ETH.ethernet_dma()
.dmardlar()
.write(|w| w.0 = descriptors.as_ptr() as u32);
Self {
descriptors,
buffers,
index: 0,
}
}
pub(crate) fn demand_poll(&self) {
ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL));
}
fn running_state(&self) -> RunningState {
match ETH.ethernet_dma().dmasr().read().rps() {
Rps::STOPPED => RunningState::Stopped,
Rps::RUNNING_FETCHING => RunningState::Running,
Rps::RUNNING_WAITING => RunningState::Running,
Rps::SUSPENDED => RunningState::Stopped,
Rps::_RESERVED_5 => RunningState::Running,
Rps::RUNNING_WRITING => RunningState::Running,
_ => RunningState::Unknown,
}
}
pub(crate) fn available(&mut self) -> Option<&mut [u8]> {
if self.running_state() != RunningState::Running {
self.demand_poll();
}
fence(Ordering::SeqCst);
loop {
let descriptor = &mut self.descriptors[self.index];
if !descriptor.available() {
return None;
}
if !descriptor.valid() {
warn!("invalid packet: {:08x}", descriptor.rdes0.get());
self.pop_packet();
continue;
}
break;
}
let descriptor = &mut self.descriptors[self.index];
let len = descriptor.packet_len();
return Some(&mut self.buffers[self.index].0[..len]);
}
pub(crate) fn pop_packet(&mut self) {
let descriptor = &mut self.descriptors[self.index];
assert!(descriptor.available());
self.descriptors[self.index].set_ready(self.buffers[self.index].0.as_mut_ptr());
self.demand_poll();
self.index += 1;
if self.index == self.descriptors.len() {
self.index = 0
}
}
}