Skip to content

Commit 0438352

Browse files
committed
Update to smoltcp 0.9 and incorporate all changes that we added with that
update
1 parent cdd57b4 commit 0438352

File tree

6 files changed

+141
-102
lines changed

6 files changed

+141
-102
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ siphasher = "*"
3434
paste = { version = "1.0", optional = true }
3535

3636
[dependencies.smoltcp]
37-
version = "0.8.2"
37+
version = "0.9"
3838
default-features = false
3939
optional = true
4040

@@ -83,7 +83,7 @@ cortex-m-rtic = "1.0"
8383
defmt-rtt = "0.4"
8484
panic-probe = { version = "0.3", features = [ "print-defmt" ] }
8585
systick-monotonic = "1.0"
86-
smoltcp = { version = "0.8", features = [ "medium-ethernet", "proto-ipv4", "socket-udp", "socket-tcp", "defmt" ], default-features = false }
86+
smoltcp = { version = "0.9", features = [ "medium-ethernet", "proto-ipv4", "socket-udp", "socket-tcp", "defmt" ], default-features = false }
8787

8888
[[example]]
8989
name = "pktgen"

src/dma/mod.rs

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -282,44 +282,31 @@ impl<'rx, 'tx> EthernetDMA<'rx, 'tx> {
282282
/// It stops if the ring is full. Call `recv_next()` to free an
283283
/// entry and to demand poll from the hardware.
284284
pub fn rx_is_running(&self) -> bool {
285-
self.rx_ring.running_state(self.eth_dma()).is_running()
285+
self.rx_ring.running_state().is_running()
286286
}
287287

288288
/// Get the current state of Tx DMA
289289
pub fn tx_state(&self) -> RunningState {
290-
self.tx_ring.running_state(self.eth_dma())
291-
}
292-
293-
fn recv_next_impl<'rx_borrow>(
294-
eth_dma: &ETHERNET_DMA,
295-
rx_ring: &'rx_borrow mut RxRing<rx::Running>,
296-
rx_packet_id: Option<PacketId>,
297-
) -> Result<RxPacket<'rx_borrow>, RxError> {
298-
rx_ring.recv_next(eth_dma, rx_packet_id.map(|p| p.into()))
290+
self.tx_ring.running_state()
299291
}
300292

301293
/// Receive the next packet (if any is ready), or return `None`
302294
/// immediately.
303295
pub fn recv_next(&mut self, packet_id: Option<PacketId>) -> Result<RxPacket, RxError> {
304-
Self::recv_next_impl(&self.parts.eth_dma, &mut self.rx_ring, packet_id)
296+
self.rx_ring.recv_next(packet_id.map(|p| p.into()))
305297
}
306298

