1use core::sync::atomic::{fence, Ordering};
11
12use crate::dma::descriptor::{RxDescriptor, TxDescriptor};
13use crate::dma::ring::DescriptorRing;
14use crate::error::EmacError;
15
16pub struct DmaEngine<const RX: usize, const TX: usize, const BUF: usize> {
23 rx_ring: DescriptorRing<RxDescriptor, RX>,
25 tx_ring: DescriptorRing<TxDescriptor, TX>,
27 rx_buffers: [[u8; BUF]; RX],
29 tx_buffers: [[u8; BUF]; TX],
31 initialized: bool,
33}
34
35impl<const RX: usize, const TX: usize, const BUF: usize> DmaEngine<RX, TX, BUF> {
36 #[must_use]
38 pub const fn new() -> Self {
39 Self {
40 rx_ring: DescriptorRing::new([const { RxDescriptor::new() }; RX]),
41 tx_ring: DescriptorRing::new([const { TxDescriptor::new() }; TX]),
42 rx_buffers: [[0u8; BUF]; RX],
43 tx_buffers: [[0u8; BUF]; TX],
44 initialized: false,
45 }
46 }
47
48 pub fn init(&mut self) -> (u32, u32) {
55 for i in 0..RX {
57 let next_idx = (i + 1) % RX;
58 let buffer_ptr = self.rx_buffers[i].as_mut_ptr();
59 let next_desc = self.rx_ring.get(next_idx) as *const RxDescriptor;
60 self.rx_ring
61 .get(i)
62 .setup_chained(buffer_ptr, BUF, next_desc);
63 }
64
65 for i in 0..TX {
67 let next_idx = (i + 1) % TX;
68 let buffer_ptr = self.tx_buffers[i].as_ptr();
69 let next_desc = self.tx_ring.get(next_idx) as *const TxDescriptor;
70 self.tx_ring.get(i).setup_chained(buffer_ptr, next_desc);
71 }
72
73 self.rx_ring.reset();
74 self.tx_ring.reset();
75 self.initialized = true;
76
77 fence(Ordering::Release);
83
84 let rx_base = self.rx_ring.base_addr() as u32;
85 let tx_base = self.tx_ring.base_addr() as u32;
86 (rx_base, tx_base)
87 }
88
89 #[inline(always)]
91 #[must_use]
92 pub fn is_initialized(&self) -> bool {
93 self.initialized
94 }
95
96 #[must_use]
98 pub const fn memory_usage() -> usize {
99 let rx_desc = RX * RxDescriptor::SIZE;
100 let tx_desc = TX * TxDescriptor::SIZE;
101 let rx_buf = RX * BUF;
102 let tx_buf = TX * BUF;
103 rx_desc + tx_desc + rx_buf + tx_buf
104 }
105
106 #[must_use]
110 pub fn can_transmit(&self, len: usize) -> bool {
111 if len == 0 || len > BUF * TX {
112 return false;
113 }
114 let needed = len.div_ceil(BUF);
115 self.tx_available() >= needed
116 }
117
118 #[must_use]
120 pub fn tx_available(&self) -> usize {
121 let mut count = 0;
122 for i in 0..TX {
123 let idx = (self.tx_ring.current_index() + i) % TX;
124 if !self.tx_ring.get(idx).is_owned() {
125 count += 1;
126 } else {
127 break;
128 }
129 }
130 count
131 }
132
133 pub fn transmit(&mut self, data: &[u8]) -> Result<usize, EmacError> {
139 if data.is_empty() {
140 return Err(EmacError::InvalidLength);
141 }
142
143 if data.len() > BUF * TX {
144 return Err(EmacError::FrameTooLarge);
145 }
146
147 let desc_count = data.len().div_ceil(BUF);
148 if self.tx_available() < desc_count {
149 return Err(EmacError::NoDescriptorsAvailable);
150 }
151
152 let current = self.tx_ring.current_index();
153 let mut remaining = data.len();
154 let mut offset = 0usize;
155
156 for i in 0..desc_count {
158 let idx = (current + i) % TX;
159 let desc = self.tx_ring.get(idx);
160
161 if desc.is_owned() {
162 return Err(EmacError::DescriptorBusy);
163 }
164
165 let chunk_size = core::cmp::min(remaining, BUF);
166 self.tx_buffers[idx][..chunk_size].copy_from_slice(&data[offset..offset + chunk_size]);
167 desc.prepare(chunk_size, i == 0, i == desc_count - 1);
168
169 remaining -= chunk_size;
170 offset += chunk_size;
171 }
172
173 fence(Ordering::Release);
179
180 for i in (0..desc_count).rev() {
182 let idx = (current + i) % TX;
183 self.tx_ring.get(idx).set_owned();
184 }
185
186 fence(Ordering::Release);
189
190 self.tx_ring.advance_by(desc_count);
191 Ok(data.len())
192 }
193
194 pub fn tx_reclaim(&mut self) -> usize {
198 fence(Ordering::Acquire);
200 let mut reclaimed = 0;
201 for i in 0..TX {
202 let idx = (self.tx_ring.current_index() + i) % TX;
203 let desc = self.tx_ring.get(idx);
204 if !desc.is_owned() {
205 reclaimed += 1;
206 }
207 }
208 reclaimed
209 }
210
211 #[must_use]
231 pub fn rx_available(&self) -> bool {
232 fence(Ordering::Acquire);
234 let desc = self.rx_ring.current();
235 if desc.is_owned() {
236 return false;
237 }
238 if desc.has_error() {
241 return true;
242 }
243 self.peek_frame_length().is_some()
244 }
245
246 pub fn receive(&mut self, buffer: &mut [u8]) -> Result<Option<usize>, EmacError> {
252 fence(Ordering::Acquire);
254 let first_desc = self.rx_ring.current();
255
256 if first_desc.is_owned() {
258 return Ok(None);
259 }
260
261 if first_desc.is_first() && first_desc.is_last() {
263 if first_desc.has_error() {
264 first_desc.recycle();
265 fence(Ordering::Release);
274 self.rx_ring.advance();
275 return Err(EmacError::FrameError);
276 }
277
278 let frame_len = first_desc.payload_length();
279 if buffer.len() < frame_len {
280 first_desc.recycle();
281 fence(Ordering::Release);
282 self.rx_ring.advance();
283 return Err(EmacError::BufferTooSmall);
284 }
285
286 let idx = self.rx_ring.current_index();
287 buffer[..frame_len].copy_from_slice(&self.rx_buffers[idx][..frame_len]);
288 first_desc.recycle();
289 fence(Ordering::Release);
290 self.rx_ring.advance();
291 return Ok(Some(frame_len));
292 }
293
294 if !first_desc.is_first() {
296 self.flush_rx_frame();
297 return Ok(None);
298 }
299
300 if first_desc.has_error() {
301 self.flush_rx_frame();
302 return Err(EmacError::FrameError);
303 }
304
305 let mut frame_len = 0usize;
307 let mut desc_count = 0usize;
308 let current = self.rx_ring.current_index();
309
310 for i in 0..RX {
311 let idx = (current + i) % RX;
312 let desc = self.rx_ring.get(idx);
313
314 if desc.is_owned() {
315 return Ok(None);
317 }
318
319 desc_count += 1;
320
321 if desc.is_last() {
322 frame_len = desc.payload_length();
323 break;
324 }
325 }
326
327 if frame_len == 0 {
328 return Ok(None);
329 }
330
331 if buffer.len() < frame_len {
332 self.flush_rx_frame();
333 return Err(EmacError::BufferTooSmall);
334 }
335
336 let mut copied = 0usize;
338 let last_desc_i = desc_count - 1;
339
340 for i in 0..desc_count {
341 let idx = (current + i) % RX;
342 let copy_len = if i == last_desc_i {
343 frame_len - copied
344 } else {
345 BUF
346 };
347 let copy_len = core::cmp::min(copy_len, frame_len - copied);
348
349 if copy_len > 0 {
350 buffer[copied..copied + copy_len]
351 .copy_from_slice(&self.rx_buffers[idx][..copy_len]);
352 copied += copy_len;
353 }
354 self.rx_ring.get(idx).recycle();
355 }
356
357 fence(Ordering::Release);
361 self.rx_ring.advance_by(desc_count);
362 Ok(Some(frame_len))
363 }
364
365 #[must_use]
367 pub fn peek_frame_length(&self) -> Option<usize> {
368 fence(Ordering::Acquire);
370 let desc = self.rx_ring.current();
371
372 if desc.is_owned() {
373 return None;
374 }
375
376 if desc.has_error() {
377 return None;
378 }
379
380 if desc.is_first() && desc.is_last() {
382 return Some(desc.payload_length());
383 }
384
385 if desc.is_first() {
387 for i in 1..RX {
388 let idx = (self.rx_ring.current_index() + i) % RX;
389 let d = self.rx_ring.get(idx);
390
391 if d.is_owned() {
392 return None;
393 }
394
395 if d.is_last() {
396 return Some(d.payload_length());
397 }
398 }
399 }
400
401 None
402 }
403
404 #[must_use]
406 pub fn rx_free_count(&self) -> usize {
407 let mut count = 0;
408 for i in 0..RX {
409 if self.rx_ring.get(i).is_owned() {
410 count += 1;
411 }
412 }
413 count
414 }
415
416 pub fn reset(&mut self) -> (u32, u32) {
420 self.init()
421 }
422
423 fn flush_rx_frame(&mut self) {
425 fence(Ordering::Acquire);
426 loop {
427 let desc = self.rx_ring.current();
428
429 if desc.is_owned() {
430 break;
431 }
432
433 let is_last = desc.is_last();
434 desc.recycle();
435 fence(Ordering::Release);
439 self.rx_ring.advance();
440
441 if is_last {
442 break;
443 }
444 }
445 }
446
447 #[must_use]
449 pub fn rx_ring_base(&self) -> u32 {
450 self.rx_ring.base_addr() as u32
451 }
452
453 #[must_use]
455 pub fn tx_ring_base(&self) -> u32 {
456 self.tx_ring.base_addr() as u32
457 }
458
459 #[must_use]
461 pub fn rx_current_index(&self) -> usize {
462 self.rx_ring.current_index()
463 }
464
465 #[must_use]
467 pub fn tx_current_index(&self) -> usize {
468 self.tx_ring.current_index()
469 }
470}
471
472impl<const RX: usize, const TX: usize, const BUF: usize> Default for DmaEngine<RX, TX, BUF> {
473 fn default() -> Self {
474 Self::new()
475 }
476}
477
478unsafe impl<const RX: usize, const TX: usize, const BUF: usize> Sync for DmaEngine<RX, TX, BUF> {}
480
481unsafe impl<const RX: usize, const TX: usize, const BUF: usize> Send for DmaEngine<RX, TX, BUF> {}
483
484#[cfg(test)]
489mod tests {
490 use super::*;
491 use crate::dma::descriptor::bits::rdes0;
492
493 #[test]
496 fn new_not_initialized() {
497 let engine: DmaEngine<4, 4, 256> = DmaEngine::new();
498 assert!(!engine.is_initialized());
499 }
500
501 #[test]
502 fn init_sets_initialized() {
503 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
504 let _ = engine.init();
505 assert!(engine.is_initialized());
506 }
507
508 #[test]
509 fn init_returns_base_addresses() {
510 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
511 let (rx_base, tx_base) = engine.init();
512
513 assert_ne!(rx_base, 0);
515 assert_ne!(tx_base, 0);
516
517 assert_ne!(rx_base, tx_base);
519 }
520
521 #[test]
522 fn init_chains_rx_descriptors() {
523 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
524 let (rx_base, _) = engine.init();
525
526 for i in 0..4 {
528 let desc = engine.rx_ring.get(i);
529 assert!(desc.is_owned(), "RX desc {} should be DMA-owned", i);
530 assert_ne!(desc.buffer_addr(), 0, "RX desc {} buffer must be set", i);
531 assert_ne!(desc.next_desc_addr(), 0, "RX desc {} chain must be set", i);
532 }
533
534 assert_eq!(engine.rx_ring.get(3).next_desc_addr(), rx_base);
536 }
537
538 #[test]
539 fn init_chains_tx_descriptors() {
540 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
541 let (_, tx_base) = engine.init();
542
543 for i in 0..4 {
545 let desc = engine.tx_ring.get(i);
546 assert!(!desc.is_owned(), "TX desc {} should be CPU-owned", i);
547 assert_ne!(desc.buffer_addr(), 0, "TX desc {} buffer must be set", i);
548 assert_ne!(desc.next_desc_addr(), 0, "TX desc {} chain must be set", i);
549 }
550
551 assert_eq!(engine.tx_ring.get(3).next_desc_addr(), tx_base);
553 }
554
555 #[test]
558 fn memory_usage_calculation() {
559 let usage = DmaEngine::<4, 4, 256>::memory_usage();
562 assert_eq!(usage, 2304);
563 }
564
565 #[test]
566 fn memory_usage_scales() {
567 let small = DmaEngine::<2, 2, 512>::memory_usage();
568 let large = DmaEngine::<10, 10, 1600>::memory_usage();
569 assert!(large > small);
570 }
571
572 #[test]
575 fn tx_available_after_init() {
576 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
577 let _ = engine.init();
578 assert_eq!(engine.tx_available(), 4);
579 }
580
581 #[test]
582 fn can_transmit_empty() {
583 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
584 let _ = engine.init();
585 assert!(!engine.can_transmit(0));
586 }
587
588 #[test]
589 fn can_transmit_single_buffer() {
590 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
591 let _ = engine.init();
592 assert!(engine.can_transmit(100));
593 assert!(engine.can_transmit(256));
594 }
595
596 #[test]
597 fn can_transmit_too_large() {
598 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
599 let _ = engine.init();
600 assert!(!engine.can_transmit(1025));
602 }
603
604 #[test]
605 fn can_transmit_multi_buffer() {
606 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
607 let _ = engine.init();
608 assert!(engine.can_transmit(512));
610 assert!(engine.can_transmit(1024));
612 }
613
614 #[test]
617 fn transmit_single_frame() {
618 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
619 let _ = engine.init();
620
621 let data = [0xABu8; 100];
622 let result = engine.transmit(&data);
623 assert_eq!(result, Ok(100));
624 }
625
626 #[test]
627 fn transmit_sets_own_bit() {
628 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
629 let _ = engine.init();
630
631 let data = [0xABu8; 100];
632 let _ = engine.transmit(&data);
633
634 assert!(engine.tx_ring.get(0).is_owned());
636 assert_eq!(engine.tx_current_index(), 1);
638 }
639
640 #[test]
641 fn transmit_copies_data_to_buffer() {
642 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
643 let _ = engine.init();
644
645 let data = [0xCA; 64];
646 let _ = engine.transmit(&data);
647
648 assert_eq!(&engine.tx_buffers[0][..64], &data[..]);
650 }
651
652 #[test]
653 fn transmit_scatter_gather() {
654 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
655 let _ = engine.init();
656
657 let data = [0xBBu8; 400];
659 let result = engine.transmit(&data);
660 assert_eq!(result, Ok(400));
661
662 assert!(engine.tx_ring.get(0).is_owned());
664 assert!(engine.tx_ring.get(1).is_owned());
665
666 assert_eq!(engine.tx_current_index(), 2);
668 }
669
670 #[test]
671 fn transmit_when_full() {
672 let mut engine: DmaEngine<2, 2, 256> = DmaEngine::new();
673 let _ = engine.init();
674
675 let data = [0xAAu8; 100];
677 assert!(engine.transmit(&data).is_ok());
678 assert!(engine.transmit(&data).is_ok());
679
680 let result = engine.transmit(&data);
682 assert_eq!(result, Err(EmacError::NoDescriptorsAvailable));
683 }
684
685 #[test]
686 fn transmit_empty_data_returns_error() {
687 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
688 let _ = engine.init();
689
690 let result = engine.transmit(&[]);
691 assert_eq!(result, Err(EmacError::InvalidLength));
692 }
693
694 #[test]
695 fn transmit_too_large_returns_error() {
696 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
697 let _ = engine.init();
698
699 let data = [0u8; 2048]; let result = engine.transmit(&data);
701 assert_eq!(result, Err(EmacError::FrameTooLarge));
702 }
703
704 #[test]
707 fn tx_reclaim_returns_completed() {
708 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
709 let _ = engine.init();
710
711 let _ = engine.transmit(&[0xAA; 100]);
713 assert!(engine.tx_ring.get(0).is_owned());
714
715 engine.tx_ring.get(0).clear_owned();
717
718 let reclaimed = engine.tx_reclaim();
719 assert_eq!(reclaimed, 4);
721 }
722
723 #[test]
726 fn rx_available_no_frame() {
727 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
728 let _ = engine.init();
729
730 assert!(!engine.rx_available());
732 }
733
734 #[test]
735 fn receive_no_frame_returns_none() {
736 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
737 let _ = engine.init();
738
739 let mut buf = [0u8; 256];
740 let result = engine.receive(&mut buf);
741 assert_eq!(result, Ok(None));
742 }
743
744 fn simulate_rx_frame(engine: &mut DmaEngine<4, 4, 256>, desc_index: usize, data: &[u8]) {
752 engine.rx_buffers[desc_index][..data.len()].copy_from_slice(data);
754
755 let frame_len_with_crc = (data.len() + 4) as u32;
757 let rdes0_val =
758 rdes0::FIRST_DESC | rdes0::LAST_DESC | (frame_len_with_crc << rdes0::FRAME_LEN_SHIFT);
759 engine.rx_ring.get(desc_index).set_raw_rdes0(rdes0_val);
761 }
762
763 #[test]
764 fn receive_simulated_frame() {
765 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
766 let _ = engine.init();
767
768 let payload = [0xDE; 64];
770 simulate_rx_frame(&mut engine, 0, &payload);
771
772 let mut buf = [0u8; 256];
773 let result = engine.receive(&mut buf);
774 assert_eq!(result, Ok(Some(64)));
775 assert_eq!(&buf[..64], &payload[..]);
776 }
777
778 #[test]
779 fn receive_advances_ring() {
780 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
781 let _ = engine.init();
782
783 simulate_rx_frame(&mut engine, 0, &[0xAA; 32]);
784 assert_eq!(engine.rx_current_index(), 0);
785
786 let mut buf = [0u8; 256];
787 let _ = engine.receive(&mut buf);
788 assert_eq!(engine.rx_current_index(), 1);
789 }
790
791 #[test]
792 fn receive_recycles_descriptor() {
793 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
794 let _ = engine.init();
795
796 simulate_rx_frame(&mut engine, 0, &[0xAA; 32]);
797 let mut buf = [0u8; 256];
798 let _ = engine.receive(&mut buf);
799
800 assert!(engine.rx_ring.get(0).is_owned());
802 }
803
804 #[test]
805 fn peek_frame_length_returns_size() {
806 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
807 let _ = engine.init();
808
809 simulate_rx_frame(&mut engine, 0, &[0xBB; 100]);
810
811 let len = engine.peek_frame_length();
812 assert_eq!(len, Some(100));
813
814 assert!(engine.rx_available());
816 }
817
818 #[test]
819 fn peek_frame_length_none_when_empty() {
820 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
821 let _ = engine.init();
822
823 assert_eq!(engine.peek_frame_length(), None);
824 }
825
826 fn simulate_rx_frame_two_descriptors(
830 engine: &mut DmaEngine<4, 4, 256>,
831 start: usize,
832 chunks: (&[u8], &[u8]),
833 ) {
834 let (a, b) = chunks;
835 engine.rx_buffers[start][..a.len()].copy_from_slice(a);
836 engine.rx_buffers[start + 1][..b.len()].copy_from_slice(b);
837
838 engine.rx_ring.get(start).set_raw_rdes0(rdes0::FIRST_DESC);
841
842 let frame_len_with_crc = (a.len() + b.len() + 4) as u32;
844 let rdes0_val = rdes0::LAST_DESC | (frame_len_with_crc << rdes0::FRAME_LEN_SHIFT);
845 engine.rx_ring.get(start + 1).set_raw_rdes0(rdes0_val);
846 }
847
848 #[test]
849 fn rx_available_true_for_errored_frame() {
850 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
856 let _ = engine.init();
857
858 let rdes0_val = rdes0::FIRST_DESC | rdes0::LAST_DESC | rdes0::ERR_SUMMARY | rdes0::CRC_ERR;
861 engine.rx_ring.get(0).set_raw_rdes0(rdes0_val);
862
863 assert_eq!(engine.peek_frame_length(), None);
866 assert!(
869 engine.rx_available(),
870 "rx_available must signal errored frames so receive can flush them"
871 );
872 }
873
874 #[test]
875 fn rx_available_true_for_multi_descriptor_frame() {
876 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
881 let _ = engine.init();
882
883 let chunk_a = [0xAA; 200];
884 let chunk_b = [0xBB; 100];
885 simulate_rx_frame_two_descriptors(&mut engine, 0, (&chunk_a, &chunk_b));
886
887 assert!(
890 engine.rx_available(),
891 "rx_available must report a multi-descriptor frame as ready"
892 );
893 assert_eq!(engine.peek_frame_length(), Some(300));
894 }
895
896 #[test]
897 fn rx_free_count_after_init() {
898 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
899 let _ = engine.init();
900
901 assert_eq!(engine.rx_free_count(), 4);
903 }
904
905 #[test]
906 fn rx_free_count_after_receive() {
907 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
908 let _ = engine.init();
909
910 simulate_rx_frame(&mut engine, 0, &[0xCC; 48]);
911 assert_eq!(engine.rx_free_count(), 3);
913
914 let mut buf = [0u8; 256];
916 let _ = engine.receive(&mut buf);
917
918 assert_eq!(engine.rx_free_count(), 4);
920 }
921
922 #[test]
923 fn receive_buffer_too_small() {
924 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
925 let _ = engine.init();
926
927 simulate_rx_frame(&mut engine, 0, &[0xDD; 200]);
928
929 let mut buf = [0u8; 32]; let result = engine.receive(&mut buf);
931 assert_eq!(result, Err(EmacError::BufferTooSmall));
932
933 assert!(engine.rx_ring.get(0).is_owned());
935 }
936
937 #[test]
940 fn reset_reinitializes() {
941 let mut engine: DmaEngine<4, 4, 256> = DmaEngine::new();
942 let _ = engine.init();
943
944 let _ = engine.transmit(&[0xAA; 100]);
946 assert_eq!(engine.tx_current_index(), 1);
947
948 let (rx_base, tx_base) = engine.reset();
950 assert_ne!(rx_base, 0);
951 assert_ne!(tx_base, 0);
952
953 assert_eq!(engine.rx_current_index(), 0);
955 assert_eq!(engine.tx_current_index(), 0);
956
957 assert_eq!(engine.tx_available(), 4);
959
960 assert_eq!(engine.rx_free_count(), 4);
962 }
963
964 #[test]
967 fn default_trait() {
968 let d1: DmaEngine<4, 4, 256> = DmaEngine::new();
969 let d2: DmaEngine<4, 4, 256> = DmaEngine::default();
970 assert_eq!(d1.is_initialized(), d2.is_initialized());
971 }
972}