Skip to content

Commit 69d3fe2

Browse files
Merge #247
247: Make ethernet::DesRing generic over the number of buffers r=richardeoin a=richardeoin This allows users to decide how many transmit and receive buffers they wish to have the the `ethernet::DesRing`. Typically this allows a trade-off in performance vs memory usage. The number of buffers need to be annotated on both `ethernet::DesRing` and `ethernet::EthernetDMA`. Requiring it on both is a slight usability downside. However this is small compared to the previous solution, which was making a local copy of the HAL in order to edit a constant value in `src/ethernet/eth.rs`. Co-authored-by: Richard Meadows <962920+richardeoin@users.noreply.github.com>
2 parents e73199a + 1c57b75 commit 69d3fe2

File tree

6 files changed

+62
-55
lines changed

6 files changed

+62
-55
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
* Rename the PeripheralREC object for BDMA2 on 7B3, 7B0, 7A3 parts from BDMA to BDMA2
1414
* pac: Upgrade to stm32-rs v0.14.0
1515

16+
* ethernet: `ethernet::DesRing` and `ethernet::EthernetDMA` require generic
17+
constants to specify how many transmit / receive buffers to include in
18+
`ethernet::DesRing`. To replicate the previous behaviour, use `DesRing<4, 4>`
19+
1620
## [v0.10.0] 2021-07-xx
1721

1822
* **Breaking**: Don't reset peripheral in DMA1/2 `StreamsTuple::new()` method #229

examples/ethernet-nucleo-h743zi2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
4343

4444
/// Ethernet descriptor rings are a global singleton
4545
#[link_section = ".sram3.eth"]
46-
static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new();
46+
static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new();
4747

4848
// the program entry point
4949
#[entry]

examples/ethernet-rtic-stm32h735g-dk.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
5656

5757
/// Ethernet descriptor rings are a global singleton
5858
#[link_section = ".axisram.eth"]
59-
static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new();
59+
static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new();
6060

6161
/// Net storage with static initialisation - another global singleton
6262
pub struct NetStorageStatic<'a> {
@@ -74,13 +74,13 @@ static mut STORE: NetStorageStatic = NetStorageStatic {
7474
};
7575

