aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/eth/v2
diff options
context:
space:
mode:
authorThales Fragoso <[email protected]>2021-06-13 08:02:38 -0300
committerDario Nieuwenhuis <[email protected]>2021-06-16 16:48:35 +0200
commitffc19a54d6bebdf90d8bd2a4d42334b36b6d22ee (patch)
treec5ed753e81632be240dbb04b5fe047499daa5416 /embassy-stm32/src/eth/v2
parent6daa55a897ec886f34ceb9e7e7026c44c109989b (diff)
eth-v2: Fix bug in Rx descriptors and add docs art
Diffstat (limited to 'embassy-stm32/src/eth/v2')
-rw-r--r--embassy-stm32/src/eth/v2/descriptors.rs75
1 files changed, 50 insertions, 25 deletions
diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs
index 4ce90d1b5..23b11857c 100644
--- a/embassy-stm32/src/eth/v2/descriptors.rs
+++ b/embassy-stm32/src/eth/v2/descriptors.rs
@@ -230,11 +230,34 @@ impl RDes {
230 } 230 }
231} 231}
232 232
233/// Rx ring of descriptors and packets
234///
235/// This ring has three major locations that work in lock-step. The DMA will never write to the tail
236/// index, so the `read_index` must never pass the tail index. The `next_tail_index` is always 1
237/// slot ahead of the real tail index, and it must never pass the `read_index` or it could overwrite
238/// a packet still to be passed to the application.
239///
240/// nt can't pass r (no alloc)
241/// +---+---+---+---+ Read ok +---+---+---+---+ No Read +---+---+---+---+
242/// | | | | | ------------> | | | | | ------------> | | | | |
243/// +---+---+---+---+ Allocation ok +---+---+---+---+ +---+---+---+---+
244/// ^ ^t ^t ^ ^t ^
245/// |r |r |r
246/// |nt |nt |nt
247///
248///
249/// +---+---+---+---+ Read ok +---+---+---+---+ Can't read +---+---+---+---+
250/// | | | | | ------------> | | | | | ------------> | | | | |
251/// +---+---+---+---+ Allocation fail +---+---+---+---+ Allocation ok +---+---+---+---+
252/// ^ ^t ^ ^t ^ ^ ^ ^t
253/// |r | |r | | |r
254/// |nt |nt |nt
255///
233pub(crate) struct RDesRing<const N: usize> { 256pub(crate) struct RDesRing<const N: usize> {
234 rd: [RDes; N], 257 rd: [RDes; N],
235 buffers: [Option<PacketBox>; N], 258 buffers: [Option<PacketBox>; N],
236 read_idx: usize, 259 read_idx: usize,
237 tail_idx: usize, 260 next_tail_idx: usize,
238} 261}
239 262
240impl<const N: usize> RDesRing<N> { 263impl<const N: usize> RDesRing<N> {
@@ -246,7 +269,7 @@ impl<const N: usize> RDesRing<N> {
246 rd: [RDES; N], 269 rd: [RDES; N],
247 buffers: [BUFFERS; N], 270 buffers: [BUFFERS; N],
248 read_idx: 0, 271 read_idx: 0,
249 tail_idx: 0, 272 next_tail_idx: 0,
250 } 273 }
251 } 274 }
252 275
@@ -274,7 +297,7 @@ impl<const N: usize> RDesRing<N> {
274 self.rd[index].set_ready(addr); 297 self.rd[index].set_ready(addr);
275 last_index = index; 298 last_index = index;
276 } 299 }
277 self.tail_idx = (last_index + 1) % N; 300 self.next_tail_idx = (last_index + 1) % N;
278 301
279 unsafe { 302 unsafe {
280 let dma = ETH.ethernet_dma(); 303 let dma = ETH.ethernet_dma();
@@ -294,7 +317,9 @@ impl<const N: usize> RDesRing<N> {
294 } 317 }
295 318
296 pub(crate) fn on_interrupt(&mut self) { 319 pub(crate) fn on_interrupt(&mut self) {
297 // TODO! 320 // XXX: Do we need to do anything here ? Maybe we should try to advance the tail ptr, but it
321 // would soon hit the read ptr anyway, and we will wake smoltcp's stack on the interrupt
322 // which should try to pop a packet...
298 } 323 }
299 324
300 pub(crate) fn pop_packet(&mut self) -> Option<PacketBuf> { 325 pub(crate) fn pop_packet(&mut self) -> Option<PacketBuf> {
@@ -304,12 +329,9 @@ impl<const N: usize> RDesRing<N> {
304 fence(Ordering::SeqCst); 329 fence(Ordering::SeqCst);
305 330
306 let read_available = self.rd[self.read_idx].available(); 331 let read_available = self.rd[self.read_idx].available();
307 if !read_available && self.read_idx == self.tail_idx { 332 let tail_index = (self.next_tail_idx + N - 1) % N;
308 // Nothing to do
309 return None;
310 }
311 333
312 let pkt = if read_available { 334 let pkt = if read_available && self.read_idx != tail_index {
313 let pkt = self.buffers[self.read_idx].take(); 335 let pkt = self.buffers[self.read_idx].take();
314 let len = (self.rd[self.read_idx].rdes3.get() & EMAC_RDES3_PKTLEN) as usize; 336 let len = (self.rd[self.read_idx].rdes3.get() & EMAC_RDES3_PKTLEN) as usize;
315 337
@@ -326,25 +348,28 @@ impl<const N: usize> RDesRing<N> {
326 None 348 None
327 }; 349 };
328 350
329 match PacketBox::new(Packet::new()) { 351 // Try to advance the tail_idx
330 Some(b) => { 352 if self.next_tail_idx != self.read_idx {
331 let addr = b.as_ptr() as u32; 353 match PacketBox::new(Packet::new()) {
332 self.buffers[self.tail_idx].replace(b); 354 Some(b) => {
333 self.rd[self.tail_idx].set_ready(addr); 355 let addr = b.as_ptr() as u32;
334 356 self.buffers[self.next_tail_idx].replace(b);
335 // "Preceding reads and writes cannot be moved past subsequent writes." 357 self.rd[self.next_tail_idx].set_ready(addr);
336 fence(Ordering::Release); 358
359 // "Preceding reads and writes cannot be moved past subsequent writes."
360 fence(Ordering::Release);
361
362 // NOTE(unsafe) atomic write
363 unsafe {
364 ETH.ethernet_dma()
365 .dmacrx_dtpr()
366 .write(|w| w.0 = &self.rd[self.next_tail_idx] as *const _ as u32);
367 }
337 368
338 // NOTE(unsafe) atomic write 369 self.next_tail_idx = (self.next_tail_idx + 1) % N;
339 unsafe {
340 ETH.ethernet_dma()
341 .dmacrx_dtpr()
342 .write(|w| w.0 = &self.rd[self.tail_idx] as *const _ as u32);
343 } 370 }
344 371 None => {}
345 self.tail_idx = (self.tail_idx + 1) % N;
346 } 372 }
347 None => {}
348 } 373 }
349 pkt 374 pkt
350 } 375 }