From: Alexandre Courbot <acourbot@nvidia.com>
To: Danilo Krummrich <dakr@kernel.org>,
Alice Ryhl <aliceryhl@google.com>,
David Airlie <airlied@gmail.com>,
Simona Vetter <simona@ffwll.ch>
Cc: John Hubbard <jhubbard@nvidia.com>,
Alistair Popple <apopple@nvidia.com>,
Timur Tabi <ttabi@nvidia.com>,
Eliot Courtney <ecourtney@nvidia.com>,
Zhi Wang <zhiw@nvidia.com>,
nova-gpu@lists.linux.dev, rust-for-linux@vger.kernel.org,
linux-kernel@vger.kernel.org,
Alexandre Courbot <acourbot@nvidia.com>
Subject: [PATCH v2 05/12] gpu: nova-core: run the generic bootloader from its own type
Date: Sat, 07 Nov 2026 18:48:01 +0900 [thread overview]
Message-ID: <20261107-r000-fw-v2-5-fb37cc5b20cd@nvidia.com> (raw)
In-Reply-To: <20261107-r000-fw-v2-0-fb37cc5b20cd@nvidia.com>
From: John Hubbard <jhubbard@nvidia.com>
The generic falcon bootloader needs a descriptor in DMEM to know what to
load, so loading it into a falcon means loading the two together by PIO
and starting the falcon. The FWSEC wrapper did that through its own
implementation of the PIO loading traits. The r000 load-and-execute
bootloader event will need to do the same thing.
Give the generic bootloader a run method, which pairs it with the
descriptor that it receives, loads the pair by PIO, starts the falcon
with the given MAILBOX0 value and returns the mailboxes once the falcon
has halted. This will allow the FWSEC and r000 load-and-execute
bootloader event to share the same code.
No functional changes.
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
Co-developed-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 70 ++-------------
drivers/gpu/nova-core/firmware/gen_bootloader.rs | 100 ++++++++++++++++++++-
2 files changed, 102 insertions(+), 68 deletions(-)
diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
index 19e047f1c1ed..90b875945766 100644
--- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
@@ -12,26 +12,15 @@
Device, //
},
dma::Coherent,
- io::{
- register::Array,
- Io, //
- },
- prelude::*,
- transmute::AsBytes,
+ prelude::*, //
};
use crate::{
falcon::{
gsp::Gsp,
Falcon,
- FalconBromParams,
FalconDmaLoadable,
- FalconFbifMemType,
- FalconFbifTarget,
- FalconFirmware,
- FalconPioDmemLoadTarget,
- FalconPioImemLoadTarget,
- FalconPioLoadable, //
+ FalconFbifTarget, //
},
firmware::{
fwsec::FwsecFirmware,
@@ -42,7 +31,6 @@
},
gpu::Chipset,
num::FromSafeCast, //
- regs,
};
/// Wrapper for [`FwsecFirmware`] that includes the bootloader performing the actual load
@@ -54,8 +42,6 @@ pub(crate) struct FwsecFirmwareWithBl<'a> {
bootloader: GenericBootloader,
/// Descriptor to be loaded into DMEM for the bootloader to read.
dmem_desc: BootloaderDmemDescV2,
- /// BROM parameters of the loaded firmware.
- brom_params: FalconBromParams,
}
impl<'a> FwsecFirmwareWithBl<'a> {
@@ -128,7 +114,6 @@ pub(crate) fn new(
_firmware_dma: firmware_dma,
bootloader,
dmem_desc,
- brom_params: firmware.brom_params(),
})
}
@@ -137,26 +122,14 @@ pub(crate) fn new(
/// The bootloader will load the FWSEC firmware and then execute it. This function returns
/// after FWSEC has reached completion.
pub(crate) fn run(&self, dev: &Device<device::Bound>, falcon: &Falcon<'_, Gsp>) -> Result<()> {
- // Reset falcon, load the firmware, and run it.
falcon
.reset()
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
- falcon
- .pio_load(self)
- .inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;
- // Configure DMA index for the bootloader to fetch the FWSEC firmware from system memory.
- falcon.pfalcon.update(
- regs::NV_PFALCON_FBIF_TRANSCFG::try_at(usize::from_safe_cast(self.dmem_desc.ctx_dma()))
- .ok_or(EINVAL)?,
- |v| {
- v.with_target(FalconFbifTarget::CoherentSysmem)
- .with_mem_type(FalconFbifMemType::Physical)
- },
- );
-
- let (mbox0, _) = falcon
- .boot(Some(0), None)
+ // Run the bootloader, which loads the FWSEC firmware and runs it.
+ let (mbox0, _) = self
+ .bootloader
+ .run(falcon, &self.dmem_desc, FalconFbifTarget::CoherentSysmem, 0)
.inspect_err(|e| dev_err!(dev, "Failed to boot FWSEC firmware: {:?}\n", e))?;
if mbox0 != 0 {
dev_err!(dev, "FWSEC firmware returned error {}\n", mbox0);
@@ -166,34 +139,3 @@ pub(crate) fn run(&self, dev: &Device<device::Bound>, falcon: &Falcon<'_, Gsp>)
}
}
}
-
-impl FalconFirmware for FwsecFirmwareWithBl<'_> {
- type Target = Gsp;
-
- fn brom_params(&self) -> FalconBromParams {
- self.brom_params.clone()
- }
-
- fn boot_addr(&self) -> u32 {
- // On V2 platforms, the boot address is extracted from the generic bootloader, because the
- // gbl is what actually copies FWSEC into memory, so that is what needs to be booted.
- self.bootloader.boot_addr()
- }
-}
-
-impl FalconPioLoadable for FwsecFirmwareWithBl<'_> {
- fn imem_sec_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> {
- None
- }
-
- fn imem_ns_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> {
- Some(self.bootloader.imem_load_params())
- }
-
- fn dmem_load_params(&self) -> FalconPioDmemLoadTarget<'_> {
- FalconPioDmemLoadTarget {
- data: self.dmem_desc.as_bytes(),
- dst_start: 0,
- }
- }
-}
diff --git a/drivers/gpu/nova-core/firmware/gen_bootloader.rs b/drivers/gpu/nova-core/firmware/gen_bootloader.rs
index f769b2b277c0..1fecb6a5f80e 100644
--- a/drivers/gpu/nova-core/firmware/gen_bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/gen_bootloader.rs
@@ -7,6 +7,10 @@
use kernel::{
device,
+ io::{
+ register::Array,
+ Io, //
+ },
num::{
Bounded,
TryIntoBounded, //
@@ -21,15 +25,22 @@
self,
gsp::Gsp,
Falcon,
+ FalconBromParams,
FalconDmaLoadTarget,
- FalconPioImemLoadTarget, //
+ FalconFbifMemType,
+ FalconFbifTarget,
+ FalconFirmware,
+ FalconPioDmemLoadTarget,
+ FalconPioImemLoadTarget,
+ FalconPioLoadable, //
},
firmware::tlv::{
request_tlv, //
Tlv,
},
gpu::Chipset,
- num::FromSafeCast, //
+ num::FromSafeCast,
+ regs, //
};
/// Structure used by the boot-loader to load the rest of the code.
@@ -184,12 +195,12 @@ pub(crate) fn new(
/// Returns the address at which the falcon starts executing the bootloader: the IMEM virtual
/// address of its first code block.
- pub(crate) fn boot_addr(&self) -> u32 {
+ fn boot_addr(&self) -> u32 {
u32::from(self.start_tag) << 8
}
/// Returns the PIO parameters that place this bootloader in non-secure IMEM.
- pub(crate) fn imem_load_params(&self) -> FalconPioImemLoadTarget<'_> {
+ fn imem_load_params(&self) -> FalconPioImemLoadTarget<'_> {
FalconPioImemLoadTarget {
data: self.ucode.as_ref(),
dst_start: self.imem_dst_start,
@@ -197,4 +208,85 @@ pub(crate) fn imem_load_params(&self) -> FalconPioImemLoadTarget<'_> {
start_tag: self.start_tag,
}
}
+
+ /// Runs the bootloader on `falcon` to load and start the image that `dmem_desc` names.
+ ///
+ /// The bootloader and the descriptor are loaded by PIO, the bootloader is started with `mbox0`
+ /// in `MAILBOX0`, and this returns the mailbox values once the falcon has halted, that is,
+ /// once the loaded image has run to completion.
+ ///
+ /// The caller is expected to reset `falcon` beforehand.
+ ///
+ /// # Errors
+ ///
+ /// - `ETIMEDOUT` if the falcon has not halted within two seconds of starting.
+ /// - `EINVAL` if `dmem_desc`'s DMA context isn't valid.
+ ///
+ /// Errors from the PIO load are propagated as-is.
+ pub(crate) fn run(
+ &self,
+ falcon: &Falcon<'_, Gsp>,
+ dmem_desc: &BootloaderDmemDescV2,
+ target: FalconFbifTarget,
+ mbox0: u32,
+ ) -> Result<(u32, u32)> {
+ // Configure DMA index for the bootloader to fetch the FWSEC firmware from system memory.
+ falcon.pfalcon.update(
+ regs::NV_PFALCON_FBIF_TRANSCFG::try_at(usize::from_safe_cast(dmem_desc.ctx_dma()))
+ .ok_or(EINVAL)?,
+ |v| {
+ v.with_target(target)
+ .with_mem_type(FalconFbifMemType::Physical)
+ },
+ );
+
+ falcon.pio_load(&GenericBootloaderLoad {
+ bootloader: self,
+ dmem_desc,
+ })?;
+
+ falcon.boot(Some(mbox0), None)
+ }
+}
+
+/// The generic bootloader together with the descriptor that it reads from DMEM offset 0, as one
+/// firmware that [`Falcon::pio_load`] accepts.
+struct GenericBootloaderLoad<'a> {
+ bootloader: &'a GenericBootloader,
+ dmem_desc: &'a BootloaderDmemDescV2,
+}
+
+impl FalconFirmware for GenericBootloaderLoad<'_> {
+ type Target = Gsp;
+
+ fn brom_params(&self) -> FalconBromParams {
+ // The bootloader is unsigned, and the falcon HALs of the chipsets that load it this way
+ // write no BROM registers, so these values never reach hardware.
+ FalconBromParams {
+ pkc_data_offset: 0,
+ engine_id_mask: 0,
+ ucode_id: 0,
+ }
+ }
+
+ fn boot_addr(&self) -> u32 {
+ self.bootloader.boot_addr()
+ }
+}
+
+impl FalconPioLoadable for GenericBootloaderLoad<'_> {
+ fn imem_sec_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> {
+ None
+ }
+
+ fn imem_ns_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> {
+ Some(self.bootloader.imem_load_params())
+ }
+
+ fn dmem_load_params(&self) -> FalconPioDmemLoadTarget<'_> {
+ FalconPioDmemLoadTarget {
+ data: self.dmem_desc.as_bytes(),
+ dst_start: 0,
+ }
+ }
}
--
2.56.0
next prev parent reply other threads:[~2026-11-07 9:48 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 9:47 [PATCH v2 00/12] gpu: nova-core: generic bootloader and falcon DMA changes for r000 Alexandre Courbot
2026-11-07 9:47 ` [PATCH v2 01/12] gpu: nova-core: separate the generic falcon bootloader from FWSEC Alexandre Courbot
2026-11-07 9:47 ` [PATCH v2 02/12] gpu: nova-core: falcon: widen the IMEM PIO offset to 24 bits Alexandre Courbot
2026-11-07 9:47 ` [PATCH v2 03/12] gpu: nova-core: place the generic bootloader at the top of IMEM Alexandre Courbot
2026-11-07 9:48 ` [PATCH v2 04/12] gpu: nova-core: move the bootloader DMEM descriptor out of FWSEC Alexandre Courbot
2026-11-07 9:48 ` Alexandre Courbot [this message]
2026-11-07 9:48 ` [PATCH v2 06/12] rust: io: register: implement Copy and Clone for RegisterArrayLoc Alexandre Courbot
2026-11-07 9:48 ` [PATCH v2 07/12] gpu: nova-core: falcon: introduce and use with_fbif_transcfg Alexandre Courbot
2026-11-07 9:48 ` [PATCH v2 08/12] gpu: nova-core: falcon: rename the local variables of dma_wr() Alexandre Courbot
2026-11-07 9:48 ` [PATCH v2 09/12] gpu: nova-core: falcon: allow DMEM DMA transfers to request tagging Alexandre Courbot
2026-11-07 9:48 ` [PATCH v2 10/12] gpu: nova-core: falcon: allow DMA transfers to read from a framebuffer address Alexandre Courbot
2026-11-07 9:48 ` [PATCH v2 11/12] gpu: nova-core: falcon: check the per-block DMA offsets for overflow Alexandre Courbot
2026-11-07 9:48 ` [PATCH v2 12/12] gpu: nova-core: falcon: program the FBIF_TRANSCFG register in dma_wr Alexandre Courbot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261107-r000-fw-v2-5-fb37cc5b20cd@nvidia.com \
--to=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=apopple@nvidia.com \
--cc=dakr@kernel.org \
--cc=ecourtney@nvidia.com \
--cc=jhubbard@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=nova-gpu@lists.linux.dev \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=ttabi@nvidia.com \
--cc=zhiw@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®