diff options
| author | Thales Fragoso <[email protected]> | 2021-06-13 08:02:38 -0300 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-06-16 16:48:35 +0200 |
| commit | ffc19a54d6bebdf90d8bd2a4d42334b36b6d22ee (patch) | |
| tree | c5ed753e81632be240dbb04b5fe047499daa5416 /embassy-stm32/src/eth/v2/descriptors.rs | |
| parent | 6daa55a897ec886f34ceb9e7e7026c44c109989b (diff) | |
eth-v2: Fix bug in Rx descriptors and add docs art
Diffstat (limited to 'embassy-stm32/src/eth/v2/descriptors.rs')
| -rw-r--r-- | embassy-stm32/src/eth/v2/descriptors.rs | 75 |
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 | /// | ||
| 233 | pub(crate) struct RDesRing<const N: usize> { | 256 | pub(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 | ||
| 240 | impl<const N: usize> RDesRing<N> { | 263 | impl<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 | } |
