Add burst transfer support to DMA buffers (#2336)

Co-authored-by: Dominic Fischer <git@dominicfischer.me>
This commit is contained in:
Dominic Fischer 2024-10-16 14:25:48 +01:00 committed by GitHub
parent 99a579973a
commit 6e2606b367
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 44 additions and 9 deletions

View File

@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Added ### Added
- Add burst transfer support to DMA buffers (#2236)
### Changed ### Changed

View File

@ -8,11 +8,22 @@ use crate::soc::is_slice_in_psram;
/// Holds all the information needed to configure a DMA channel for a transfer. /// Holds all the information needed to configure a DMA channel for a transfer.
pub struct Preparation { pub struct Preparation {
pub(super) start: *mut DmaDescriptor, pub(super) start: *mut DmaDescriptor,
/// block size for PSRAM transfers (TODO: enable burst mode for non external
/// memory?) /// block size for PSRAM transfers
#[cfg_attr(not(esp32s3), allow(dead_code))] #[cfg_attr(not(esp32s3), allow(dead_code))]
pub(super) block_size: Option<DmaBufBlkSize>, pub(super) block_size: Option<DmaBufBlkSize>,
// burst_mode, alignment, check_owner, etc.
/// Specifies whether descriptor linked list specified in `start` conforms
/// to the alignment requirements required to enable burst transfers.
///
/// Note: This only applies to burst transfer of the buffer data, not the
/// descriptors themselves.
///
/// There are no additional alignment requirements for TX burst transfers,
/// but RX transfers require all descriptors to have buffer pointers and
/// sizes that are a multiple of 4 (word aligned).
pub(super) is_burstable: bool,
// alignment, check_owner, etc.
} }
/// [DmaTxBuffer] is a DMA descriptor + memory combo that can be used for /// [DmaTxBuffer] is a DMA descriptor + memory combo that can be used for
@ -290,6 +301,8 @@ unsafe impl DmaTxBuffer for DmaTxBuf {
Preparation { Preparation {
start: self.descriptors.head(), start: self.descriptors.head(),
block_size: self.block_size, block_size: self.block_size,
// This is TX, the DMA channel is free to do a burst transfer.
is_burstable: true,
} }
} }
@ -436,6 +449,10 @@ unsafe impl DmaRxBuffer for DmaRxBuf {
Preparation { Preparation {
start: self.descriptors.head(), start: self.descriptors.head(),
block_size: None, block_size: None,
// DmaRxBuf doesn't currently enforce the alignment requirements required for bursting.
// In the future, it could either enforce the alignment or calculate if the alignment
// requirements happen to be met.
is_burstable: false,
} }
} }
@ -560,6 +577,9 @@ unsafe impl DmaTxBuffer for DmaRxTxBuf {
Preparation { Preparation {
start: self.tx_descriptors.head(), start: self.tx_descriptors.head(),
block_size: None, // TODO: support block size! block_size: None, // TODO: support block size!
// This is TX, the DMA channel is free to do a burst transfer.
is_burstable: true,
} }
} }
@ -587,6 +607,10 @@ unsafe impl DmaRxBuffer for DmaRxTxBuf {
Preparation { Preparation {
start: self.rx_descriptors.head(), start: self.rx_descriptors.head(),
block_size: None, // TODO: support block size! block_size: None, // TODO: support block size!
// DmaRxTxBuf doesn't currently enforce the alignment requirements required for
// bursting.
is_burstable: false,
} }
} }
@ -723,6 +747,10 @@ unsafe impl DmaRxBuffer for DmaRxStreamBuf {
Preparation { Preparation {
start: self.descriptors.as_mut_ptr(), start: self.descriptors.as_mut_ptr(),
block_size: None, block_size: None,
// DmaRxStreamBuf doesn't currently enforce the alignment requirements required for
// bursting.
is_burstable: false,
} }
} }
@ -927,6 +955,9 @@ unsafe impl DmaTxBuffer for EmptyBuf {
Preparation { Preparation {
start: unsafe { core::ptr::addr_of_mut!(EMPTY).cast() }, start: unsafe { core::ptr::addr_of_mut!(EMPTY).cast() },
block_size: None, block_size: None,
// This is TX, the DMA channel is free to do a burst transfer.
is_burstable: true,
} }
} }
@ -951,6 +982,9 @@ unsafe impl DmaRxBuffer for EmptyBuf {
Preparation { Preparation {
start: unsafe { core::ptr::addr_of_mut!(EMPTY).cast() }, start: unsafe { core::ptr::addr_of_mut!(EMPTY).cast() },
block_size: None, block_size: None,
// As much as bursting is meaningless here, the descriptor does meet the requirements.
is_burstable: true,
} }
} }

View File

@ -1703,10 +1703,8 @@ where
) -> Result<(), DmaError> { ) -> Result<(), DmaError> {
let preparation = buffer.prepare(); let preparation = buffer.prepare();
// TODO: Get burst mode from DmaBuf. self.rx_impl
if self.burst_mode { .set_burst_mode(self.burst_mode && preparation.is_burstable);
return Err(DmaError::InvalidAlignment);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst); compiler_fence(core::sync::atomic::Ordering::SeqCst);
@ -1916,13 +1914,15 @@ where
self.set_ext_mem_block_size(block_size.into()); self.set_ext_mem_block_size(block_size.into());
} }
} else { } else {
// we insure that block_size is some only for PSRAM addresses // we ensure that block_size is some only for PSRAM addresses
if preparation.block_size.is_some() { if preparation.block_size.is_some() {
return Err(DmaError::UnsupportedMemoryRegion); return Err(DmaError::UnsupportedMemoryRegion);
} }
} }
); );
// TODO: Get burst mode from DmaBuf.
self.tx_impl
.set_burst_mode(self.burst_mode && preparation.is_burstable);
compiler_fence(core::sync::atomic::Ordering::SeqCst); compiler_fence(core::sync::atomic::Ordering::SeqCst);