Skip to content

Commit 669d03e

Browse files
committed
Add fences
1 parent 730275a commit 669d03e

File tree

4 files changed

+57
-9
lines changed

4 files changed

+57
-9
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ volatile-register = "0.2"
2222
aligned = "0.3"
2323
stm32f7xx-hal = {version = "0.2.0", optional = true}
2424
stm32f4xx-hal = {version = "0.8.3", optional = true}
25-
cortex-m = "0.6.0"
25+
cortex-m = "0.6.2"
2626

2727
smoltcp = { version = "0.6.0", default-features = false, features = ["proto-ipv4", "proto-ipv6", "socket-icmp", "socket-udp", "socket-tcp", "ethernet"], optional = true }
2828
log = { version = "0.4", optional = true }

src/lib.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ pub use stm32f4xx_hal::stm32;
1717
use hal::rcc::Clocks;
1818
use stm32::{Interrupt, ETHERNET_DMA, ETHERNET_MAC, NVIC};
1919

20-
use cortex_m::asm;
21-
2220
pub mod phy;
2321
use phy::{Phy, PhyStatus};
2422
mod ring;
@@ -88,7 +86,7 @@ impl<'rx, 'tx> Eth<'rx, 'tx> {
8886
///
8987
/// Make sure that the buffers reside in a memory region that is
9088
/// accessible by the peripheral. Core-Coupled Memory (CCM) is
91-
/// usually not accessible. HCLK must be between 25MHz and 168MHz for STM32F4xx
89+
/// usually not accessible. HCLK must be between 25MHz and 168MHz for STM32F4xx
9290
/// or 25MHz to 216MHz for STM32F7xx.
9391
///
9492
/// Uses an interrupt free critical section to turn on the ethernet clock for STM32F7xx.
@@ -314,8 +312,6 @@ impl<'rx, 'tx> Eth<'rx, 'tx> {
314312
f: F,
315313
) -> Result<R, TxError> {
316314
let result = self.tx_ring.send(length, f);
317-
//Make sure the memory write occurs before triggering DMA
318-
asm::dmb();
319315
self.tx_ring.demand_poll(&self.eth_dma);
320316
result
321317
}

src/rx.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ use stm32f7xx_hal::device as stm32;
55

66
use stm32::ETHERNET_DMA;
77

8-
use core::default::Default;
9-
use core::ops::{Deref, DerefMut};
8+
use core::{
9+
default::Default,
10+
ops::{Deref, DerefMut},
11+
sync::atomic::{self, Ordering},
12+
};
1013

1114
use crate::{
1215
desc::Descriptor,
@@ -122,6 +125,7 @@ impl RingDescriptor for RxDescriptor {
122125
self.set_end_of_ring();
123126
}
124127
};
128+
// There is already a fence before starting the DMA engine
125129
self.set_owned();
126130
}
127131
}
@@ -136,6 +140,9 @@ impl RxRingEntry {
136140
} else if self.desc().is_first() && self.desc().is_last() {
137141
let frame_len = self.desc().get_frame_len();
138142

143+
// "Subsequent reads and writes cannot be moved ahead of preceding reads."
144+
atomic::compiler_fence(Ordering::Acquire);
145+
139146
// TODO: obtain ethernet frame type (RDESC_1_FT)
140147
let pkt = RxPacket {
141148
entry: self,
@@ -170,6 +177,13 @@ impl<'a> DerefMut for RxPacket<'a> {
170177

171178
impl<'a> Drop for RxPacket<'a> {
172179
fn drop(&mut self) {
180+
// "Preceding reads and writes cannot be moved past subsequent writes."
181+
#[cfg(feature = "stm32f7xx-hal")]
182+
atomic::fence(Ordering::Release);
183+
184+
#[cfg(not(feature = "stm32f7xx-hal"))]
185+
atomic::compiler_fence(Ordering::Release);
186+
173187
self.entry.desc_mut().set_owned();
174188
}
175189
}
@@ -216,6 +230,13 @@ impl<'a> RxRing<'a> {
216230
// Register RxDescriptor
217231
eth_dma.dmardlar.write(|w| w.srl().bits(ring_ptr as u32));
218232

233+
// "Preceding reads and writes cannot be moved past subsequent writes."
234+
#[cfg(feature = "stm32f7xx-hal")]
235+
atomic::fence(Ordering::Release);
236+
237+
// We don't need a compiler fence here because all interactions with `Descriptor` are
238+
// volatiles
239+
219240
// Start receive
220241
eth_dma.dmaomr.modify(|_, w| w.sr().set_bit());
221242

@@ -225,6 +246,11 @@ impl<'a> RxRing<'a> {
225246
/// Demand that the DMA engine polls the current `RxDescriptor`
226247
/// (when in `RunningState::Stopped`.)
227248
pub fn demand_poll(&self, eth_dma: &ETHERNET_DMA) {
249+
// Prevent `set_owned` to me moved to after the poll
250+
// "Preceding reads and writes cannot be moved past subsequent writes."
251+
#[cfg(feature = "stm32f7xx-hal")]
252+
atomic::fence(Ordering::Release);
253+
228254
eth_dma.dmarpdr.write(|w| unsafe { w.rpd().bits(1) });
229255
}
230256

src/tx.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ use stm32f7xx_hal::device as stm32;
55

66
use stm32::ETHERNET_DMA;
77

8-
use core::ops::{Deref, DerefMut};
8+
use core::{
9+
ops::{Deref, DerefMut},
10+
sync::atomic::{self, Ordering},
11+
};
912

1013
use crate::{
1114
desc::Descriptor,
@@ -152,6 +155,13 @@ impl<'a> DerefMut for TxPacket<'a> {
152155
impl<'a> TxPacket<'a> {
153156
// Pass to DMA engine
154157
pub fn send(self) {
158+
// "Preceding reads and writes cannot be moved past subsequent writes."
159+
#[cfg(feature = "stm32f7xx-hal")]
160+
atomic::fence(Ordering::Release);
161+
162+
#[cfg(not(feature = "stm32f7xx-hal"))]
163+
atomic::compiler_fence(Ordering::Release);
164+
155165
self.entry.desc_mut().set_owned();
156166
}
157167
}
@@ -193,6 +203,13 @@ impl<'a> TxRing<'a> {
193203
// Register TxDescriptor
194204
eth_dma.dmatdlar.write(|w| w.stl().bits(ring_ptr as u32));
195205

206+
// "Preceding reads and writes cannot be moved past subsequent writes."
207+
#[cfg(feature = "stm32f7xx-hal")]
208+
atomic::fence(Ordering::Release);
209+
210+
// We don't need a compiler fence here because all interactions with `Descriptor` are
211+
// volatiles
212+
196213
// Start transmission
197214
eth_dma.dmaomr.modify(|_, w| w.st().set_bit());
198215
}
@@ -222,6 +239,15 @@ impl<'a> TxRing<'a> {
222239
/// Demand that the DMA engine polls the current `TxDescriptor`
223240
/// (when we just transferred ownership to the hardware).
224241
pub fn demand_poll(&self, eth_dma: &ETHERNET_DMA) {
242+
// "Preceding reads and writes cannot be moved past subsequent writes."
243+
#[cfg(feature = "stm32f7xx-hal")]
244+
atomic::fence(Ordering::Release);
245+
246+
// We don't need a compiler fence here because all operations to the buffer were done before
247+
// setting the owned bit (see fences in `TxPacket::send`). We also don't need a compiler
248+
// fence between setting the owned bit and starting the poll, because setting the owned bit
249+
// is a volatile operation
250+
225251
eth_dma.dmatpdr.write(|w| w.tpd().poll());
226252
}
227253

0 commit comments

Comments
 (0)