1use core::mem::{align_of, offset_of, size_of};
13use core::sync::atomic::{fence, AtomicU32, Ordering};
14
15pub static RX_RUNT_FRAMES_TOTAL: AtomicU32 = AtomicU32::new(0);
17pub static RX_OVERSIZED_FRAMES_TOTAL: AtomicU32 = AtomicU32::new(0);
19pub static RX_ERROR_FRAMES_TOTAL: AtomicU32 = AtomicU32::new(0);
21pub static RX_LAST_FRAME_LEN: AtomicU32 = AtomicU32::new(0);
23pub static RX_LAST_RDES0: AtomicU32 = AtomicU32::new(0);
25pub static RX_LARGE_FRAMES: AtomicU32 = AtomicU32::new(0);
27
28use vcell::VolatileCell;
29
30use crate::dma::Dma;
31#[cfg(test)]
32use crate::regs;
33
34pub const TX_DESC_COUNT: usize = 8;
36pub const RX_DESC_COUNT: usize = 8;
38pub const BUF_SIZE: usize = 1536;
40pub const MIN_RX_FRAME_SIZE: usize = 64;
42
43pub const TDES0_OWN: u32 = 1 << 31;
45pub const TDES0_IC: u32 = 1 << 30;
47pub const TDES0_LS: u32 = 1 << 29;
49pub const TDES0_FS: u32 = 1 << 28;
51pub const TDES0_CHAINED: u32 = 1 << 20;
53
54pub const RDES0_OWN: u32 = 1 << 31;
56pub const RDES0_FL_SHIFT: u32 = 16;
58pub const RDES0_FL_MASK: u32 = 0x3fff << RDES0_FL_SHIFT;
60pub const RDES0_ES: u32 = 1 << 15;
62pub const RDES0_FS: u32 = 1 << 9;
64pub const RDES0_LS: u32 = 1 << 8;
66
67pub const RDES1_BUF1_SIZE_MASK: u32 = 0x1fff;
69pub const RDES1_CHAINED: u32 = 1 << 14;
71
72#[derive(Clone, Copy, Debug, Eq, PartialEq)]
74pub enum OwnedBy {
75 Cpu,
77 Dma,
79}
80
81#[derive(Clone, Copy, Debug, Eq, PartialEq)]
83pub enum BufferTooLarge {
84 Frame { len: usize, max: usize },
86}
87
88#[derive(Clone, Copy, Debug, Eq, PartialEq)]
90pub enum DescriptorError {
91 BufferTooLarge(BufferTooLarge),
93 RingFull,
95 NoFrame,
97}
98
99#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
101pub struct TxRingStats {
102 pub transmitted_frames: u32,
104 pub ring_full_events: u32,
106}
107
108#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
110pub struct RxRingStats {
111 pub received_frames: u32,
113 pub error_frames: u32,
115 pub runt_frames: u32,
117 pub oversized_frames: u32,
119 pub overflow_resets: u32,
121}
122
123pub const DMA_DESCRIPTOR_WORDS_SIZE: usize = 16;
125pub const DMA_DESCRIPTOR_ALIGN: usize = 128;
128
129#[repr(C, align(128))]
131pub struct DmaBuffers<const N: usize> {
132 pub inner: [[u8; BUF_SIZE]; N],
134}
135
136impl<const N: usize> DmaBuffers<N> {
137 pub const ZERO: Self = Self {
139 inner: [[0; BUF_SIZE]; N],
140 };
141}
142
143pub type SplitDmaResources<'a> = (
145 &'a mut [TDes; TX_DESC_COUNT],
146 &'a mut [RDes; RX_DESC_COUNT],
147 &'a mut [[u8; BUF_SIZE]; TX_DESC_COUNT],
148 &'a mut [[u8; BUF_SIZE]; RX_DESC_COUNT],
149);
150
151pub struct StaticDmaResources {
153 tx_desc: [TDes; TX_DESC_COUNT],
154 rx_desc: [RDes; RX_DESC_COUNT],
155 tx_buf: DmaBuffers<TX_DESC_COUNT>,
156 rx_buf: DmaBuffers<RX_DESC_COUNT>,
157}
158
159impl StaticDmaResources {
160 pub const fn new() -> Self {
162 Self {
163 tx_desc: zeroed_tx_desc_array(),
164 rx_desc: zeroed_rx_desc_array(),
165 tx_buf: DmaBuffers::ZERO,
166 rx_buf: DmaBuffers::ZERO,
167 }
168 }
169
170 pub fn split(&mut self) -> SplitDmaResources<'_> {
172 (
173 &mut self.tx_desc,
174 &mut self.rx_desc,
175 &mut self.tx_buf.inner,
176 &mut self.rx_buf.inner,
177 )
178 }
179}
180
181impl Default for StaticDmaResources {
182 fn default() -> Self {
183 Self::new()
184 }
185}
186
187#[repr(C, align(128))]
189pub struct TDes {
190 tdes0: VolatileCell<u32>,
191 tdes1: VolatileCell<u32>,
192 buf_addr: VolatileCell<u32>,
193 next_desc: VolatileCell<u32>,
194}
195
196const _: [(); DMA_DESCRIPTOR_ALIGN] = [(); size_of::<TDes>()];
197const _: [(); DMA_DESCRIPTOR_ALIGN] = [(); align_of::<TDes>()];
198const _: [(); 0] = [(); offset_of!(TDes, tdes0)];
199const _: [(); 4] = [(); offset_of!(TDes, tdes1)];
200const _: [(); 8] = [(); offset_of!(TDes, buf_addr)];
201const _: [(); 12] = [(); offset_of!(TDes, next_desc)];
202
203impl TDes {
204 pub const fn new_zeroed() -> Self {
206 Self {
207 tdes0: VolatileCell::new(0),
208 tdes1: VolatileCell::new(0),
209 buf_addr: VolatileCell::new(0),
210 next_desc: VolatileCell::new(0),
211 }
212 }
213
214 pub fn set_owned_by(&self, owner: OwnedBy) {
216 let value = match owner {
217 OwnedBy::Cpu => self.tdes0.get() & !TDES0_OWN,
218 OwnedBy::Dma => self.tdes0.get() | TDES0_OWN,
219 };
220 self.tdes0.set(value);
221 }
222
223 pub fn owned_by(&self) -> OwnedBy {
225 if self.tdes0.get() & TDES0_OWN != 0 {
226 OwnedBy::Dma
227 } else {
228 OwnedBy::Cpu
229 }
230 }
231
232 fn set_len_and_flags(&self, len: usize) {
233 self.tdes1.set((len as u32) & RDES1_BUF1_SIZE_MASK);
234 self.tdes0
235 .set((self.tdes0.get() & TDES0_CHAINED) | TDES0_FS | TDES0_LS | TDES0_IC);
236 }
237
238 fn set_chained(&self) {
239 self.tdes0.set(self.tdes0.get() | TDES0_CHAINED);
240 }
241
242 fn set_buffer_addr(&self, addr: *const u8) {
243 self.buf_addr.set(addr as usize as u32);
244 }
245
246 fn set_next_desc(&self, addr: *const TDes) {
247 self.next_desc.set(addr as usize as u32);
248 }
249}
250
251#[cfg(target_arch = "riscv32")]
254pub static CPU_DESC0_SNAPSHOT: [core::sync::atomic::AtomicU32; 4] = [
255 core::sync::atomic::AtomicU32::new(0),
256 core::sync::atomic::AtomicU32::new(0),
257 core::sync::atomic::AtomicU32::new(0),
258 core::sync::atomic::AtomicU32::new(0),
259];
260
261#[cfg(target_arch = "riscv32")]
263pub static TX_LAST_DESC_ADDR: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
264#[cfg(target_arch = "riscv32")]
266pub static TX_LAST_BUF_ADDR: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
267#[cfg(target_arch = "riscv32")]
269pub static TX_LAST_TDES0: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
270#[cfg(target_arch = "riscv32")]
272pub static TX_LAST_TDES1: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
273
274#[repr(C, align(128))]
276pub struct RDes {
277 rdes0: VolatileCell<u32>,
278 rdes1: VolatileCell<u32>,
279 buf_addr: VolatileCell<u32>,
280 next_desc: VolatileCell<u32>,
281}
282
283const _: [(); DMA_DESCRIPTOR_ALIGN] = [(); size_of::<RDes>()];
284const _: [(); DMA_DESCRIPTOR_ALIGN] = [(); align_of::<RDes>()];
285const _: [(); 0] = [(); offset_of!(RDes, rdes0)];
286const _: [(); 4] = [(); offset_of!(RDes, rdes1)];
287const _: [(); 8] = [(); offset_of!(RDes, buf_addr)];
288const _: [(); 12] = [(); offset_of!(RDes, next_desc)];
289
290const _: [(); DMA_DESCRIPTOR_ALIGN] = [(); align_of::<DmaBuffers<TX_DESC_COUNT>>()];
291const _: [(); DMA_DESCRIPTOR_ALIGN] = [(); align_of::<DmaBuffers<RX_DESC_COUNT>>()];
292const _: [(); DMA_DESCRIPTOR_ALIGN] = [(); align_of::<StaticDmaResources>()];
293
294impl RDes {
295 pub const fn new_zeroed() -> Self {
297 Self {
298 rdes0: VolatileCell::new(0),
299 rdes1: VolatileCell::new(0),
300 buf_addr: VolatileCell::new(0),
301 next_desc: VolatileCell::new(0),
302 }
303 }
304
305 pub fn set_owned_by(&self, owner: OwnedBy) {
307 let value = match owner {
308 OwnedBy::Cpu => self.rdes0.get() & !RDES0_OWN,
309 OwnedBy::Dma => self.rdes0.get() | RDES0_OWN,
310 };
311 self.rdes0.set(value);
312 }
313
314 pub fn owned_by(&self) -> OwnedBy {
316 if self.rdes0.get() & RDES0_OWN != 0 {
317 OwnedBy::Dma
318 } else {
319 OwnedBy::Cpu
320 }
321 }
322
323 pub fn frame_len(&self) -> usize {
325 ((self.rdes0.get() & RDES0_FL_MASK) >> RDES0_FL_SHIFT) as usize
326 }
327
328 pub fn is_complete_frame(&self) -> bool {
330 let status = self.rdes0.get();
331 status & RDES0_FS != 0 && status & RDES0_LS != 0
332 }
333
334 fn set_buffer_addr(&self, addr: *const u8) {
335 self.buf_addr.set(addr as usize as u32);
336 }
337
338 fn set_next_desc(&self, addr: *const RDes) {
339 self.next_desc.set(addr as usize as u32);
340 }
341
342 fn configure_buffer(&self, len: usize) {
343 self.rdes1
344 .set(((len as u32) & RDES1_BUF1_SIZE_MASK) | RDES1_CHAINED);
345 }
346}
347
348const fn zeroed_tx_desc_array() -> [TDes; TX_DESC_COUNT] {
349 [const { TDes::new_zeroed() }; TX_DESC_COUNT]
350}
351
352const fn zeroed_rx_desc_array() -> [RDes; RX_DESC_COUNT] {
353 [const { RDes::new_zeroed() }; RX_DESC_COUNT]
354}
355
356pub fn zeroed_tx_descriptors() -> [TDes; TX_DESC_COUNT] {
358 zeroed_tx_desc_array()
359}
360
361pub fn zeroed_rx_descriptors() -> [RDes; RX_DESC_COUNT] {
363 zeroed_rx_desc_array()
364}
365
366pub struct TDesRing<'a> {
368 descriptors: &'a mut [TDes],
369 buffers: &'a mut [[u8; BUF_SIZE]],
370 index: usize,
371 stats: TxRingStats,
372}
373
374impl<'a> TDesRing<'a> {
375 pub fn new(descriptors: &'a mut [TDes], buffers: &'a mut [[u8; BUF_SIZE]]) -> Self {
377 assert!(
378 !descriptors.is_empty(),
379 "TX descriptor ring must not be empty"
380 );
381 assert_eq!(
382 descriptors.len(),
383 buffers.len(),
384 "TX descriptors and buffers must have identical lengths"
385 );
386
387 let mut ring = Self {
388 descriptors,
389 buffers,
390 index: 0,
391 stats: TxRingStats::default(),
392 };
393 ring.reset();
394 ring
395 }
396
397 pub fn reset(&mut self) {
416 let desc_len = self.descriptors.len();
417 for i in 0..desc_len {
418 let desc = &self.descriptors[i];
419 desc.tdes0.set(0);
420 desc.tdes1.set(0);
421 desc.set_chained();
422 desc.set_buffer_addr(self.buffers[i].as_ptr());
423 let next = if i + 1 == desc_len {
424 &self.descriptors[0]
425 } else {
426 &self.descriptors[i + 1]
427 };
428 desc.set_next_desc(next as *const TDes);
429 desc.set_owned_by(OwnedBy::Cpu);
430 }
431 self.index = 0;
432 }
433
434 pub fn flush_all(&self) {
439 for desc in self.descriptors.iter() {
440 Dma::flush_descriptor(desc);
441 }
442 }
443
444 pub fn descriptors_ptr(&self) -> *const TDes {
446 self.descriptors.as_ptr()
447 }
448
449 pub fn transmit(&mut self, frame: &[u8]) -> Result<(), DescriptorError> {
451 if frame.len() > BUF_SIZE {
452 return Err(DescriptorError::BufferTooLarge(BufferTooLarge::Frame {
453 len: frame.len(),
454 max: BUF_SIZE,
455 }));
456 }
457
458 let desc = &self.descriptors[self.index];
459 Dma::invalidate_descriptor(desc);
460 if desc.owned_by() != OwnedBy::Cpu {
461 self.stats.ring_full_events = self.stats.ring_full_events.saturating_add(1);
462 return Err(DescriptorError::RingFull);
463 }
464
465 self.buffers[self.index][..frame.len()].copy_from_slice(frame);
466 desc.set_len_and_flags(frame.len());
467 Dma::flush_buffer(&self.buffers[self.index]);
468 Dma::flush_descriptor(desc);
469 fence(Ordering::Release);
470 desc.set_owned_by(OwnedBy::Dma);
471 Dma::flush_descriptor(desc);
472 Dma::demand_tx_poll();
473
474 #[cfg(target_arch = "riscv32")]
476 {
477 use core::sync::atomic::Ordering::Relaxed;
478 TX_LAST_DESC_ADDR
479 .store(desc as *const _ as usize as u32, Relaxed);
480 TX_LAST_BUF_ADDR
481 .store(self.buffers[self.index].as_ptr() as usize as u32, Relaxed);
482 TX_LAST_TDES0.store(desc.tdes0.get(), Relaxed);
483 TX_LAST_TDES1.store(desc.tdes1.get(), Relaxed);
484 }
485
486 self.index = (self.index + 1) % self.descriptors.len();
487 self.stats.transmitted_frames = self.stats.transmitted_frames.saturating_add(1);
488 Ok(())
489 }
490
491 pub fn has_capacity(&self) -> bool {
493 let desc = &self.descriptors[self.index];
494 Dma::invalidate_descriptor(desc);
495 desc.owned_by() == OwnedBy::Cpu
496 }
497
498 pub fn stats(&self) -> TxRingStats {
500 self.stats
501 }
502
503 #[cfg(any(test, feature = "fuzzing"))]
505 #[doc(hidden)]
506 pub fn fuzz_current_index(&self) -> usize {
507 self.index
508 }
509}
510
511pub struct RDesRing<'a> {
513 descriptors: &'a mut [RDes],
514 buffers: &'a mut [[u8; BUF_SIZE]],
515 index: usize,
516 stats: RxRingStats,
517}
518
519impl<'a> RDesRing<'a> {
520 pub fn new(descriptors: &'a mut [RDes], buffers: &'a mut [[u8; BUF_SIZE]]) -> Self {
522 assert!(
523 !descriptors.is_empty(),
524 "RX descriptor ring must not be empty"
525 );
526 assert_eq!(
527 descriptors.len(),
528 buffers.len(),
529 "RX descriptors and buffers must have identical lengths"
530 );
531
532 let mut ring = Self {
533 descriptors,
534 buffers,
535 index: 0,
536 stats: RxRingStats::default(),
537 };
538 ring.reset();
539 ring
540 }
541
542 pub fn reset(&mut self) {
550 let desc_len = self.descriptors.len();
551 for i in 0..desc_len {
552 let desc = &self.descriptors[i];
553 desc.rdes0.set(0);
554 desc.configure_buffer(BUF_SIZE);
555 desc.set_buffer_addr(self.buffers[i].as_ptr());
556 let next = if i + 1 == desc_len {
557 &self.descriptors[0]
558 } else {
559 &self.descriptors[i + 1]
560 };
561 desc.set_next_desc(next as *const RDes);
562 desc.set_owned_by(OwnedBy::Dma);
563 }
564 self.index = 0;
565
566 #[cfg(target_arch = "riscv32")]
570 {
571 let d = &self.descriptors[0];
572 CPU_DESC0_SNAPSHOT[0].store(d.rdes0.get(), core::sync::atomic::Ordering::Relaxed);
573 CPU_DESC0_SNAPSHOT[1].store(d.rdes1.get(), core::sync::atomic::Ordering::Relaxed);
574 CPU_DESC0_SNAPSHOT[2].store(d.buf_addr.get(), core::sync::atomic::Ordering::Relaxed);
575 CPU_DESC0_SNAPSHOT[3].store(d.next_desc.get(), core::sync::atomic::Ordering::Relaxed);
576 }
577 }
578
579 pub fn descriptors_ptr(&self) -> *const RDes {
581 self.descriptors.as_ptr()
582 }
583
584 pub fn flush_all(&self) {
587 for desc in self.descriptors.iter() {
588 Dma::flush_descriptor(desc);
589 }
590 }
591
592 pub fn receive(&mut self) -> Option<(usize, &[u8])> {
594 let desc = &self.descriptors[self.index];
595 Dma::invalidate_descriptor(desc);
596 if desc.owned_by() != OwnedBy::Cpu {
597 return None;
598 }
599
600 let status = desc.rdes0.get();
601 RX_LAST_RDES0.store(status, Ordering::Relaxed);
602 if status & RDES0_ES != 0 || !desc.is_complete_frame() {
603 self.stats.error_frames = self.stats.error_frames.saturating_add(1);
604 RX_ERROR_FRAMES_TOTAL.fetch_add(1, Ordering::Relaxed);
605 self.recycle_current();
606 return None;
607 }
608
609 let len = desc.frame_len();
610 if len != 0 && len < MIN_RX_FRAME_SIZE {
611 self.stats.runt_frames = self.stats.runt_frames.saturating_add(1);
612 RX_RUNT_FRAMES_TOTAL.fetch_add(1, Ordering::Relaxed);
613 self.recycle_current();
614 return None;
615 }
616
617 if len > BUF_SIZE {
618 self.stats.oversized_frames = self.stats.oversized_frames.saturating_add(1);
619 RX_OVERSIZED_FRAMES_TOTAL.fetch_add(1, Ordering::Relaxed);
620 self.recycle_current();
621 return None;
622 }
623
624 Dma::invalidate_buffer_prefix(&self.buffers[self.index], len);
625 fence(Ordering::Acquire);
626 self.stats.received_frames = self.stats.received_frames.saturating_add(1);
627 RX_LAST_FRAME_LEN.store(len as u32, Ordering::Relaxed);
628 if len >= 200 {
629 RX_LARGE_FRAMES.fetch_add(1, Ordering::Relaxed);
630 }
631 Some((len, &self.buffers[self.index][..len]))
632 }
633
634 pub fn pop(&mut self) {
636 self.recycle_current();
637 }
638
639 fn recycle_current(&mut self) {
640 let desc = &self.descriptors[self.index];
641 desc.rdes0.set(RDES0_OWN);
642 Dma::flush_descriptor(desc);
643 self.index = (self.index + 1) % self.descriptors.len();
644 }
645
646 pub fn has_packet(&self) -> bool {
648 let desc = &self.descriptors[self.index];
649 Dma::invalidate_descriptor(desc);
650 desc.owned_by() == OwnedBy::Cpu
651 }
652
653 pub fn handle_overflow(&mut self) {
655 self.stats.overflow_resets = self.stats.overflow_resets.saturating_add(1);
656 self.reset();
657 Dma::demand_rx_poll();
658 }
659
660 pub fn stats(&self) -> RxRingStats {
662 self.stats
663 }
664
665 #[cfg(any(test, feature = "fuzzing"))]
667 #[doc(hidden)]
668 pub fn fuzz_seed_current(&mut self, status: u32, owner: OwnedBy, payload: &[u8]) {
669 let index = self.index;
670 let used = payload.len().min(BUF_SIZE);
671 self.buffers[index][..used].copy_from_slice(&payload[..used]);
672 self.descriptors[index].rdes0.set(status);
673 self.descriptors[index].set_owned_by(owner);
674 }
675
676 #[cfg(any(test, feature = "fuzzing"))]
678 #[doc(hidden)]
679 pub fn fuzz_current_index(&self) -> usize {
680 self.index
681 }
682}
683
684#[cfg(test)]
685mod tests {
686 use super::*;
687
688 const STRESS_ITERATIONS: usize = 10_000;
689 const FUZZ_ITERATIONS: usize = 4_096;
690
691 fn tx_fixture() -> ([TDes; TX_DESC_COUNT], [[u8; BUF_SIZE]; TX_DESC_COUNT]) {
692 (zeroed_tx_descriptors(), [[0; BUF_SIZE]; TX_DESC_COUNT])
693 }
694
695 fn rx_fixture() -> ([RDes; RX_DESC_COUNT], [[u8; BUF_SIZE]; RX_DESC_COUNT]) {
696 (zeroed_rx_descriptors(), [[0; BUF_SIZE]; RX_DESC_COUNT])
697 }
698
699 fn advance_lcg(state: &mut u32) -> u32 {
700 *state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
701 *state
702 }
703
704 #[test]
705 fn tx_reset_builds_closed_ring() {
706 let (mut descriptors, mut buffers) = tx_fixture();
707 let ring = TDesRing::new(&mut descriptors, &mut buffers);
708
709 assert_eq!(ring.index, 0);
710 assert_eq!(
711 ring.descriptors[0].next_desc.get(),
712 (&ring.descriptors[1] as *const TDes as usize) as u32
713 );
714 assert_eq!(
715 ring.descriptors[TX_DESC_COUNT - 1].next_desc.get(),
716 (&ring.descriptors[0] as *const TDes as usize) as u32
717 );
718 assert_eq!(ring.descriptors[0].owned_by(), OwnedBy::Cpu);
719 }
720
721 #[test]
722 fn tx_transmit_copies_payload_and_advances() {
723 let (mut descriptors, mut buffers) = tx_fixture();
724 let mut ring = TDesRing::new(&mut descriptors, &mut buffers);
725 let payload = [0xAB; 64];
726
727 ring.transmit(&payload).unwrap();
728
729 assert_eq!(&ring.buffers[0][..payload.len()], &payload);
730 assert_eq!(ring.descriptors[0].owned_by(), OwnedBy::Dma);
731 assert_eq!(ring.index, 1);
732 assert_eq!(
733 ring.descriptors[0].tdes0.get(),
734 TDES0_OWN | TDES0_FS | TDES0_LS | TDES0_IC | TDES0_CHAINED
735 );
736 assert_eq!(ring.descriptors[0].tdes1.get(), payload.len() as u32);
737 }
738
739 #[test]
740 fn tx_transmit_keeps_descriptor_chained() {
741 let (mut descriptors, mut buffers) = tx_fixture();
742 let mut ring = TDesRing::new(&mut descriptors, &mut buffers);
743
744 ring.transmit(&[0xAB; 64]).unwrap();
745
746 assert_ne!(ring.descriptors[0].tdes0.get() & TDES0_CHAINED, 0);
747 }
748
749 #[test]
750 fn tx_transmit_fails_when_ring_is_full() {
751 let (mut descriptors, mut buffers) = tx_fixture();
752 let mut ring = TDesRing::new(&mut descriptors, &mut buffers);
753
754 for descriptor in ring.descriptors.iter() {
755 descriptor.set_owned_by(OwnedBy::Dma);
756 }
757
758 let err = ring.transmit(&[1, 2, 3]).unwrap_err();
759 assert_eq!(err, DescriptorError::RingFull);
760 assert_eq!(ring.stats().ring_full_events, 1);
761 }
762
763 #[test]
764 fn tx_transmit_rejects_oversized_frame_without_touching_ring() {
765 let (mut descriptors, mut buffers) = tx_fixture();
766 let mut ring = TDesRing::new(&mut descriptors, &mut buffers);
767 let payload = [0xA5; BUF_SIZE + 1];
768
769 let err = ring.transmit(&payload).unwrap_err();
770
771 assert_eq!(
772 err,
773 DescriptorError::BufferTooLarge(BufferTooLarge::Frame {
774 len: BUF_SIZE + 1,
775 max: BUF_SIZE,
776 })
777 );
778 assert_eq!(ring.index, 0);
779 assert_eq!(ring.descriptors[0].owned_by(), OwnedBy::Cpu);
780 assert_eq!(ring.stats(), TxRingStats::default());
781 assert!(ring.buffers[0].iter().all(|byte| *byte == 0));
782 }
783
784 #[test]
785 fn tx_ring_full_does_not_advance_or_copy_payload() {
786 let (mut descriptors, mut buffers) = tx_fixture();
787 let mut ring = TDesRing::new(&mut descriptors, &mut buffers);
788
789 ring.descriptors[0].set_owned_by(OwnedBy::Dma);
790
791 assert_eq!(ring.transmit(&[0x5A; 64]), Err(DescriptorError::RingFull));
792 assert_eq!(ring.index, 0);
793 assert!(ring.buffers[0][..64].iter().all(|byte| *byte == 0));
794 assert_eq!(ring.stats().transmitted_frames, 0);
795 }
796
797 #[test]
798 fn tx_has_capacity_tracks_current_descriptor_owner() {
799 let (mut descriptors, mut buffers) = tx_fixture();
800 let ring = TDesRing::new(&mut descriptors, &mut buffers);
801
802 assert!(ring.has_capacity());
803
804 ring.descriptors[0].set_owned_by(OwnedBy::Dma);
805 assert!(!ring.has_capacity());
806
807 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
808 assert!(ring.has_capacity());
809 }
810
811 #[test]
812 fn tx_transmit_wraps_index_after_last_descriptor() {
813 let (mut descriptors, mut buffers) = tx_fixture();
814 let mut ring = TDesRing::new(&mut descriptors, &mut buffers);
815
816 for expected_index in 0..TX_DESC_COUNT {
817 ring.descriptors[expected_index].set_owned_by(OwnedBy::Cpu);
818 ring.transmit(&[expected_index as u8]).unwrap();
819 }
820
821 assert_eq!(ring.index, 0);
822 }
823
824 #[test]
825 fn tx_transmit_accepts_min_and_max_frame_sizes() {
826 let (mut descriptors, mut buffers) = tx_fixture();
827 let mut ring = TDesRing::new(&mut descriptors, &mut buffers);
828
829 ring.transmit(&[]).unwrap();
830 ring.descriptors[1].set_owned_by(OwnedBy::Cpu);
831
832 let payload = [0x5A; BUF_SIZE];
833 ring.transmit(&payload).unwrap();
834
835 assert_eq!(ring.descriptors[0].tdes1.get(), 0);
836 assert_eq!(ring.descriptors[1].tdes1.get(), BUF_SIZE as u32);
837 assert_eq!(&ring.buffers[1], &payload);
838 assert_eq!(ring.stats().transmitted_frames, 2);
839 }
840
841 #[test]
842 fn tx_transmit_recovers_after_descriptor_returns_to_cpu() {
843 let (mut descriptors, mut buffers) = tx_fixture();
844 let mut ring = TDesRing::new(&mut descriptors, &mut buffers);
845
846 for descriptor in ring.descriptors.iter() {
847 descriptor.set_owned_by(OwnedBy::Dma);
848 }
849
850 assert_eq!(ring.transmit(&[0xA5; 64]), Err(DescriptorError::RingFull));
851
852 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
853 ring.transmit(&[0x5A; 64]).unwrap();
854
855 assert_eq!(ring.index, 1);
856 assert_eq!(ring.stats().ring_full_events, 1);
857 assert_eq!(ring.stats().transmitted_frames, 1);
858 }
859
860 #[test]
861 fn tx_transmit_survives_ten_thousand_cycles() {
862 let (mut descriptors, mut buffers) = tx_fixture();
863 let mut ring = TDesRing::new(&mut descriptors, &mut buffers);
864 let mut payload = [0u8; BUF_SIZE];
865
866 for cycle in 0..STRESS_ITERATIONS {
867 let slot = ring.index;
868 let len = if cycle % 17 == 0 {
869 0
870 } else {
871 MIN_RX_FRAME_SIZE + (cycle % 257)
872 };
873
874 for (offset, byte) in payload[..len].iter_mut().enumerate() {
875 *byte = cycle.wrapping_add(offset) as u8;
876 }
877
878 ring.transmit(&payload[..len]).unwrap();
879
880 assert_eq!(ring.descriptors[slot].tdes1.get(), len as u32);
881 assert_eq!(&ring.buffers[slot][..len], &payload[..len]);
882
883 ring.descriptors[slot].set_owned_by(OwnedBy::Cpu);
884 }
885
886 assert_eq!(ring.index, STRESS_ITERATIONS % TX_DESC_COUNT);
887 assert_eq!(ring.stats().transmitted_frames, STRESS_ITERATIONS as u32);
888 assert_eq!(ring.stats().ring_full_events, 0);
889 }
890
891 #[test]
892 fn rx_receive_reads_frame_and_pop_returns_it_to_dma() {
893 let (mut descriptors, mut buffers) = rx_fixture();
894 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
895 let payload = [0x11; MIN_RX_FRAME_SIZE];
896
897 ring.buffers[0][..payload.len()].copy_from_slice(&payload);
898 ring.descriptors[0]
899 .rdes0
900 .set(RDES0_FS | RDES0_LS | ((payload.len() as u32) << RDES0_FL_SHIFT));
901 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
902
903 {
904 let (len, packet) = ring.receive().unwrap();
905 assert_eq!(len, payload.len());
906 assert_eq!(packet, &payload);
907 }
908
909 ring.pop();
910 assert_eq!(ring.descriptors[0].owned_by(), OwnedBy::Dma);
911 assert_eq!(ring.index, 1);
912 assert_eq!(ring.stats().received_frames, 1);
913 }
914
915 #[test]
916 fn rx_receive_valid_frame_waits_for_explicit_pop() {
917 let (mut descriptors, mut buffers) = rx_fixture();
918 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
919 let payload = [0x22; MIN_RX_FRAME_SIZE];
920
921 ring.buffers[0][..payload.len()].copy_from_slice(&payload);
922 ring.descriptors[0]
923 .rdes0
924 .set(RDES0_FS | RDES0_LS | ((payload.len() as u32) << RDES0_FL_SHIFT));
925 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
926
927 let (len, frame) = ring.receive().unwrap();
928
929 assert_eq!(len, payload.len());
930 assert_eq!(frame, &payload);
931 assert_eq!(ring.index, 0);
932 assert_eq!(ring.descriptors[0].owned_by(), OwnedBy::Cpu);
933 }
934
935 #[test]
936 fn rx_receive_returns_none_for_dma_owned_descriptor() {
937 let (mut descriptors, mut buffers) = rx_fixture();
938 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
939
940 assert!(ring.receive().is_none());
941 }
942
943 #[test]
944 fn rx_has_packet_tracks_current_descriptor_owner() {
945 let (mut descriptors, mut buffers) = rx_fixture();
946 let ring = RDesRing::new(&mut descriptors, &mut buffers);
947
948 assert!(!ring.has_packet());
949
950 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
951 assert!(ring.has_packet());
952
953 ring.descriptors[0].set_owned_by(OwnedBy::Dma);
954 assert!(!ring.has_packet());
955 }
956
957 #[test]
958 fn rx_receive_wraps_index_after_pop() {
959 let (mut descriptors, mut buffers) = rx_fixture();
960 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
961
962 ring.index = RX_DESC_COUNT - 1;
963 ring.descriptors[RX_DESC_COUNT - 1]
964 .rdes0
965 .set(RDES0_FS | RDES0_LS);
966 ring.descriptors[RX_DESC_COUNT - 1].set_owned_by(OwnedBy::Cpu);
967
968 let _ = ring.receive().unwrap();
969 ring.pop();
970
971 assert_eq!(ring.index, 0);
972 }
973
974 #[test]
975 fn rx_receive_skips_error_frame_and_recycles_descriptor() {
976 let (mut descriptors, mut buffers) = rx_fixture();
977 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
978
979 ring.descriptors[0]
980 .rdes0
981 .set(RDES0_ES | RDES0_FS | RDES0_LS | (32 << RDES0_FL_SHIFT));
982 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
983
984 assert!(ring.receive().is_none());
985 assert_eq!(ring.descriptors[0].owned_by(), OwnedBy::Dma);
986 assert_eq!(ring.index, 1);
987 assert_eq!(ring.stats().error_frames, 1);
988 }
989
990 #[test]
991 fn rx_receive_recycles_incomplete_frame() {
992 let (mut descriptors, mut buffers) = rx_fixture();
993 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
994
995 ring.descriptors[0]
996 .rdes0
997 .set(RDES0_FS | ((MIN_RX_FRAME_SIZE as u32) << RDES0_FL_SHIFT));
998 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
999
1000 assert!(ring.receive().is_none());
1001 assert_eq!(ring.index, 1);
1002 assert_eq!(ring.descriptors[0].owned_by(), OwnedBy::Dma);
1003 assert_eq!(ring.stats().error_frames, 1);
1004 }
1005
1006 #[test]
1007 fn rx_receive_handles_zero_length_frame() {
1008 let (mut descriptors, mut buffers) = rx_fixture();
1009 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
1010
1011 ring.descriptors[0].rdes0.set(RDES0_FS | RDES0_LS);
1012 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
1013
1014 let (len, packet) = ring.receive().unwrap();
1015 assert_eq!(len, 0);
1016 assert!(packet.is_empty());
1017 }
1018
1019 #[test]
1020 fn rx_receive_accepts_max_buffer_sized_frame() {
1021 let (mut descriptors, mut buffers) = rx_fixture();
1022 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
1023 let payload = [0x7E; BUF_SIZE];
1024
1025 ring.buffers[0].copy_from_slice(&payload);
1026 ring.descriptors[0]
1027 .rdes0
1028 .set(RDES0_FS | RDES0_LS | ((BUF_SIZE as u32) << RDES0_FL_SHIFT));
1029 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
1030
1031 let (len, packet) = ring.receive().unwrap();
1032
1033 assert_eq!(len, BUF_SIZE);
1034 assert_eq!(packet, &payload);
1035 }
1036
1037 #[test]
1038 fn rx_error_flag_takes_precedence_over_runt_classification() {
1039 let (mut descriptors, mut buffers) = rx_fixture();
1040 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
1041
1042 ring.descriptors[0].rdes0.set(
1043 RDES0_ES | RDES0_FS | RDES0_LS | (((MIN_RX_FRAME_SIZE - 1) as u32) << RDES0_FL_SHIFT),
1044 );
1045 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
1046
1047 assert!(ring.receive().is_none());
1048 assert_eq!(ring.stats().error_frames, 1);
1049 assert_eq!(ring.stats().runt_frames, 0);
1050 assert_eq!(ring.index, 1);
1051 }
1052
1053 #[test]
1054 fn rx_receive_handles_consecutive_frames() {
1055 let (mut descriptors, mut buffers) = rx_fixture();
1056 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
1057 let payload0 = [0xAA; MIN_RX_FRAME_SIZE];
1058 let payload1 = [0xCC; 96];
1059
1060 ring.buffers[0][..payload0.len()].copy_from_slice(&payload0);
1061 ring.buffers[1][..payload1.len()].copy_from_slice(&payload1);
1062 ring.descriptors[0]
1063 .rdes0
1064 .set(RDES0_FS | RDES0_LS | ((payload0.len() as u32) << RDES0_FL_SHIFT));
1065 ring.descriptors[1]
1066 .rdes0
1067 .set(RDES0_FS | RDES0_LS | ((payload1.len() as u32) << RDES0_FL_SHIFT));
1068 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
1069 ring.descriptors[1].set_owned_by(OwnedBy::Cpu);
1070
1071 let (len0, frame0) = ring.receive().unwrap();
1072 assert_eq!(len0, payload0.len());
1073 assert_eq!(frame0, &payload0);
1074 ring.pop();
1075
1076 let (len1, frame1) = ring.receive().unwrap();
1077 assert_eq!(len1, payload1.len());
1078 assert_eq!(frame1, &payload1);
1079 ring.pop();
1080
1081 assert_eq!(ring.index, 2);
1082 assert_eq!(ring.stats().received_frames, 2);
1083 }
1084
1085 #[test]
1086 fn rx_receive_drops_runt_frame_and_counts_it() {
1087 let (mut descriptors, mut buffers) = rx_fixture();
1088 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
1089
1090 ring.descriptors[0]
1091 .rdes0
1092 .set(RDES0_FS | RDES0_LS | (((MIN_RX_FRAME_SIZE - 1) as u32) << RDES0_FL_SHIFT));
1093 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
1094
1095 assert!(ring.receive().is_none());
1096 assert_eq!(ring.index, 1);
1097 assert_eq!(ring.descriptors[0].owned_by(), OwnedBy::Dma);
1098 assert_eq!(ring.stats().runt_frames, 1);
1099 }
1100
1101 #[test]
1102 fn rx_receive_drops_oversized_frame_without_touching_buffer() {
1103 let (mut descriptors, mut buffers) = rx_fixture();
1104 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
1105
1106 ring.descriptors[0]
1107 .rdes0
1108 .set(RDES0_FS | RDES0_LS | (((BUF_SIZE + 1) as u32) << RDES0_FL_SHIFT));
1109 ring.descriptors[0].set_owned_by(OwnedBy::Cpu);
1110
1111 assert!(ring.receive().is_none());
1112 assert_eq!(ring.index, 1);
1113 assert_eq!(ring.descriptors[0].owned_by(), OwnedBy::Dma);
1114 assert_eq!(ring.stats().oversized_frames, 1);
1115 }
1116
1117 #[test]
1118 fn rx_handle_overflow_rebuilds_ring_and_restarts_from_zero() {
1119 let (mut descriptors, mut buffers) = rx_fixture();
1120 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
1121
1122 ring.index = 2;
1123 ring.descriptors[2].set_owned_by(OwnedBy::Cpu);
1124 ring.descriptors[2].rdes0.set(0);
1125
1126 ring.handle_overflow();
1127
1128 assert_eq!(ring.index, 0);
1129 assert_eq!(ring.stats().overflow_resets, 1);
1130 for descriptor in ring.descriptors.iter() {
1131 assert_eq!(descriptor.owned_by(), OwnedBy::Dma);
1132 assert_eq!(
1133 descriptor.rdes1.get() & RDES1_BUF1_SIZE_MASK,
1134 BUF_SIZE as u32
1135 );
1136 assert_ne!(descriptor.rdes1.get() & RDES1_CHAINED, 0);
1137 }
1138 }
1139
1140 #[test]
1141 fn rx_handle_overflow_preserves_ring_invariants_under_repetition() {
1142 let (mut descriptors, mut buffers) = rx_fixture();
1143 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
1144 let mut rng = 0x51F1_AA77u32;
1145
1146 for expected_resets in 1..=FUZZ_ITERATIONS {
1147 let random = advance_lcg(&mut rng) as usize;
1148 ring.index = random % RX_DESC_COUNT;
1149
1150 for (slot, descriptor) in ring.descriptors.iter().enumerate() {
1151 descriptor.set_owned_by(if (random + slot) & 1 == 0 {
1152 OwnedBy::Cpu
1153 } else {
1154 OwnedBy::Dma
1155 });
1156 descriptor
1157 .rdes0
1158 .set(((random + slot) as u32) << RDES0_FL_SHIFT);
1159 }
1160
1161 ring.handle_overflow();
1162
1163 assert_eq!(ring.index, 0);
1164 assert_eq!(ring.stats().overflow_resets, expected_resets as u32);
1165 assert_eq!(regs::read(regs::dma::RX_POLL_DEMAND), 1);
1166
1167 for slot in 0..RX_DESC_COUNT {
1168 let descriptor = &ring.descriptors[slot];
1169 assert_eq!(descriptor.owned_by(), OwnedBy::Dma);
1170 assert_eq!(
1171 descriptor.rdes1.get() & RDES1_BUF1_SIZE_MASK,
1172 BUF_SIZE as u32
1173 );
1174 assert_ne!(descriptor.rdes1.get() & RDES1_CHAINED, 0);
1175 let expected_next = if slot + 1 == RX_DESC_COUNT {
1176 &ring.descriptors[0] as *const RDes as usize as u32
1177 } else {
1178 &ring.descriptors[slot + 1] as *const RDes as usize as u32
1179 };
1180 assert_eq!(descriptor.next_desc.get(), expected_next);
1181 }
1182 }
1183 }
1184
1185 #[test]
1186 fn rx_receive_survives_ten_thousand_cycles() {
1187 let (mut descriptors, mut buffers) = rx_fixture();
1188 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
1189 let mut payload = [0u8; BUF_SIZE];
1190
1191 for cycle in 0..STRESS_ITERATIONS {
1192 let slot = ring.index;
1193 let len = MIN_RX_FRAME_SIZE + (cycle % 321);
1194
1195 for (offset, byte) in payload[..len].iter_mut().enumerate() {
1196 *byte = cycle.wrapping_mul(3).wrapping_add(offset) as u8;
1197 }
1198
1199 ring.buffers[slot][..len].copy_from_slice(&payload[..len]);
1200 ring.descriptors[slot]
1201 .rdes0
1202 .set(RDES0_FS | RDES0_LS | ((len as u32) << RDES0_FL_SHIFT));
1203 ring.descriptors[slot].set_owned_by(OwnedBy::Cpu);
1204
1205 let (received_len, frame) = ring.receive().unwrap();
1206 assert_eq!(received_len, len);
1207 assert_eq!(frame, &payload[..len]);
1208
1209 ring.pop();
1210 assert_eq!(ring.descriptors[slot].owned_by(), OwnedBy::Dma);
1211 }
1212
1213 assert_eq!(ring.index, STRESS_ITERATIONS % RX_DESC_COUNT);
1214 assert_eq!(ring.stats().received_frames, STRESS_ITERATIONS as u32);
1215 assert_eq!(ring.stats().error_frames, 0);
1216 assert_eq!(ring.stats().runt_frames, 0);
1217 assert_eq!(ring.stats().oversized_frames, 0);
1218 }
1219
1220 #[test]
1221 fn rx_receive_fuzz_preserves_ring_invariants() {
1222 let (mut descriptors, mut buffers) = rx_fixture();
1223 let mut ring = RDesRing::new(&mut descriptors, &mut buffers);
1224 let mut rng = 0xC0DE_1234u32;
1225
1226 let mut expected_received = 0u32;
1227 let mut expected_errors = 0u32;
1228 let mut expected_runts = 0u32;
1229 let mut expected_oversized = 0u32;
1230
1231 for _ in 0..FUZZ_ITERATIONS {
1232 let slot = ring.index;
1233 let random = advance_lcg(&mut rng);
1234 let len = (random as usize) % (BUF_SIZE + 256);
1235 let owner_dma = random & 0x1 != 0;
1236 let set_error = random & 0x2 != 0;
1237 let set_fs = random & 0x4 != 0;
1238 let set_ls = random & 0x8 != 0;
1239
1240 if !owner_dma {
1241 let fill_len = len.min(BUF_SIZE);
1242 for (offset, byte) in ring.buffers[slot][..fill_len].iter_mut().enumerate() {
1243 *byte = random.wrapping_add(offset as u32) as u8;
1244 }
1245 }
1246
1247 let mut status = ((len as u32) << RDES0_FL_SHIFT) & RDES0_FL_MASK;
1248 if set_error {
1249 status |= RDES0_ES;
1250 }
1251 if set_fs {
1252 status |= RDES0_FS;
1253 }
1254 if set_ls {
1255 status |= RDES0_LS;
1256 }
1257
1258 ring.descriptors[slot].rdes0.set(status);
1259 ring.descriptors[slot].set_owned_by(if owner_dma {
1260 OwnedBy::Dma
1261 } else {
1262 OwnedBy::Cpu
1263 });
1264
1265 let expected = if owner_dma {
1266 None
1267 } else if set_error || !(set_fs && set_ls) {
1268 expected_errors = expected_errors.saturating_add(1);
1269 Some(("error", None))
1270 } else if len != 0 && len < MIN_RX_FRAME_SIZE {
1271 expected_runts = expected_runts.saturating_add(1);
1272 Some(("runt", None))
1273 } else if len > BUF_SIZE {
1274 expected_oversized = expected_oversized.saturating_add(1);
1275 Some(("oversized", None))
1276 } else {
1277 expected_received = expected_received.saturating_add(1);
1278 Some(("ok", Some(len)))
1279 };
1280
1281 let start_index = ring.index;
1282 match (expected, ring.receive()) {
1283 (None, None) => {
1284 assert_eq!(ring.index, start_index);
1285 assert_eq!(ring.descriptors[slot].owned_by(), OwnedBy::Dma);
1286 }
1287 (Some((_kind, None)), None) => {
1288 assert_eq!(ring.index, (start_index + 1) % RX_DESC_COUNT);
1289 let recycled_slot = start_index;
1290 assert_eq!(ring.descriptors[recycled_slot].owned_by(), OwnedBy::Dma);
1291 }
1292 (Some(("ok", Some(expected_len))), Some((len, frame))) => {
1293 assert_eq!(len, expected_len);
1294 assert_eq!(frame.len(), expected_len);
1295 assert_eq!(ring.index, start_index);
1296 ring.pop();
1297 assert_eq!(ring.index, (start_index + 1) % RX_DESC_COUNT);
1298 }
1299 other => panic!("unexpected fuzz outcome: {other:?}"),
1300 }
1301
1302 let stats = ring.stats();
1303 assert_eq!(stats.received_frames, expected_received);
1304 assert_eq!(stats.error_frames, expected_errors);
1305 assert_eq!(stats.runt_frames, expected_runts);
1306 assert_eq!(stats.oversized_frames, expected_oversized);
1307 assert!(ring.index < RX_DESC_COUNT);
1308 }
1309 }
1310
1311 #[test]
1312 fn descriptor_layout_matches_checklist() {
1313 assert_eq!(size_of::<TDes>(), 128);
1314 assert_eq!(align_of::<TDes>(), 128);
1315 assert_eq!(size_of::<RDes>(), 128);
1316 assert_eq!(align_of::<RDes>(), 128);
1317 assert_eq!(offset_of!(TDes, tdes0), 0);
1318 assert_eq!(offset_of!(TDes, tdes1), 4);
1319 assert_eq!(offset_of!(TDes, buf_addr), 8);
1320 assert_eq!(offset_of!(TDes, next_desc), 12);
1321 assert_eq!(offset_of!(RDes, rdes0), 0);
1322 assert_eq!(offset_of!(RDes, rdes1), 4);
1323 assert_eq!(offset_of!(RDes, buf_addr), 8);
1324 assert_eq!(offset_of!(RDes, next_desc), 12);
1325 }
1326
1327 #[test]
1328 fn descriptor_bit_constants_match_idf_layout() {
1329 assert_eq!(TDES0_OWN, 1 << 31);
1330 assert_eq!(TDES0_IC, 1 << 30);
1331 assert_eq!(TDES0_LS, 1 << 29);
1332 assert_eq!(TDES0_FS, 1 << 28);
1333 assert_eq!(RDES0_OWN, 1 << 31);
1334 assert_eq!(RDES0_ES, 1 << 15);
1335 assert_eq!(RDES0_FS, 1 << 9);
1336 assert_eq!(RDES0_LS, 1 << 8);
1337 assert_eq!(RDES0_FL_MASK, 0x3fff << 16);
1338 assert_eq!(RDES1_CHAINED, 1 << 14);
1339 assert_eq!(RDES1_BUF1_SIZE_MASK, 0x1fff);
1340 }
1341
1342 #[test]
1343 fn dma_buffer_wrapper_is_cacheline_aligned() {
1344 let buffers = DmaBuffers::<TX_DESC_COUNT>::ZERO;
1345
1346 assert_eq!(align_of::<DmaBuffers<TX_DESC_COUNT>>(), 128);
1347 assert_eq!((buffers.inner.as_ptr() as usize) % 128, 0);
1348 }
1349
1350 #[test]
1351 fn static_dma_resources_split_exposes_all_zeroed_dma_storage() {
1352 let mut resources = StaticDmaResources::new();
1353 let (tx_desc, rx_desc, tx_buf, rx_buf) = resources.split();
1354
1355 assert_eq!(tx_desc.len(), TX_DESC_COUNT);
1356 assert_eq!(rx_desc.len(), RX_DESC_COUNT);
1357 assert_eq!(tx_buf.len(), TX_DESC_COUNT);
1358 assert_eq!(rx_buf.len(), RX_DESC_COUNT);
1359 assert!(tx_desc.iter().all(|desc| desc.owned_by() == OwnedBy::Cpu));
1360 assert!(rx_desc.iter().all(|desc| desc.owned_by() == OwnedBy::Cpu));
1361 assert!(tx_buf.iter().flatten().all(|byte| *byte == 0));
1362 assert!(rx_buf.iter().flatten().all(|byte| *byte == 0));
1363 }
1364}