1pub mod bits;
32
33use bits::{rdes0, rdes1, tdes0, tdes1};
34
35#[repr(transparent)]
44pub struct VolatileCell<T: Copy> {
45 value: core::cell::UnsafeCell<T>,
46}
47
48unsafe impl<T: Copy> Sync for VolatileCell<T> {}
51
52impl<T: Copy> VolatileCell<T> {
53 #[inline(always)]
55 pub const fn new(value: T) -> Self {
56 Self {
57 value: core::cell::UnsafeCell::new(value),
58 }
59 }
60
61 #[inline(always)]
63 pub fn get(&self) -> T {
64 unsafe { core::ptr::read_volatile(self.value.get()) }
66 }
67
68 #[inline(always)]
70 pub fn set(&self, value: T) {
71 unsafe { core::ptr::write_volatile(self.value.get(), value) }
73 }
74
75 #[inline(always)]
77 pub fn update<F>(&self, f: F)
78 where
79 F: FnOnce(T) -> T,
80 {
81 let old = self.get();
82 self.set(f(old));
83 }
84}
85
86impl<T: Copy + Default> Default for VolatileCell<T> {
87 fn default() -> Self {
88 Self::new(T::default())
89 }
90}
91
92#[repr(C, align(4))]
104pub struct TxDescriptor {
105 tdes0: VolatileCell<u32>,
107 tdes1: VolatileCell<u32>,
109 buffer_addr: VolatileCell<u32>,
111 next_desc_addr: VolatileCell<u32>,
113 _reserved4: VolatileCell<u32>,
115 _reserved5: VolatileCell<u32>,
117 _ts_low: VolatileCell<u32>,
119 _ts_high: VolatileCell<u32>,
121}
122
123const _: () = assert!(core::mem::size_of::<TxDescriptor>() == 32);
128const _: () = assert!(core::mem::align_of::<TxDescriptor>() >= 4);
129const _: () = assert!(core::mem::offset_of!(TxDescriptor, tdes0) == 0);
130const _: () = assert!(core::mem::offset_of!(TxDescriptor, tdes1) == 4);
131const _: () = assert!(core::mem::offset_of!(TxDescriptor, buffer_addr) == 8);
132const _: () = assert!(core::mem::offset_of!(TxDescriptor, next_desc_addr) == 12);
133
134#[allow(dead_code)]
135impl TxDescriptor {
136 pub const SIZE: usize = 32;
138
139 #[must_use]
141 pub const fn new() -> Self {
142 Self {
143 tdes0: VolatileCell::new(0),
144 tdes1: VolatileCell::new(0),
145 buffer_addr: VolatileCell::new(0),
146 next_desc_addr: VolatileCell::new(0),
147 _reserved4: VolatileCell::new(0),
148 _reserved5: VolatileCell::new(0),
149 _ts_low: VolatileCell::new(0),
150 _ts_high: VolatileCell::new(0),
151 }
152 }
153
154 pub fn setup_chained(&self, buffer: *const u8, next_desc: *const TxDescriptor) {
159 self.buffer_addr.set(buffer as u32);
160 self.next_desc_addr.set(next_desc as u32);
161 self.tdes0.set(tdes0::SECOND_ADDR_CHAINED);
162 self.tdes1.set(0);
163 }
164
165 #[inline(always)]
167 #[must_use]
168 pub fn is_owned(&self) -> bool {
169 (self.tdes0.get() & tdes0::OWN) != 0
170 }
171
172 #[inline(always)]
174 pub fn set_owned(&self) {
175 self.tdes0.update(|v| v | tdes0::OWN);
176 }
177
178 #[inline(always)]
180 pub fn clear_owned(&self) {
181 self.tdes0.update(|v| v & !tdes0::OWN);
182 }
183
184 pub fn prepare(&self, len: usize, first: bool, last: bool) {
196 let mut flags = tdes0::SECOND_ADDR_CHAINED;
210
211 if first {
212 flags |= tdes0::FIRST_SEGMENT;
213 }
214 if last {
215 flags |= tdes0::LAST_SEGMENT | tdes0::INTERRUPT_ON_COMPLETE;
216 }
217
218 self.tdes1.set((len as u32) & tdes1::BUFFER1_SIZE_MASK);
219 self.tdes0.set(flags);
220 }
221
222 pub fn prepare_and_submit(&self, len: usize, first: bool, last: bool) {
224 self.prepare(len, first, last);
225 self.set_owned();
226 }
227
228 #[inline(always)]
230 #[must_use]
231 pub fn has_error(&self) -> bool {
232 (self.tdes0.get() & tdes0::ERR_SUMMARY) != 0
233 }
234
235 #[inline(always)]
237 #[must_use]
238 pub fn error_flags(&self) -> u32 {
239 self.tdes0.get() & tdes0::ALL_ERRORS
240 }
241
242 #[inline(always)]
244 #[must_use]
245 pub fn buffer_addr(&self) -> u32 {
246 self.buffer_addr.get()
247 }
248
249 #[inline(always)]
251 #[must_use]
252 pub fn next_desc_addr(&self) -> u32 {
253 self.next_desc_addr.get()
254 }
255
256 pub fn reset(&self) {
258 let next = self.next_desc_addr.get();
259 self.tdes0.set(tdes0::SECOND_ADDR_CHAINED);
260 self.tdes1.set(0);
261 self.next_desc_addr.set(next);
262 }
263
264 #[inline(always)]
266 #[must_use]
267 pub fn raw_tdes0(&self) -> u32 {
268 self.tdes0.get()
269 }
270
271 #[inline(always)]
273 #[must_use]
274 pub fn raw_tdes1(&self) -> u32 {
275 self.tdes1.get()
276 }
277}
278
279impl Default for TxDescriptor {
280 fn default() -> Self {
281 Self::new()
282 }
283}
284
285unsafe impl Sync for TxDescriptor {}
287unsafe impl Send for TxDescriptor {}
289
290#[repr(C, align(4))]
298pub struct RxDescriptor {
299 rdes0: VolatileCell<u32>,
301 rdes1: VolatileCell<u32>,
303 buffer_addr: VolatileCell<u32>,
305 next_desc_addr: VolatileCell<u32>,
307 _ext_status: VolatileCell<u32>,
309 _reserved5: VolatileCell<u32>,
311 _ts_low: VolatileCell<u32>,
313 _ts_high: VolatileCell<u32>,
315}
316
317const _: () = assert!(core::mem::size_of::<RxDescriptor>() == 32);
319const _: () = assert!(core::mem::align_of::<RxDescriptor>() >= 4);
320const _: () = assert!(core::mem::offset_of!(RxDescriptor, rdes0) == 0);
321const _: () = assert!(core::mem::offset_of!(RxDescriptor, rdes1) == 4);
322const _: () = assert!(core::mem::offset_of!(RxDescriptor, buffer_addr) == 8);
323const _: () = assert!(core::mem::offset_of!(RxDescriptor, next_desc_addr) == 12);
324
325#[allow(dead_code)]
326impl RxDescriptor {
327 pub const SIZE: usize = 32;
329
330 #[must_use]
332 pub const fn new() -> Self {
333 Self {
334 rdes0: VolatileCell::new(0),
335 rdes1: VolatileCell::new(0),
336 buffer_addr: VolatileCell::new(0),
337 next_desc_addr: VolatileCell::new(0),
338 _ext_status: VolatileCell::new(0),
339 _reserved5: VolatileCell::new(0),
340 _ts_low: VolatileCell::new(0),
341 _ts_high: VolatileCell::new(0),
342 }
343 }
344
345 pub fn setup_chained(
350 &self,
351 buffer: *mut u8,
352 buffer_size: usize,
353 next_desc: *const RxDescriptor,
354 ) {
355 self.buffer_addr.set(buffer as u32);
356 self.next_desc_addr.set(next_desc as u32);
357 self.rdes1
358 .set(rdes1::SECOND_ADDR_CHAINED | ((buffer_size as u32) & rdes1::BUFFER1_SIZE_MASK));
359 self.rdes0.set(rdes0::OWN);
361 }
362
363 #[inline(always)]
365 #[must_use]
366 pub fn is_owned(&self) -> bool {
367 (self.rdes0.get() & rdes0::OWN) != 0
368 }
369
370 #[inline(always)]
372 pub fn set_owned(&self) {
373 self.rdes0.set(rdes0::OWN);
374 }
375
376 #[inline(always)]
378 pub fn clear_owned(&self) {
379 self.rdes0.update(|v| v & !rdes0::OWN);
380 }
381
382 #[inline(always)]
384 #[must_use]
385 pub fn is_first(&self) -> bool {
386 (self.rdes0.get() & rdes0::FIRST_DESC) != 0
387 }
388
389 #[inline(always)]
391 #[must_use]
392 pub fn is_last(&self) -> bool {
393 (self.rdes0.get() & rdes0::LAST_DESC) != 0
394 }
395
396 #[inline(always)]
398 #[must_use]
399 pub fn is_complete_frame(&self) -> bool {
400 let status = self.rdes0.get();
401 (status & (rdes0::FIRST_DESC | rdes0::LAST_DESC)) == (rdes0::FIRST_DESC | rdes0::LAST_DESC)
402 }
403
404 #[inline(always)]
406 #[must_use]
407 pub fn has_error(&self) -> bool {
408 (self.rdes0.get() & rdes0::ERR_SUMMARY) != 0
409 }
410
411 #[inline(always)]
413 #[must_use]
414 pub fn error_flags(&self) -> u32 {
415 self.rdes0.get() & rdes0::ALL_ERRORS
416 }
417
418 #[inline(always)]
420 #[must_use]
421 pub fn frame_length(&self) -> usize {
422 ((self.rdes0.get() & rdes0::FRAME_LEN_MASK) >> rdes0::FRAME_LEN_SHIFT) as usize
423 }
424
425 #[inline(always)]
427 #[must_use]
428 pub fn payload_length(&self) -> usize {
429 self.frame_length().saturating_sub(4)
430 }
431
432 #[inline(always)]
434 #[must_use]
435 pub fn buffer_addr(&self) -> u32 {
436 self.buffer_addr.get()
437 }
438
439 #[inline(always)]
441 #[must_use]
442 pub fn next_desc_addr(&self) -> u32 {
443 self.next_desc_addr.get()
444 }
445
446 #[inline(always)]
448 #[must_use]
449 pub fn buffer_size(&self) -> usize {
450 (self.rdes1.get() & rdes1::BUFFER1_SIZE_MASK) as usize
451 }
452
453 pub fn recycle(&self) {
455 self.rdes0.set(rdes0::OWN);
456 }
457
458 #[inline(always)]
460 #[must_use]
461 pub fn raw_rdes0(&self) -> u32 {
462 self.rdes0.get()
463 }
464
465 #[inline(always)]
467 #[must_use]
468 pub fn raw_rdes1(&self) -> u32 {
469 self.rdes1.get()
470 }
471
472 #[cfg(test)]
474 pub fn set_raw_rdes0(&self, val: u32) {
475 self.rdes0.set(val);
476 }
477}
478
479impl Default for RxDescriptor {
480 fn default() -> Self {
481 Self::new()
482 }
483}
484
485unsafe impl Sync for RxDescriptor {}
487unsafe impl Send for RxDescriptor {}
489
490#[cfg(test)]
495mod tests {
496 use super::*;
497
498 #[test]
503 fn volatile_cell_new() {
504 let cell = VolatileCell::new(42u32);
505 assert_eq!(cell.get(), 42);
506 }
507
508 #[test]
509 fn volatile_cell_get_set() {
510 let cell = VolatileCell::new(0u32);
511 assert_eq!(cell.get(), 0);
512 cell.set(0xDEAD_BEEF);
513 assert_eq!(cell.get(), 0xDEAD_BEEF);
514 }
515
516 #[test]
517 fn volatile_cell_update() {
518 let cell = VolatileCell::new(0x0000_00FFu32);
519 cell.update(|v| v | 0xFF00_0000);
520 assert_eq!(cell.get(), 0xFF00_00FF);
521 }
522
523 #[test]
524 fn volatile_cell_default() {
525 let cell = VolatileCell::<u32>::default();
526 assert_eq!(cell.get(), 0);
527 }
528
529 #[test]
534 fn tx_descriptor_size() {
535 assert_eq!(core::mem::size_of::<TxDescriptor>(), 32);
536 assert_eq!(TxDescriptor::SIZE, core::mem::size_of::<TxDescriptor>());
537 }
538
539 #[test]
540 fn tx_descriptor_alignment() {
541 assert_eq!(core::mem::align_of::<TxDescriptor>(), 4);
542 }
543
544 #[test]
549 fn tx_descriptor_new_not_owned() {
550 let desc = TxDescriptor::new();
551 assert!(!desc.is_owned());
552 }
553
554 #[test]
555 fn tx_descriptor_is_owned() {
556 let desc = TxDescriptor::new();
557 desc.set_owned();
558 assert!(desc.is_owned());
559 desc.clear_owned();
560 assert!(!desc.is_owned());
561 }
562
563 #[test]
564 fn tdes0_own_bit() {
565 let desc = TxDescriptor::new();
567 desc.set_owned();
568 assert_eq!(desc.raw_tdes0() & tdes0::OWN, tdes0::OWN);
569 assert_eq!(tdes0::OWN, 1 << 31);
570 }
571
572 #[test]
577 fn tx_descriptor_setup_chained() {
578 let desc = TxDescriptor::new();
579 let buf = [0u8; 64];
580 let next = TxDescriptor::new();
581
582 desc.setup_chained(buf.as_ptr(), &next as *const TxDescriptor);
583
584 assert_eq!(desc.buffer_addr(), buf.as_ptr() as u32);
585 assert_eq!(desc.next_desc_addr(), &next as *const TxDescriptor as u32);
586 assert!(desc.raw_tdes0() & tdes0::SECOND_ADDR_CHAINED != 0);
587 assert!(!desc.is_owned());
588 }
589
590 #[test]
591 fn tx_descriptor_prepare_single_frame() {
592 let desc = TxDescriptor::new();
593 desc.prepare(1500, true, true);
594
595 let raw0 = desc.raw_tdes0();
596 assert!(raw0 & tdes0::FIRST_SEGMENT != 0);
597 assert!(raw0 & tdes0::LAST_SEGMENT != 0);
598 assert!(raw0 & tdes0::INTERRUPT_ON_COMPLETE != 0);
599 assert!(raw0 & tdes0::OWN == 0, "prepare must not set OWN");
600
601 let len = desc.raw_tdes1() & tdes1::BUFFER1_SIZE_MASK;
602 assert_eq!(len, 1500);
603 }
604
605 #[test]
606 fn tdes0_first_last_bits() {
607 let desc = TxDescriptor::new();
608
609 desc.prepare(100, true, false);
611 let raw = desc.raw_tdes0();
612 assert!(raw & tdes0::FIRST_SEGMENT != 0);
613 assert!(raw & tdes0::LAST_SEGMENT == 0);
614
615 desc.prepare(100, false, true);
617 let raw = desc.raw_tdes0();
618 assert!(raw & tdes0::FIRST_SEGMENT == 0);
619 assert!(raw & tdes0::LAST_SEGMENT != 0);
620 }
621
622 #[test]
623 fn tx_descriptor_prepare_disables_cic() {
624 let desc = TxDescriptor::new();
630 desc.prepare(64, true, true);
631 let raw = desc.raw_tdes0();
632 let cic = (raw >> tdes0::CHECKSUM_INSERT_SHIFT) & 0x3;
633 assert_eq!(cic, 0b00, "CIC must be 0b00 — HW checksum offload disabled");
634 }
635
636 #[test]
637 fn tx_descriptor_prepare_and_submit() {
638 let desc = TxDescriptor::new();
639 desc.prepare_and_submit(256, true, true);
640 assert!(desc.is_owned());
641 assert_eq!(desc.raw_tdes1() & tdes1::BUFFER1_SIZE_MASK, 256);
642 }
643
644 #[test]
645 fn tx_descriptor_no_errors_initially() {
646 let desc = TxDescriptor::new();
647 assert!(!desc.has_error());
648 assert_eq!(desc.error_flags(), 0);
649 }
650
651 #[test]
652 fn tx_descriptor_error_detection() {
653 let desc = TxDescriptor::new();
654 desc.tdes0.set(tdes0::ERR_SUMMARY | tdes0::UNDERFLOW_ERR);
655 assert!(desc.has_error());
656 assert!(desc.error_flags() & tdes0::UNDERFLOW_ERR != 0);
657 }
658
659 #[test]
660 fn tx_descriptor_reset_preserves_chain() {
661 let desc = TxDescriptor::new();
662 let next_addr = 0x1234_5678u32;
663 desc.next_desc_addr.set(next_addr);
664 desc.prepare_and_submit(1000, true, true);
665
666 desc.reset();
667
668 assert!(!desc.is_owned());
669 assert_eq!(desc.raw_tdes1() & tdes1::BUFFER1_SIZE_MASK, 0);
670 assert_eq!(desc.next_desc_addr(), next_addr);
671 assert!(desc.raw_tdes0() & tdes0::SECOND_ADDR_CHAINED != 0);
672 }
673
674 #[test]
679 fn rx_descriptor_size() {
680 assert_eq!(core::mem::size_of::<RxDescriptor>(), 32);
681 assert_eq!(RxDescriptor::SIZE, core::mem::size_of::<RxDescriptor>());
682 }
683
684 #[test]
685 fn rx_descriptor_alignment() {
686 assert_eq!(core::mem::align_of::<RxDescriptor>(), 4);
687 }
688
689 #[test]
694 fn rx_descriptor_new_not_owned() {
695 let desc = RxDescriptor::new();
696 assert!(!desc.is_owned());
697 }
698
699 #[test]
700 fn rdes0_own_bit() {
701 let desc = RxDescriptor::new();
702 desc.set_owned();
703 assert_eq!(desc.raw_rdes0() & rdes0::OWN, rdes0::OWN);
704 assert_eq!(rdes0::OWN, 1 << 31);
705 }
706
707 #[test]
712 fn rx_descriptor_setup_chained() {
713 let desc = RxDescriptor::new();
714 let mut buf = [0u8; 1600];
715 let next = RxDescriptor::new();
716
717 desc.setup_chained(buf.as_mut_ptr(), 1600, &next as *const RxDescriptor);
718
719 assert_eq!(desc.buffer_addr(), buf.as_ptr() as u32);
720 assert_eq!(desc.next_desc_addr(), &next as *const RxDescriptor as u32);
721 assert_eq!(desc.buffer_size(), 1600);
722 assert!(desc.is_owned(), "setup_chained gives to DMA");
723 assert!(desc.raw_rdes1() & rdes1::SECOND_ADDR_CHAINED != 0);
724 }
725
726 #[test]
731 fn rx_descriptor_first_last_flags() {
732 let desc = RxDescriptor::new();
733 assert!(!desc.is_first());
734 assert!(!desc.is_last());
735
736 desc.rdes0.set(rdes0::FIRST_DESC | rdes0::LAST_DESC);
737 assert!(desc.is_first());
738 assert!(desc.is_last());
739 assert!(desc.is_complete_frame());
740 }
741
742 #[test]
743 fn rx_descriptor_payload_length() {
744 let desc = RxDescriptor::new();
745
746 desc.rdes0.set(1504 << rdes0::FRAME_LEN_SHIFT);
748 assert_eq!(desc.frame_length(), 1504);
749 assert_eq!(desc.payload_length(), 1500);
750 }
751
752 #[test]
753 fn rx_descriptor_payload_length_short_frame() {
754 let desc = RxDescriptor::new();
755 desc.rdes0.set(2 << rdes0::FRAME_LEN_SHIFT);
757 assert_eq!(desc.payload_length(), 0);
758 }
759
760 #[test]
761 fn rx_descriptor_error_detection() {
762 let desc = RxDescriptor::new();
763 assert!(!desc.has_error());
764
765 desc.rdes0
766 .set(rdes0::ERR_SUMMARY | rdes0::CRC_ERR | rdes0::OVERFLOW_ERR);
767 assert!(desc.has_error());
768 assert!(desc.error_flags() & rdes0::CRC_ERR != 0);
769 assert!(desc.error_flags() & rdes0::OVERFLOW_ERR != 0);
770 }
771
772 #[test]
777 fn rx_descriptor_recycle() {
778 let desc = RxDescriptor::new();
779 desc.rdes1.set(1600);
780 desc.rdes0
781 .set(rdes0::FIRST_DESC | rdes0::LAST_DESC | (100 << rdes0::FRAME_LEN_SHIFT));
782
783 desc.recycle();
784
785 assert!(desc.is_owned());
786 assert_eq!(desc.buffer_size(), 1600);
788 }
789}