stm32_eth/dma/rx/
mod.rs

1pub(crate) use self::descriptor::RxDescriptor;
2
3use self::descriptor::RxDescriptorError;
4pub use self::descriptor::RxRingEntry;
5
6use super::PacketId;
7use crate::peripherals::ETHERNET_DMA;
8
9mod descriptor;
10
11#[cfg(feature = "ptp")]
12use crate::{dma::PacketIdNotFound, ptp::Timestamp};
13
14#[cfg(feature = "async-await")]
15use core::task::Poll;
16
17/// Errors that can occur during RX
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19#[derive(Debug, PartialEq)]
20pub enum RxError {
21    /// The received packet was truncated
22    Truncated,
23    /// An error occured with the DMA
24    DmaError,
25    /// Receiving would block
26    WouldBlock,
27}
28
29impl From<RxDescriptorError> for RxError {
30    fn from(value: RxDescriptorError) -> Self {
31        match value {
32            RxDescriptorError::Truncated => Self::Truncated,
33            RxDescriptorError::DmaError => Self::DmaError,
34        }
35    }
36}
37
38/// Rx DMA state
39pub struct RxRing<'a> {
40    entries: &'a mut [RxRingEntry],
41    next_entry: usize,
42}
43
44impl<'a> RxRing<'a> {
45    /// Allocate
46    pub(crate) fn new(entries: &'a mut [RxRingEntry]) -> Self {
47        RxRing {
48            entries,
49            next_entry: 0,
50        }
51    }
52
53    /// Setup the DMA engine (**required**)
54    pub(crate) fn start(&mut self, eth_dma: &ETHERNET_DMA) {
55        // Setup ring
56        {
57            let mut previous: Option<&mut RxRingEntry> = None;
58            for entry in self.entries.iter_mut() {
59                if let Some(prev_entry) = &mut previous {
60                    prev_entry.setup(Some(entry));
61                }
62                previous = Some(entry);
63            }
64            if let Some(entry) = &mut previous {
65                entry.setup(None);
66            }
67        }
68        self.next_entry = 0;
69        let ring_ptr = self.entries[0].desc() as *const RxDescriptor;
70
71        // Register RxDescriptor
72        eth_dma
73            .dmardlar
74            .write(|w| unsafe { w.srl().bits(ring_ptr as u32) });
75
76        // We already have fences in `set_owned`, which is called in `setup`
77
78        // Start receive
79        eth_dma.dmaomr.modify(|_, w| w.sr().set_bit());
80
81        self.demand_poll();
82    }
83
84    /// Stop the RX DMA
85    pub(crate) fn stop(&self, eth_dma: &ETHERNET_DMA) {
86        eth_dma.dmaomr.modify(|_, w| w.sr().clear_bit());
87
88        // DMA accesses do not stop before the running state
89        // of the DMA has changed to something other than
90        // running.
91        while self.running_state().is_running() {}
92    }
93
94    /// Demand that the DMA engine polls the current `RxDescriptor`
95    /// (when in [`RunningState::Stopped`].)
96    fn demand_poll(&self) {
97        // SAFETY: we only perform an atomic write to `dmarpdr`.
98        let eth_dma = unsafe { &*ETHERNET_DMA::ptr() };
99        eth_dma.dmarpdr.write(|w| unsafe { w.rpd().bits(1) });
100    }
101
102    /// Get current `RunningState`
103    pub fn running_state(&self) -> RunningState {
104        // SAFETY: we only perform an atomic read of `dmasr`.
105        let eth_dma = unsafe { &*ETHERNET_DMA::ptr() };
106        match eth_dma.dmasr.read().rps().bits() {
107            //  Reset or Stop Receive Command issued
108            0b000 => RunningState::Stopped,
109            //  Fetching receive transfer descriptor
110            0b001 => RunningState::Running,
111            //  Waiting for receive packet
112            0b011 => RunningState::Running,
113            //  Receive descriptor unavailable
114            0b100 => RunningState::Stopped,
115            //  Closing receive descriptor
116            0b101 => RunningState::Running,
117            //  Transferring the receive packet data from receive buffer to host memory
118            0b111 => RunningState::Running,
119            _ => RunningState::Unknown,
120        }
121    }
122
123    /// Check if we can receive a new packet
124    pub fn next_entry_available(&self) -> bool {
125        if !self.running_state().is_running() {
126            self.demand_poll();
127        }
128
129        self.entries[self.next_entry].is_available()
130    }
131
132    /// Receive the next packet (if any is ready).
133    ///
134    /// This function returns a tuple of `Ok((entry_index, length))` on
135    /// success. Whoever receives the `Ok` must ensure that `set_owned`
136    /// is eventually called on the entry with that index.
137    fn recv_next_impl(
138        &mut self,
139        // NOTE(allow): packet_id is unused if ptp is disabled.
140        #[allow(unused_variables)] packet_id: Option<PacketId>,
141    ) -> Result<(usize, usize), RxError> {
142        if !self.running_state().is_running() {
143            self.demand_poll();
144        }
145
146        let entries_len = self.entries.len();
147        let entry_num = self.next_entry;
148        let entry = &mut self.entries[entry_num];
149
150        if entry.is_available() {
151            let length = entry.recv(packet_id)?;
152
153            self.next_entry = (self.next_entry + 1) % entries_len;
154
155            Ok((entry_num, length))
156        } else {
157            Err(RxError::WouldBlock)
158        }
159    }
160
161    /// Receive the next packet (if any is ready), or return [`Err`]
162    /// immediately.
163    pub fn recv_next(&mut self, packet_id: Option<PacketId>) -> Result<RxPacket, RxError> {
164        let (entry, length) = self.recv_next_impl(packet_id.map(|p| p.into()))?;
165        Ok(RxPacket {
166            entry: &mut self.entries[entry],
167            length,
168        })
169    }
170
171    /// Receive the next packet.
172    ///
173    /// The returned [`RxPacket`] can be used as a slice, and
174    /// will contain the ethernet data.
175    #[cfg(feature = "async-await")]
176    pub async fn recv(&mut self, packet_id: Option<PacketId>) -> RxPacket {
177        let (entry, length) = core::future::poll_fn(|ctx| {
178            let res = self.recv_next_impl(packet_id.clone());
179
180            match res {
181                Ok(value) => Poll::Ready(value),
182                Err(_) => {
183                    crate::dma::EthernetDMA::rx_waker().register(ctx.waker());
184                    Poll::Pending
185                }
186            }
187        })
188        .await;
189
190        RxPacket {
191            entry: &mut self.entries[entry],
192            length,
193        }
194    }
195}
196
197#[cfg(feature = "ptp")]
198impl<'a> RxRing<'a> {
199    /// Get the timestamp for a specific ID
200    pub fn timestamp(&self, id: &PacketId) -> Result<Option<Timestamp>, PacketIdNotFound> {
201        let entry = self.entries.iter().find(|e| e.has_packet_id(id));
202
203        let entry = entry.ok_or(PacketIdNotFound)?;
204
205        Ok(entry.read_timestamp())
206    }
207}
208
209/// Running state of the `RxRing`
210#[derive(PartialEq, Eq, Debug)]
211pub enum RunningState {
212    /// Running state is unknown.
213    Unknown,
214    /// The RX DMA is stopped.
215    Stopped,
216    /// The RX DMA is running.
217    Running,
218}
219
220impl RunningState {
221    /// whether self equals to `RunningState::Running`
222    pub fn is_running(&self) -> bool {
223        *self == RunningState::Running
224    }
225}
226
227/// A received packet.
228///
229/// This packet implements [Deref<\[u8\]>](core::ops::Deref) and should be used
230/// as a slice.
231pub struct RxPacket<'a> {
232    entry: &'a mut RxRingEntry,
233    length: usize,
234}
235
236impl<'a> core::ops::Deref for RxPacket<'a> {
237    type Target = [u8];
238
239    fn deref(&self) -> &Self::Target {
240        &self.entry.as_slice()[0..self.length]
241    }
242}
243
244impl<'a> core::ops::DerefMut for RxPacket<'a> {
245    fn deref_mut(&mut self) -> &mut Self::Target {
246        &mut self.entry.as_mut_slice()[0..self.length]
247    }
248}
249
250impl<'a> Drop for RxPacket<'a> {
251    fn drop(&mut self) {
252        self.entry.desc_mut().set_owned();
253    }
254}
255
256impl<'a> RxPacket<'a> {
257    /// Pass the received packet back to the DMA engine.
258    pub fn free(self) {
259        drop(self)
260    }
261
262    /// Get the timestamp associated with this packet
263    #[cfg(feature = "ptp")]
264    pub fn timestamp(&self) -> Option<Timestamp> {
265        self.entry.read_timestamp()
266    }
267}