Skip to content

Commit e20ea4d

Browse files
committed
Type-state-ify Rx and Tx ring, and stop transmissions on drop
1 parent 3d577bf commit e20ea4d

File tree

6 files changed

+135
-106
lines changed

6 files changed

+135
-106
lines changed

src/dma/mod.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ pub enum TimestampError {
6060

6161
/// Ethernet DMA.
6262
pub struct EthernetDMA<'rx, 'tx> {
63-
pub(crate) eth_dma: ETHERNET_DMA,
64-
pub(crate) rx_ring: RxRing<'rx>,
65-
pub(crate) tx_ring: TxRing<'tx>,
63+
eth_dma: ETHERNET_DMA,
64+
rx_ring: RxRing<'rx, rx::Running>,
65+
tx_ring: TxRing<'tx, tx::Running>,
6666
}
6767

6868
impl<'rx, 'tx> EthernetDMA<'rx, 'tx> {
@@ -137,16 +137,14 @@ impl<'rx, 'tx> EthernetDMA<'rx, 'tx> {
137137
// Configure word skip length.
138138
eth_dma.dmabmr.modify(|_, w| w.dsl().bits(DESC_WORD_SKIP));
139139

140-
let mut dma = EthernetDMA {
141-
eth_dma,
142-
rx_ring: RxRing::new(rx_buffer),
143-
tx_ring: TxRing::new(tx_buffer),
144-
};
145-
146-
dma.rx_ring.start(&dma.eth_dma);
147-
dma.tx_ring.start(&dma.eth_dma);
140+
let rx_ring = RxRing::new(rx_buffer).start(&eth_dma);
141+
let tx_ring = TxRing::new(tx_buffer).start(&eth_dma);
148142

149-
dma
143+
EthernetDMA {
144+
eth_dma,
145+
rx_ring,
146+
tx_ring,
147+
}
150148
}
151149

152150
/// Enable RX and TX interrupts
@@ -201,9 +199,9 @@ impl<'rx, 'tx> EthernetDMA<'rx, 'tx> {
201199
self.tx_ring.running_state(&self.eth_dma)
202200
}
203201

204-
pub(crate) fn recv_next_impl<'rx_borrow>(
202+
fn recv_next_impl<'rx_borrow>(
205203
eth_dma: &ETHERNET_DMA,
206-
rx_ring: &'rx_borrow mut RxRing,
204+
rx_ring: &'rx_borrow mut RxRing<rx::Running>,
207205
rx_packet_id: Option<PacketId>,
208206
) -> Result<RxPacket<'rx_borrow>, RxError> {
209207
rx_ring.recv_next(eth_dma, rx_packet_id.map(|p| p.into()))
@@ -222,7 +220,7 @@ impl<'rx, 'tx> EthernetDMA<'rx, 'tx> {
222220

223221
pub(crate) fn send_impl<F: FnOnce(&mut [u8]) -> R, R>(
224222
eth_dma: &ETHERNET_DMA,
225-
tx_ring: &mut TxRing,
223+
tx_ring: &mut TxRing<tx::Running>,
226224
length: usize,
227225
tx_packet_id: Option<PacketId>,
228226
f: F,
@@ -276,6 +274,13 @@ impl<'rx, 'tx> EthernetDMA<'rx, 'tx> {
276274
}
277275
}
278276

277+
impl<'rx, 'tx> Drop for EthernetDMA<'rx, 'tx> {
278+
fn drop(&mut self) {
279+
self.rx_ring.stop(&self.eth_dma);
280+
self.tx_ring.stop(&self.eth_dma);
281+
}
282+
}
283+
279284
/// A summary of the reasons for the interrupt
280285
/// that occured
281286
#[cfg_attr(feature = "defmt", derive(defmt::Format))]

src/dma/raw_descriptor.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,7 @@ pub struct DescriptorRing<'data, T> {
5959
buffers: &'data mut [[u8; MTU]],
6060
}
6161

62-
pub trait DescriptorRingEntry {
63-
/// Set up this [`Descriptor`] with the given buffer.
64-
fn setup(&mut self, buffer: &mut [u8]);
65-
}
66-
67-
impl<'data, T> DescriptorRing<'data, T>
68-
where
69-
T: DescriptorRingEntry,
70-
{
62+
impl<'data, T> DescriptorRing<'data, T> {
7163
pub fn new(descriptors: &'data mut [T], buffers: &'data mut [[u8; MTU]]) -> Self {
7264
assert!(descriptors.len() == buffers.len());
7365
buffers.iter().for_each(|b| assert!(b.len() <= super::MTU));

src/dma/rx/descriptor.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
use core::sync::atomic::{self, Ordering};
22

33
use crate::{
4-
dma::{
5-
raw_descriptor::{DescriptorRingEntry, RawDescriptor},
6-
PacketId,
7-
},
4+
dma::{raw_descriptor::RawDescriptor, PacketId},
85
ptp::Timestamp,
96
};
107

@@ -52,13 +49,6 @@ impl Default for RxDescriptor {
5249
}
5350
}
5451

55-
impl DescriptorRingEntry for RxDescriptor {
56-
fn setup(&mut self, buffer: &mut [u8]) {
57-
self.set_buffer(buffer);
58-
self.set_owned();
59-
}
60-
}
61-
6252
impl RxDescriptor {
6353
/// Creates a new [`RxDescriptor`].
6454
pub const fn new() -> Self {
@@ -70,6 +60,11 @@ impl RxDescriptor {
7060
}
7161
}
7262

63+
pub(super) fn setup(&mut self, buffer: &mut [u8]) {
64+
self.set_buffer(buffer);
65+
self.set_owned();
66+
}
67+
7368
/// Is owned by the DMA engine?
7469
fn is_owned(&self) -> bool {
7570
(self.inner_raw.read(0) & RXDESC_0_OWN) == RXDESC_0_OWN
@@ -191,7 +186,7 @@ impl RxDescriptor {
191186
}
192187
}
193188

194-
pub(super) fn attach_timestamp(&mut self, packet_id: Option<PacketId>) {
189+
fn attach_timestamp(&mut self, packet_id: Option<PacketId>) {
195190
if packet_id != self.packet_id {
196191
self.cached_timestamp.take();
197192
}

src/dma/rx/mod.rs

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use super::{
2-
raw_descriptor::{DescriptorRing, DescriptorRingEntry},
3-
PacketId,
4-
};
1+
use core::marker::PhantomData;
2+
3+
use super::{raw_descriptor::DescriptorRing, PacketId};
54
use crate::peripherals::ETHERNET_DMA;
65

76
#[cfg(feature = "ptp")]
@@ -25,23 +24,55 @@ pub enum RxError {
2524
/// An RX descriptor ring.
2625
pub type RxDescriptorRing<'rx> = DescriptorRing<'rx, RxDescriptor>;
2726

27+
pub struct NotRunning;
28+
pub struct Running;
29+
2830
/// Rx DMA state
29-
pub(crate) struct RxRing<'data> {
31+
pub struct RxRing<'data, STATE> {
3032
ring: RxDescriptorRing<'data>,
3133
next_entry: usize,
34+
state: PhantomData<STATE>,
35+
}
36+
37+
impl<'data, STATE> RxRing<'data, STATE> {
38+
/// Demand that the DMA engine polls the current `RxDescriptor`
39+
/// (when in `RunningState::Stopped`.)
40+
pub fn demand_poll(&self, eth_dma: &ETHERNET_DMA) {
41+
eth_dma.dmarpdr.write(|w| unsafe { w.rpd().bits(1) });
42+
}
43+
44+
/// Get current `RunningState`
45+
pub fn running_state(&self, eth_dma: &ETHERNET_DMA) -> RunningState {
46+
match eth_dma.dmasr.read().rps().bits() {
47+
// Reset or Stop Receive Command issued
48+
0b000 => RunningState::Stopped,
49+
// Fetching receive transfer descriptor
50+
0b001 => RunningState::Running,
51+
// Waiting for receive packet
52+
0b011 => RunningState::Running,
53+
// Receive descriptor unavailable
54+
0b100 => RunningState::Stopped,
55+
// Closing receive descriptor
56+
0b101 => RunningState::Running,
57+
// Transferring the receive packet data from receive buffer to host memory
58+
0b111 => RunningState::Running,
59+
_ => RunningState::Unknown,
60+
}
61+
}
3262
}
3363

34-
impl<'data> RxRing<'data> {
64+
impl<'data> RxRing<'data, NotRunning> {
3565
/// Allocate
3666
pub fn new(ring: RxDescriptorRing<'data>) -> Self {
3767
RxRing {
3868
ring,
3969
next_entry: 0,
70+
state: Default::default(),
4071
}
4172
}
4273

43-
/// Setup the DMA engine (**required**)
44-
pub fn start(&mut self, eth_dma: &ETHERNET_DMA) {
74+
/// Start the RX ring
75+
pub fn start(mut self, eth_dma: &ETHERNET_DMA) -> RxRing<'data, Running> {
4576
// Setup ring
4677
for (entry, buffer) in self.ring.descriptors_and_buffers() {
4778
entry.setup(buffer);
@@ -64,31 +95,21 @@ impl<'data> RxRing<'data> {
6495
eth_dma.dmaomr.modify(|_, w| w.sr().set_bit());
6596

6697
self.demand_poll(eth_dma);
67-
}
6898

69-
/// Demand that the DMA engine polls the current `RxDescriptor`
70-
/// (when in `RunningState::Stopped`.)
71-
pub fn demand_poll(&self, eth_dma: &ETHERNET_DMA) {
72-
eth_dma.dmarpdr.write(|w| unsafe { w.rpd().bits(1) });
99+
RxRing {
100+
ring: self.ring,
101+
next_entry: self.next_entry,
102+
state: Default::default(),
103+
}
73104
}
105+
}
74106

75-
/// Get current `RunningState`
76-
pub fn running_state(&self, eth_dma: &ETHERNET_DMA) -> RunningState {
77-
match eth_dma.dmasr.read().rps().bits() {
78-
// Reset or Stop Receive Command issued
79-
0b000 => RunningState::Stopped,
80-
// Fetching receive transfer descriptor
81-
0b001 => RunningState::Running,
82-
// Waiting for receive packet
83-
0b011 => RunningState::Running,
84-
// Receive descriptor unavailable
85-
0b100 => RunningState::Stopped,
86-
// Closing receive descriptor
87-
0b101 => RunningState::Running,
88-
// Transferring the receive packet data from receive buffer to host memory
89-
0b111 => RunningState::Running,
90-
_ => RunningState::Unknown,
91-
}
107+
impl<'data> RxRing<'data, Running> {
108+
/// Stop the DMA engine.
109+
pub fn stop(&mut self, eth_dma: &ETHERNET_DMA) {
110+
eth_dma.dmaomr.modify(|_, w| w.sr().clear_bit());
111+
112+
while self.running_state(eth_dma) != RunningState::Stopped {}
92113
}
93114

94115
/// Receive the next packet (if any is ready), or return `None`
@@ -126,7 +147,7 @@ impl<'data> RxRing<'data> {
126147
}
127148

128149
#[cfg(feature = "ptp")]
129-
impl<'a> RxRing<'a> {
150+
impl<'data, STATE> RxRing<'data, STATE> {
130151
pub fn get_timestamp_for_id(&mut self, id: PacketId) -> Result<Timestamp, TimestampError> {
131152
for descriptor in self.ring.descriptors() {
132153
if let (Some(packet_id), Some(timestamp)) =

src/dma/tx/descriptor.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use core::sync::atomic::{self, Ordering};
22

3-
use crate::dma::{
4-
raw_descriptor::{DescriptorRingEntry, RawDescriptor},
5-
PacketId,
6-
};
3+
use crate::dma::{raw_descriptor::RawDescriptor, PacketId};
74

85
#[cfg(feature = "ptp")]
96
use crate::ptp::Timestamp;
@@ -51,18 +48,6 @@ pub struct TxDescriptor {
5148
cached_timestamp: Option<Timestamp>,
5249
}
5350

54-
impl DescriptorRingEntry for TxDescriptor {
55-
fn setup(&mut self, buffer: &mut [u8]) {
56-
self.set_buffer(buffer);
57-
unsafe {
58-
self.inner_raw.write(
59-
0,
60-
TXDESC_0_CIC0 | TXDESC_0_CIC1 | TXDESC_0_FS | TXDESC_0_LS | TXDESC_0_IC,
61-
);
62-
}
63-
}
64-
}
65-
6651
impl Default for TxDescriptor {
6752
fn default() -> Self {
6853
Self::new()
@@ -80,6 +65,16 @@ impl TxDescriptor {
8065
}
8166
}
8267

68+
pub(super) fn setup(&mut self, buffer: &mut [u8]) {
69+
self.set_buffer(buffer);
70+
unsafe {
71+
self.inner_raw.write(
72+
0,
73+
TXDESC_0_CIC0 | TXDESC_0_CIC1 | TXDESC_0_FS | TXDESC_0_LS | TXDESC_0_IC,
74+
);
75+
}
76+
}
77+
8378
#[allow(unused)]
8479
fn has_error(&self) -> bool {
8580
(self.inner_raw.read(0) & TXDESC_0_ES) == TXDESC_0_ES

0 commit comments

Comments
 (0)