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] {
1186 let (slice, _) = self.peek_internal(false);
1187 slice
1188 }
1189
1190 pub fn peek_until_eof(&mut self) -> (&[u8], bool) {
1195 self.peek_internal(true)
1196 }
1197
1198 pub fn consume(&mut self, n: usize) -> usize {
1204 let mut remaining_bytes_to_consume = n;
1205 let mut descriptors_modified = false;
1206
1207 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1208 self.buf.descriptors.invalidate();
1209
1210 loop {
1211 let desc = &mut self.buf.descriptors[self.descriptor_idx];
1212
1213 if desc.owner() == Owner::Dma {
1214 break;
1217 }
1218
1219 let remaining_bytes_in_descriptor = desc.len() - self.descriptor_offset;
1220 if remaining_bytes_to_consume < remaining_bytes_in_descriptor {
1221 self.descriptor_offset += remaining_bytes_to_consume;
1222 remaining_bytes_to_consume = 0;
1223 break;
1224 }
1225
1226 desc.set_owner(Owner::Dma);
1228 desc.set_suc_eof(false);
1229 desc.set_length(0);
1230
1231 desc.next = null_mut();
1235
1236 let desc_ptr: *mut _ = desc;
1237
1238 let prev_descriptor_index = self
1239 .descriptor_idx
1240 .checked_sub(1)
1241 .unwrap_or(self.buf.descriptors.len() - 1);
1242
1243 self.buf.descriptors[prev_descriptor_index].next = desc_ptr;
1245 descriptors_modified = true;
1246
1247 self.descriptor_idx += 1;
1248 if self.descriptor_idx >= self.buf.descriptors.len() {
1249 self.descriptor_idx = 0;
1250 }
1251 self.descriptor_offset = 0;
1252
1253 remaining_bytes_to_consume -= remaining_bytes_in_descriptor;
1254 }
1255
1256 if descriptors_modified {
1257 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1258 self.buf.descriptors.writeback();
1259 }
1260
1261 n - remaining_bytes_to_consume
1262 }
1263
1264 fn peek_internal(&mut self, stop_at_eof: bool) -> (&[u8], bool) {
1265 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1266 self.buf.descriptors.invalidate();
1267
1268 let descriptors = &self.buf.descriptors[self.descriptor_idx..];
1269
1270 debug_assert!(!descriptors.is_empty());
1272
1273 if descriptors.len() == 1 {
1274 let last_descriptor = &descriptors[0];
1275 if last_descriptor.owner() == Owner::Dma {
1276 (&[], false)
1278 } else {
1279 let length = last_descriptor.len() - self.descriptor_offset;
1280 let chunk_size = last_descriptor.size();
1281 let buffer_start = self.buf.buffer.len() - chunk_size;
1282 #[cfg(soc_internal_memory_cached)]
1283 if length != 0 {
1284 unsafe {
1285 crate::soc::cache_invalidate_addr(
1286 self.buf.buffer.as_ptr().add(buffer_start) as u32,
1287 length as u32,
1288 );
1289 }
1290 }
1291 (
1292 &self.buf.buffer[buffer_start..][..length],
1293 last_descriptor.flags.suc_eof(),
1294 )
1295 }
1296 } else {
1297 let chunk_size = descriptors[0].size();
1298 let mut found_eof = false;
1299
1300 let mut number_of_contiguous_bytes = 0;
1301 for desc in descriptors {
1302 if desc.owner() == Owner::Dma {
1303 break;
1304 }
1305 number_of_contiguous_bytes += desc.len();
1306
1307 if stop_at_eof && desc.flags.suc_eof() {
1308 found_eof = true;
1309 break;
1310 }
1311 if desc.len() < desc.size() {
1313 break;
1314 }
1315 }
1316
1317 #[cfg(soc_internal_memory_cached)]
1318 {
1319 let buffer_start = chunk_size * self.descriptor_idx + self.descriptor_offset;
1320 let buffer_len = number_of_contiguous_bytes - self.descriptor_offset;
1321 if buffer_len != 0 {
1322 unsafe {
1323 crate::soc::cache_invalidate_addr(
1324 self.buf.buffer.as_ptr().add(buffer_start) as u32,
1325 buffer_len as u32,
1326 );
1327 }
1328 }
1329 }
1330
1331 (
1332 &self.buf.buffer[chunk_size * self.descriptor_idx..][..number_of_contiguous_bytes]
1333 [self.descriptor_offset..],
1334 found_eof,
1335 )
1336 }
1337 }
1338}
1339
1340#[derive(Debug)]
1362#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1363pub struct DmaTxStreamBuf {
1364 descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
1365 buffer: DmaAlignedMut<'static, [u8]>,
1366 burst: BurstConfig,
1367 pre_filled: Option<usize>,
1368 view_descriptor_idx: usize,
1369 view_descriptor_offset: usize,
1370}
1371
1372impl DmaTxStreamBuf {
1373 pub fn new(
1376 mut descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
1377 mut buffer: DmaAlignedMut<'static, [u8]>,
1378 ) -> Result<Self, DmaBufError> {
1379 if descriptors.len() < 4 {
1380 return Err(DmaBufError::InsufficientDescriptors);
1383 }
1384
1385 let chunk_size = Some(buffer.len() / descriptors.len())
1387 .filter(|x| *x <= 4095)
1388 .ok_or(DmaBufError::InsufficientDescriptors)?;
1389
1390 let mut chunks = buffer.chunks_exact_mut(chunk_size);
1391 for (desc, chunk) in descriptors.iter_mut().zip(chunks.by_ref()) {
1392 desc.buffer = chunk.as_mut_ptr();
1393 desc.set_size(chunk.len());
1394 desc.set_length(chunk.len());
1395 }
1396 let remainder = chunks.into_remainder();
1397
1398 if !remainder.is_empty() {
1399 let last_descriptor = descriptors.last_mut().unwrap();
1401 let size = last_descriptor.size() + remainder.len();
1402 if size > 4095 {
1403 Err(DmaBufError::InsufficientDescriptors)?;
1404 }
1405 last_descriptor.set_size(size);
1406 }
1407
1408 Ok(Self {
1409 descriptors,
1410 buffer,
1411 burst: Default::default(),
1412 pre_filled: None,
1413 view_descriptor_idx: 0,
1414 view_descriptor_offset: 0,
1415 })
1416 }
1417
1418 pub fn split(
1420 self,
1421 ) -> (
1422 DmaAlignedMut<'static, [DmaDescriptor]>,
1423 DmaAlignedMut<'static, [u8]>,
1424 ) {
1425 (self.descriptors, self.buffer)
1426 }
1427
1428 pub fn push(&mut self, data: &[u8]) -> usize {
1433 self.push_with(|buf| {
1434 let len = buf.len().min(data.len());
1435 buf[..len].copy_from_slice(&data[..len]);
1436 len
1437 })
1438 }
1439
1440 pub fn push_with(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
1447 let start = self.pre_filled.unwrap_or(0);
1448 let bytes_pushed = f(&mut self.buffer[start..]);
1449 self.pre_filled = Some(start + bytes_pushed);
1450 bytes_pushed
1451 }
1452
1453 fn setup_view_state(&mut self) {
1454 let pre_filled = self.pre_filled.unwrap_or(self.buffer.len());
1455 let (idx, offset) = mark_tx_stream_descriptors_ready(&mut self.descriptors, pre_filled);
1456 self.view_descriptor_idx = idx;
1457 self.view_descriptor_offset = offset;
1458 #[cfg(soc_internal_memory_cached)]
1459 if pre_filled != 0 {
1460 unsafe {
1461 crate::soc::cache_writeback_addr(self.buffer.as_ptr() as u32, pre_filled as u32);
1462 }
1463 }
1464 }
1465}
1466
1467fn mark_tx_stream_descriptors_ready(
1470 descriptors: &mut DmaAlignedMut<'_, [DmaDescriptor]>,
1471 bytes_pushed: usize,
1472) -> (usize, usize) {
1473 if bytes_pushed == 0 {
1474 return (0, 0);
1475 }
1476
1477 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1478 descriptors.invalidate();
1479
1480 let num = descriptors.len();
1481 let mut bytes_filled = 0;
1482 let mut cursor = (0, 0);
1483
1484 for d in 0..num {
1485 let remaining = bytes_pushed - bytes_filled;
1486 let size = descriptors[d].size();
1487
1488 if remaining == 0 {
1489 terminate_tx_stream_at(descriptors, d);
1490 cursor = (d, 0);
1491 break;
1492 }
1493
1494 if remaining < size {
1495 if d == 0 {
1496 descriptors[d].set_owner(Owner::Dma);
1499 descriptors[d].set_length(remaining);
1500 descriptors[d].set_suc_eof(true);
1501 if num > 1 {
1502 terminate_tx_stream_at(descriptors, 1);
1503 cursor = (1, 0);
1504 } else {
1505 descriptors[d].next = null_mut();
1506 }
1507 } else {
1508 terminate_tx_stream_at(descriptors, d);
1509 cursor = (d, remaining);
1510 }
1511 break;
1512 }
1513
1514 bytes_filled += size;
1515 descriptors[d].set_owner(Owner::Dma);
1516 descriptors[d].set_length(size);
1517 descriptors[d].set_suc_eof(true);
1518 }
1519
1520 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1521 descriptors.writeback();
1522
1523 cursor
1524}
1525
1526fn terminate_tx_stream_at(descriptors: &mut DmaAlignedMut<'_, [DmaDescriptor]>, start: usize) {
1527 if start > 0 {
1528 descriptors[start - 1].next = null_mut();
1529 }
1530 for desc in descriptors.iter_mut().skip(start) {
1531 desc.set_owner(Owner::Cpu);
1532 }
1533}
1534
1535fn advance_tx_stream_descriptors(
1536 descriptors: &mut DmaAlignedMut<'_, [DmaDescriptor]>,
1537 descriptor_idx: &mut usize,
1538 descriptor_offset: &mut usize,
1539 bytes_pushed: usize,
1540) {
1541 if bytes_pushed == 0 {
1542 return;
1543 }
1544
1545 let mut bytes_filled = 0;
1546 let num_descriptors = descriptors.len();
1547
1548 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1549 descriptors.invalidate();
1550
1551 for i in 0..num_descriptors {
1552 let d = (*descriptor_idx + i) % num_descriptors;
1553 let desc = &mut descriptors[d];
1554 let bytes_in_d = desc.size() - *descriptor_offset;
1555 if bytes_in_d + bytes_filled > bytes_pushed {
1556 *descriptor_idx = d;
1557 *descriptor_offset = *descriptor_offset + bytes_pushed - bytes_filled;
1558 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1559 descriptors.writeback();
1560 return;
1561 }
1562 bytes_filled += bytes_in_d;
1563 *descriptor_offset = 0;
1564
1565 desc.set_owner(Owner::Dma);
1567 desc.set_length(desc.size());
1568 desc.set_suc_eof(true);
1569 let p = d.checked_sub(1).unwrap_or(num_descriptors - 1);
1570 if p != d {
1571 let [prev, desc] = descriptors.get_disjoint_mut([p, d]).unwrap();
1572 desc.next = null_mut();
1573 prev.next = desc;
1574 }
1575 }
1576
1577 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1578 descriptors.writeback();
1579}
1580
1581unsafe impl DmaTxBuffer for DmaTxStreamBuf {
1582 type View = DmaTxStreamBufView;
1583 type Final = Self;
1584
1585 fn prepare(&mut self) -> Preparation {
1586 let mut next = null_mut();
1588 for desc in self.descriptors.iter_mut().rev() {
1589 desc.next = next;
1590 desc.set_owner(Owner::Dma);
1591 next = desc;
1592 }
1593 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1594 self.descriptors.writeback();
1595
1596 self.setup_view_state();
1597
1598 Preparation {
1599 start: self.descriptors.as_mut_ptr(),
1600 #[cfg(dma_can_access_psram)]
1601 accesses_psram: false,
1602 burst_transfer: self.burst,
1603
1604 check_owner: None,
1609 auto_write_back: true,
1610 }
1611 }
1612
1613 fn into_view(self) -> Self::View {
1614 DmaTxStreamBufView {
1615 descriptor_idx: self.view_descriptor_idx,
1616 descriptor_offset: self.view_descriptor_offset,
1617 buf: self,
1618 }
1619 }
1620
1621 fn from_view(view: Self::View) -> Self {
1622 let DmaTxStreamBufView {
1623 mut buf,
1624 descriptor_idx,
1625 descriptor_offset,
1626 } = view;
1627 buf.view_descriptor_idx = descriptor_idx;
1628 buf.view_descriptor_offset = descriptor_offset;
1629 buf
1630 }
1631}
1632
1633pub struct DmaTxStreamBufView {
1635 buf: DmaTxStreamBuf,
1636 descriptor_idx: usize,
1637 descriptor_offset: usize,
1638}
1639
1640impl DmaTxStreamBufView {
1641 pub fn available_bytes(&mut self) -> usize {
1643 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1644 self.buf.descriptors.invalidate();
1645
1646 let (tail, head) = self.buf.descriptors.split_at(self.descriptor_idx);
1647 head.iter()
1648 .chain(tail)
1649 .take_while(|d| d.owner() == Owner::Cpu)
1650 .map(|d| d.size())
1651 .sum::<usize>()
1652 .saturating_sub(self.descriptor_offset)
1653 }
1654
1655 fn write_position(&self) -> usize {
1656 let desc = &self.buf.descriptors[self.descriptor_idx];
1657 desc.buffer
1658 .addr()
1659 .wrapping_sub(self.buf.buffer.as_ptr().addr())
1660 + self.descriptor_offset
1661 }
1662
1663 pub fn push_with(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
1666 let dma_start = self.write_position();
1667 let dma_end = dma_start
1668 .saturating_add(self.available_bytes())
1669 .min(self.buf.buffer.len())
1670 .max(dma_start);
1671 let bytes_pushed = f(&mut self.buf.buffer[dma_start..dma_end]).min(dma_end - dma_start);
1672 #[cfg(soc_internal_memory_cached)]
1673 if bytes_pushed != 0 {
1674 unsafe {
1675 crate::soc::cache_writeback_addr(
1676 self.buf.buffer.as_ptr().add(dma_start) as u32,
1677 bytes_pushed as u32,
1678 );
1679 }
1680 }
1681
1682 self.advance(bytes_pushed);
1683 bytes_pushed
1684 }
1685
1686 pub fn advance(&mut self, bytes_pushed: usize) {
1688 advance_tx_stream_descriptors(
1689 &mut self.buf.descriptors,
1690 &mut self.descriptor_idx,
1691 &mut self.descriptor_offset,
1692 bytes_pushed,
1693 );
1694 }
1695
1696 pub fn push(&mut self, data: &[u8]) -> usize {
1699 let total_len = data.len();
1700 let mut remaining = data;
1701
1702 while !remaining.is_empty() && self.available_bytes() > 0 {
1703 let written = self.push_with(|buffer| {
1704 let len = usize::min(buffer.len(), remaining.len());
1705 buffer[..len].copy_from_slice(&remaining[..len]);
1706 len
1707 });
1708 if written == 0 {
1709 break;
1710 }
1711 remaining = &remaining[written..];
1712 }
1713
1714 total_len - remaining.len()
1715 }
1716}
1717
1718static mut EMPTY: InternalMemory<[DmaDescriptor; 1]> = InternalMemory::new([DmaDescriptor::EMPTY]);
1719
1720pub struct EmptyBuf;
1722
1723unsafe impl DmaTxBuffer for EmptyBuf {
1724 type View = EmptyBuf;
1725 type Final = EmptyBuf;
1726
1727 fn prepare(&mut self) -> Preparation {
1728 #[cfg(soc_internal_memory_cached)]
1729 #[allow(static_mut_refs)]
1730 unsafe {
1731 EMPTY.get_mut().writeback();
1732 }
1733
1734 Preparation {
1735 start: (&raw mut EMPTY).cast(),
1736 #[cfg(dma_can_access_psram)]
1737 accesses_psram: false,
1738 burst_transfer: BurstConfig::default(),
1739
1740 check_owner: Some(false),
1743
1744 auto_write_back: false,
1746 }
1747 }
1748
1749 fn into_view(self) -> EmptyBuf {
1750 self
1751 }
1752
1753 fn from_view(view: Self::View) -> Self {
1754 view
1755 }
1756}
1757
1758unsafe impl DmaRxBuffer for EmptyBuf {
1759 type View = EmptyBuf;
1760 type Final = EmptyBuf;
1761
1762 fn prepare(&mut self) -> Preparation {
1763 #[cfg(soc_internal_memory_cached)]
1764 #[allow(static_mut_refs)]
1765 unsafe {
1766 EMPTY.get_mut().writeback();
1767 }
1768
1769 Preparation {
1770 start: (&raw mut EMPTY).cast(),
1771 #[cfg(dma_can_access_psram)]
1772 accesses_psram: false,
1773 burst_transfer: BurstConfig::default(),
1774
1775 check_owner: Some(false),
1778 auto_write_back: true,
1779 }
1780 }
1781
1782 fn into_view(self) -> EmptyBuf {
1783 self
1784 }
1785
1786 fn from_view(view: Self::View) -> Self {
1787 view
1788 }
1789}
1790
1791pub struct DmaLoopBuf {
1802 descriptor: DmaAlignedMut<'static, [DmaDescriptor]>,
1803 buffer: DmaAlignedMut<'static, [u8]>,
1804}
1805
1806impl DmaLoopBuf {
1807 pub fn new(
1809 mut descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
1810 mut buffer: DmaAlignedMut<'static, [u8]>,
1811 ) -> Result<DmaLoopBuf, DmaBufError> {
1812 if buffer.len() > BurstConfig::default().max_chunk_size_for(&buffer, TransferDirection::Out)
1813 {
1814 return Err(DmaBufError::InsufficientDescriptors);
1815 }
1816
1817 descriptors[0].set_owner(Owner::Dma); descriptors[0].set_suc_eof(false);
1819 descriptors[0].set_length(buffer.len());
1820 descriptors[0].set_size(buffer.len());
1821 descriptors[0].buffer = buffer.as_mut_ptr();
1822 descriptors[0].next = descriptors.as_mut_ptr();
1823
1824 Ok(Self {
1825 descriptor: descriptors,
1826 buffer,
1827 })
1828 }
1829
1830 pub fn split(
1832 self,
1833 ) -> (
1834 DmaAlignedMut<'static, [DmaDescriptor]>,
1835 DmaAlignedMut<'static, [u8]>,
1836 ) {
1837 (self.descriptor, self.buffer)
1838 }
1839}
1840
1841unsafe impl DmaTxBuffer for DmaLoopBuf {
1842 type View = DmaLoopBuf;
1843 type Final = DmaLoopBuf;
1844
1845 fn prepare(&mut self) -> Preparation {
1846 Preparation {
1847 start: self.descriptor.as_mut_ptr(),
1848 #[cfg(dma_can_access_psram)]
1849 accesses_psram: false,
1850 burst_transfer: BurstConfig::default(),
1851 check_owner: Some(false),
1853
1854 auto_write_back: false,
1856 }
1857 }
1858
1859 fn into_view(self) -> Self::View {
1860 self
1861 }
1862
1863 fn from_view(view: Self::View) -> Self {
1864 view
1865 }
1866}
1867
1868impl Deref for DmaLoopBuf {
1869 type Target = [u8];
1870
1871 fn deref(&self) -> &Self::Target {
1872 &self.buffer
1873 }
1874}
1875
1876impl DerefMut for DmaLoopBuf {
1877 fn deref_mut(&mut self) -> &mut Self::Target {
1878 &mut self.buffer
1879 }
1880}
1881
1882pub(crate) struct NoBuffer(pub(crate) Preparation);
1888impl NoBuffer {
1889 fn prep(&self) -> Preparation {
1890 Preparation {
1891 start: self.0.start,
1892 #[cfg(dma_can_access_psram)]
1893 accesses_psram: self.0.accesses_psram,
1894 burst_transfer: self.0.burst_transfer,
1895 check_owner: self.0.check_owner,
1896 auto_write_back: self.0.auto_write_back,
1897 }
1898 }
1899}
1900unsafe impl DmaTxBuffer for NoBuffer {
1901 type View = ();
1902 type Final = ();
1903
1904 fn prepare(&mut self) -> Preparation {
1905 self.prep()
1906 }
1907
1908 fn into_view(self) -> Self::View {}
1909 fn from_view(_view: Self::View) {}
1910}
1911unsafe impl DmaRxBuffer for NoBuffer {
1912 type View = ();
1913 type Final = ();
1914
1915 fn prepare(&mut self) -> Preparation {
1916 self.prep()
1917 }
1918
1919 fn into_view(self) -> Self::View {}
1920 fn from_view(_view: Self::View) {}
1921}
1922
1923#[cfg_attr(not(any(aes_supports_dma, spi_master_supports_dma)), expect(unused))]
1936pub(crate) unsafe fn prepare_for_tx(
1937 descriptors: &mut [DmaDescriptor],
1938 mut data: NonNull<[u8]>,
1939 block_size: usize,
1940) -> Result<(NoBuffer, usize), DmaError> {
1941 let alignment =
1942 BurstConfig::DEFAULT.min_alignment(unsafe { data.as_ref() }, TransferDirection::Out);
1943
1944 if !data.addr().get().is_multiple_of(alignment) {
1945 return Err(DmaError::InvalidAlignment(DmaAlignmentError::Address));
1947 }
1948
1949 let alignment = alignment.max(block_size);
1955 let chunk_size = 4096 - alignment;
1956
1957 let data_len = data.len().min(chunk_size * descriptors.len());
1958
1959 cfg_select! {
1960 dma_can_access_psram => {
1961 let data_addr = data.addr().get();
1962 let data_in_psram = crate::psram::psram_range().contains(&data_addr);
1963
1964 if data_in_psram || cfg!(soc_internal_memory_cached) {
1966 unsafe { crate::soc::cache_writeback_addr(data_addr as u32, data_len as u32) };
1967 }
1968 }
1969 soc_internal_memory_cached => {
1970 unsafe { crate::soc::cache_writeback_addr(data.addr().get() as u32, data_len as u32) };
1971 }
1972 _ => {}
1973 }
1974
1975 let descriptors = unsafe { DmaAlignedMut::new_unchecked(descriptors) };
1976 let mut descriptors = unwrap!(DescriptorSet::new(descriptors));
1977 unwrap!(descriptors.link_with_buffer(unsafe { data.as_mut() }, chunk_size));
1980 unwrap!(descriptors.set_tx_length(data_len, chunk_size));
1981
1982 for desc in descriptors.linked_iter_mut() {
1983 desc.reset_for_tx(desc.next.is_null());
1984 }
1985
1986 #[cfg(soc_internal_memory_cached)]
1987 descriptors.descriptors.writeback();
1988
1989 Ok((
1990 NoBuffer(Preparation {
1991 start: descriptors.head(),
1992 burst_transfer: BurstConfig::DEFAULT,
1993 check_owner: None,
1994 auto_write_back: false,
1995 #[cfg(dma_can_access_psram)]
1996 accesses_psram: data_in_psram,
1997 }),
1998 data_len,
1999 ))
2000}
2001
2002#[cfg_attr(not(any(aes_supports_dma, spi_master_supports_dma)), expect(unused))]
2011pub(crate) unsafe fn prepare_for_rx(
2012 descriptors: &mut [DmaDescriptor],
2013 #[cfg(dma_can_access_psram)] align_buffers: &mut [Option<ManualWritebackBuffer>; 2],
2014 mut data: NonNull<[u8]>,
2015) -> (NoBuffer, usize) {
2016 let chunk_size =
2017 BurstConfig::DEFAULT.max_chunk_size_for(unsafe { data.as_ref() }, TransferDirection::In);
2018
2019 cfg_select! {
2024 dma_can_access_psram => {
2025 let data_addr = data.addr().get();
2026 let data_in_psram = crate::psram::psram_range().contains(&data_addr);
2027 }
2028 _ => {
2029 let data_in_psram = false;
2030 }
2031 }
2032
2033 let descriptors = unsafe { DmaAlignedMut::new_unchecked(descriptors) };
2034 let mut descriptors = unwrap!(DescriptorSet::new(descriptors));
2035 let data_len = if data_in_psram {
2036 cfg_select! {
2037 dma_can_access_psram => {
2038 let consumed_bytes =
2041 build_descriptor_list_for_psram(&mut descriptors, align_buffers, data);
2042
2043 unsafe {
2046 crate::soc::cache_writeback_addr(data_addr as u32, consumed_bytes as u32);
2047 crate::soc::cache_invalidate_addr(data_addr as u32, consumed_bytes as u32);
2048 }
2049
2050 consumed_bytes
2051 }
2052 _ => {
2053 unreachable!()
2054 }
2055 }
2056 } else {
2057 let data_len = data.len();
2059 unwrap!(descriptors.link_with_buffer(unsafe { data.as_mut() }, chunk_size));
2060 unwrap!(descriptors.set_tx_length(data_len, chunk_size));
2061
2062 #[cfg(soc_internal_memory_cached)]
2063 unsafe {
2066 crate::soc::cache_writeback_addr(data.addr().get() as u32, data_len as u32);
2067 crate::soc::cache_invalidate_addr(data.addr().get() as u32, data_len as u32);
2068 }
2069
2070 data_len
2071 };
2072
2073 for desc in descriptors.linked_iter_mut() {
2074 desc.reset_for_rx();
2075 }
2076
2077 #[cfg(soc_internal_memory_cached)]
2078 descriptors.descriptors.writeback();
2079
2080 (
2081 NoBuffer(Preparation {
2082 start: descriptors.head(),
2083 burst_transfer: BurstConfig::DEFAULT,
2084 check_owner: None,
2085 auto_write_back: true,
2086 #[cfg(dma_can_access_psram)]
2087 accesses_psram: data_in_psram,
2088 }),
2089 data_len,
2090 )
2091}
2092
2093#[cfg(dma_can_access_psram)]
2094fn build_descriptor_list_for_psram(
2095 descriptors: &mut DescriptorSet<'_>,
2096 copy_buffers: &mut [Option<ManualWritebackBuffer>; 2],
2097 data: NonNull<[u8]>,
2098) -> usize {
2099 let data_len = data.len();
2100 let data_addr = data.addr().get();
2101
2102 let min_alignment = ExternalBurstConfig::DEFAULT.min_psram_alignment(TransferDirection::In);
2103 let chunk_size = 4096 - min_alignment;
2104
2105 let mut desciptor_iter = DescriptorChainingIter::new(&mut descriptors.descriptors);
2106 let mut copy_buffer_iter = copy_buffers.iter_mut();
2107
2108 let has_aligned_data = data_len > BUF_LEN;
2113
2114 let offset = data_addr % min_alignment;
2116 let head_to_copy = min_alignment - offset;
2117 let head_to_copy = if !has_aligned_data {
2118 BUF_LEN
2119 } else if head_to_copy > 0 && head_to_copy < MIN_LAST_DMA_LEN {
2120 head_to_copy + min_alignment
2121 } else {
2122 head_to_copy
2123 };
2124 let head_to_copy = head_to_copy.min(data_len);
2125
2126 let tail_to_copy = (data_len - head_to_copy) % min_alignment;
2128 let tail_to_copy = if tail_to_copy > 0 && tail_to_copy < MIN_LAST_DMA_LEN {
2129 tail_to_copy + min_alignment
2130 } else {
2131 tail_to_copy
2132 };
2133
2134 let mut consumed = 0;
2135
2136 if head_to_copy > 0 {
2138 let copy_buffer = unwrap!(copy_buffer_iter.next());
2139 let buffer =
2140 copy_buffer.insert(ManualWritebackBuffer::new(get_range(data, 0..head_to_copy)));
2141 buffer.prepare_for_dma();
2142
2143 let Some(descriptor) = desciptor_iter.next() else {
2144 return consumed;
2145 };
2146 descriptor.set_size(head_to_copy);
2147 descriptor.buffer = buffer.mut_buffer_ptr();
2148 consumed += head_to_copy;
2149 };
2150
2151 let mut aligned_data = get_range(data, head_to_copy..data.len() - tail_to_copy);
2153 while !aligned_data.is_empty() {
2154 let Some(descriptor) = desciptor_iter.next() else {
2155 return consumed;
2156 };
2157 let chunk = aligned_data.len().min(chunk_size);
2158
2159 descriptor.set_size(chunk);
2160 descriptor.buffer = aligned_data.cast::<u8>().as_ptr();
2161 consumed += chunk;
2162 aligned_data = get_range(aligned_data, chunk..aligned_data.len());
2163 }
2164
2165 if tail_to_copy > 0 {
2167 let copy_buffer = unwrap!(copy_buffer_iter.next());
2168 let buffer = copy_buffer.insert(ManualWritebackBuffer::new(get_range(
2169 data,
2170 data.len() - tail_to_copy..data.len(),
2171 )));
2172 buffer.prepare_for_dma();
2173
2174 let Some(descriptor) = desciptor_iter.next() else {
2175 return consumed;
2176 };
2177 descriptor.set_size(tail_to_copy);
2178 descriptor.buffer = buffer.mut_buffer_ptr();
2179 consumed += tail_to_copy;
2180 }
2181
2182 consumed
2183}
2184
2185#[cfg(dma_can_access_psram)]
2186fn get_range(ptr: NonNull<[u8]>, range: Range<usize>) -> NonNull<[u8]> {
2187 let len = range.end - range.start;
2188 NonNull::slice_from_raw_parts(unsafe { ptr.cast().byte_add(range.start) }, len)
2189}
2190
2191#[cfg(dma_can_access_psram)]
2192struct DescriptorChainingIter<'a> {
2193 index: usize,
2195 descriptors: &'a mut [DmaDescriptor],
2196}
2197#[cfg(dma_can_access_psram)]
2198impl<'a> DescriptorChainingIter<'a> {
2199 fn new(descriptors: &'a mut [DmaDescriptor]) -> Self {
2200 Self {
2201 descriptors,
2202 index: 0,
2203 }
2204 }
2205
2206 fn next(&mut self) -> Option<&'_ mut DmaDescriptor> {
2207 if self.index == 0 {
2208 self.index += 1;
2209 self.descriptors.get_mut(0)
2210 } else if self.index < self.descriptors.len() {
2211 let index = self.index;
2212 self.index += 1;
2213
2214 let ptr = &raw mut self.descriptors[index];
2216
2217 self.descriptors[index - 1].next = ptr;
2219
2220 Some(unsafe { &mut *ptr })
2223 } else {
2224 None
2225 }
2226 }
2227}
2228
2229#[cfg(dma_can_access_psram)]
2230const MIN_LAST_DMA_LEN: usize = if cfg!(esp32s2) { 5 } else { 1 };
2231#[cfg(dma_can_access_psram)]
2232const BUF_LEN: usize = 16 + 2 * (MIN_LAST_DMA_LEN - 1); #[cfg(dma_can_access_psram)]
2237pub(crate) struct ManualWritebackBuffer {
2238 buffer: InternalMemory<MaybeUninit<[u8; BUF_LEN]>>,
2239 dst_address: NonNull<u8>,
2240 n_bytes: u8,
2241}
2242
2243#[cfg(dma_can_access_psram)]
2244impl ManualWritebackBuffer {
2245 pub fn new(ptr: NonNull<[u8]>) -> Self {
2246 assert!(ptr.len() <= BUF_LEN);
2247 Self {
2248 buffer: InternalMemory::new(MaybeUninit::uninit()),
2249 dst_address: ptr.cast(),
2250 n_bytes: ptr.len() as u8,
2251 }
2252 }
2253
2254 pub fn prepare_for_dma(&mut self) {
2255 #[cfg(soc_internal_memory_cached)]
2258 self.buffer.get_mut().invalidate();
2259 }
2260
2261 pub fn write_back(&mut self) {
2262 #[cfg(soc_internal_memory_cached)]
2266 self.buffer.get_mut().invalidate();
2267
2268 let src = self.mut_buffer_ptr().cast_const();
2269 unsafe {
2270 self.dst_address
2271 .as_ptr()
2272 .copy_from(src, self.n_bytes as usize);
2273 }
2274 }
2275
2276 pub fn mut_buffer_ptr(&mut self) -> *mut u8 {
2277 self.buffer.get_mut().as_mut_ptr().cast::<u8>()
2278 }
2279}