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
123#[allow(dead_code)]
124impl TxDescriptor {
125 pub const SIZE: usize = 32;
127
128 #[must_use]
130 pub const fn new() -> Self {
131 Self {
132 tdes0: VolatileCell::new(0),
133 tdes1: VolatileCell::new(0),
134 buffer_addr: VolatileCell::new(0),
135 next_desc_addr: VolatileCell::new(0),
136 _reserved4: VolatileCell::new(0),
137 _reserved5: VolatileCell::new(0),
138 _ts_low: VolatileCell::new(0),
139 _ts_high: VolatileCell::new(0),
140 }
141 }
142
143 pub fn setup_chained(&self, buffer: *const u8, next_desc: *const TxDescriptor) {
148 self.buffer_addr.set(buffer as u32);
149 self.next_desc_addr.set(next_desc as u32);
150 self.tdes0.set(tdes0::SECOND_ADDR_CHAINED);
151 self.tdes1.set(0);
152 }
153
154 #[inline(always)]
156 #[must_use]
157 pub fn is_owned(&self) -> bool {
158 (self.tdes0.get() & tdes0::OWN) != 0
159 }
160
161 #[inline(always)]
163 pub fn set_owned(&self) {
164 self.tdes0.update(|v| v | tdes0::OWN);
165 }
166
167 #[inline(always)]
169 pub fn clear_owned(&self) {
170 self.tdes0.update(|v| v & !tdes0::OWN);
171 }
172
173 pub fn prepare(&self, len: usize, first: bool, last: bool) {
179 let mut flags = tdes0::SECOND_ADDR_CHAINED;
180
181 if first {
182 flags |= tdes0::FIRST_SEGMENT;
183 }
184 if last {
185 flags |= tdes0::LAST_SEGMENT | tdes0::INTERRUPT_ON_COMPLETE;
186 }
187
188 self.tdes1.set((len as u32) & tdes1::BUFFER1_SIZE_MASK);
189 self.tdes0.set(flags);
190 }
191
192 pub fn prepare_and_submit(&self, len: usize, first: bool, last: bool) {
194 self.prepare(len, first, last);
195 self.set_owned();
196 }
197
198 #[inline(always)]
200 #[must_use]
201 pub fn has_error(&self) -> bool {
202 (self.tdes0.get() & tdes0::ERR_SUMMARY) != 0
203 }
204
205 #[inline(always)]
207 #[must_use]
208 pub fn error_flags(&self) -> u32 {
209 self.tdes0.get() & tdes0::ALL_ERRORS
210 }
211
212 #[inline(always)]
214 #[must_use]
215 pub fn buffer_addr(&self) -> u32 {
216 self.buffer_addr.get()
217 }
218
219 #[inline(always)]
221 #[must_use]
222 pub fn next_desc_addr(&self) -> u32 {
223 self.next_desc_addr.get()
224 }
225
226 pub fn reset(&self) {
228 let next = self.next_desc_addr.get();
229 self.tdes0.set(tdes0::SECOND_ADDR_CHAINED);
230 self.tdes1.set(0);
231 self.next_desc_addr.set(next);
232 }
233
234 #[inline(always)]
236 #[must_use]
237 pub fn raw_tdes0(&self) -> u32 {
238 self.tdes0.get()
239 }
240
241 #[inline(always)]
243 #[must_use]
244 pub fn raw_tdes1(&self) -> u32 {
245 self.tdes1.get()
246 }
247}
248
249impl Default for TxDescriptor {
250 fn default() -> Self {
251 Self::new()
252 }
253}
254
255unsafe impl Sync for TxDescriptor {}
257unsafe impl Send for TxDescriptor {}
259
260#[repr(C, align(4))]
268pub struct RxDescriptor {
269 rdes0: VolatileCell<u32>,
271 rdes1: VolatileCell<u32>,
273 buffer_addr: VolatileCell<u32>,
275 next_desc_addr: VolatileCell<u32>,
277 _ext_status: VolatileCell<u32>,
279 _reserved5: VolatileCell<u32>,
281 _ts_low: VolatileCell<u32>,
283 _ts_high: VolatileCell<u32>,
285}
286
287#[allow(dead_code)]
288impl RxDescriptor {
289 pub const SIZE: usize = 32;
291
292 #[must_use]
294 pub const fn new() -> Self {
295 Self {
296 rdes0: VolatileCell::new(0),
297 rdes1: VolatileCell::new(0),
298 buffer_addr: VolatileCell::new(0),
299 next_desc_addr: VolatileCell::new(0),
300 _ext_status: VolatileCell::new(0),
301 _reserved5: VolatileCell::new(0),
302 _ts_low: VolatileCell::new(0),
303 _ts_high: VolatileCell::new(0),
304 }
305 }
306
307 pub fn setup_chained(
312 &self,
313 buffer: *mut u8,
314 buffer_size: usize,
315 next_desc: *const RxDescriptor,
316 ) {
317 self.buffer_addr.set(buffer as u32);
318 self.next_desc_addr.set(next_desc as u32);
319 self.rdes1
320 .set(rdes1::SECOND_ADDR_CHAINED | ((buffer_size as u32) & rdes1::BUFFER1_SIZE_MASK));
321 self.rdes0.set(rdes0::OWN);
323 }
324
325 #[inline(always)]
327 #[must_use]
328 pub fn is_owned(&self) -> bool {
329 (self.rdes0.get() & rdes0::OWN) != 0
330 }
331
332 #[inline(always)]
334 pub fn set_owned(&self) {
335 self.rdes0.set(rdes0::OWN);
336 }
337
338 #[inline(always)]
340 pub fn clear_owned(&self) {
341 self.rdes0.update(|v| v & !rdes0::OWN);
342 }
343
344 #[inline(always)]
346 #[must_use]
347 pub fn is_first(&self) -> bool {
348 (self.rdes0.get() & rdes0::FIRST_DESC) != 0
349 }
350
351 #[inline(always)]
353 #[must_use]
354 pub fn is_last(&self) -> bool {
355 (self.rdes0.get() & rdes0::LAST_DESC) != 0
356 }
357
358 #[inline(always)]
360 #[must_use]
361 pub fn is_complete_frame(&self) -> bool {
362 let status = self.rdes0.get();
363 (status & (rdes0::FIRST_DESC | rdes0::LAST_DESC)) == (rdes0::FIRST_DESC | rdes0::LAST_DESC)
364 }
365
366 #[inline(always)]
368 #[must_use]
369 pub fn has_error(&self) -> bool {
370 (self.rdes0.get() & rdes0::ERR_SUMMARY) != 0
371 }
372
373 #[inline(always)]
375 #[must_use]
376 pub fn error_flags(&self) -> u32 {
377 self.rdes0.get() & rdes0::ALL_ERRORS
378 }
379
380 #[inline(always)]
382 #[must_use]
383 pub fn frame_length(&self) -> usize {
384 ((self.rdes0.get() & rdes0::FRAME_LEN_MASK) >> rdes0::FRAME_LEN_SHIFT) as usize
385 }
386
387 #[inline(always)]
389 #[must_use]
390 pub fn payload_length(&self) -> usize {
391 self.frame_length().saturating_sub(4)
392 }
393
394 #[inline(always)]
396 #[must_use]
397 pub fn buffer_addr(&self) -> u32 {
398 self.buffer_addr.get()
399 }
400
401 #[inline(always)]
403 #[must_use]
404 pub fn next_desc_addr(&self) -> u32 {
405 self.next_desc_addr.get()
406 }
407
408 #[inline(always)]
410 #[must_use]
411 pub fn buffer_size(&self) -> usize {
412 (self.rdes1.get() & rdes1::BUFFER1_SIZE_MASK) as usize
413 }
414
415 pub fn recycle(&self) {
417 self.rdes0.set(rdes0::OWN);
418 }
419
420 #[inline(always)]
422 #[must_use]
423 pub fn raw_rdes0(&self) -> u32 {
424 self.rdes0.get()
425 }
426
427 #[inline(always)]
429 #[must_use]
430 pub fn raw_rdes1(&self) -> u32 {
431 self.rdes1.get()
432 }
433
434 #[cfg(test)]
436 pub fn set_raw_rdes0(&self, val: u32) {
437 self.rdes0.set(val);
438 }
439}
440
441impl Default for RxDescriptor {
442 fn default() -> Self {
443 Self::new()
444 }
445}
446
447unsafe impl Sync for RxDescriptor {}
449unsafe impl Send for RxDescriptor {}
451
452#[cfg(test)]
457mod tests {
458 use super::*;
459
460 #[test]
465 fn volatile_cell_new() {
466 let cell = VolatileCell::new(42u32);
467 assert_eq!(cell.get(), 42);
468 }
469
470 #[test]
471 fn volatile_cell_get_set() {
472 let cell = VolatileCell::new(0u32);
473 assert_eq!(cell.get(), 0);
474 cell.set(0xDEAD_BEEF);
475 assert_eq!(cell.get(), 0xDEAD_BEEF);
476 }
477
478 #[test]
479 fn volatile_cell_update() {
480 let cell = VolatileCell::new(0x0000_00FFu32);
481 cell.update(|v| v | 0xFF00_0000);
482 assert_eq!(cell.get(), 0xFF00_00FF);
483 }
484
485 #[test]
486 fn volatile_cell_default() {
487 let cell = VolatileCell::<u32>::default();
488 assert_eq!(cell.get(), 0);
489 }
490
491 #[test]
496 fn tx_descriptor_size() {
497 assert_eq!(core::mem::size_of::<TxDescriptor>(), 32);
498 assert_eq!(TxDescriptor::SIZE, core::mem::size_of::<TxDescriptor>());
499 }
500
501 #[test]
502 fn tx_descriptor_alignment() {
503 assert_eq!(core::mem::align_of::<TxDescriptor>(), 4);
504 }
505
506 #[test]
511 fn tx_descriptor_new_not_owned() {
512 let desc = TxDescriptor::new();
513 assert!(!desc.is_owned());
514 }
515
516 #[test]
517 fn tx_descriptor_is_owned() {
518 let desc = TxDescriptor::new();
519 desc.set_owned();
520 assert!(desc.is_owned());
521 desc.clear_owned();
522 assert!(!desc.is_owned());
523 }
524
525 #[test]
526 fn tdes0_own_bit() {
527 let desc = TxDescriptor::new();
529 desc.set_owned();
530 assert_eq!(desc.raw_tdes0() & tdes0::OWN, tdes0::OWN);
531 assert_eq!(tdes0::OWN, 1 << 31);
532 }
533
534 #[test]
539 fn tx_descriptor_setup_chained() {
540 let desc = TxDescriptor::new();
541 let buf = [0u8; 64];
542 let next = TxDescriptor::new();
543
544 desc.setup_chained(buf.as_ptr(), &next as *const TxDescriptor);
545
546 assert_eq!(desc.buffer_addr(), buf.as_ptr() as u32);
547 assert_eq!(desc.next_desc_addr(), &next as *const TxDescriptor as u32);
548 assert!(desc.raw_tdes0() & tdes0::SECOND_ADDR_CHAINED != 0);
549 assert!(!desc.is_owned());
550 }
551
552 #[test]
553 fn tx_descriptor_prepare_single_frame() {
554 let desc = TxDescriptor::new();
555 desc.prepare(1500, true, true);
556
557 let raw0 = desc.raw_tdes0();
558 assert!(raw0 & tdes0::FIRST_SEGMENT != 0);
559 assert!(raw0 & tdes0::LAST_SEGMENT != 0);
560 assert!(raw0 & tdes0::INTERRUPT_ON_COMPLETE != 0);
561 assert!(raw0 & tdes0::OWN == 0, "prepare must not set OWN");
562
563 let len = desc.raw_tdes1() & tdes1::BUFFER1_SIZE_MASK;
564 assert_eq!(len, 1500);
565 }
566
567 #[test]
568 fn tdes0_first_last_bits() {
569 let desc = TxDescriptor::new();
570
571 desc.prepare(100, true, false);
573 let raw = desc.raw_tdes0();
574 assert!(raw & tdes0::FIRST_SEGMENT != 0);
575 assert!(raw & tdes0::LAST_SEGMENT == 0);
576
577 desc.prepare(100, false, true);
579 let raw = desc.raw_tdes0();
580 assert!(raw & tdes0::FIRST_SEGMENT == 0);
581 assert!(raw & tdes0::LAST_SEGMENT != 0);
582 }
583
584 #[test]
585 fn tx_descriptor_prepare_and_submit() {
586 let desc = TxDescriptor::new();
587 desc.prepare_and_submit(256, true, true);
588 assert!(desc.is_owned());
589 assert_eq!(desc.raw_tdes1() & tdes1::BUFFER1_SIZE_MASK, 256);
590 }
591
592 #[test]
593 fn tx_descriptor_no_errors_initially() {
594 let desc = TxDescriptor::new();
595 assert!(!desc.has_error());
596 assert_eq!(desc.error_flags(), 0);
597 }
598
599 #[test]
600 fn tx_descriptor_error_detection() {
601 let desc = TxDescriptor::new();
602 desc.tdes0.set(tdes0::ERR_SUMMARY | tdes0::UNDERFLOW_ERR);
603 assert!(desc.has_error());
604 assert!(desc.error_flags() & tdes0::UNDERFLOW_ERR != 0);
605 }
606
607 #[test]
608 fn tx_descriptor_reset_preserves_chain() {
609 let desc = TxDescriptor::new();
610 let next_addr = 0x1234_5678u32;
611 desc.next_desc_addr.set(next_addr);
612 desc.prepare_and_submit(1000, true, true);
613
614 desc.reset();
615
616 assert!(!desc.is_owned());
617 assert_eq!(desc.raw_tdes1() & tdes1::BUFFER1_SIZE_MASK, 0);
618 assert_eq!(desc.next_desc_addr(), next_addr);
619 assert!(desc.raw_tdes0() & tdes0::SECOND_ADDR_CHAINED != 0);
620 }
621
622 #[test]
627 fn rx_descriptor_size() {
628 assert_eq!(core::mem::size_of::<RxDescriptor>(), 32);
629 assert_eq!(RxDescriptor::SIZE, core::mem::size_of::<RxDescriptor>());
630 }
631
632 #[test]
633 fn rx_descriptor_alignment() {
634 assert_eq!(core::mem::align_of::<RxDescriptor>(), 4);
635 }
636
637 #[test]
642 fn rx_descriptor_new_not_owned() {
643 let desc = RxDescriptor::new();
644 assert!(!desc.is_owned());
645 }
646
647 #[test]
648 fn rdes0_own_bit() {
649 let desc = RxDescriptor::new();
650 desc.set_owned();
651 assert_eq!(desc.raw_rdes0() & rdes0::OWN, rdes0::OWN);
652 assert_eq!(rdes0::OWN, 1 << 31);
653 }
654
655 #[test]
660 fn rx_descriptor_setup_chained() {
661 let desc = RxDescriptor::new();
662 let mut buf = [0u8; 1600];
663 let next = RxDescriptor::new();
664
665 desc.setup_chained(buf.as_mut_ptr(), 1600, &next as *const RxDescriptor);
666
667 assert_eq!(desc.buffer_addr(), buf.as_ptr() as u32);
668 assert_eq!(desc.next_desc_addr(), &next as *const RxDescriptor as u32);
669 assert_eq!(desc.buffer_size(), 1600);
670 assert!(desc.is_owned(), "setup_chained gives to DMA");
671 assert!(desc.raw_rdes1() & rdes1::SECOND_ADDR_CHAINED != 0);
672 }
673
674 #[test]
679 fn rx_descriptor_first_last_flags() {
680 let desc = RxDescriptor::new();
681 assert!(!desc.is_first());
682 assert!(!desc.is_last());
683
684 desc.rdes0.set(rdes0::FIRST_DESC | rdes0::LAST_DESC);
685 assert!(desc.is_first());
686 assert!(desc.is_last());
687 assert!(desc.is_complete_frame());
688 }
689
690 #[test]
691 fn rx_descriptor_payload_length() {
692 let desc = RxDescriptor::new();
693
694 desc.rdes0.set(1504 << rdes0::FRAME_LEN_SHIFT);
696 assert_eq!(desc.frame_length(), 1504);
697 assert_eq!(desc.payload_length(), 1500);
698 }
699
700 #[test]
701 fn rx_descriptor_payload_length_short_frame() {
702 let desc = RxDescriptor::new();
703 desc.rdes0.set(2 << rdes0::FRAME_LEN_SHIFT);
705 assert_eq!(desc.payload_length(), 0);
706 }
707
708 #[test]
709 fn rx_descriptor_error_detection() {
710 let desc = RxDescriptor::new();
711 assert!(!desc.has_error());
712
713 desc.rdes0
714 .set(rdes0::ERR_SUMMARY | rdes0::CRC_ERR | rdes0::OVERFLOW_ERR);
715 assert!(desc.has_error());
716 assert!(desc.error_flags() & rdes0::CRC_ERR != 0);
717 assert!(desc.error_flags() & rdes0::OVERFLOW_ERR != 0);
718 }
719
720 #[test]
725 fn rx_descriptor_recycle() {
726 let desc = RxDescriptor::new();
727 desc.rdes1.set(1600);
728 desc.rdes0
729 .set(rdes0::FIRST_DESC | rdes0::LAST_DESC | (100 << rdes0::FRAME_LEN_SHIFT));
730
731 desc.recycle();
732
733 assert!(desc.is_owned());
734 assert_eq!(desc.buffer_size(), 1600);
736 }
737}