Skip to content

Commit bc70c93

Browse files
committed
Fix a caching issue on the RX timestamp
1 parent ef4fa36 commit bc70c93

File tree

6 files changed

+131
-36
lines changed

6 files changed

+131
-36
lines changed

src/dma/cache.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use crate::ptp::Timestamp;
2+
3+
use super::PacketId;
4+
5+
/// A cache for timestamping information,
6+
/// used to keep the size of Descriptors down.
7+
#[derive(Clone, Copy)]
8+
#[repr(C, packed)]
9+
pub struct Cache {
10+
has_packet_id: bool,
11+
#[cfg(feature = "ptp")]
12+
has_timestamp: bool,
13+
14+
packet_id: PacketId,
15+
#[cfg(feature = "ptp")]
16+
timestamp: Timestamp,
17+
}
18+
19+
impl Default for Cache {
20+
fn default() -> Self {
21+
Self::new()
22+
}
23+
}
24+
25+
impl Cache {
26+
pub const fn new() -> Self {
27+
Self {
28+
has_packet_id: false,
29+
packet_id: PacketId(0),
30+
31+
#[cfg(feature = "ptp")]
32+
has_timestamp: false,
33+
#[cfg(feature = "ptp")]
34+
timestamp: Timestamp::new_raw(0),
35+
}
36+
}
37+
38+
/// Set the packet ID of this [`Cache`]
39+
///
40+
/// Removes the timestamp id if `ptp` feature is enabled.
41+
pub fn set_id_and_clear_ts(&mut self, packet_id: Option<PacketId>) {
42+
#[cfg(feature = "ptp")]
43+
{
44+
self.has_timestamp = false;
45+
}
46+
47+
if let Some(id) = packet_id {
48+
self.packet_id = id;
49+
self.has_packet_id = true
50+
} else {
51+
self.has_packet_id = false;
52+
}
53+
}
54+
55+
pub fn id(&self) -> Option<PacketId> {
56+
if self.has_packet_id {
57+
Some(self.packet_id)
58+
} else {
59+
None
60+
}
61+
}
62+
}
63+
64+
#[cfg(feature = "ptp")]
65+
impl Cache {
66+
pub fn set_ts(&mut self, timestamp: Option<Timestamp>) {
67+
if let Some(ts) = timestamp {
68+
self.timestamp = ts;
69+
self.has_timestamp = true;
70+
} else {
71+
self.has_timestamp = false;
72+
}
73+
}
74+
75+
pub fn ts(&self) -> Option<Timestamp> {
76+
if self.has_timestamp {
77+
Some(self.timestamp)
78+
} else {
79+
None
80+
}
81+
}
82+
}

src/dma/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ use cortex_m::peripheral::NVIC;
44

55
use crate::{peripherals::ETHERNET_DMA, stm32::Interrupt};
66

7+
mod cache;
8+
pub(crate) use cache::Cache;
9+
710
#[cfg(feature = "smoltcp-phy")]
811
mod smoltcp_phy;
912
#[cfg(feature = "smoltcp-phy")]
@@ -42,6 +45,8 @@ const _TXDESC_SIZE: usize = core::mem::size_of::<TxDescriptor>();
4245
/// value which applies to both TX and RX descriptors.
4346
const _ASSERT_DESCRIPTOR_SIZES: () = assert!(_RXDESC_SIZE == _TXDESC_SIZE);
4447

48+
const _ASSERT_DESCRIPTOR_ALIGN: () = assert!(_RXDESC_SIZE % 4 == 0);
49+
4550
const DESC_WORD_SKIP: u8 = ((_RXDESC_SIZE / 4) - self::generic_ring::DESC_SIZE) as u8;
4651

4752
const _ASSERT_DESC_WORD_SKIP_SIZE: () = assert!(DESC_WORD_SKIP <= 0b111);

src/dma/rx/f_series_descriptor.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::dma::generic_ring::RawDescriptor;
2+
use crate::dma::Cache;
23

34
use crate::dma::{rx::RxDescriptorError, PacketId};
45

@@ -34,7 +35,7 @@ const RXDESC_1_RER: u32 = 1 << 15;
3435
#[derive(Clone, Copy)]
3536
pub struct RxDescriptor {
3637
desc: RawDescriptor,
37-
packet_id: Option<PacketId>,
38+
cache: Cache,
3839
last: bool,
3940
}
4041