7676
pub struct Net<'a> {
77-
iface: EthernetInterface<'a, ethernet::EthernetDMA<'a>>,
77+
iface: EthernetInterface<'a, ethernet::EthernetDMA<'a, 4, 4>>,
7878
sockets: SocketSet<'a>,
7979
}
8080
impl<'a> Net<'a> {
8181
pub fn new(
8282
store: &'static mut NetStorageStatic<'a>,
83-
ethdev: ethernet::EthernetDMA<'a>,
83+
ethdev: ethernet::EthernetDMA<'a, 4, 4>,
8484
ethernet_addr: EthernetAddress,
8585
) -> Self {
8686
// Set IP address

examples/ethernet-rtic-stm32h747i-disco.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
5656

5757
/// Ethernet descriptor rings are a global singleton
5858
#[link_section = ".sram3.eth"]
59-
static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new();
59+
static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new();
6060

6161
/// Net storage with static initialisation - another global singleton
6262
pub struct NetStorageStatic<'a> {
@@ -74,13 +74,13 @@ static mut STORE: NetStorageStatic = NetStorageStatic {
7474
};
7575

7676
pub struct Net<'a> {
77-
iface: EthernetInterface<'a, ethernet::EthernetDMA<'a>>,
77+
iface: EthernetInterface<'a, ethernet::EthernetDMA<'a, 4, 4>>,
7878
sockets: SocketSet<'a>,
7979
}
8080
impl<'a> Net<'a> {
8181
pub fn new(
8282
store: &'static mut NetStorageStatic<'a>,
83-
ethdev: ethernet::EthernetDMA<'a>,
83+
ethdev: ethernet::EthernetDMA<'a, 4, 4>,
8484
ethernet_addr: EthernetAddress,
8585
) -> Self {
8686
// Set IP address

examples/ethernet-stm32h747i-disco.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
2828

2929
/// Ethernet descriptor rings are a global singleton
3030
#[link_section = ".sram3.eth"]
31-
static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new();
31+
static mut DES_RING: ethernet::DesRing<4, 4> = ethernet::DesRing::new();
3232

3333
// the program entry point
3434
#[entry]

src/ethernet/eth.rs

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ use crate::ethernet::StationManagement;
3939
// 6 DMAC, 6 SMAC, 4 q tag, 2 ethernet type II, 1500 ip MTU, 4 CRC, 2
4040
// padding
4141
const ETH_BUF_SIZE: usize = 1536;
42-
const ETH_NUM_TD: usize = 4;
43-
const ETH_NUM_RD: usize = 4;
4442

4543
/// Transmit and Receive Descriptor fields
4644
#[allow(dead_code)]
@@ -95,22 +93,22 @@ impl TDes {
9593

9694
/// Store a ring of TDes and associated buffers
9795
#[repr(C, packed)]
98-
struct TDesRing {
99-
td: [TDes; ETH_NUM_TD],
100-
tbuf: [[u32; ETH_BUF_SIZE / 4]; ETH_NUM_TD],
96+
struct TDesRing<const TD: usize> {
97+
td: [TDes; TD],
98+
tbuf: [[u32; ETH_BUF_SIZE / 4]; TD],
10199
tdidx: usize,
102100
}
103101

104-
impl TDesRing {
102+
impl<const TD: usize> TDesRing<TD> {
105103
const fn new() -> Self {
106104
Self {
107105
td: [TDes {
108106
tdes0: 0,
109107
tdes1: 0,
110108
tdes2: 0,
111109
tdes3: 0,
112-
}; ETH_NUM_TD],
113-
tbuf: [[0; ETH_BUF_SIZE / 4]; ETH_NUM_TD],
110+
}; TD],
111+
tbuf: [[0; ETH_BUF_SIZE / 4]; TD],
114112
tdidx: 0,
115113
}
116114
}
@@ -121,8 +119,8 @@ impl TDesRing {
121119
/// will be stored in the descriptors, so ensure the TDesRing is
122120
/// not moved after initialisation.
123121
pub fn init(&mut self) {
124-
for td in self.td.iter_mut() {
125-
td.init();
122+
for x in 0..TD {
123+
self.td[x].init();
126124
}
127125
self.tdidx = 0;
128126

@@ -131,9 +129,8 @@ impl TDesRing {
131129
unsafe {
132130
let dma = &*stm32::ETHERNET_DMA::ptr();
133131
dma.dmactx_dlar
134-
.write(|w| w.bits(&self.td as *const _ as u32));
135-
dma.dmactx_rlr
136-
.write(|w| w.tdrl().bits(self.td.len() as u16 - 1));
132+
.write(|w| w.bits(&self.td[0] as *const _ as u32));
133+
dma.dmactx_rlr.write(|w| w.tdrl().bits(TD as u16 - 1));
137134
dma.dmactx_dtpr
138135
.write(|w| w.bits(&self.td[0] as *const _ as u32));
139136
}
@@ -166,7 +163,7 @@ impl TDesRing {
166163
cortex_m::asm::dsb();
167164

168165
// Move the tail pointer (TPR) to the next descriptor
169-
let x = (x + 1) % ETH_NUM_TD;
166+
let x = (x + 1) % TD;
170167
unsafe {
171168
let dma = &*stm32::ETHERNET_DMA::ptr();
172169
dma.dmactx_dtpr
@@ -241,22 +238,22 @@ impl RDes {
241238

242239
/// Store a ring of RDes and associated buffers
243240
#[repr(C, packed)]
244-
struct RDesRing {
245-
rd: [RDes; ETH_NUM_RD],
246-
rbuf: [[u32; ETH_BUF_SIZE / 4]; ETH_NUM_RD],
241+
struct RDesRing<const RD: usize> {
242+
rd: [RDes; RD],
243+
rbuf: [[u32; ETH_BUF_SIZE / 4]; RD],
247244
rdidx: usize,
248245
}
249246

250-
impl RDesRing {
247+
impl<const RD: usize> RDesRing<RD> {
251248
const fn new() -> Self {
252249
Self {
253250
rd: [RDes {
254251
rdes0: 0,
255252
rdes1: 0,
256253
rdes2: 0,
257254
rdes3: 0,
258-
}; ETH_NUM_RD],
259-
rbuf: [[0; ETH_BUF_SIZE / 4]; ETH_NUM_RD],
255+
}; RD],
256+
rbuf: [[0; ETH_BUF_SIZE / 4]; RD],
260257
rdidx: 0,
261258
}
262259
}
@@ -267,18 +264,17 @@ impl RDesRing {
267264
/// will be stored in the descriptors, so ensure the RDesRing is
268265
/// not moved after initialisation.
269266
pub fn init(&mut self) {
270-
for rd in self.rd.iter_mut() {
271-
rd.init();
267+
for x in 0..RD {
268+
self.rd[x].init();
272269
}
273270
self.rdidx = 0;
274271

275272
// Initialise pointers in the DMA engine
276273
unsafe {
277274
let dma = &*stm32::ETHERNET_DMA::ptr();
278275
dma.dmacrx_dlar
279-
.write(|w| w.bits(&self.rd as *const _ as u32));
280-
dma.dmacrx_rlr
281-
.write(|w| w.rdrl().bits(self.rd.len() as u16 - 1));
276+
.write(|w| w.bits(&self.rd[0] as *const _ as u32));
277+
dma.dmacrx_rlr.write(|w| w.rdrl().bits(RD as u16 - 1));
282278
}
283279

284280
// Release descriptors to the DMA engine
@@ -325,7 +321,7 @@ impl RDesRing {
325321
}
326322

327323
// Update active descriptor
328-
self.rdidx = (x + 1) % ETH_NUM_RD;
324+
self.rdidx = (x + 1) % RD;
329325
}
330326

331327
/// Access the buffer pointed to by the next RDes
@@ -347,24 +343,29 @@ impl RDesRing {
347343
}
348344
}
349345

350-
pub struct DesRing {
351-
tx: TDesRing,
352-
rx: RDesRing,
346+
pub struct DesRing<const TD: usize, const RD: usize> {
347+
tx: TDesRing<TD>,
348+
rx: RDesRing<RD>,
353349
}
354-
impl DesRing {
355-
pub const fn new() -> DesRing {
350+
impl<const TD: usize, const RD: usize> DesRing<TD, RD> {
351+
pub const fn new() -> Self {
356352
DesRing {
357353
tx: TDesRing::new(),
358354
rx: RDesRing::new(),
359355
}
360356
}
361357
}
358+
impl<const TD: usize, const RD: usize> Default for DesRing<TD, RD> {
359+
fn default() -> Self {
360+
Self::new()
361+
}
362+
}
362363

363364
///
364365
/// Ethernet DMA
365366
///
366-
pub struct EthernetDMA<'a> {
367-
ring: &'a mut DesRing,
367+
pub struct EthernetDMA<'a, const TD: usize, const RD: usize> {
368+
ring: &'a mut DesRing<TD, RD>,
368369
eth_dma: stm32::ETHERNET_DMA,
369370
}
370371

@@ -393,15 +394,15 @@ pub struct EthernetMAC {
393394
/// # Safety
394395
///
395396
/// `EthernetDMA` shall not be moved as it is initialised here
396-
pub unsafe fn new_unchecked<'a>(
397+
pub unsafe fn new_unchecked<'a, const TD: usize, const RD: usize>(
397398
eth_mac: stm32::ETHERNET_MAC,
398399
eth_mtl: stm32::ETHERNET_MTL,
399400
eth_dma: stm32::ETHERNET_DMA,
400-
ring: &'a mut DesRing,
401+
ring: &'a mut DesRing<TD, RD>,
401402
mac_addr: EthernetAddress,
402403
prec: rec::Eth1Mac,
403404
clocks: &CoreClocks,
404-
) -> (EthernetDMA<'a>, EthernetMAC) {
405+
) -> (EthernetDMA<'a, TD, RD>, EthernetMAC) {
405406
// RCC
406407
{
407408
let rcc = &*stm32::RCC::ptr();
@@ -713,9 +714,9 @@ impl StationManagement for EthernetMAC {
713714
}
714715

715716
/// Define TxToken type and implement consume method
716-
pub struct TxToken<'a>(&'a mut TDesRing);
717+
pub struct TxToken<'a, const TD: usize>(&'a mut TDesRing<TD>);
717718

718-
impl<'a> phy::TxToken for TxToken<'a> {
719+
impl<'a, const TD: usize> phy::TxToken for TxToken<'a, TD> {
719720
fn consume<R, F>(
720721
self,
721722
_timestamp: Instant,
@@ -734,9 +735,9 @@ impl<'a> phy::TxToken for TxToken<'a> {
734735
}
735736

736737
/// Define RxToken type and implement consume method
737-
pub struct RxToken<'a>(&'a mut RDesRing);
738+
pub struct RxToken<'a, const RD: usize>(&'a mut RDesRing<RD>);
738739

739-
impl<'a> phy::RxToken for RxToken<'a> {
740+
impl<'a, const RD: usize> phy::RxToken for RxToken<'a, RD> {
740741
fn consume<R, F>(self, _timestamp: Instant, f: F) -> smoltcp::Result<R>
741742
where
742743
F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
@@ -748,9 +749,11 @@ impl<'a> phy::RxToken for RxToken<'a> {
748749
}
749750

750751
/// Implement the smoltcp Device interface
751-
impl<'a> phy::Device<'a> for EthernetDMA<'_> {
752-
type RxToken = RxToken<'a>;
753-
type TxToken = TxToken<'a>;
752+
impl<'a, const TD: usize, const RD: usize> phy::Device<'a>
753+
for EthernetDMA<'_, TD, RD>
754+
{
755+
type RxToken = RxToken<'a, RD>;
756+
type TxToken = TxToken<'a, TD>;
754757

755758
// Clippy false positive because DeviceCapabilities is non-exhaustive
756759
#[allow(clippy::field_reassign_with_default)]
@@ -759,11 +762,11 @@ impl<'a> phy::Device<'a> for EthernetDMA<'_> {
759762
// ethernet frame type II (6 smac, 6 dmac, 2 ethertype),
760763
// sans CRC (4), 1500 IP MTU
761764
caps.max_transmission_unit = 1514;
762-
caps.max_burst_size = Some(core::cmp::min(ETH_NUM_TD, ETH_NUM_RD));
765+
caps.max_burst_size = Some(core::cmp::min(TD, RD));
763766
caps
764767
}
765768

766-
fn receive(&mut self) -> Option<(RxToken, TxToken)> {
769+
fn receive(&mut self) -> Option<(RxToken<RD>, TxToken<TD>)> {
767770
// Skip all queued packets with errors.
768771
while self.ring.rx.available() && !self.ring.rx.valid() {
769772
self.ring.rx.release()
@@ -776,7 +779,7 @@ impl<'a> phy::Device<'a> for EthernetDMA<'_> {
776779
}
777780
}
778781

779-
fn transmit(&mut self) -> Option<TxToken> {
782+
fn transmit(&mut self) -> Option<TxToken<TD>> {
780783
if self.ring.tx.available() {
781784
Some(TxToken(&mut self.ring.tx))
782785
} else {
@@ -785,7 +788,7 @@ impl<'a> phy::Device<'a> for EthernetDMA<'_> {
785788
}
786789
}
787790

788-
impl EthernetDMA<'_> {
791+
impl<const TD: usize, const RD: usize> EthernetDMA<'_, TD, RD> {
789792
/// Return the number of packets dropped since this method was
790793
/// last called
791794
pub fn number_packets_dropped(&self) -> u32 {

0 commit comments

Comments
 (0)