307-
/// Is Tx DMA currently running?
308-
pub fn tx_is_running(&self) -> bool {
309-
self.tx_ring.is_running(self.eth_dma())
299+
/// Check whether a frame is available for reception.
300+
///
301+
/// If this function returns `true`, the next [`TxRing::recv_next`] is
302+
/// guaranteed to succeed.
303+
pub fn rx_available(&mut self) -> bool {
304+
self.rx_ring.available()
310305
}
311306

312-
pub(crate) fn send_impl<F: FnOnce(&mut [u8]) -> R, R>(
313-
eth_dma: &ETHERNET_DMA,
314-
tx_ring: &mut TxRing<tx::Running>,
315-
length: usize,
316-
tx_packet_id: Option<PacketId>,
317-
f: F,
318-
) -> Result<R, TxError> {
319-
let result = tx_ring.send(length, tx_packet_id.map(|p| p.into()), f);
320-
tx_ring.demand_poll(eth_dma);
321-
322-
result
307+
/// Is Tx DMA currently running?
308+
pub fn tx_is_running(&self) -> bool {
309+
self.tx_ring.is_running()
323310
}
324311

325312
/// Send a packet
@@ -329,7 +316,15 @@ impl<'rx, 'tx> EthernetDMA<'rx, 'tx> {
329316
packet_id: Option<PacketId>,
330317
f: F,
331318
) -> Result<R, TxError> {
332-
Self::send_impl(&self.parts.eth_dma, &mut self.tx_ring, length, packet_id, f)
319+
self.tx_ring.send(length, packet_id.map(|p| p.into()), f)
320+
}
321+
322+
/// Check whether a descriptor is available for sending.
323+
///
324+
/// If this function returns `true`, the next [`EthernetDMA::send`] is
325+
/// guarantted to succeed.
326+
pub fn tx_available(&mut self) -> bool {
327+
self.tx_ring.available()
333328
}
334329

335330
#[cfg(feature = "ptp")]

src/dma/rx/f_series_desc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ impl RxDescriptor {
6363
}
6464

6565
/// Is owned by the DMA engine?
66-
fn is_owned(&self) -> bool {
66+
pub(super) fn is_owned(&self) -> bool {
6767
(self.inner_raw.read(0) & RXDESC_0_OWN) == RXDESC_0_OWN
6868
}
6969

src/dma/rx/mod.rs

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,11 @@ pub struct RxRing<'data, STATE> {
4444
}
4545

4646
impl<'data, STATE> RxRing<'data, STATE> {
47-
/// Demand that the DMA engine polls the current `RxDescriptor`
48-
/// (when in `RunningState::Stopped`.)
49-
pub fn demand_poll(&self, eth_dma: &ETHERNET_DMA) {
50-
#[cfg(feature = "f-series")]
51-
eth_dma.dmarpdr.write(|w| unsafe { w.rpd().bits(1) });
52-
53-
// On H7, we poll by re-writing the tail pointer register.
54-
#[cfg(feature = "stm32h7xx-hal")]
55-
eth_dma
56-
.dmacrx_dtpr
57-
.modify(|r, w| unsafe { w.bits(r.bits()) });
58-
}
59-
6047
/// Get current `RunningState`
61-
pub fn running_state(&self, eth_dma: &ETHERNET_DMA) -> RunningState {
48+
pub fn running_state(&self) -> RunningState {
49+
// SAFETY: we only perform an atomic read of `dmasr`
50+
let eth_dma = unsafe { &*ETHERNET_DMA::ptr() };
51+
6252
#[cfg(feature = "f-series")]
6353
let rps = eth_dma.dmasr.read().rps().bits();
6454
#[cfg(feature = "stm32h7xx-hal")]
@@ -164,17 +154,43 @@ impl<'data> RxRing<'data, NotRunning> {
164154
});
165155
}
166156

167-
self.demand_poll(eth_dma);
168-
169-
RxRing {
157+
let me = RxRing {
170158
ring: self.ring,
171159
next_entry: self.next_entry,
172160
state: Default::default(),
173-
}
161+
};
162+
163+
me.demand_poll();
164+
165+
me
174166
}
175167
}
176168

177169
impl<'data> RxRing<'data, Running> {
170+
/// Demand that the DMA engine polls the current `RxDescriptor`
171+
/// (when in `RunningState::Stopped`.)
172+
pub fn demand_poll(&self) {
173+
// # SAFETY
174+
//
175+
// On F7, we only perform an atomic write to `damrpdr`.
176+
//
177+
// On H7, we only perform a Read-Write to `dmacrx_dtpr`,
178+
// always with the same value. Running `demand_poll` concurrently
179+
// with the other location in which this register is written ([`RxRing::start`])
180+
// is impossible, which is guaranteed the state transition from NotRunning to
181+
// Running.
182+
let eth_dma = unsafe { &*ETHERNET_DMA::ptr() };
183+
184+
#[cfg(feature = "f-series")]
185+
eth_dma.dmarpdr.write(|w| unsafe { w.rpd().bits(1) });
186+
187+
// On H7, we poll by re-writing the tail pointer register.
188+
#[cfg(feature = "stm32h7xx-hal")]
189+
eth_dma
190+
.dmacrx_dtpr
191+
.modify(|r, w| unsafe { w.bits(r.bits()) });
192+
}
193+
178194
/// Stop the DMA engine.
179195
pub fn stop(&mut self, eth_dma: &ETHERNET_DMA) {
180196
#[cfg(feature = "f-series")]
@@ -185,18 +201,17 @@ impl<'data> RxRing<'data, Running> {
185201

186202
start_reg.modify(|_, w| w.sr().clear_bit());
187203

188-
while self.running_state(eth_dma) != RunningState::Stopped {}
204+
while self.running_state() != RunningState::Stopped {}
189205
}
190206

191207
/// Receive the next packet (if any is ready), or return `None`
192208
/// immediately.
193209
pub fn recv_next(
194210
&mut self,
195-
eth_dma: &ETHERNET_DMA,
196211
#[allow(unused_variables)] packet_id: Option<PacketId>,
197212
) -> Result<RxPacket, RxError> {
198-
if !self.running_state(eth_dma).is_running() {
199-
self.demand_poll(eth_dma);
213+
if !self.running_state().is_running() {
214+
self.demand_poll();
200215
}
201216

202217
let entry = self.next_entry;
@@ -257,6 +272,11 @@ impl<'data> RxRing<'data, Running> {
257272
}
258273
})
259274
}
275+
276+
pub fn available(&mut self) -> bool {
277+
let (desc, _) = self.ring.get(self.next_entry);
278+
!desc.is_owned()
279+
}
260280
}
261281

262282
#[cfg(feature = "ptp")]

src/dma/smoltcp_phy.rs

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
use super::{rx::RxPacket, tx::TxError, EthernetDMA};
2-
use core::intrinsics::transmute;
1+
use super::rx::{self, RxRing};
2+
use super::tx::{self, TxRing};
3+
use super::EthernetDMA;
34
use smoltcp::phy::{ChecksumCapabilities, Device, DeviceCapabilities, RxToken, TxToken};
45
use smoltcp::time::Instant;
5-
use smoltcp::Error;
66

77
/// Use this Ethernet driver with [smoltcp](https://github.com/smoltcp-rs/smoltcp)
8-
impl<'a, 'rx, 'tx, 'b> Device<'a> for &'b mut EthernetDMA<'rx, 'tx> {
9-
type RxToken = EthRxToken<'a>;
10-
type TxToken = EthTxToken<'a>;
8+
impl<'a, 'rx, 'tx> Device for &'a mut EthernetDMA<'rx, 'tx> {
9+
type RxToken<'token> = EthRxToken<'token, 'rx> where Self: 'token;
10+
type TxToken<'token> = EthTxToken<'token, 'tx> where Self: 'token;
1111

1212
fn capabilities(&self) -> DeviceCapabilities {
1313
let mut caps = DeviceCapabilities::default();
@@ -17,65 +17,63 @@ impl<'a, 'rx, 'tx, 'b> Device<'a> for &'b mut EthernetDMA<'rx, 'tx> {
1717
caps
1818
}
1919

20-
fn receive(&mut self) -> Option<(Self::RxToken, Self::TxToken)> {
21-
let self_ = unsafe {
22-
// HACK: eliminate lifetimes
23-
transmute::<&mut EthernetDMA<'rx, 'tx>, &mut EthernetDMA<'a, 'a>>(*self)
24-
};
25-
let eth = self_ as *mut EthernetDMA<'a, 'a>;
26-
match self_.recv_next(None) {
27-
Ok(packet) => {
28-
let rx = EthRxToken { packet };
29-
let tx = EthTxToken { eth };
30-
Some((rx, tx))
31-
}
32-
Err(_) => None,
20+
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
21+
if self.tx_available() && self.rx_available() {
22+
let EthernetDMA {
23+
rx_ring, tx_ring, ..
24+
} = self;
25+
26+
let rx = EthRxToken { rx_ring };
27+
28+
let tx = EthTxToken { tx_ring };
29+
Some((rx, tx))
30+
} else {
31+
None
3332
}
3433
}
3534

36-
fn transmit(&mut self) -> Option<Self::TxToken> {
37-
let eth = unsafe {
38-
transmute::<&mut EthernetDMA<'rx, 'tx>, &mut EthernetDMA<'a, 'a>>(*self)
39-
as *mut EthernetDMA<'a, 'a>
40-
};
41-
Some(EthTxToken { eth })
35+
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
36+
if self.tx_available() {
37+
let EthernetDMA { tx_ring, .. } = self;
38+
Some(EthTxToken { tx_ring })
39+
} else {
40+
None
41+
}
4242
}
4343
}
4444

4545
/// An Ethernet RX token that can be consumed in order to receive
4646
/// an ethernet packet.
47-
pub struct EthRxToken<'a> {
48-
packet: RxPacket<'a>,
47+
pub struct EthRxToken<'a, 'rx> {
48+
rx_ring: &'a mut RxRing<'rx, rx::Running>,
4949
}
5050

51-
impl<'a> RxToken for EthRxToken<'a> {
52-
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> Result<R, Error>
51+
impl<'dma, 'rx> RxToken for EthRxToken<'dma, 'rx> {
52+
fn consume<R, F>(self, f: F) -> R
5353
where
54-
F: FnOnce(&mut [u8]) -> Result<R, Error>,
54+
F: FnOnce(&mut [u8]) -> R,
5555
{
56-
let result = f(&mut self.packet);
57-
self.packet.free();
56+
// NOTE(unwrap): an `EthRxToken` is only created when `eth.rx_available()`
57+
let mut packet = self.rx_ring.recv_next(None).ok().unwrap();
58+
let result = f(&mut packet);
59+
packet.free();
5860
result
5961
}
6062
}
6163

62-
/// Just a reference to [`Eth`](../struct.EthernetDMA.html) for sending a
63-
/// packet later with [`consume()`](#method.consume).
64-
pub struct EthTxToken<'a> {
65-
eth: *mut EthernetDMA<'a, 'a>,
64+
/// Just a reference to [`EthernetDMA`] for sending a
65+
/// packet later with [`TxToken::consume()`].
66+
pub struct EthTxToken<'a, 'tx> {
67+
tx_ring: &'a mut TxRing<'tx, tx::Running>,
6668
}
6769

68-
impl<'a> TxToken for EthTxToken<'a> {
69-
/// Allocate a [`Buffer`](../struct.Buffer.html), yield with
70-
/// `f(buffer)`, and send it as an Ethernet packet.
71-
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R, Error>
70+
impl<'dma, 'tx> TxToken for EthTxToken<'dma, 'tx> {
71+
fn consume<R, F>(self, len: usize, f: F) -> R
7272
where
73-
F: FnOnce(&mut [u8]) -> Result<R, Error>,
73+
F: FnOnce(&mut [u8]) -> R,
7474
{
75-
let eth = unsafe { &mut *self.eth };
76-
match eth.send(len, None, f) {
77-
Err(TxError::WouldBlock) => Err(Error::Exhausted),
78-
Ok(r) => r,
79-
}
75+
// NOTE(unwrap): an `EthTxToken` is only created if
76+
// there is a descriptor available for sending.
77+
self.tx_ring.send(len, None, f).ok().unwrap()
8078
}
8179
}

0 commit comments

Comments
 (0)