1#[cfg(dma_can_access_psram)]
2use core::{mem::MaybeUninit, ops::Range};
3use core::{
4 ops::{Deref, DerefMut},
5 ptr::{NonNull, null_mut},
6};
7
8use super::*;
9#[cfg(dma_can_access_psram)]
10use crate::soc::{is_slice_in_psram, is_valid_psram_address, is_valid_ram_address};
11use crate::{
12 dma::aligned::{DmaAlignedMut, InternalMemory},
13 soc::is_slice_in_dram,
14};
15
16pub(crate) mod scoped;
17pub(crate) use scoped::*;
18
19#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub enum DmaBufError {
23 BufferTooSmall,
25
26 InsufficientDescriptors,
28
29 UnsupportedMemoryRegion,
31
32 InvalidAlignment(DmaAlignmentError),
34
35 InvalidChunkSize,
37}
38
39impl core::fmt::Display for DmaBufError {
40 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
41 match self {
42 DmaBufError::BufferTooSmall => {
43 write!(f, "The buffer is smaller than the requested size")
44 }
45 DmaBufError::InsufficientDescriptors => {
46 write!(f, "More descriptors are needed for the buffer size")
47 }
48 DmaBufError::UnsupportedMemoryRegion => write!(
49 f,
50 "Descriptors or buffers are not located in a supported memory region"
51 ),
52 DmaBufError::InvalidAlignment(x) => write!(f, "{x}"),
53 DmaBufError::InvalidChunkSize => {
54 write!(f, "Invalid chunk size: must be > 0 and <= 4095")
55 }
56 }
57 }
58}
59
60impl core::error::Error for DmaBufError {}
61
62#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65pub enum DmaAlignmentError {
66 Address,
68
69 Size,
71}
72
73impl From<DmaAlignmentError> for DmaBufError {
74 fn from(err: DmaAlignmentError) -> Self {
75 DmaBufError::InvalidAlignment(err)
76 }
77}
78
79impl core::fmt::Display for DmaAlignmentError {
80 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81 match self {
82 DmaAlignmentError::Address => write!(f, "Buffer address is not properly aligned"),
83 DmaAlignmentError::Size => write!(f, "Buffer size is not properly aligned"),
84 }
85 }
86}
87
88impl core::error::Error for DmaAlignmentError {}
89
90cfg_select! {
91 dma_can_access_psram => {
92 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
94 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
95 pub enum ExternalBurstConfig {
96 Size16 = 16,
98
99 Size32 = 32,
101
102 #[cfg(not(esp32s2))]
105 Size64 = 64,
106 }
107
108 impl ExternalBurstConfig {
109 pub const DEFAULT: Self = Self::Size16;
111 }
112
113 impl Default for ExternalBurstConfig {
114 fn default() -> Self {
115 Self::DEFAULT
116 }
117 }
118
119 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
121 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
122 pub enum InternalBurstConfig {
123 Disabled,
125
126 Enabled,
128 }
129
130 impl InternalBurstConfig {
131 pub const DEFAULT: Self = Self::Disabled;
133 }
134
135 impl Default for InternalBurstConfig {
136 fn default() -> Self {
137 Self::DEFAULT
138 }
139 }
140
141 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
143 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
144 pub struct BurstConfig {
145 pub external_memory: ExternalBurstConfig,
149
150 pub internal_memory: InternalBurstConfig,
154 }
155
156 impl BurstConfig {
157 pub const DEFAULT: Self = Self {
159 external_memory: ExternalBurstConfig::DEFAULT,
160 internal_memory: InternalBurstConfig::DEFAULT,
161 };
162 }
163
164 impl Default for BurstConfig {
165 fn default() -> Self {
166 Self::DEFAULT
167 }
168 }
169
170 impl From<InternalBurstConfig> for BurstConfig {
171 fn from(internal_memory: InternalBurstConfig) -> Self {
172 Self {
173 external_memory: ExternalBurstConfig::DEFAULT,
174 internal_memory,
175 }
176 }
177 }
178
179 impl From<ExternalBurstConfig> for BurstConfig {
180 fn from(external_memory: ExternalBurstConfig) -> Self {
181 Self {
182 external_memory,
183 internal_memory: InternalBurstConfig::DEFAULT,
184 }
185 }
186 }
187 }
188 _ => {
189 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
191 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
192 pub enum BurstConfig {
193 Disabled,
195
196 Enabled,
198 }
199
200 impl BurstConfig {
201 pub const DEFAULT: Self = Self::Disabled;
203 }
204
205 impl Default for BurstConfig {
206 fn default() -> Self {
207 Self::DEFAULT
208 }
209 }
210
211 type InternalBurstConfig = BurstConfig;
212 }
213}
214
215#[cfg(dma_can_access_psram)]
216impl ExternalBurstConfig {
217 const fn min_psram_alignment(self, direction: TransferDirection) -> usize {
218 if matches!(direction, TransferDirection::In) {
229 self as usize
230 } else {
231 1
237 }
238 }
239}
240
241impl InternalBurstConfig {
242 pub(super) const fn is_burst_enabled(self) -> bool {
243 !matches!(self, Self::Disabled)
244 }
245
246 const fn min_dram_alignment(self, direction: TransferDirection) -> usize {
248 if matches!(direction, TransferDirection::In) {
249 if cfg!(esp32) {
250 4
253 } else if self.is_burst_enabled() {
254 4
256 } else {
257 1
258 }
259 } else {
260 if cfg!(esp32) {
263 4
269 } else {
270 1
271 }
272 }
273 }
274}
275
276const fn max(a: usize, b: usize) -> usize {
277 if a > b { a } else { b }
278}
279
280impl BurstConfig {
281 delegate::delegate! {
282 to self.internal_memory {
283 #[cfg(dma_can_access_psram)]
284 pub(super) const fn min_dram_alignment(self, direction: TransferDirection) -> usize;
285
286 #[cfg(all(dma_can_access_psram, not(esp32s31)))] pub(super) fn is_burst_enabled(self) -> bool;
288 }
289 }
290
291 pub const fn min_compatible_alignment(self) -> usize {
297 let in_alignment = self.min_dram_alignment(TransferDirection::In);
298 let out_alignment = self.min_dram_alignment(TransferDirection::Out);
299 let alignment = max(in_alignment, out_alignment);
300
301 #[cfg(dma_can_access_psram)]
302 let alignment = max(alignment, self.external_memory as usize);
303
304 alignment
305 }
306
307 const fn chunk_size_for_alignment(alignment: usize) -> usize {
308 4096 - alignment
312 }
313
314 pub const fn max_compatible_chunk_size(self) -> usize {
320 Self::chunk_size_for_alignment(self.min_compatible_alignment())
321 }
322
323 fn min_alignment(self, _buffer: &[u8], direction: TransferDirection) -> usize {
324 let alignment = self.min_dram_alignment(direction);
325
326 cfg_select! {
327 dma_can_access_psram => {
328 let mut alignment = alignment;
329 if is_valid_psram_address(_buffer.as_ptr() as usize) {
330 alignment = max(
331 alignment,
332 self.external_memory.min_psram_alignment(direction),
333 );
334 }
335 }
336 _ => {}
337 }
338
339 alignment
340 }
341
342 fn max_chunk_size_for(self, buffer: &[u8], direction: TransferDirection) -> usize {
345 Self::chunk_size_for_alignment(self.min_alignment(buffer, direction))
346 }
347
348 fn ensure_buffer_aligned(
349 self,
350 buffer: &[u8],
351 direction: TransferDirection,
352 ) -> Result<(), DmaAlignmentError> {
353 let alignment = self.min_alignment(buffer, direction);
354 if !(buffer.as_ptr() as usize).is_multiple_of(alignment) {
355 return Err(DmaAlignmentError::Address);
356 }
357
358 if direction == TransferDirection::In && !buffer.len().is_multiple_of(alignment) {
362 return Err(DmaAlignmentError::Size);
363 }
364
365 Ok(())
366 }
367
368 fn ensure_buffer_compatible(
369 self,
370 buffer: &[u8],
371 direction: TransferDirection,
372 ) -> Result<(), DmaBufError> {
373 if buffer.is_empty() {
374 return Ok(());
375 }
376 let is_in_dram = is_slice_in_dram(buffer);
378 cfg_select! {
379 dma_can_access_psram => {
380 let is_in_psram = is_slice_in_psram(buffer);
381 }
382 _ => {
383 let is_in_psram = false;
384 }
385 }
386
387 if !(is_in_dram || is_in_psram) {
388 return Err(DmaBufError::UnsupportedMemoryRegion);
389 }
390
391 self.ensure_buffer_aligned(buffer, direction)?;
392
393 Ok(())
394 }
395}
396
397#[derive(Clone, Copy, PartialEq, Eq, Debug)]
399#[cfg_attr(feature = "defmt", derive(defmt::Format))]
400pub enum TransferDirection {
401 In,
403 Out,
405}
406
407#[derive(PartialEq, Eq, Debug)]
409#[cfg_attr(feature = "defmt", derive(defmt::Format))]
410pub struct Preparation {
411 pub start: *mut DmaDescriptor,
413
414 #[cfg(dma_can_access_psram)]
416 pub accesses_psram: bool,
417
418 #[doc = crate::trm_markdown_link!()]
426 pub burst_transfer: BurstConfig,
427
428 pub check_owner: Option<bool>,
455
456 pub auto_write_back: bool,
466}
467
468pub unsafe trait DmaTxBuffer {
476 type View;
479
480 type Final;
484
485 fn prepare(&mut self) -> Preparation;
490
491 fn into_view(self) -> Self::View;
493
494 fn from_view(view: Self::View) -> Self::Final;
496}
497
498pub unsafe trait DmaRxBuffer {
510 type View;
513
514 type Final;
518
519 fn prepare(&mut self) -> Preparation;
524
525 fn into_view(self) -> Self::View;
527
528 fn from_view(view: Self::View) -> Self::Final;
530}
531
532pub struct BufView<T>(T);
537
538#[derive(Debug)]
544#[cfg_attr(feature = "defmt", derive(defmt::Format))]
545pub struct DmaTxBuf(ScopedDmaTxBuf<'static>);
546
547impl DmaTxBuf {
548 pub fn new(
550 descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
551 buffer: DmaAlignedMut<'static, [u8]>,
552 ) -> Result<Self, DmaBufError> {
553 ScopedDmaTxBuf::new(descriptors, buffer).map(Self)
554 }
555
556 pub fn new_with_config(
565 descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
566 buffer: DmaAlignedMut<'static, [u8]>,
567 config: impl Into<BurstConfig>,
568 ) -> Result<Self, DmaBufError> {
569 ScopedDmaTxBuf::new_with_config(descriptors, buffer, config).map(Self)
570 }
571
572 pub fn set_burst_config(&mut self, burst: BurstConfig) -> Result<(), DmaBufError> {
574 self.0.set_burst_config(burst)
575 }
576
577 pub fn split(
579 self,
580 ) -> (
581 DmaAlignedMut<'static, [DmaDescriptor]>,
582 DmaAlignedMut<'static, [u8]>,
583 ) {
584 self.0.split()
585 }
586
587 pub fn capacity(&self) -> usize {
589 self.0.capacity()
590 }
591
592 #[allow(clippy::len_without_is_empty)]
594 pub fn len(&self) -> usize {
595 self.0.len()
596 }
597
598 pub fn set_length(&mut self, len: usize) {
604 self.0.set_length(len);
605 }
606
607 pub fn fill(&mut self, data: &[u8]) {
613 self.0.fill(data);
614 }
615
616 pub fn as_mut_slice(&mut self) -> &mut [u8] {
618 self.0.as_mut_slice()
619 }
620
621 pub fn as_slice(&self) -> &[u8] {
623 self.0.as_slice()
624 }
625
626 pub(crate) fn into_scoped(self) -> ScopedDmaTxBuf<'static> {
628 self.0
629 }
630}
631
632unsafe impl DmaTxBuffer for DmaTxBuf {
633 type View = BufView<DmaTxBuf>;
634 type Final = DmaTxBuf;
635
636 fn prepare(&mut self) -> Preparation {
637 self.0.prepare()
638 }
639
640 fn into_view(self) -> BufView<DmaTxBuf> {
641 BufView(self)
642 }
643
644 fn from_view(view: Self::View) -> Self {
645 view.0
646 }
647}
648
649#[derive(Debug)]
655#[cfg_attr(feature = "defmt", derive(defmt::Format))]
656pub struct DmaRxBuf(ScopedDmaRxBuf<'static>);
657
658impl DmaRxBuf {
659 pub fn new(
661 descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
662 buffer: DmaAlignedMut<'static, [u8]>,
663 ) -> Result<Self, DmaBufError> {
664 ScopedDmaRxBuf::new(descriptors, buffer).map(Self)
665 }
666
667 pub fn new_with_config(
676 descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
677 buffer: DmaAlignedMut<'static, [u8]>,
678 config: impl Into<BurstConfig>,
679 ) -> Result<Self, DmaBufError> {
680 ScopedDmaRxBuf::new_with_config(descriptors, buffer, config).map(Self)
681 }
682
683 pub fn set_burst_config(&mut self, burst: BurstConfig) -> Result<(), DmaBufError> {
685 self.0.set_burst_config(burst)
686 }
687
688 pub fn split(
690 self,
691 ) -> (
692 DmaAlignedMut<'static, [DmaDescriptor]>,
693 DmaAlignedMut<'static, [u8]>,
694 ) {
695 self.0.split()
696 }
697
698 pub fn capacity(&self) -> usize {
700 self.0.capacity()
701 }
702
703 #[allow(clippy::len_without_is_empty)]
706 pub fn len(&self) -> usize {
707 self.0.len()
708 }
709
710 pub fn set_length(&mut self, len: usize) {
716 self.0.set_length(len)
717 }
718
719 pub fn as_slice(&self) -> &[u8] {
721 self.0.as_slice()
722 }
723
724 pub fn as_mut_slice(&mut self) -> &mut [u8] {
726 self.0.as_mut_slice()
727 }
728
729 pub fn number_of_received_bytes(&self) -> usize {
731 self.0.number_of_received_bytes()
732 }
733
734 pub fn read_received_data(&self, buf: &mut [u8]) -> usize {
741 self.0.read_received_data(buf)
742 }
743
744 pub fn received_data(&self) -> impl Iterator<Item = &[u8]> {
746 self.0.received_data()
747 }
748
749 pub(crate) fn into_scoped(self) -> ScopedDmaRxBuf<'static> {
751 self.0
752 }
753}
754
755unsafe impl DmaRxBuffer for DmaRxBuf {
756 type View = BufView<DmaRxBuf>;
757 type Final = DmaRxBuf;
758
759 fn prepare(&mut self) -> Preparation {
760 self.0.prepare()
761 }
762
763 fn into_view(self) -> BufView<DmaRxBuf> {
764 BufView(self)
765 }
766
767 fn from_view(view: Self::View) -> Self {
768 view.0
769 }
770}
771
772#[derive(Debug)]
779#[cfg_attr(feature = "defmt", derive(defmt::Format))]
780pub struct DmaRxTxBuf {
781 rx_descriptors: DescriptorSet<'static>,
782 tx_descriptors: DescriptorSet<'static>,
783 buffer: DmaAlignedMut<'static, [u8]>,
784 burst: BurstConfig,
785}
786
787impl DmaRxTxBuf {
788 pub fn new(
790 rx_descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
791 tx_descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
792 buffer: DmaAlignedMut<'static, [u8]>,
793 ) -> Result<Self, DmaBufError> {
794 let mut buf = Self {
795 rx_descriptors: DescriptorSet::new(rx_descriptors)?,
796 tx_descriptors: DescriptorSet::new(tx_descriptors)?,
797 buffer,
798 burst: BurstConfig::default(),
799 };
800
801 let capacity = buf.capacity();
802 buf.configure(buf.burst, capacity)?;
803
804 Ok(buf)
805 }
806
807 fn configure(
808 &mut self,
809 burst: impl Into<BurstConfig>,
810 length: usize,
811 ) -> Result<(), DmaBufError> {
812 let burst = burst.into();
813 self.set_length_fallible(length, burst)?;
814
815 let max_chunk_size_in = burst.max_chunk_size_for(&self.buffer, TransferDirection::In);
816 let max_chunk_size_out = burst.max_chunk_size_for(&self.buffer, TransferDirection::Out);
817 self.rx_descriptors
818 .link_with_buffer(&mut self.buffer, max_chunk_size_in)?;
819 self.tx_descriptors
820 .link_with_buffer(&mut self.buffer, max_chunk_size_out)?;
821
822 self.burst = burst;
823
824 Ok(())
825 }
826
827 pub fn set_burst_config(&mut self, burst: BurstConfig) -> Result<(), DmaBufError> {
829 let len = self.len();
830 self.configure(burst, len)
831 }
832
833 #[allow(clippy::type_complexity)]
836 pub fn split(
837 self,
838 ) -> (
839 DmaAlignedMut<'static, [DmaDescriptor]>,
840 DmaAlignedMut<'static, [DmaDescriptor]>,
841 DmaAlignedMut<'static, [u8]>,
842 ) {
843 (
844 self.rx_descriptors.into_inner(),
845 self.tx_descriptors.into_inner(),
846 self.buffer,
847 )
848 }
849
850 pub fn capacity(&self) -> usize {
852 self.buffer.len()
853 }
854
855 #[allow(clippy::len_without_is_empty)]
857 pub fn len(&self) -> usize {
858 self.tx_descriptors
859 .linked_iter()
860 .map(|d| d.len())
861 .sum::<usize>()
862 }
863
864 pub fn as_slice(&self) -> &[u8] {
866 &self.buffer
867 }
868
869 pub fn as_mut_slice(&mut self) -> &mut [u8] {
871 &mut self.buffer
872 }
873
874 fn set_length_fallible(&mut self, len: usize, burst: BurstConfig) -> Result<(), DmaBufError> {
875 if len > self.capacity() {
876 return Err(DmaBufError::BufferTooSmall);
877 }
878 burst.ensure_buffer_compatible(&self.buffer[..len], TransferDirection::In)?;
879 burst.ensure_buffer_compatible(&self.buffer[..len], TransferDirection::Out)?;
880
881 let max_chunk_size_in = burst.max_chunk_size_for(&self.buffer, TransferDirection::In);
882 let max_chunk_size_out = burst.max_chunk_size_for(&self.buffer, TransferDirection::Out);
883 self.rx_descriptors.set_rx_length(len, max_chunk_size_in)?;
884 self.tx_descriptors.set_tx_length(len, max_chunk_size_out)?;
885
886 Ok(())
887 }
888
889 pub fn set_length(&mut self, len: usize) {
894 unwrap!(self.set_length_fallible(len, self.burst));
895 }
896}
897
898unsafe impl DmaTxBuffer for DmaRxTxBuf {
899 type View = BufView<DmaRxTxBuf>;
900 type Final = DmaRxTxBuf;
901
902 fn prepare(&mut self) -> Preparation {
903 for desc in self.tx_descriptors.linked_iter_mut() {
904 desc.reset_for_tx(desc.next.is_null());
907 }
908
909 #[cfg(dma_can_access_psram)]
910 let is_data_in_psram = !is_valid_ram_address(self.buffer.as_ptr() as usize);
911
912 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
913 self.buffer.writeback();
914
915 Preparation {
916 start: self.tx_descriptors.head(),
917 #[cfg(dma_can_access_psram)]
918 accesses_psram: is_data_in_psram,
919 burst_transfer: self.burst,
920 check_owner: None,
921 auto_write_back: false,
922 }
923 }
924
925 fn into_view(self) -> BufView<DmaRxTxBuf> {
926 BufView(self)
927 }
928
929 fn from_view(view: Self::View) -> Self {
930 view.0
931 }
932}
933
934unsafe impl DmaRxBuffer for DmaRxTxBuf {
935 type View = BufView<DmaRxTxBuf>;
936 type Final = DmaRxTxBuf;
937
938 fn prepare(&mut self) -> Preparation {
939 for desc in self.rx_descriptors.linked_iter_mut() {
940 desc.reset_for_rx();
941 }
942
943 cfg_select! {
944 dma_can_access_psram => {
945 let is_data_in_psram = !is_valid_ram_address(self.buffer.as_ptr() as usize);
947 if is_data_in_psram || cfg!(soc_internal_memory_cached) {
948 unsafe {
949 crate::soc::cache_invalidate_addr(
950 self.buffer.as_ptr() as u32,
951 self.buffer.len() as u32,
952 )
953 };
954 }
955 }
956 _ => {}
957 }
958
959 Preparation {
960 start: self.rx_descriptors.head(),
961 #[cfg(dma_can_access_psram)]
962 accesses_psram: is_data_in_psram,
963 burst_transfer: self.burst,
964 check_owner: None,
965 auto_write_back: true,
966 }
967 }
968
969 fn into_view(self) -> BufView<DmaRxTxBuf> {
970 BufView(self)
971 }
972
973 fn from_view(view: Self::View) -> Self {
974 view.0
975 }
976}
977
978#[derive(Debug)]
1019#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1020pub struct DmaRxStreamBuf {
1021 descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
1022 buffer: DmaAlignedMut<'static, [u8]>,
1023 burst: BurstConfig,
1024}
1025
1026impl DmaRxStreamBuf {
1027 pub fn new(
1030 mut descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
1031 mut buffer: DmaAlignedMut<'static, [u8]>,
1032 ) -> Result<Self, DmaBufError> {
1033 if descriptors.len() < 4 {
1036 return Err(DmaBufError::InsufficientDescriptors);
1037 }
1038
1039 let chunk_size = Some(buffer.len() / descriptors.len())
1041 .filter(|x| *x <= 4095)
1042 .ok_or(DmaBufError::InsufficientDescriptors)?;
1043
1044 let mut chunks = buffer.chunks_exact_mut(chunk_size);
1045 for (desc, chunk) in descriptors.iter_mut().zip(chunks.by_ref()) {
1046 desc.buffer = chunk.as_mut_ptr();
1047 desc.set_size(chunk.len());
1048 }
1049
1050 let remainder = chunks.into_remainder();
1051
1052 if !remainder.is_empty() {
1053 let last_descriptor = descriptors.last_mut().unwrap();
1055 let size = last_descriptor.size() + remainder.len();
1056 if size > 4095 {
1057 return Err(DmaBufError::InsufficientDescriptors);
1058 }
1059 last_descriptor.set_size(size);
1060 }
1061
1062 Ok(Self {
1063 descriptors,
1064 buffer,
1065 burst: BurstConfig::default(),
1066 })
1067 }
1068
1069 pub fn split(
1071 self,
1072 ) -> (
1073 DmaAlignedMut<'static, [DmaDescriptor]>,
1074 DmaAlignedMut<'static, [u8]>,
1075 ) {
1076 (self.descriptors, self.buffer)
1077 }
1078}
1079
1080unsafe impl DmaRxBuffer for DmaRxStreamBuf {
1081 type View = DmaRxStreamBufView;
1082 type Final = DmaRxStreamBuf;
1083
1084 fn prepare(&mut self) -> Preparation {
1085 let mut next = null_mut();
1087 for desc in self.descriptors.iter_mut().rev() {
1088 desc.next = next;
1089 next = desc;
1090
1091 desc.reset_for_rx();
1092 }
1093
1094 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1095 self.descriptors.writeback();
1096
1097 Preparation {
1098 start: self.descriptors.as_mut_ptr(),
1099 #[cfg(dma_can_access_psram)]
1100 accesses_psram: false,
1101 burst_transfer: self.burst,
1102
1103 check_owner: None,
1108 auto_write_back: true,
1109 }
1110 }
1111
1112 fn into_view(self) -> DmaRxStreamBufView {
1113 DmaRxStreamBufView {
1114 buf: self,
1115 descriptor_idx: 0,
1116 descriptor_offset: 0,
1117 }
1118 }
1119
1120 fn from_view(view: Self::View) -> Self {
1121 view.buf
1122 }
1123}
1124
1125pub struct DmaRxStreamBufView {
1127 buf: DmaRxStreamBuf,
1128 descriptor_idx: usize,
1129 descriptor_offset: usize,
1130}
1131
1132impl DmaRxStreamBufView {
1133 pub fn available_bytes(&mut self) -> usize {
1135 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1136 self.buf.descriptors.invalidate();
1137
1138 let (tail, head) = self.buf.descriptors.split_at(self.descriptor_idx);
1139 let mut result = 0;
1140 for desc in head.iter().chain(tail) {
1141 if desc.owner() == Owner::Dma {
1142 break;
1143 }
1144 result += desc.len();
1145 }
1146 result - self.descriptor_offset
1147 }
1148
1149 pub fn pop(&mut self, buf: &mut [u8]) -> usize {
1151 if buf.is_empty() {
1152 return 0;
1153 }
1154 let total_bytes = buf.len();
1155
1156 let mut remaining = buf;
1157 loop {
1158 let available = self.peek();
1159 if available.is_empty() {
1160 break;
1161 }
1162 if available.len() >= remaining.len() {
1163 remaining.copy_from_slice(&available[0..remaining.len()]);
1164 self.consume(remaining.len());
1165 let consumed = remaining.len();
1166 remaining = &mut remaining[consumed..];
1167 break;
1168 } else {
1169 let to_consume = available.len();
1170 remaining[0..to_consume].copy_from_slice(available);
1171 self.consume(to_consume);
1172 remaining = &mut remaining[to_consume..];
1173 }
1174 }
1175
1176 total_bytes - remaining.len()
1177 }
1178
1179 pub fn peek(&mut self) -> &[u8] {
1185 let (slice, _) = self.peek_internal(false);
1186 slice
1187 }
1188
1189 pub fn peek_until_eof(&mut self) -> (&[u8], bool) {
1194 self.peek_internal(true)
1195 }
1196
1197 pub fn consume(&mut self, n: usize) -> usize {
1203 let mut remaining_bytes_to_consume = n;
1204 let mut descriptors_modified = false;
1205
1206 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1207 self.buf.descriptors.invalidate();
1208
1209 loop {
1210 let desc = &mut self.buf.descriptors[self.descriptor_idx];
1211
1212 if desc.owner() == Owner::Dma {
1213 break;
1216 }
1217
1218 let remaining_bytes_in_descriptor = desc.len() - self.descriptor_offset;
1219 if remaining_bytes_to_consume < remaining_bytes_in_descriptor {
1220 self.descriptor_offset += remaining_bytes_to_consume;
1221 remaining_bytes_to_consume = 0;
1222 break;
1223 }
1224
1225 desc.set_owner(Owner::Dma);
1227 desc.set_suc_eof(false);
1228 desc.set_length(0);
1229
1230 desc.next = null_mut();
1234
1235 let desc_ptr: *mut _ = desc;
1236
1237 let prev_descriptor_index = self
1238 .descriptor_idx
1239 .checked_sub(1)
1240 .unwrap_or(self.buf.descriptors.len() - 1);
1241
1242 self.buf.descriptors[prev_descriptor_index].next = desc_ptr;
1244 descriptors_modified = true;
1245
1246 self.descriptor_idx += 1;
1247 if self.descriptor_idx >= self.buf.descriptors.len() {
1248 self.descriptor_idx = 0;
1249 }
1250 self.descriptor_offset = 0;
1251
1252 remaining_bytes_to_consume -= remaining_bytes_in_descriptor;
1253 }
1254
1255 if descriptors_modified {
1256 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1257 self.buf.descriptors.writeback();
1258 }
1259
1260 n - remaining_bytes_to_consume
1261 }
1262
1263 fn peek_internal(&mut self, stop_at_eof: bool) -> (&[u8], bool) {
1264 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1265 self.buf.descriptors.invalidate();
1266
1267 let descriptors = &self.buf.descriptors[self.descriptor_idx..];
1268
1269 debug_assert!(!descriptors.is_empty());
1271
1272 if descriptors.len() == 1 {
1273 let last_descriptor = &descriptors[0];
1274 if last_descriptor.owner() == Owner::Dma {
1275 (&[], false)
1277 } else {
1278 let length = last_descriptor.len() - self.descriptor_offset;
1279 let chunk_size = last_descriptor.size();
1280 let buffer_start = self.buf.buffer.len() - chunk_size;
1281 #[cfg(soc_internal_memory_cached)]
1282 if length != 0 {
1283 unsafe {
1284 crate::soc::cache_invalidate_addr(
1285 self.buf.buffer.as_ptr().add(buffer_start) as u32,
1286 length as u32,
1287 );
1288 }
1289 }
1290 (
1291 &self.buf.buffer[buffer_start..][..length],
1292 last_descriptor.flags.suc_eof(),
1293 )
1294 }
1295 } else {
1296 let chunk_size = descriptors[0].size();
1297 let mut found_eof = false;
1298
1299 let mut number_of_contiguous_bytes = 0;
1300 for desc in descriptors {
1301 if desc.owner() == Owner::Dma {
1302 break;
1303 }
1304 number_of_contiguous_bytes += desc.len();
1305
1306 if stop_at_eof && desc.flags.suc_eof() {
1307 found_eof = true;
1308 break;
1309 }
1310 if desc.len() < desc.size() {
1312 break;
1313 }
1314 }
1315
1316 #[cfg(soc_internal_memory_cached)]
1317 {
1318 let buffer_start = chunk_size * self.descriptor_idx + self.descriptor_offset;
1319 let buffer_len = number_of_contiguous_bytes - self.descriptor_offset;
1320 if buffer_len != 0 {
1321 unsafe {
1322 crate::soc::cache_invalidate_addr(
1323 self.buf.buffer.as_ptr().add(buffer_start) as u32,
1324 buffer_len as u32,
1325 );
1326 }
1327 }
1328 }
1329
1330 (
1331 &self.buf.buffer[chunk_size * self.descriptor_idx..][..number_of_contiguous_bytes]
1332 [self.descriptor_offset..],
1333 found_eof,
1334 )
1335 }
1336 }
1337}
1338
1339#[derive(Debug)]
1361#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1362pub struct DmaTxStreamBuf {
1363 descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
1364 buffer: DmaAlignedMut<'static, [u8]>,
1365 burst: BurstConfig,
1366 pre_filled: Option<usize>,
1367 view_descriptor_idx: usize,
1368 view_descriptor_offset: usize,
1369}
1370
1371impl DmaTxStreamBuf {
1372 pub fn new(
1375 mut descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
1376 mut buffer: DmaAlignedMut<'static, [u8]>,
1377 ) -> Result<Self, DmaBufError> {
1378 if descriptors.len() < 4 {
1379 return Err(DmaBufError::InsufficientDescriptors);
1382 }
1383
1384 let chunk_size = Some(buffer.len() / descriptors.len())
1386 .filter(|x| *x <= 4095)
1387 .ok_or(DmaBufError::InsufficientDescriptors)?;
1388
1389 let mut chunks = buffer.chunks_exact_mut(chunk_size);
1390 for (desc, chunk) in descriptors.iter_mut().zip(chunks.by_ref()) {
1391 desc.buffer = chunk.as_mut_ptr();
1392 desc.set_size(chunk.len());
1393 desc.set_length(chunk.len());
1394 }
1395 let remainder = chunks.into_remainder();
1396
1397 if !remainder.is_empty() {
1398 let last_descriptor = descriptors.last_mut().unwrap();
1400 let size = last_descriptor.size() + remainder.len();
1401 if size > 4095 {
1402 Err(DmaBufError::InsufficientDescriptors)?;
1403 }
1404 last_descriptor.set_size(size);
1405 }
1406
1407 Ok(Self {
1408 descriptors,
1409 buffer,
1410 burst: Default::default(),
1411 pre_filled: None,
1412 view_descriptor_idx: 0,
1413 view_descriptor_offset: 0,
1414 })
1415 }
1416
1417 pub fn split(
1419 self,
1420 ) -> (
1421 DmaAlignedMut<'static, [DmaDescriptor]>,
1422 DmaAlignedMut<'static, [u8]>,
1423 ) {
1424 (self.descriptors, self.buffer)
1425 }
1426
1427 pub fn push(&mut self, data: &[u8]) -> usize {
1436 self.push_with(|buf| {
1437 let len = buf.len().min(data.len());
1438 buf[..len].copy_from_slice(&data[..len]);
1439 len
1440 })
1441 }
1442
1443 pub fn push_with(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
1454 let start = self.pre_filled.unwrap_or(0);
1455 let bytes_pushed = f(&mut self.buffer[start..]);
1456 self.pre_filled = Some(start + bytes_pushed);
1457 bytes_pushed
1458 }
1459
1460 fn setup_view_state(&mut self) {
1461 let pre_filled = self.pre_filled.unwrap_or(self.buffer.len());
1462 let (idx, offset) = mark_tx_stream_descriptors_ready(&mut self.descriptors, pre_filled);
1463 self.view_descriptor_idx = idx;
1464 self.view_descriptor_offset = offset;
1465 #[cfg(soc_internal_memory_cached)]
1466 if pre_filled != 0 {
1467 unsafe {
1468 crate::soc::cache_writeback_addr(self.buffer.as_ptr() as u32, pre_filled as u32);
1469 }
1470 }
1471 }
1472}
1473
1474fn mark_tx_stream_descriptors_ready(
1477 descriptors: &mut DmaAlignedMut<'_, [DmaDescriptor]>,
1478 bytes_pushed: usize,
1479) -> (usize, usize) {
1480 if bytes_pushed == 0 {
1481 return (0, 0);
1482 }
1483
1484 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1485 descriptors.invalidate();
1486
1487 let num = descriptors.len();
1488 let mut bytes_filled = 0;
1489 let mut cursor = (0, 0);
1490
1491 for d in 0..num {
1492 let remaining = bytes_pushed - bytes_filled;
1493 let size = descriptors[d].size();
1494
1495 if remaining == 0 {
1496 terminate_tx_stream_at(descriptors, d);
1497 cursor = (d, 0);
1498 break;
1499 }
1500
1501 if remaining < size {
1502 if d == 0 {
1503 descriptors[d].set_owner(Owner::Dma);
1506 descriptors[d].set_length(remaining);
1507 descriptors[d].set_suc_eof(true);
1508 if num > 1 {
1509 terminate_tx_stream_at(descriptors, 1);
1510 cursor = (1, 0);
1511 } else {
1512 descriptors[d].next = null_mut();
1513 }
1514 } else {
1515 terminate_tx_stream_at(descriptors, d);
1516 cursor = (d, remaining);
1517 }
1518 break;
1519 }
1520
1521 bytes_filled += size;
1522 descriptors[d].set_owner(Owner::Dma);
1523 descriptors[d].set_length(size);
1524 descriptors[d].set_suc_eof(true);
1525 }
1526
1527 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1528 descriptors.writeback();
1529
1530 cursor
1531}
1532
1533fn terminate_tx_stream_at(descriptors: &mut DmaAlignedMut<'_, [DmaDescriptor]>, start: usize) {
1534 if start > 0 {
1535 descriptors[start - 1].next = null_mut();
1536 }
1537 for desc in descriptors.iter_mut().skip(start) {
1538 desc.set_owner(Owner::Cpu);
1539 }
1540}
1541
1542fn advance_tx_stream_descriptors(
1543 descriptors: &mut DmaAlignedMut<'_, [DmaDescriptor]>,
1544 descriptor_idx: &mut usize,
1545 descriptor_offset: &mut usize,
1546 bytes_pushed: usize,
1547) {
1548 if bytes_pushed == 0 {
1549 return;
1550 }
1551
1552 let mut bytes_filled = 0;
1553 let num_descriptors = descriptors.len();
1554
1555 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1556 descriptors.invalidate();
1557
1558 for i in 0..num_descriptors {
1559 let d = (*descriptor_idx + i) % num_descriptors;
1560 let desc = &mut descriptors[d];
1561 let bytes_in_d = desc.size() - *descriptor_offset;
1562 if bytes_in_d + bytes_filled > bytes_pushed {
1563 *descriptor_idx = d;
1564 *descriptor_offset = *descriptor_offset + bytes_pushed - bytes_filled;
1565 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1566 descriptors.writeback();
1567 return;
1568 }
1569 bytes_filled += bytes_in_d;
1570 *descriptor_offset = 0;
1571
1572 desc.set_owner(Owner::Dma);
1574 desc.set_length(desc.size());
1575 desc.set_suc_eof(true);
1576 let p = d.checked_sub(1).unwrap_or(num_descriptors - 1);
1577 if p != d {
1578 let [prev, desc] = descriptors.get_disjoint_mut([p, d]).unwrap();
1579 desc.next = null_mut();
1580 prev.next = desc;
1581 }
1582 }
1583
1584 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1585 descriptors.writeback();
1586}
1587
1588unsafe impl DmaTxBuffer for DmaTxStreamBuf {
1589 type View = DmaTxStreamBufView;
1590 type Final = Self;
1591
1592 fn prepare(&mut self) -> Preparation {
1593 let mut next = null_mut();
1595 for desc in self.descriptors.iter_mut().rev() {
1596 desc.next = next;
1597 desc.set_owner(Owner::Dma);
1598 next = desc;
1599 }
1600 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1601 self.descriptors.writeback();
1602
1603 self.setup_view_state();
1604
1605 Preparation {
1606 start: self.descriptors.as_mut_ptr(),
1607 #[cfg(dma_can_access_psram)]
1608 accesses_psram: false,
1609 burst_transfer: self.burst,
1610
1611 check_owner: None,
1616 auto_write_back: true,
1617 }
1618 }
1619
1620 fn into_view(self) -> Self::View {
1621 DmaTxStreamBufView {
1622 descriptor_idx: self.view_descriptor_idx,
1623 descriptor_offset: self.view_descriptor_offset,
1624 buf: self,
1625 }
1626 }
1627
1628 fn from_view(view: Self::View) -> Self {
1629 let DmaTxStreamBufView {
1630 mut buf,
1631 descriptor_idx,
1632 descriptor_offset,
1633 } = view;
1634 buf.view_descriptor_idx = descriptor_idx;
1635 buf.view_descriptor_offset = descriptor_offset;
1636 buf.pre_filled = None;
1637 buf
1638 }
1639}
1640
1641pub struct DmaTxStreamBufView {
1643 buf: DmaTxStreamBuf,
1644 descriptor_idx: usize,
1645 descriptor_offset: usize,
1646}
1647
1648impl DmaTxStreamBufView {
1649 pub fn available_bytes(&mut self) -> usize {
1651 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1652 self.buf.descriptors.invalidate();
1653
1654 let (tail, head) = self.buf.descriptors.split_at(self.descriptor_idx);
1655 head.iter()
1656 .chain(tail)
1657 .take_while(|d| d.owner() == Owner::Cpu)
1658 .map(|d| d.size())
1659 .sum::<usize>()
1660 .saturating_sub(self.descriptor_offset)
1661 }
1662
1663 fn write_position(&self) -> usize {
1664 let desc = &self.buf.descriptors[self.descriptor_idx];
1665 desc.buffer
1666 .addr()
1667 .wrapping_sub(self.buf.buffer.as_ptr().addr())
1668 + self.descriptor_offset
1669 }
1670
1671 pub fn push_with(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
1674 let dma_start = self.write_position();
1675 let dma_end = dma_start
1676 .saturating_add(self.available_bytes())
1677 .min(self.buf.buffer.len())
1678 .max(dma_start);
1679 let bytes_pushed = f(&mut self.buf.buffer[dma_start..dma_end]).min(dma_end - dma_start);
1680 #[cfg(soc_internal_memory_cached)]
1681 if bytes_pushed != 0 {
1682 unsafe {
1683 crate::soc::cache_writeback_addr(
1684 self.buf.buffer.as_ptr().add(dma_start) as u32,
1685 bytes_pushed as u32,
1686 );
1687 }
1688 }
1689
1690 self.advance(bytes_pushed);
1691 bytes_pushed
1692 }
1693
1694 pub fn advance(&mut self, bytes_pushed: usize) {
1696 advance_tx_stream_descriptors(
1697 &mut self.buf.descriptors,
1698 &mut self.descriptor_idx,
1699 &mut self.descriptor_offset,
1700 bytes_pushed,
1701 );
1702 }
1703
1704 pub fn push(&mut self, data: &[u8]) -> usize {
1707 let total_len = data.len();
1708 let mut remaining = data;
1709
1710 while !remaining.is_empty() && self.available_bytes() > 0 {
1711 let written = self.push_with(|buffer| {
1712 let len = usize::min(buffer.len(), remaining.len());
1713 buffer[..len].copy_from_slice(&remaining[..len]);
1714 len
1715 });
1716 if written == 0 {
1717 break;
1718 }
1719 remaining = &remaining[written..];
1720 }
1721
1722 total_len - remaining.len()
1723 }
1724}
1725
1726static mut EMPTY: InternalMemory<[DmaDescriptor; 1]> = InternalMemory::new([DmaDescriptor::EMPTY]);
1727
1728pub struct EmptyBuf;
1730
1731unsafe impl DmaTxBuffer for EmptyBuf {
1732 type View = EmptyBuf;
1733 type Final = EmptyBuf;
1734
1735 fn prepare(&mut self) -> Preparation {
1736 #[cfg(soc_internal_memory_cached)]
1737 #[allow(static_mut_refs)]
1738 unsafe {
1739 EMPTY.get_mut().writeback();
1740 }
1741
1742 Preparation {
1743 start: (&raw mut EMPTY).cast(),
1744 #[cfg(dma_can_access_psram)]
1745 accesses_psram: false,
1746 burst_transfer: BurstConfig::default(),
1747
1748 check_owner: Some(false),
1751
1752 auto_write_back: false,
1754 }
1755 }
1756
1757 fn into_view(self) -> EmptyBuf {
1758 self
1759 }
1760
1761 fn from_view(view: Self::View) -> Self {
1762 view
1763 }
1764}
1765
1766unsafe impl DmaRxBuffer for EmptyBuf {
1767 type View = EmptyBuf;
1768 type Final = EmptyBuf;
1769
1770 fn prepare(&mut self) -> Preparation {
1771 #[cfg(soc_internal_memory_cached)]
1772 #[allow(static_mut_refs)]
1773 unsafe {
1774 EMPTY.get_mut().writeback();
1775 }
1776
1777 Preparation {
1778 start: (&raw mut EMPTY).cast(),
1779 #[cfg(dma_can_access_psram)]
1780 accesses_psram: false,
1781 burst_transfer: BurstConfig::default(),
1782
1783 check_owner: Some(false),
1786 auto_write_back: true,
1787 }
1788 }
1789
1790 fn into_view(self) -> EmptyBuf {
1791 self
1792 }
1793
1794 fn from_view(view: Self::View) -> Self {
1795 view
1796 }
1797}
1798
1799pub struct DmaLoopBuf {
1810 descriptor: DmaAlignedMut<'static, [DmaDescriptor]>,
1811 buffer: DmaAlignedMut<'static, [u8]>,
1812}
1813
1814impl DmaLoopBuf {
1815 pub fn new(
1817 mut descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
1818 mut buffer: DmaAlignedMut<'static, [u8]>,
1819 ) -> Result<DmaLoopBuf, DmaBufError> {
1820 if buffer.len() > BurstConfig::default().max_chunk_size_for(&buffer, TransferDirection::Out)
1821 {
1822 return Err(DmaBufError::InsufficientDescriptors);
1823 }
1824
1825 descriptors[0].set_owner(Owner::Dma); descriptors[0].set_suc_eof(false);
1827 descriptors[0].set_length(buffer.len());
1828 descriptors[0].set_size(buffer.len());
1829 descriptors[0].buffer = buffer.as_mut_ptr();
1830 descriptors[0].next = descriptors.as_mut_ptr();
1831
1832 Ok(Self {
1833 descriptor: descriptors,
1834 buffer,
1835 })
1836 }
1837
1838 pub fn split(
1840 self,
1841 ) -> (
1842 DmaAlignedMut<'static, [DmaDescriptor]>,
1843 DmaAlignedMut<'static, [u8]>,
1844 ) {
1845 (self.descriptor, self.buffer)
1846 }
1847}
1848
1849unsafe impl DmaTxBuffer for DmaLoopBuf {
1850 type View = DmaLoopBuf;
1851 type Final = DmaLoopBuf;
1852
1853 fn prepare(&mut self) -> Preparation {
1854 Preparation {
1855 start: self.descriptor.as_mut_ptr(),
1856 #[cfg(dma_can_access_psram)]
1857 accesses_psram: false,
1858 burst_transfer: BurstConfig::default(),
1859 check_owner: Some(false),
1861
1862 auto_write_back: false,
1864 }
1865 }
1866
1867 fn into_view(self) -> Self::View {
1868 self
1869 }
1870
1871 fn from_view(view: Self::View) -> Self {
1872 view
1873 }
1874}
1875
1876impl Deref for DmaLoopBuf {
1877 type Target = [u8];
1878
1879 fn deref(&self) -> &Self::Target {
1880 &self.buffer
1881 }
1882}
1883
1884impl DerefMut for DmaLoopBuf {
1885 fn deref_mut(&mut self) -> &mut Self::Target {
1886 &mut self.buffer
1887 }
1888}
1889
1890pub(crate) struct NoBuffer(pub(crate) Preparation);
1896impl NoBuffer {
1897 fn prep(&self) -> Preparation {
1898 Preparation {
1899 start: self.0.start,
1900 #[cfg(dma_can_access_psram)]
1901 accesses_psram: self.0.accesses_psram,
1902 burst_transfer: self.0.burst_transfer,
1903 check_owner: self.0.check_owner,
1904 auto_write_back: self.0.auto_write_back,
1905 }
1906 }
1907}
1908unsafe impl DmaTxBuffer for NoBuffer {
1909 type View = ();
1910 type Final = ();
1911
1912 fn prepare(&mut self) -> Preparation {
1913 self.prep()
1914 }
1915
1916 fn into_view(self) -> Self::View {}
1917 fn from_view(_view: Self::View) {}
1918}
1919unsafe impl DmaRxBuffer for NoBuffer {
1920 type View = ();
1921 type Final = ();
1922
1923 fn prepare(&mut self) -> Preparation {
1924 self.prep()
1925 }
1926
1927 fn into_view(self) -> Self::View {}
1928 fn from_view(_view: Self::View) {}
1929}
1930
1931#[cfg_attr(not(any(aes_supports_dma, spi_master_supports_dma)), expect(unused))]
1944pub(crate) unsafe fn prepare_for_tx(
1945 descriptors: &mut [DmaDescriptor],
1946 mut data: NonNull<[u8]>,
1947 block_size: usize,
1948) -> Result<(NoBuffer, usize), DmaError> {
1949 let alignment =
1950 BurstConfig::DEFAULT.min_alignment(unsafe { data.as_ref() }, TransferDirection::Out);
1951
1952 if !data.addr().get().is_multiple_of(alignment) {
1953 return Err(DmaError::InvalidAlignment(DmaAlignmentError::Address));
1955 }
1956
1957 let alignment = alignment.max(block_size);
1963 let chunk_size = 4096 - alignment;
1964
1965 let data_len = data.len().min(chunk_size * descriptors.len());
1966
1967 cfg_select! {
1968 dma_can_access_psram => {
1969 let data_addr = data.addr().get();
1970 let data_in_psram = crate::psram::psram_range().contains(&data_addr);
1971
1972 if data_in_psram || cfg!(soc_internal_memory_cached) {
1974 unsafe { crate::soc::cache_writeback_addr(data_addr as u32, data_len as u32) };
1975 }
1976 }
1977 soc_internal_memory_cached => {
1978 unsafe { crate::soc::cache_writeback_addr(data.addr().get() as u32, data_len as u32) };
1979 }
1980 _ => {}
1981 }
1982
1983 let descriptors = unsafe { DmaAlignedMut::new_unchecked(descriptors) };
1984 let mut descriptors = unwrap!(DescriptorSet::new(descriptors));
1985 unwrap!(descriptors.link_with_buffer(unsafe { data.as_mut() }, chunk_size));
1988 unwrap!(descriptors.set_tx_length(data_len, chunk_size));
1989
1990 for desc in descriptors.linked_iter_mut() {
1991 desc.reset_for_tx(desc.next.is_null());
1992 }
1993
1994 #[cfg(soc_internal_memory_cached)]
1995 descriptors.descriptors.writeback();
1996
1997 Ok((
1998 NoBuffer(Preparation {
1999 start: descriptors.head(),
2000 burst_transfer: BurstConfig::DEFAULT,
2001 check_owner: None,
2002 auto_write_back: false,
2003 #[cfg(dma_can_access_psram)]
2004 accesses_psram: data_in_psram,
2005 }),
2006 data_len,
2007 ))
2008}
2009
2010#[cfg_attr(not(any(aes_supports_dma, spi_master_supports_dma)), expect(unused))]
2019pub(crate) unsafe fn prepare_for_rx(
2020 descriptors: &mut [DmaDescriptor],
2021 #[cfg(dma_can_access_psram)] align_buffers: &mut [Option<ManualWritebackBuffer>; 2],
2022 mut data: NonNull<[u8]>,
2023) -> (NoBuffer, usize) {
2024 let chunk_size =
2025 BurstConfig::DEFAULT.max_chunk_size_for(unsafe { data.as_ref() }, TransferDirection::In);
2026
2027 cfg_select! {
2032 dma_can_access_psram => {
2033 let data_addr = data.addr().get();
2034 let data_in_psram = crate::psram::psram_range().contains(&data_addr);
2035 }
2036 _ => {
2037 let data_in_psram = false;
2038 }
2039 }
2040
2041 let descriptors = unsafe { DmaAlignedMut::new_unchecked(descriptors) };
2042 let mut descriptors = unwrap!(DescriptorSet::new(descriptors));
2043 let data_len = if data_in_psram {
2044 cfg_select! {
2045 dma_can_access_psram => {
2046 let consumed_bytes =
2049 build_descriptor_list_for_psram(&mut descriptors, align_buffers, data);
2050
2051 unsafe {
2054 crate::soc::cache_writeback_addr(data_addr as u32, consumed_bytes as u32);
2055 crate::soc::cache_invalidate_addr(data_addr as u32, consumed_bytes as u32);
2056 }
2057
2058 consumed_bytes
2059 }
2060 _ => {
2061 unreachable!()
2062 }
2063 }
2064 } else {
2065 let data_len = data.len();
2067 unwrap!(descriptors.link_with_buffer(unsafe { data.as_mut() }, chunk_size));
2068 unwrap!(descriptors.set_tx_length(data_len, chunk_size));
2069
2070 #[cfg(soc_internal_memory_cached)]
2071 unsafe {
2074 crate::soc::cache_writeback_addr(data.addr().get() as u32, data_len as u32);
2075 crate::soc::cache_invalidate_addr(data.addr().get() as u32, data_len as u32);
2076 }
2077
2078 data_len
2079 };
2080
2081 for desc in descriptors.linked_iter_mut() {
2082 desc.reset_for_rx();
2083 }
2084
2085 #[cfg(soc_internal_memory_cached)]
2086 descriptors.descriptors.writeback();
2087
2088 (
2089 NoBuffer(Preparation {
2090 start: descriptors.head(),
2091 burst_transfer: BurstConfig::DEFAULT,
2092 check_owner: None,
2093 auto_write_back: true,
2094 #[cfg(dma_can_access_psram)]
2095 accesses_psram: data_in_psram,
2096 }),
2097 data_len,
2098 )
2099}
2100
2101#[cfg(dma_can_access_psram)]
2102fn build_descriptor_list_for_psram(
2103 descriptors: &mut DescriptorSet<'_>,
2104 copy_buffers: &mut [Option<ManualWritebackBuffer>; 2],
2105 data: NonNull<[u8]>,
2106) -> usize {
2107 let data_len = data.len();
2108 let data_addr = data.addr().get();
2109
2110 let min_alignment = ExternalBurstConfig::DEFAULT.min_psram_alignment(TransferDirection::In);
2111 let chunk_size = 4096 - min_alignment;
2112
2113 let mut desciptor_iter = DescriptorChainingIter::new(&mut descriptors.descriptors);
2114 let mut copy_buffer_iter = copy_buffers.iter_mut();
2115
2116 let has_aligned_data = data_len > BUF_LEN;
2121
2122 let offset = data_addr % min_alignment;
2125 let head_to_copy = (min_alignment - offset) % min_alignment;
2126 let head_to_copy = if !has_aligned_data {
2127 BUF_LEN
2128 } else if head_to_copy > 0 && head_to_copy < MIN_LAST_DMA_LEN {
2129 head_to_copy + min_alignment
2130 } else {
2131 head_to_copy
2132 };
2133 let head_to_copy = head_to_copy.min(data_len);
2134
2135 let tail_to_copy = (data_len - head_to_copy) % min_alignment;
2137 let tail_to_copy = if tail_to_copy > 0 && tail_to_copy < MIN_LAST_DMA_LEN {
2138 tail_to_copy + min_alignment
2139 } else {
2140 tail_to_copy
2141 };
2142
2143 let mut consumed = 0;
2144
2145 if head_to_copy > 0 {
2147 let copy_buffer = unwrap!(copy_buffer_iter.next());
2148 let buffer =
2149 copy_buffer.insert(ManualWritebackBuffer::new(get_range(data, 0..head_to_copy)));
2150 buffer.prepare_for_dma();
2151
2152 let Some(descriptor) = desciptor_iter.next() else {
2153 return consumed;
2154 };
2155 descriptor.set_size(head_to_copy);
2156 descriptor.buffer = buffer.mut_buffer_ptr();
2157 consumed += head_to_copy;
2158 };
2159
2160 let mut aligned_data = get_range(data, head_to_copy..data.len() - tail_to_copy);
2162 while !aligned_data.is_empty() {
2163 let Some(descriptor) = desciptor_iter.next() else {
2164 return consumed;
2165 };
2166 let chunk = aligned_data.len().min(chunk_size);
2167
2168 descriptor.set_size(chunk);
2169 descriptor.buffer = aligned_data.cast::<u8>().as_ptr();
2170 consumed += chunk;
2171 aligned_data = get_range(aligned_data, chunk..aligned_data.len());
2172 }
2173
2174 if tail_to_copy > 0 {
2176 let copy_buffer = unwrap!(copy_buffer_iter.next());
2177 let buffer = copy_buffer.insert(ManualWritebackBuffer::new(get_range(
2178 data,
2179 data.len() - tail_to_copy..data.len(),
2180 )));
2181 buffer.prepare_for_dma();
2182
2183 let Some(descriptor) = desciptor_iter.next() else {
2184 return consumed;
2185 };
2186 descriptor.set_size(tail_to_copy);
2187 descriptor.buffer = buffer.mut_buffer_ptr();
2188 consumed += tail_to_copy;
2189 }
2190
2191 consumed
2192}
2193
2194#[cfg(dma_can_access_psram)]
2195fn get_range(ptr: NonNull<[u8]>, range: Range<usize>) -> NonNull<[u8]> {
2196 let len = range.end - range.start;
2197 NonNull::slice_from_raw_parts(unsafe { ptr.cast().byte_add(range.start) }, len)
2198}
2199
2200#[cfg(dma_can_access_psram)]
2201struct DescriptorChainingIter<'a> {
2202 index: usize,
2204 descriptors: &'a mut [DmaDescriptor],
2205}
2206#[cfg(dma_can_access_psram)]
2207impl<'a> DescriptorChainingIter<'a> {
2208 fn new(descriptors: &'a mut [DmaDescriptor]) -> Self {
2209 Self {
2210 descriptors,
2211 index: 0,
2212 }
2213 }
2214
2215 fn next(&mut self) -> Option<&'_ mut DmaDescriptor> {
2216 if self.index == 0 {
2217 self.index += 1;
2218 self.descriptors.get_mut(0)
2219 } else if self.index < self.descriptors.len() {
2220 let index = self.index;
2221 self.index += 1;
2222
2223 let ptr = &raw mut self.descriptors[index];
2225
2226 self.descriptors[index - 1].next = ptr;
2228
2229 Some(unsafe { &mut *ptr })
2232 } else {
2233 None
2234 }
2235 }
2236}
2237
2238#[cfg(dma_can_access_psram)]
2239const MIN_LAST_DMA_LEN: usize = if cfg!(esp32s2) { 5 } else { 1 };
2240#[cfg(dma_can_access_psram)]
2241const BUF_LEN: usize = 16 + 2 * (MIN_LAST_DMA_LEN - 1); #[cfg(dma_can_access_psram)]
2246pub(crate) struct ManualWritebackBuffer {
2247 buffer: InternalMemory<MaybeUninit<[u8; BUF_LEN]>>,
2248 dst_address: NonNull<u8>,
2249 n_bytes: u8,
2250}
2251
2252#[cfg(dma_can_access_psram)]
2253impl ManualWritebackBuffer {
2254 pub fn new(ptr: NonNull<[u8]>) -> Self {
2255 assert!(ptr.len() <= BUF_LEN);
2256 Self {
2257 buffer: InternalMemory::new(MaybeUninit::uninit()),
2258 dst_address: ptr.cast(),
2259 n_bytes: ptr.len() as u8,
2260 }
2261 }
2262
2263 pub fn prepare_for_dma(&mut self) {
2264 #[cfg(soc_internal_memory_cached)]
2267 self.buffer.get_mut().invalidate();
2268 }
2269
2270 pub fn write_back(&mut self) {
2271 #[cfg(soc_internal_memory_cached)]
2275 self.buffer.get_mut().invalidate();
2276
2277 let src = self.mut_buffer_ptr().cast_const();
2278 unsafe {
2279 self.dst_address
2280 .as_ptr()
2281 .copy_from(src, self.n_bytes as usize);
2282 }
2283 }
2284
2285 pub fn mut_buffer_ptr(&mut self) -> *mut u8 {
2286 self.buffer.get_mut().as_mut_ptr().cast::<u8>()
2287 }
2288}