@@ -49,8 +50,10 @@ impl RxDescriptor {
4950
pub const fn new() -> Self {
5051
Self {
5152
desc: RawDescriptor::new(),
52-
packet_id: None,
5353
last: false,
54+
cache: Cache::new(),
55+
#[cfg(not(feature = "ptp"))]
56+
_padding: [0u8; 4],
5457
}
5558
}
5659

@@ -69,8 +72,6 @@ impl RxDescriptor {
6972
}
7073

7174
/// Pass ownership to the DMA engine
72-
///
73-
/// Overrides old timestamp data
7475
pub fn set_owned(&mut self, buffer: &mut [u8]) {
7576
self.set_buffer(buffer);
7677

@@ -121,7 +122,10 @@ impl RxDescriptor {
121122
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Acquire);
122123

123124
// Set the Packet ID for this descriptor.
124-
self.packet_id = packet_id;
125+
self.cache.set_id_and_clear_ts(packet_id);
126+
127+
#[cfg(feature = "ptp")]
128+
self.cache.set_ts(self.read_timestamp());
125129

126130
Ok(())
127131
} else {
@@ -152,11 +156,10 @@ impl RxDescriptor {
152156
#[cfg(feature = "ptp")]
153157
impl RxDescriptor {
154158
pub(super) fn has_packet_id(&self, id: &PacketId) -> bool {
155-
Some(id) == self.packet_id.as_ref()
159+
Some(id) == self.cache.id().as_ref()
156160
}
157161

158-
/// Get PTP timestamp if available
159-
pub(super) fn timestamp(&self) -> Option<Timestamp> {
162+
fn read_timestamp(&self) -> Option<Timestamp> {
160163
#[cfg(any(feature = "stm32f4xx-hal", feature = "stm32f7xx-hal"))]
161164
let (high, low) = { (self.desc.read(7), self.desc.read(6)) };
162165

@@ -184,4 +187,9 @@ impl RxDescriptor {
184187
None
185188
}
186189
}
190+
191+
/// Get PTP timestamp if available
192+
pub(super) fn timestamp(&self) -> Option<Timestamp> {
193+
self.cache.ts()
194+
}
187195
}

src/dma/rx/h_descriptor.rs

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

3-
use crate::dma::{generic_ring::RawDescriptor, PacketId};
3+
use crate::dma::{generic_ring::RawDescriptor, Cache, PacketId};
44

55
#[cfg(feature = "ptp")]
66
use crate::ptp::Timestamp;
@@ -85,9 +85,7 @@ use super::RxDescriptorError;
8585
/// An RX DMA Descriptor.
8686
pub struct RxDescriptor {
8787
inner_raw: RawDescriptor,
88-
packet_id: Option<PacketId>,
89-
#[cfg(feature = "ptp")]
90-
cached_timestamp: Option<Timestamp>,
88+
cache: Cache,
9189
}
9290

9391
impl Default for RxDescriptor {
@@ -101,9 +99,7 @@ impl RxDescriptor {
10199
pub const fn new() -> Self {
102100
Self {
103101
inner_raw: RawDescriptor::new(),
104-
packet_id: None,
105-
#[cfg(feature = "ptp")]
106-
cached_timestamp: None,
102+
cache: Cache::new(),
107103
}
108104
}
109105

@@ -201,9 +197,7 @@ impl RxDescriptor {
201197
// "Subsequent reads and writes cannot be moved ahead of preceding reads."
202198
atomic::compiler_fence(Ordering::Acquire);
203199

204-
self.packet_id = packet_id;
205-
#[cfg(feature = "ptp")]
206-
self.cached_timestamp.take();
200+
self.cache.set_id_and_clear_ts(packet_id);
207201

208202
Ok(())
209203
} else {
@@ -230,14 +224,14 @@ impl RxDescriptor {
230224
}
231225

232226
pub(super) fn has_packet_id(&self, packet_id: &PacketId) -> bool {
233-
self.packet_id.as_ref() == Some(packet_id)
227+
self.cache.id().as_ref() == Some(packet_id)
234228
}
235229

236230
pub(super) fn attach_timestamp(&mut self, timestamp: Option<Timestamp>) {
237-
self.cached_timestamp = timestamp;
231+
self.cache.set_ts(timestamp);
238232
}
239233

240234
pub(super) fn timestamp(&self) -> Option<Timestamp> {
241-
self.cached_timestamp.clone()
235+
self.cache.ts()
242236
}
243237
}

src/dma/tx/f_series_descriptor.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::dma::{generic_ring::RawDescriptor, PacketId};
1+
use crate::dma::{generic_ring::RawDescriptor, Cache, PacketId};
22

33
#[cfg(feature = "ptp")]
44
use crate::ptp::Timestamp;
@@ -38,8 +38,8 @@ const TXDESC_1_TBS2_MASK: u32 = 0x0fff << TXDESC_1_TBS2_SHIFT;
3838
#[derive(Clone, Copy)]
3939
pub struct TxDescriptor {
4040
desc: RawDescriptor,
41-
packet_id: Option<PacketId>,
4241
last: bool,
42+
cache: Cache,
4343
}
4444

4545
impl Default for TxDescriptor {
@@ -53,8 +53,8 @@ impl TxDescriptor {
5353
pub const fn new() -> Self {
5454
Self {
5555
desc: RawDescriptor::new(),
56-
packet_id: None,
5756
last: false,
57+
cache: Cache::new(),
5858
}
5959
}
6060

@@ -101,7 +101,7 @@ impl TxDescriptor {
101101
extra_flags
102102
};
103103

104-
self.packet_id = packet_id;
104+
self.cache.set_id_and_clear_ts(packet_id);
105105

106106
// "Preceding reads and writes cannot be moved past subsequent writes."
107107
#[cfg(feature = "fence")]
@@ -154,9 +154,14 @@ impl TxDescriptor {
154154
#[cfg(feature = "ptp")]
155155
impl TxDescriptor {
156156
pub(super) fn has_packet_id(&self, packet_id: &PacketId) -> bool {
157-
self.packet_id.as_ref() == Some(packet_id)
157+
self.cache.id().as_ref() == Some(packet_id)
158158
}
159159

160+
/// For the TxDescriptor we ignore [`Cache::ts`] because:
161+
/// * We're only really using the cache so that the size of RxDescriptor and TxDescriptor
162+
/// is the same.
163+
/// * We want to be able to retrieve the timestamp immutably.
164+
/// * The Timestamp in the TX descriptor is valid until we perform another transmission.
160165
pub(super) fn timestamp(&self) -> Option<Timestamp> {
161166
let tdes0 = self.desc.read(0);
162167

src/dma/tx/h_descriptor.rs

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

3-
use crate::dma::{generic_ring::RawDescriptor, PacketId};
3+
use crate::dma::{generic_ring::RawDescriptor, Cache, PacketId};
44

55
#[cfg(feature = "ptp")]
66
use crate::ptp::Timestamp;
@@ -122,9 +122,7 @@ pub use consts::*;
122122
#[derive(Clone, Copy)]
123123
pub struct TxDescriptor {
124124
inner_raw: RawDescriptor,
125-
packet_id: Option<PacketId>,
126-
#[cfg(feature = "ptp")]
127-
_padding: Option<Timestamp>,
125+
cache: Cache,
128126
}
129127

130128
impl Default for TxDescriptor {
@@ -138,9 +136,7 @@ impl TxDescriptor {
138136
pub const fn new() -> Self {
139137
Self {
140138
inner_raw: RawDescriptor::new(),
141-
packet_id: None,
142-
#[cfg(feature = "ptp")]
143-
_padding: None,
139+
cache: Cache::new(),
144140
}
145141
}
146142

@@ -152,7 +148,7 @@ impl TxDescriptor {
152148
pub(super) fn setup(&mut self) {
153149
// Zero-out all fields in the descriptor
154150
(0..4).for_each(|n| unsafe { self.inner_raw.write(n, 0) });
155-
self.packet_id.take();
151+
self.cache.set_id_and_clear_ts(None);
156152
}
157153

158154
pub(super) fn is_owned(&self) -> bool {
@@ -178,7 +174,7 @@ impl TxDescriptor {
178174
}
179175
}
180176

181-
self.packet_id = packet_id;
177+
self.cache.set_id_and_clear_ts(packet_id);
182178

183179
// "Preceding reads and writes cannot be moved past subsequent writes."
184180
atomic::fence(Ordering::Release);
@@ -230,9 +226,14 @@ impl TxDescriptor {
230226
#[cfg(feature = "ptp")]
231227
impl TxDescriptor {
232228
pub(super) fn has_packet_id(&self, packet_id: &PacketId) -> bool {
233-
self.packet_id.as_ref() == Some(packet_id)
229+
self.cache.id().as_ref() == Some(packet_id)
234230
}
235231

232+
/// For the TxDescriptor we ignore [`Cache::ts`] because:
233+
/// * We're only really using the cache so that the size of RxDescriptor and TxDescriptor
234+
/// is the same.
235+
/// * We want to be able to retrieve the timestamp immutably.
236+
/// * The Timestamp in the TX descriptor is valid until we perform another transmission.
236237
pub(super) fn timestamp(&self) -> Option<Timestamp> {
237238
let contains_timestamp = (self.inner_raw.read(3) & TXDESC_3_TTSS) == TXDESC_3_TTSS;
238239

0 commit comments

Comments
 (0)