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 {
1432 self.push_with(|buf| {
1433 let len = buf.len().min(data.len());
1434 buf[..len].copy_from_slice(&data[..len]);
1435 len
1436 })
1437 }
1438
1439 pub fn push_with(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
1446 let start = self.pre_filled.unwrap_or(0);
1447 let bytes_pushed = f(&mut self.buffer[start..]);
1448 self.pre_filled = Some(start + bytes_pushed);
1449 bytes_pushed
1450 }
1451
1452 fn setup_view_state(&mut self) {
1453 let pre_filled = self.pre_filled.unwrap_or(self.buffer.len());
1454 let (idx, offset) = mark_tx_stream_descriptors_ready(&mut self.descriptors, pre_filled);
1455 self.view_descriptor_idx = idx;
1456 self.view_descriptor_offset = offset;
1457 #[cfg(soc_internal_memory_cached)]
1458 if pre_filled != 0 {
1459 unsafe {
1460 crate::soc::cache_writeback_addr(self.buffer.as_ptr() as u32, pre_filled as u32);
1461 }
1462 }
1463 }
1464}
1465
1466fn mark_tx_stream_descriptors_ready(
1469 descriptors: &mut DmaAlignedMut<'_, [DmaDescriptor]>,
1470 bytes_pushed: usize,
1471) -> (usize, usize) {
1472 if bytes_pushed == 0 {
1473 return (0, 0);
1474 }
1475
1476 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1477 descriptors.invalidate();
1478
1479 let num = descriptors.len();
1480 let mut bytes_filled = 0;
1481 let mut cursor = (0, 0);
1482
1483 for d in 0..num {
1484 let remaining = bytes_pushed - bytes_filled;
1485 let size = descriptors[d].size();
1486
1487 if remaining == 0 {
1488 terminate_tx_stream_at(descriptors, d);
1489 cursor = (d, 0);
1490 break;
1491 }
1492
1493 if remaining < size {
1494 if d == 0 {
1495 descriptors[d].set_owner(Owner::Dma);
1498 descriptors[d].set_length(remaining);
1499 descriptors[d].set_suc_eof(true);
1500 if num > 1 {
1501 terminate_tx_stream_at(descriptors, 1);
1502 cursor = (1, 0);
1503 } else {
1504 descriptors[d].next = null_mut();
1505 }
1506 } else {
1507 terminate_tx_stream_at(descriptors, d);
1508 cursor = (d, remaining);
1509 }
1510 break;
1511 }
1512
1513 bytes_filled += size;
1514 descriptors[d].set_owner(Owner::Dma);
1515 descriptors[d].set_length(size);
1516 descriptors[d].set_suc_eof(true);
1517 }
1518
1519 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1520 descriptors.writeback();
1521
1522 cursor
1523}
1524
1525fn terminate_tx_stream_at(descriptors: &mut DmaAlignedMut<'_, [DmaDescriptor]>, start: usize) {
1526 if start > 0 {
1527 descriptors[start - 1].next = null_mut();
1528 }
1529 for desc in descriptors.iter_mut().skip(start) {
1530 desc.set_owner(Owner::Cpu);
1531 }
1532}
1533
1534fn advance_tx_stream_descriptors(
1535 descriptors: &mut DmaAlignedMut<'_, [DmaDescriptor]>,
1536 descriptor_idx: &mut usize,
1537 descriptor_offset: &mut usize,
1538 bytes_pushed: usize,
1539) {
1540 if bytes_pushed == 0 {
1541 return;
1542 }
1543
1544 let mut bytes_filled = 0;
1545 let num_descriptors = descriptors.len();
1546
1547 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1548 descriptors.invalidate();
1549
1550 for i in 0..num_descriptors {
1551 let d = (*descriptor_idx + i) % num_descriptors;
1552 let desc = &mut descriptors[d];
1553 let bytes_in_d = desc.size() - *descriptor_offset;
1554 if bytes_in_d + bytes_filled > bytes_pushed {
1555 *descriptor_idx = d;
1556 *descriptor_offset = *descriptor_offset + bytes_pushed - bytes_filled;
1557 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1558 descriptors.writeback();
1559 return;
1560 }
1561 bytes_filled += bytes_in_d;
1562 *descriptor_offset = 0;
1563
1564 desc.set_owner(Owner::Dma);
1566 desc.set_length(desc.size());
1567 desc.set_suc_eof(true);
1568 let p = d.checked_sub(1).unwrap_or(num_descriptors - 1);
1569 if p != d {
1570 let [prev, desc] = descriptors.get_disjoint_mut([p, d]).unwrap();
1571 desc.next = null_mut();
1572 prev.next = desc;
1573 }
1574 }
1575
1576 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1577 descriptors.writeback();
1578}
1579
1580unsafe impl DmaTxBuffer for DmaTxStreamBuf {
1581 type View = DmaTxStreamBufView;
1582 type Final = Self;
1583
1584 fn prepare(&mut self) -> Preparation {
1585 let mut next = null_mut();
1587 for desc in self.descriptors.iter_mut().rev() {
1588 desc.next = next;
1589 desc.set_owner(Owner::Dma);
1590 next = desc;
1591 }
1592 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1593 self.descriptors.writeback();
1594
1595 self.setup_view_state();
1596
1597 Preparation {
1598 start: self.descriptors.as_mut_ptr(),
1599 #[cfg(dma_can_access_psram)]
1600 accesses_psram: false,
1601 burst_transfer: self.burst,
1602
1603 check_owner: None,
1608 auto_write_back: true,
1609 }
1610 }
1611
1612 fn into_view(self) -> Self::View {
1613 DmaTxStreamBufView {
1614 descriptor_idx: self.view_descriptor_idx,
1615 descriptor_offset: self.view_descriptor_offset,
1616 buf: self,
1617 }
1618 }
1619
1620 fn from_view(view: Self::View) -> Self {
1621 let DmaTxStreamBufView {
1622 mut buf,
1623 descriptor_idx,
1624 descriptor_offset,
1625 } = view;
1626 buf.view_descriptor_idx = descriptor_idx;
1627 buf.view_descriptor_offset = descriptor_offset;
1628 buf
1629 }
1630}
1631
1632pub struct DmaTxStreamBufView {
1634 buf: DmaTxStreamBuf,
1635 descriptor_idx: usize,
1636 descriptor_offset: usize,
1637}
1638
1639impl DmaTxStreamBufView {
1640 pub fn available_bytes(&mut self) -> usize {
1642 #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
1643 self.buf.descriptors.invalidate();
1644
1645 let (tail, head) = self.buf.descriptors.split_at(self.descriptor_idx);
1646 head.iter()
1647 .chain(tail)
1648 .take_while(|d| d.owner() == Owner::Cpu)
1649 .map(|d| d.size())
1650 .sum::<usize>()
1651 .saturating_sub(self.descriptor_offset)
1652 }
1653
1654 fn write_position(&self) -> usize {
1655 let desc = &self.buf.descriptors[self.descriptor_idx];
1656 desc.buffer
1657 .addr()
1658 .wrapping_sub(self.buf.buffer.as_ptr().addr())
1659 + self.descriptor_offset
1660 }
1661
1662 pub fn push_with(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
1665 let dma_start = self.write_position();
1666 let dma_end = dma_start
1667 .saturating_add(self.available_bytes())
1668 .min(self.buf.buffer.len())
1669 .max(dma_start);
1670 let bytes_pushed = f(&mut self.buf.buffer[dma_start..dma_end]).min(dma_end - dma_start);
1671 #[cfg(soc_internal_memory_cached)]
1672 if bytes_pushed != 0 {
1673 unsafe {
1674 crate::soc::cache_writeback_addr(
1675 self.buf.buffer.as_ptr().add(dma_start) as u32,
1676 bytes_pushed as u32,
1677 );
1678 }
1679 }
1680
1681 self.advance(bytes_pushed);
1682 bytes_pushed
1683 }
1684
1685 pub fn advance(&mut self, bytes_pushed: usize) {
1687 advance_tx_stream_descriptors(
1688 &mut self.buf.descriptors,
1689 &mut self.descriptor_idx,
1690 &mut self.descriptor_offset,
1691 bytes_pushed,
1692 );
1693 }
1694
1695 pub fn push(&mut self, data: &[u8]) -> usize {
1698 let total_len = data.len();
1699 let mut remaining = data;
1700
1701 while !remaining.is_empty() && self.available_bytes() > 0 {
1702 let written = self.push_with(|buffer| {
1703 let len = usize::min(buffer.len(), remaining.len());
1704 buffer[..len].copy_from_slice(&remaining[..len]);
1705 len
1706 });
1707 if written == 0 {
1708 break;
1709 }
1710 remaining = &remaining[written..];
1711 }
1712
1713 total_len - remaining.len()
1714 }
1715}
1716
1717static mut EMPTY: InternalMemory<[DmaDescriptor; 1]> = InternalMemory::new([DmaDescriptor::EMPTY]);
1718
1719pub struct EmptyBuf;
1721
1722unsafe impl DmaTxBuffer for EmptyBuf {
1723 type View = EmptyBuf;
1724 type Final = EmptyBuf;
1725
1726 fn prepare(&mut self) -> Preparation {
1727 #[cfg(soc_internal_memory_cached)]
1728 #[allow(static_mut_refs)]
1729 unsafe {
1730 EMPTY.get_mut().writeback();
1731 }
1732
1733 Preparation {
1734 start: (&raw mut EMPTY).cast(),
1735 #[cfg(dma_can_access_psram)]
1736 accesses_psram: false,
1737 burst_transfer: BurstConfig::default(),
1738
1739 check_owner: Some(false),
1742
1743 auto_write_back: false,
1745 }
1746 }
1747
1748 fn into_view(self) -> EmptyBuf {
1749 self
1750 }
1751
1752 fn from_view(view: Self::View) -> Self {
1753 view
1754 }
1755}
1756
1757unsafe impl DmaRxBuffer for EmptyBuf {
1758 type View = EmptyBuf;
1759 type Final = EmptyBuf;
1760
1761 fn prepare(&mut self) -> Preparation {
1762 #[cfg(soc_internal_memory_cached)]
1763 #[allow(static_mut_refs)]
1764 unsafe {
1765 EMPTY.get_mut().writeback();
1766 }
1767
1768 Preparation {
1769 start: (&raw mut EMPTY).cast(),
1770 #[cfg(dma_can_access_psram)]
1771 accesses_psram: false,
1772 burst_transfer: BurstConfig::default(),
1773
1774 check_owner: Some(false),
1777 auto_write_back: true,
1778 }
1779 }
1780
1781 fn into_view(self) -> EmptyBuf {
1782 self
1783 }
1784
1785 fn from_view(view: Self::View) -> Self {
1786 view
1787 }
1788}
1789
1790pub struct DmaLoopBuf {
1801 descriptor: DmaAlignedMut<'static, [DmaDescriptor]>,
1802 buffer: DmaAlignedMut<'static, [u8]>,
1803}
1804
1805impl DmaLoopBuf {
1806 pub fn new(
1808 mut descriptors: DmaAlignedMut<'static, [DmaDescriptor]>,
1809 mut buffer: DmaAlignedMut<'static, [u8]>,
1810 ) -> Result<DmaLoopBuf, DmaBufError> {
1811 if buffer.len() > BurstConfig::default().max_chunk_size_for(&buffer, TransferDirection::Out)
1812 {
1813 return Err(DmaBufError::InsufficientDescriptors);
1814 }
1815
1816 descriptors[0].set_owner(Owner::Dma); descriptors[0].set_suc_eof(false);
1818 descriptors[0].set_length(buffer.len());
1819 descriptors[0].set_size(buffer.len());
1820 descriptors[0].buffer = buffer.as_mut_ptr();
1821 descriptors[0].next = descriptors.as_mut_ptr();
1822
1823 Ok(Self {
1824 descriptor: descriptors,
1825 buffer,
1826 })
1827 }
1828
1829 pub fn split(
1831 self,
1832 ) -> (
1833 DmaAlignedMut<'static, [DmaDescriptor]>,
1834 DmaAlignedMut<'static, [u8]>,
1835 ) {
1836 (self.descriptor, self.buffer)
1837 }
1838}
1839
1840unsafe impl DmaTxBuffer for DmaLoopBuf {
1841 type View = DmaLoopBuf;
1842 type Final = DmaLoopBuf;
1843
1844 fn prepare(&mut self) -> Preparation {
1845 Preparation {
1846 start: self.descriptor.as_mut_ptr(),
1847 #[cfg(dma_can_access_psram)]
1848 accesses_psram: false,
1849 burst_transfer: BurstConfig::default(),
1850 check_owner: Some(false),
1852
1853 auto_write_back: false,
1855 }
1856 }
1857
1858 fn into_view(self) -> Self::View {
1859 self
1860 }
1861
1862 fn from_view(view: Self::View) -> Self {
1863 view
1864 }
1865}
1866
1867impl Deref for DmaLoopBuf {
1868 type Target = [u8];
1869
1870 fn deref(&self) -> &Self::Target {
1871 &self.buffer
1872 }
1873}
1874
1875impl DerefMut for DmaLoopBuf {
1876 fn deref_mut(&mut self) -> &mut Self::Target {
1877 &mut self.buffer
1878 }
1879}
1880
1881pub(crate) struct NoBuffer(pub(crate) Preparation);
1887impl NoBuffer {
1888 fn prep(&self) -> Preparation {
1889 Preparation {
1890 start: self.0.start,
1891 #[cfg(dma_can_access_psram)]
1892 accesses_psram: self.0.accesses_psram,
1893 burst_transfer: self.0.burst_transfer,
1894 check_owner: self.0.check_owner,
1895 auto_write_back: self.0.auto_write_back,
1896 }
1897 }
1898}
1899unsafe impl DmaTxBuffer for NoBuffer {
1900 type View = ();
1901 type Final = ();
1902
1903 fn prepare(&mut self) -> Preparation {
1904 self.prep()
1905 }
1906
1907 fn into_view(self) -> Self::View {}
1908 fn from_view(_view: Self::View) {}
1909}
1910unsafe impl DmaRxBuffer for NoBuffer {
1911 type View = ();
1912 type Final = ();
1913
1914 fn prepare(&mut self) -> Preparation {
1915 self.prep()
1916 }
1917
1918 fn into_view(self) -> Self::View {}
1919 fn from_view(_view: Self::View) {}
1920}
1921
1922#[cfg_attr(not(any(aes_supports_dma, spi_master_supports_dma)), expect(unused))]
1935pub(crate) unsafe fn prepare_for_tx(
1936 descriptors: &mut [DmaDescriptor],
1937 mut data: NonNull<[u8]>,
1938 block_size: usize,
1939) -> Result<(NoBuffer, usize), DmaError> {
1940 let alignment =
1941 BurstConfig::DEFAULT.min_alignment(unsafe { data.as_ref() }, TransferDirection::Out);
1942
1943 if !data.addr().get().is_multiple_of(alignment) {
1944 return Err(DmaError::InvalidAlignment(DmaAlignmentError::Address));
1946 }
1947
1948 let alignment = alignment.max(block_size);
1954 let chunk_size = 4096 - alignment;
1955
1956 let data_len = data.len().min(chunk_size * descriptors.len());
1957
1958 cfg_select! {
1959 dma_can_access_psram => {
1960 let data_addr = data.addr().get();
1961 let data_in_psram = crate::psram::psram_range().contains(&data_addr);
1962
1963 if data_in_psram || cfg!(soc_internal_memory_cached) {
1965 unsafe { crate::soc::cache_writeback_addr(data_addr as u32, data_len as u32) };
1966 }
1967 }
1968 soc_internal_memory_cached => {
1969 unsafe { crate::soc::cache_writeback_addr(data.addr().get() as u32, data_len as u32) };
1970 }
1971 _ => {}
1972 }
1973
1974 let descriptors = unsafe { DmaAlignedMut::new_unchecked(descriptors) };
1975 let mut descriptors = unwrap!(DescriptorSet::new(descriptors));
1976 unwrap!(descriptors.link_with_buffer(unsafe { data.as_mut() }, chunk_size));
1979 unwrap!(descriptors.set_tx_length(data_len, chunk_size));
1980
1981 for desc in descriptors.linked_iter_mut() {
1982 desc.reset_for_tx(desc.next.is_null());
1983 }
1984
1985 #[cfg(soc_internal_memory_cached)]
1986 descriptors.descriptors.writeback();
1987
1988 Ok((
1989 NoBuffer(Preparation {
1990 start: descriptors.head(),
1991 burst_transfer: BurstConfig::DEFAULT,
1992 check_owner: None,
1993 auto_write_back: false,
1994 #[cfg(dma_can_access_psram)]
1995 accesses_psram: data_in_psram,
1996 }),
1997 data_len,
1998 ))
1999}
2000
2001#[cfg_attr(not(any(aes_supports_dma, spi_master_supports_dma)), expect(unused))]
2010pub(crate) unsafe fn prepare_for_rx(
2011 descriptors: &mut [DmaDescriptor],
2012 #[cfg(dma_can_access_psram)] align_buffers: &mut [Option<ManualWritebackBuffer>; 2],
2013 mut data: NonNull<[u8]>,
2014) -> (NoBuffer, usize) {
2015 let chunk_size =
2016 BurstConfig::DEFAULT.max_chunk_size_for(unsafe { data.as_ref() }, TransferDirection::In);
2017
2018 cfg_select! {
2023 dma_can_access_psram => {
2024 let data_addr = data.addr().get();
2025 let data_in_psram = crate::psram::psram_range().contains(&data_addr);
2026 }
2027 _ => {
2028 let data_in_psram = false;
2029 }
2030 }
2031
2032 let descriptors = unsafe { DmaAlignedMut::new_unchecked(descriptors) };
2033 let mut descriptors = unwrap!(DescriptorSet::new(descriptors));
2034 let data_len = if data_in_psram {
2035 cfg_select! {
2036 dma_can_access_psram => {
2037 let consumed_bytes =
2040 build_descriptor_list_for_psram(&mut descriptors, align_buffers, data);
2041
2042 unsafe {
2045 crate::soc::cache_writeback_addr(data_addr as u32, consumed_bytes as u32);
2046 crate::soc::cache_invalidate_addr(data_addr as u32, consumed_bytes as u32);
2047 }
2048
2049 consumed_bytes
2050 }
2051 _ => {
2052 unreachable!()
2053 }
2054 }
2055 } else {
2056 let data_len = data.len();
2058 unwrap!(descriptors.link_with_buffer(unsafe { data.as_mut() }, chunk_size));
2059 unwrap!(descriptors.set_tx_length(data_len, chunk_size));
2060
2061 #[cfg(soc_internal_memory_cached)]
2062 unsafe {
2065 crate::soc::cache_writeback_addr(data.addr().get() as u32, data_len as u32);
2066 crate::soc::cache_invalidate_addr(data.addr().get() as u32, data_len as u32);
2067 }
2068
2069 data_len
2070 };
2071
2072 for desc in descriptors.linked_iter_mut() {
2073 desc.reset_for_rx();
2074 }
2075
2076 #[cfg(soc_internal_memory_cached)]
2077 descriptors.descriptors.writeback();
2078
2079 (
2080 NoBuffer(Preparation {
2081 start: descriptors.head(),
2082 burst_transfer: BurstConfig::DEFAULT,
2083 check_owner: None,
2084 auto_write_back: true,
2085 #[cfg(dma_can_access_psram)]
2086 accesses_psram: data_in_psram,
2087 }),
2088 data_len,
2089 )
2090}
2091
2092#[cfg(dma_can_access_psram)]
2093fn build_descriptor_list_for_psram(
2094 descriptors: &mut DescriptorSet<'_>,
2095 copy_buffers: &mut [Option<ManualWritebackBuffer>; 2],
2096 data: NonNull<[u8]>,
2097) -> usize {
2098 let data_len = data.len();
2099 let data_addr = data.addr().get();
2100
2101 let min_alignment = ExternalBurstConfig::DEFAULT.min_psram_alignment(TransferDirection::In);
2102 let chunk_size = 4096 - min_alignment;
2103
2104 let mut desciptor_iter = DescriptorChainingIter::new(&mut descriptors.descriptors);
2105 let mut copy_buffer_iter = copy_buffers.iter_mut();
2106
2107 let has_aligned_data = data_len > BUF_LEN;
2112
2113 let offset = data_addr % min_alignment;
2115 let head_to_copy = min_alignment - offset;
2116 let head_to_copy = if !has_aligned_data {
2117 BUF_LEN
2118 } else if head_to_copy > 0 && head_to_copy < MIN_LAST_DMA_LEN {
2119 head_to_copy + min_alignment
2120 } else {
2121 head_to_copy
2122 };
2123 let head_to_copy = head_to_copy.min(data_len);
2124
2125 let tail_to_copy = (data_len - head_to_copy) % min_alignment;
2127 let tail_to_copy = if tail_to_copy > 0 && tail_to_copy < MIN_LAST_DMA_LEN {
2128 tail_to_copy + min_alignment
2129 } else {
2130 tail_to_copy
2131 };
2132
2133 let mut consumed = 0;
2134
2135 if head_to_copy > 0 {
2137 let copy_buffer = unwrap!(copy_buffer_iter.next());
2138 let buffer =
2139 copy_buffer.insert(ManualWritebackBuffer::new(get_range(data, 0..head_to_copy)));
2140 buffer.prepare_for_dma();
2141
2142 let Some(descriptor) = desciptor_iter.next() else {
2143 return consumed;
2144 };
2145 descriptor.set_size(head_to_copy);
2146 descriptor.buffer = buffer.mut_buffer_ptr();
2147 consumed += head_to_copy;
2148 };
2149
2150 let mut aligned_data = get_range(data, head_to_copy..data.len() - tail_to_copy);
2152 while !aligned_data.is_empty() {
2153 let Some(descriptor) = desciptor_iter.next() else {
2154 return consumed;
2155 };
2156 let chunk = aligned_data.len().min(chunk_size);
2157
2158 descriptor.set_size(chunk);
2159 descriptor.buffer = aligned_data.cast::<u8>().as_ptr();
2160 consumed += chunk;
2161 aligned_data = get_range(aligned_data, chunk..aligned_data.len());
2162 }
2163
2164 if tail_to_copy > 0 {
2166 let copy_buffer = unwrap!(copy_buffer_iter.next());
2167 let buffer = copy_buffer.insert(ManualWritebackBuffer::new(get_range(
2168 data,
2169 data.len() - tail_to_copy..data.len(),
2170 )));
2171 buffer.prepare_for_dma();
2172
2173 let Some(descriptor) = desciptor_iter.next() else {
2174 return consumed;
2175 };
2176 descriptor.set_size(tail_to_copy);
2177 descriptor.buffer = buffer.mut_buffer_ptr();
2178 consumed += tail_to_copy;
2179 }
2180
2181 consumed
2182}
2183
2184#[cfg(dma_can_access_psram)]
2185fn get_range(ptr: NonNull<[u8]>, range: Range<usize>) -> NonNull<[u8]> {
2186 let len = range.end - range.start;
2187 NonNull::slice_from_raw_parts(unsafe { ptr.cast().byte_add(range.start) }, len)
2188}
2189
2190#[cfg(dma_can_access_psram)]
2191struct DescriptorChainingIter<'a> {
2192 index: usize,
2194 descriptors: &'a mut [DmaDescriptor],
2195}
2196#[cfg(dma_can_access_psram)]
2197impl<'a> DescriptorChainingIter<'a> {
2198 fn new(descriptors: &'a mut [DmaDescriptor]) -> Self {
2199 Self {
2200 descriptors,
2201 index: 0,
2202 }
2203 }
2204
2205 fn next(&mut self) -> Option<&'_ mut DmaDescriptor> {
2206 if self.index == 0 {
2207 self.index += 1;
2208 self.descriptors.get_mut(0)
2209 } else if self.index < self.descriptors.len() {
2210 let index = self.index;
2211 self.index += 1;
2212
2213 let ptr = &raw mut self.descriptors[index];
2215
2216 self.descriptors[index - 1].next = ptr;
2218
2219 Some(unsafe { &mut *ptr })
2222 } else {
2223 None
2224 }
2225 }
2226}
2227
2228#[cfg(dma_can_access_psram)]
2229const MIN_LAST_DMA_LEN: usize = if cfg!(esp32s2) { 5 } else { 1 };
2230#[cfg(dma_can_access_psram)]
2231const BUF_LEN: usize = 16 + 2 * (MIN_LAST_DMA_LEN - 1); #[cfg(dma_can_access_psram)]
2236pub(crate) struct ManualWritebackBuffer {
2237 buffer: InternalMemory<MaybeUninit<[u8; BUF_LEN]>>,
2238 dst_address: NonNull<u8>,
2239 n_bytes: u8,
2240}
2241
2242#[cfg(dma_can_access_psram)]
2243impl ManualWritebackBuffer {
2244 pub fn new(ptr: NonNull<[u8]>) -> Self {
2245 assert!(ptr.len() <= BUF_LEN);
2246 Self {
2247 buffer: InternalMemory::new(MaybeUninit::uninit()),
2248 dst_address: ptr.cast(),
2249 n_bytes: ptr.len() as u8,
2250 }
2251 }
2252
2253 pub fn prepare_for_dma(&mut self) {
2254 #[cfg(soc_internal_memory_cached)]
2257 self.buffer.get_mut().invalidate();
2258 }
2259
2260 pub fn write_back(&mut self) {
2261 #[cfg(soc_internal_memory_cached)]
2265 self.buffer.get_mut().invalidate();
2266
2267 let src = self.mut_buffer_ptr().cast_const();
2268 unsafe {
2269 self.dst_address
2270 .as_ptr()
2271 .copy_from(src, self.n_bytes as usize);
2272 }
2273 }
2274
2275 pub fn mut_buffer_ptr(&mut self) -> *mut u8 {
2276 self.buffer.get_mut().as_mut_ptr().cast::<u8>()
2277 }
2278}