[PATCH] gpu: nova-core: falcon: align DMA transfers to 256 bytes
Alexandre Courbot
acourbot at nvidia.com
Fri Aug 8 03:08:15 UTC 2025
Falcon DMA transfers are done in 256 bytes increments, and the method
responsible for initiating the transfer checked that the required length
was indeed a multiple of 256. While correct, this also requires callers
to specifically account for this limitation of DMA transfers, and we had
for instance the fwsec code performing a seemingly arbitrary (and
potentially overflowing) upwards alignment of the DMEM load size to
match this requirement.
Let's move that alignment into the loading code itself instead: since it
is working in terms of number of transfers, we can turn this upwards
alignment into a non-overflowing operation, and check that the requested
transfer remains into the limits of the DMA object. This also allows us
to remove a DMA-specific constant in the fwsec code.
Signed-off-by: Alexandre Courbot <acourbot at nvidia.com>
---
This came up as I was writing the next iteration of the `Alignment`
patchset: the alignment operation done in `fwsec.rs` would have required
an unsightly unwrap, so let's fix it beforehand.
---
drivers/gpu/nova-core/falcon.rs | 24 +++++++++++++++++-------
drivers/gpu/nova-core/firmware/fwsec.rs | 9 +--------
2 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 50437c67c14a89b6974a121d4408efbcdcb3fdd0..29fa7a2bcb580597762c9b4c7aa4239e51096cd6 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -451,14 +451,24 @@ fn dma_wr<F: FalconFirmware<Target = E>>(
);
return Err(EINVAL);
}
- if load_offsets.len % DMA_LEN > 0 {
+
+ // DMA transfers can only be done in units of 256 bytes.
+ let num_transfers = load_offsets.len.div_ceil(DMA_LEN);
+
+ // Check that the area we are about to transfer is within the bounds of the DMA object.
+ // SAFETY: we are not doing anything with the slice, only checking that it is valid.
+ let _ = unsafe {
+ fw.as_slice(
+ load_offsets.src_start as usize,
+ (num_transfers * DMA_LEN) as usize,
+ )
+ }
+ .inspect_err(|_| {
dev_err!(
self.dev,
- "DMA transfer length must be a multiple of {}",
- DMA_LEN
- );
- return Err(EINVAL);
- }
+ "DMA transfer length goes beyond range of DMA object"
+ )
+ })?;
// Set up the base source DMA address.
@@ -474,7 +484,7 @@ fn dma_wr<F: FalconFirmware<Target = E>>(
.set_imem(target_mem == FalconMem::Imem)
.set_sec(if sec { 1 } else { 0 });
- for pos in (0..load_offsets.len).step_by(DMA_LEN as usize) {
+ for pos in (0..num_transfers).map(|i| i * DMA_LEN) {
// Perform a transfer of size `DMA_LEN`.
regs::NV_PFALCON_FALCON_DMATRFMOFFS::default()
.set_offs(load_offsets.dst_start + pos)
diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs
index 0dff3cfa90afee0cd4c3348023c8bfd7edccdb29..47f5e4524072888cc3f89520ff4beea766071958 100644
--- a/drivers/gpu/nova-core/firmware/fwsec.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec.rs
@@ -202,9 +202,6 @@ pub(crate) struct FwsecFirmware {
ucode: FirmwareDmaObject<Self, Signed>,
}
-// We need to load full DMEM pages.
-const DMEM_LOAD_SIZE_ALIGN: u32 = 256;
-
impl FalconLoadParams for FwsecFirmware {
fn imem_load_params(&self) -> FalconLoadTarget {
FalconLoadTarget {
@@ -218,11 +215,7 @@ fn dmem_load_params(&self) -> FalconLoadTarget {
FalconLoadTarget {
src_start: self.desc.imem_load_size,
dst_start: self.desc.dmem_phys_base,
- // TODO[NUMM]: replace with `align_up` once it lands.
- len: self
- .desc
- .dmem_load_size
- .next_multiple_of(DMEM_LOAD_SIZE_ALIGN),
+ len: self.desc.dmem_load_size,
}
}
---
base-commit: 14ae91a81ec8fa0bc23170d4aa16dd2a20d54105
change-id: 20250808-falcondma_256b-5fb8a28ed274
Best regards,
--
Alexandre Courbot <acourbot at nvidia.com>
More information about the dri-devel
mailing list