stm32/eth_v1: update to new embassy-net trait, remove PeripheralMutex.
This commit is contained in:
@ -1,20 +1,10 @@
|
||||
use core::sync::atomic::{compiler_fence, fence, Ordering};
|
||||
|
||||
use embassy_net::PacketBuf;
|
||||
use stm32_metapac::eth::vals::St;
|
||||
use vcell::VolatileCell;
|
||||
|
||||
use crate::eth::TX_BUFFER_SIZE;
|
||||
use crate::pac::ETH;
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Error {
|
||||
NoBufferAvailable,
|
||||
// TODO: Break down this error into several others
|
||||
TransmissionError,
|
||||
}
|
||||
|
||||
/// Transmit and Receive Descriptor fields
|
||||
#[allow(dead_code)]
|
||||
mod tx_consts {
|
||||
@ -37,6 +27,8 @@ mod tx_consts {
|
||||
}
|
||||
use tx_consts::*;
|
||||
|
||||
use super::Packet;
|
||||
|
||||
/// Transmit Descriptor representation
|
||||
///
|
||||
/// * tdes0: control
|
||||
@ -44,7 +36,7 @@ use tx_consts::*;
|
||||
/// * tdes2: data buffer address
|
||||
/// * tdes3: next descriptor address
|
||||
#[repr(C)]
|
||||
struct TDes {
|
||||
pub(crate) struct TDes {
|
||||
tdes0: VolatileCell<u32>,
|
||||
tdes1: VolatileCell<u32>,
|
||||
tdes2: VolatileCell<u32>,
|
||||
@ -62,7 +54,7 @@ impl TDes {
|
||||
}
|
||||
|
||||
/// Return true if this TDes is not currently owned by the DMA
|
||||
pub fn available(&self) -> bool {
|
||||
fn available(&self) -> bool {
|
||||
(self.tdes0.get() & TXDESC_0_OWN) == 0
|
||||
}
|
||||
|
||||
@ -79,26 +71,26 @@ impl TDes {
|
||||
fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
fn set_buffer1(&mut self, buffer: *const u8) {
|
||||
fn set_buffer1(&self, buffer: *const u8) {
|
||||
self.tdes2.set(buffer as u32);
|
||||
}
|
||||
|
||||
fn set_buffer1_len(&mut self, len: usize) {
|
||||
fn set_buffer1_len(&self, len: usize) {
|
||||
self.tdes1
|
||||
.set((self.tdes1.get() & !TXDESC_1_TBS_MASK) | ((len as u32) << TXDESC_1_TBS_SHIFT));
|
||||
}
|
||||
|
||||
// points to next descriptor (RCH)
|
||||
fn set_buffer2(&mut self, buffer: *const u8) {
|
||||
fn set_buffer2(&self, buffer: *const u8) {
|
||||
self.tdes3.set(buffer as u32);
|
||||
}
|
||||
|
||||
fn set_end_of_ring(&mut self) {
|
||||
fn set_end_of_ring(&self) {
|
||||
self.tdes0.set(self.tdes0.get() | TXDESC_0_TER);
|
||||
}
|
||||
|
||||
// set up as a part fo the ring buffer - configures the tdes
|
||||
pub fn setup(&mut self, next: Option<&Self>) {
|
||||
fn setup(&self, next: Option<&Self>) {
|
||||
// Defer this initialization to this function, so we can have `RingEntry` on bss.
|
||||
self.tdes0.set(TXDESC_0_TCH | TXDESC_0_IOC | TXDESC_0_FS | TXDESC_0_LS);
|
||||
match next {
|
||||
@ -111,85 +103,58 @@ impl TDes {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TDesRing<const N: usize> {
|
||||
descriptors: [TDes; N],
|
||||
buffers: [Option<PacketBuf>; N],
|
||||
next_entry: usize,
|
||||
pub(crate) struct TDesRing<'a> {
|
||||
descriptors: &'a mut [TDes],
|
||||
buffers: &'a mut [Packet<TX_BUFFER_SIZE>],
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<const N: usize> TDesRing<N> {
|
||||
pub const fn new() -> Self {
|
||||
const TDES: TDes = TDes::new();
|
||||
const BUFFERS: Option<PacketBuf> = None;
|
||||
|
||||
Self {
|
||||
descriptors: [TDES; N],
|
||||
buffers: [BUFFERS; N],
|
||||
next_entry: 0,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TDesRing<'a> {
|
||||
/// Initialise this TDesRing. Assume TDesRing is corrupt
|
||||
///
|
||||
/// The current memory address of the buffers inside this TDesRing
|
||||
/// will be stored in the descriptors, so ensure the TDesRing is
|
||||
/// not moved after initialisation.
|
||||
pub(crate) fn init(&mut self) {
|
||||
assert!(N > 0);
|
||||
pub(crate) fn new(descriptors: &'a mut [TDes], buffers: &'a mut [Packet<TX_BUFFER_SIZE>]) -> Self {
|
||||
assert!(descriptors.len() > 0);
|
||||
assert!(descriptors.len() == buffers.len());
|
||||
|
||||
{
|
||||
let mut previous: Option<&mut TDes> = None;
|
||||
for entry in self.descriptors.iter_mut() {
|
||||
if let Some(prev) = &mut previous {
|
||||
prev.setup(Some(entry));
|
||||
}
|
||||
previous = Some(entry);
|
||||
}
|
||||
|
||||
if let Some(entry) = &mut previous {
|
||||
entry.setup(None);
|
||||
}
|
||||
for (i, entry) in descriptors.iter().enumerate() {
|
||||
entry.setup(descriptors.get(i + 1));
|
||||
}
|
||||
self.next_entry = 0;
|
||||
|
||||
// Register txdescriptor start
|
||||
// NOTE (unsafe) Used for atomic writes
|
||||
unsafe {
|
||||
ETH.ethernet_dma()
|
||||
.dmatdlar()
|
||||
.write(|w| w.0 = &self.descriptors as *const _ as u32);
|
||||
.write(|w| w.0 = descriptors.as_ptr() as u32);
|
||||
}
|
||||
|
||||
// "Preceding reads and writes cannot be moved past subsequent writes."
|
||||
#[cfg(feature = "fence")]
|
||||
fence(Ordering::Release);
|
||||
|
||||
// We don't need a compiler fence here because all interactions with `Descriptor` are
|
||||
// volatiles
|
||||
|
||||
// Start transmission
|
||||
unsafe { ETH.ethernet_dma().dmaomr().modify(|w| w.set_st(St::STARTED)) };
|
||||
}
|
||||
|
||||
/// Return true if a TDes is available for use
|
||||
pub(crate) fn available(&self) -> bool {
|
||||
self.descriptors[self.next_entry].available()
|
||||
}
|
||||
|
||||
pub(crate) fn transmit(&mut self, pkt: PacketBuf) -> Result<(), Error> {
|
||||
if !self.available() {
|
||||
return Err(Error::NoBufferAvailable);
|
||||
Self {
|
||||
descriptors,
|
||||
buffers,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
let descriptor = &mut self.descriptors[self.next_entry];
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.descriptors.len()
|
||||
}
|
||||
|
||||
let pkt_len = pkt.len();
|
||||
let address = pkt.as_ptr() as *const u8;
|
||||
/// Return the next available packet buffer for transmitting, or None
|
||||
pub(crate) fn available(&mut self) -> Option<&mut [u8]> {
|
||||
let descriptor = &mut self.descriptors[self.index];
|
||||
if descriptor.available() {
|
||||
Some(&mut self.buffers[self.index].0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
descriptor.set_buffer1(address);
|
||||
descriptor.set_buffer1_len(pkt_len);
|
||||
/// Transmit the packet written in a buffer returned by `available`.
|
||||
pub(crate) fn transmit(&mut self, len: usize) {
|
||||
let descriptor = &mut self.descriptors[self.index];
|
||||
assert!(descriptor.available());
|
||||
|
||||
self.buffers[self.next_entry].replace(pkt);
|
||||
descriptor.set_buffer1(self.buffers[self.index].0.as_ptr());
|
||||
descriptor.set_buffer1_len(len);
|
||||
|
||||
descriptor.set_owned();
|
||||
|
||||
@ -198,36 +163,12 @@ impl<const N: usize> TDesRing<N> {
|
||||
// "Preceding reads and writes cannot be moved past subsequent writes."
|
||||
fence(Ordering::Release);
|
||||
|
||||
// Move the tail pointer (TPR) to the next descriptor
|
||||
self.next_entry = (self.next_entry + 1) % N;
|
||||
|
||||
// Move the index to the next descriptor
|
||||
self.index += 1;
|
||||
if self.index == self.descriptors.len() {
|
||||
self.index = 0
|
||||
}
|
||||
// Request the DMA engine to poll the latest tx descriptor
|
||||
unsafe { ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn on_interrupt(&mut self) -> Result<(), Error> {
|
||||
let previous = (self.next_entry + N - 1) % N;
|
||||
let td = &self.descriptors[previous];
|
||||
|
||||
// DMB to ensure that we are reading an updated value, probably not needed at the hardware
|
||||
// level, but this is also a hint to the compiler that we're syncing on the buffer.
|
||||
fence(Ordering::SeqCst);
|
||||
|
||||
let tdes0 = td.tdes0.get();
|
||||
|
||||
if tdes0 & TXDESC_0_OWN != 0 {
|
||||
// Transmission isn't done yet, probably a receive interrupt that fired this
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Release the buffer
|
||||
self.buffers[previous].take();
|
||||
|
||||
if tdes0 & TXDESC_0_ES != 0 {
|
||||
Err(Error::TransmissionError)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user