* Re: [PATCH v2 1/2] signal: avoid shared siginfo namespace rewrites
From: Oleg Nesterov @ 2026-06-24 15:52 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Bradley Morgan, Christian Brauner, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, Andrew Morton,
Peter Zijlstra, Marco Elver, Aleksandr Nogikh, Thomas Gleixner,
Adrian Huang, Kexin Sun, linux-kernel, linux-trace-kernel, stable
In-Reply-To: <87bjd0c5xk.fsf@email.froward.int.ebiederm.org>
On 06/24, Eric W. Biederman wrote:
>
> Oleg Nesterov <oleg@redhat.com> writes:
>
> > Add Eric.
> >
> > OK, I agree, it seems we need a simple fix.
> >
> > Acked-by: Oleg Nesterov <oleg@redhat.com>
> >
> > -------------------------------------------------------------------------
> > But let me add some "offtopic" notes... Why do we actually need this fix?
> >
> > kill_something_info(). But at first glance sys_kill/kill_something_info
> > can simply use SEND_SIG_NOINFO? If yes, this makes sense anyway, I will
> > re-check...
....
> So I think tracing the basic kill syscall is interesting.
>
> It uses an explicit siginfo. It does that so it can choose
> between setting si_code to SI_TKILL and SI_USER.
>
> If the signal number is -1 it sends to every process in the
> system (or at least the pid namespace).
>
> That will require translation.
Most probably I was wrong, I didn't try to re-check yet.
But at first glance kill_something_info() never use SI_TKILL, and
__send_signal_locked(SEND_SIG_NOINFO) will do the necessary translation,
in this case si_pid/si_uid are the current task's pid/uid.
But again, I am not sure. Didn't have to to actually look at this code.
> I suspect just fixing send_signal_locked looks the easiest,
> especially if you make the siginfo parameter const.
Yes, agreed, and I have already acked this patch.
I think we can improve this unconditional rewrite later, on top of this fix.
Oleg.
^ permalink raw reply
* [PATCH] gpu: nova-core: falcon: store bar and dev in falcon
From: Tim Kovalenko @ 2026-06-24 15:51 UTC (permalink / raw)
To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
Simona Vetter, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti
Cc: nova-gpu, dri-devel, linux-kernel, linux-riscv, Tim Kovalenko
Store the bound device and `BAR0` mapping in `Falcon` instead of passing
them through every `Falcon` operation. This simplifies the `Falcon` API and
removes repeated `dev`/`bar` plumbing from reset, load, boot, mailbox, DMA,
and GSP/FSP-specific Falcon helpers.
Add a named helper for configuring Falcon FBIF transaction slots for
physical coherent system memory, avoiding direct `BAR0` access from the
FWSEC bootloader path without exposing BAR0 publicly.
Future work / questions:
- Focused only on the Falcon for this patch - more to follow.
- Not sure about the FalconHal and if I should modify the Trait
- Could be part of the next patch
- But it could definitively be simplified
- Also, how far should the refactor go and to what extend add new
methods to avoid passing `bar` or `dev` but also not exposing them as
pub. For `dev`, there's a lot of `dev_err` usage that requires us to
pass it as a param.
- I've created the `set_fbif_transcfg_phys_sysmem` method to
address such issue and remove some code duplication but that
method could be made a bit more generic.
- Also, is there a reason why we are not passing the `GspBootContext`
when we need stuff like `bar`, `dev` and both falcons?
Reported-by: Alexandre Courbot <acourbot@nvidia.com>
Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/509436-Nova/topic/Storing.20driver-bound.20references.20into.20sub-devices/near/599137882
Signed-off-by: Tim Kovalenko <tim.kovalenko@proton.me>
---
drivers/gpu/nova-core/falcon.rs | 206 ++++++++++-----------
drivers/gpu/nova-core/falcon/fsp.rs | 44 +++--
drivers/gpu/nova-core/falcon/gsp.rs | 21 ++-
drivers/gpu/nova-core/falcon/hal.rs | 6 +-
drivers/gpu/nova-core/falcon/hal/ga102.rs | 8 +-
drivers/gpu/nova-core/falcon/hal/tu102.rs | 6 +-
drivers/gpu/nova-core/firmware/booter.rs | 25 +--
drivers/gpu/nova-core/firmware/fwsec.rs | 19 +-
drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 33 +---
drivers/gpu/nova-core/fsp.rs | 23 ++-
drivers/gpu/nova-core/gpu.rs | 9 +-
drivers/gpu/nova-core/gsp.rs | 4 +-
drivers/gpu/nova-core/gsp/boot.rs | 22 +--
drivers/gpu/nova-core/gsp/hal.rs | 4 +-
drivers/gpu/nova-core/gsp/hal/gh100.rs | 32 ++--
drivers/gpu/nova-core/gsp/hal/tu102.rs | 75 ++++----
drivers/gpu/nova-core/gsp/sequencer.rs | 31 ++--
17 files changed, 253 insertions(+), 315 deletions(-)
diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 94c7696a6493..ca12cc11a370 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -5,10 +5,7 @@
use hal::FalconHal;
use kernel::{
- device::{
- self,
- Device, //
- },
+ device,
dma::{
Coherent,
CoherentBox,
@@ -24,7 +21,6 @@
Io,
},
prelude::*,
- sync::aref::ARef,
time::Delta,
};
@@ -358,41 +354,47 @@ pub(crate) trait FalconFirmware {
}
/// Contains the base parameters common to all Falcon instances.
-pub(crate) struct Falcon<E: FalconEngine> {
+pub(crate) struct Falcon<'a, E: FalconEngine> {
hal: KBox<dyn FalconHal<E>>,
- dev: ARef<device::Device>,
+ dev: &'a device::Device<device::Bound>,
+ bar: Bar0<'a>,
}
-impl<E: FalconEngine + 'static> Falcon<E> {
+impl<'a, E: FalconEngine + 'static> Falcon<'a, E> {
/// Create a new falcon instance.
- pub(crate) fn new(dev: &device::Device, chipset: Chipset) -> Result<Self> {
+ pub(crate) fn new(
+ dev: &'a device::Device<device::Bound>,
+ chipset: Chipset,
+ bar: Bar0<'a>,
+ ) -> Result<Self> {
Ok(Self {
hal: hal::falcon_hal(chipset)?,
- dev: dev.into(),
+ dev,
+ bar,
})
}
/// Resets DMA-related registers.
- pub(crate) fn dma_reset(&self, bar: Bar0<'_>) {
- bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
+ pub(crate) fn dma_reset(&self) {
+ self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
v.with_allow_phys_no_ctx(true)
});
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMACTL::zeroed(),
);
}
/// Reset the controller, select the falcon core, and wait for memory scrubbing to complete.
- pub(crate) fn reset(&self, bar: Bar0<'_>) -> Result {
- self.hal.reset_eng(bar)?;
- self.hal.select_core(self, bar)?;
- self.hal.reset_wait_mem_scrubbing(bar)?;
+ pub(crate) fn reset(&self) -> Result {
+ self.hal.reset_eng(self.bar)?;
+ self.hal.select_core(self, self.bar)?;
+ self.hal.reset_wait_mem_scrubbing(self.bar)?;
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
- regs::NV_PFALCON_FALCON_RM::from(bar.read(regs::NV_PMC_BOOT_0).into_raw()),
+ regs::NV_PFALCON_FALCON_RM::from(self.bar.read(regs::NV_PMC_BOOT_0).into_raw()),
);
Ok(())
@@ -404,18 +406,14 @@ pub(crate) fn reset(&self, bar: Bar0<'_>) -> Result {
/// Write a slice to Falcon IMEM memory using programmed I/O (PIO).
///
/// Returns `EINVAL` if `img.len()` is not a multiple of 4.
- fn pio_wr_imem_slice(
- &self,
- bar: Bar0<'_>,
- load_offsets: FalconPioImemLoadTarget<'_>,
- ) -> Result {
+ fn pio_wr_imem_slice(&self, load_offsets: FalconPioImemLoadTarget<'_>) -> Result {
// Rejecting misaligned images here allows us to avoid checking
// inside the loops.
if load_offsets.data.len() % 4 != 0 {
return Err(EINVAL);
}
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMC::zeroed()
.with_secure(load_offsets.secure)
@@ -426,13 +424,13 @@ fn pio_wr_imem_slice(
for (n, block) in load_offsets.data.chunks(MEM_BLOCK_ALIGNMENT).enumerate() {
let n = u16::try_from(n)?;
let tag: u16 = load_offsets.start_tag.checked_add(n).ok_or(ERANGE)?;
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMT::zeroed().with_tag(tag),
);
for word in block.chunks_exact(4) {
let w = [word[0], word[1], word[2], word[3]];
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMD::zeroed().with_data(u32::from_le_bytes(w)),
);
@@ -445,18 +443,14 @@ fn pio_wr_imem_slice(
/// Write a slice to Falcon DMEM memory using programmed I/O (PIO).
///
/// Returns `EINVAL` if `img.len()` is not a multiple of 4.
- fn pio_wr_dmem_slice(
- &self,
- bar: Bar0<'_>,
- load_offsets: FalconPioDmemLoadTarget<'_>,
- ) -> Result {
+ fn pio_wr_dmem_slice(&self, load_offsets: FalconPioDmemLoadTarget<'_>) -> Result {
// Rejecting misaligned images here allows us to avoid checking
// inside the loops.
if load_offsets.data.len() % 4 != 0 {
return Err(EINVAL);
}
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_DMEMC::zeroed()
.with_aincw(true)
@@ -465,7 +459,7 @@ fn pio_wr_dmem_slice(
for word in load_offsets.data.chunks_exact(4) {
let w = [word[0], word[1], word[2], word[3]];
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_DMEMD::zeroed().with_data(u32::from_le_bytes(w)),
);
@@ -477,29 +471,28 @@ fn pio_wr_dmem_slice(
/// Perform a PIO copy into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
pub(crate) fn pio_load<F: FalconFirmware<Target = E> + FalconPioLoadable>(
&self,
- bar: Bar0<'_>,
fw: &F,
) -> Result {
- bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
+ self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
v.with_allow_phys_no_ctx(true)
});
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMACTL::zeroed(),
);
if let Some(imem_ns) = fw.imem_ns_load_params() {
- self.pio_wr_imem_slice(bar, imem_ns)?;
+ self.pio_wr_imem_slice(imem_ns)?;
}
if let Some(imem_sec) = fw.imem_sec_load_params() {
- self.pio_wr_imem_slice(bar, imem_sec)?;
+ self.pio_wr_imem_slice(imem_sec)?;
}
- self.pio_wr_dmem_slice(bar, fw.dmem_load_params())?;
+ self.pio_wr_dmem_slice(fw.dmem_load_params())?;
- self.hal.program_brom(self, bar, &fw.brom_params());
+ self.hal.program_brom(self, self.bar, &fw.brom_params());
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()),
);
@@ -513,7 +506,6 @@ pub(crate) fn pio_load<F: FalconFirmware<Target = E> + FalconPioLoadable>(
/// `sec` is set if the loaded firmware is expected to run in secure mode.
fn dma_wr(
&self,
- bar: Bar0<'_>,
dma_obj: &Coherent<[u8]>,
target_mem: FalconMem,
load_offsets: FalconDmaLoadTarget,
@@ -571,7 +563,7 @@ fn dma_wr(
// Set up the base source DMA address.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_base(
// CAST: `as u32` is used on purpose since we do want to strip the upper bits,
@@ -579,7 +571,7 @@ fn dma_wr(
(dma_start >> 8) as u32,
),
);
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed().try_with_base(dma_start >> 40)?,
);
@@ -590,23 +582,23 @@ fn dma_wr(
for pos in (0..num_transfers).map(|i| i * DMA_LEN) {
// Perform a transfer of size `DMA_LEN`.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed()
.try_with_offs(load_offsets.dst_start + pos)?,
);
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(src_start + pos),
);
- bar.write(WithBase::of::<E>(), cmd);
+ self.bar.write(WithBase::of::<E>(), cmd);
// Wait for the transfer to complete.
// TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories
// should ever take that long.
read_poll_timeout(
- || Ok(bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())),
+ || Ok(self.bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())),
|r| r.idle(),
Delta::ZERO,
Delta::from_secs(2),
@@ -617,12 +609,7 @@ fn dma_wr(
}
/// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
- fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
- &self,
- dev: &Device<device::Bound>,
- bar: Bar0<'_>,
- fw: &F,
- ) -> Result {
+ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
// DMA object with firmware content as the source of the DMA engine.
let dma_obj = {
let fw_slice = fw.as_slice();
@@ -630,7 +617,7 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
// DMA copies are done in chunks of `MEM_BLOCK_ALIGNMENT`, so pad the length
// accordingly and fill with `0`.
let mut dma_obj = CoherentBox::zeroed_slice(
- dev,
+ self.dev,
fw_slice.len().next_multiple_of(MEM_BLOCK_ALIGNMENT),
GFP_KERNEL,
)?;
@@ -642,24 +629,16 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
dma_obj.into()
};
- self.dma_reset(bar);
- bar.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| {
- v.with_target(FalconFbifTarget::CoherentSysmem)
- .with_mem_type(FalconFbifMemType::Physical)
- });
+ self.dma_reset();
+ self.set_fbif_transcfg_phys_sysmem(0)?;
- self.dma_wr(
- bar,
- &dma_obj,
- FalconMem::ImemSecure,
- fw.imem_sec_load_params(),
- )?;
- self.dma_wr(bar, &dma_obj, FalconMem::Dmem, fw.dmem_load_params())?;
+ self.dma_wr(&dma_obj, FalconMem::ImemSecure, fw.imem_sec_load_params())?;
+ self.dma_wr(&dma_obj, FalconMem::Dmem, fw.dmem_load_params())?;
- self.hal.program_brom(self, bar, &fw.brom_params());
+ self.hal.program_brom(self, self.bar, &fw.brom_params());
// Set `BootVec` to start of non-secure code.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()),
);
@@ -667,11 +646,26 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
Ok(())
}
+ /// Configure a Falcon FBIF transaction slot to access physical coherent system memory.
+ pub(crate) fn set_fbif_transcfg_phys_sysmem(&self, dmaidx: u32) -> Result {
+ self.bar.update(
+ regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>()
+ .try_at(usize::from_safe_cast(dmaidx))
+ .ok_or(EINVAL)?,
+ |v| {
+ v.with_target(FalconFbifTarget::CoherentSysmem)
+ .with_mem_type(FalconFbifMemType::Physical)
+ },
+ );
+
+ Ok(())
+ }
+
/// Wait until the falcon CPU is halted.
- pub(crate) fn wait_till_halted(&self, bar: Bar0<'_>) -> Result<()> {
+ pub(crate) fn wait_till_halted(&self) -> Result<()> {
// TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds.
read_poll_timeout(
- || Ok(bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())),
+ || Ok(self.bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())),
|r| r.halted(),
Delta::ZERO,
Delta::from_secs(2),
@@ -681,16 +675,17 @@ pub(crate) fn wait_till_halted(&self, bar: Bar0<'_>) -> Result<()> {
}
/// Start the falcon CPU.
- pub(crate) fn start(&self, bar: Bar0<'_>) -> Result<()> {
- match bar
+ pub(crate) fn start(&self) -> Result<()> {
+ match self
+ .bar
.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())
.alias_en()
{
- true => bar.write(
+ true => self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed().with_startcpu(true),
),
- false => bar.write(
+ false => self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_CPUCTL::zeroed().with_startcpu(true),
),
@@ -700,16 +695,16 @@ pub(crate) fn start(&self, bar: Bar0<'_>) -> Result<()> {
}
/// Writes values to the mailbox registers if provided.
- pub(crate) fn write_mailboxes(&self, bar: Bar0<'_>, mbox0: Option<u32>, mbox1: Option<u32>) {
+ pub(crate) fn write_mailboxes(&self, mbox0: Option<u32>, mbox1: Option<u32>) {
if let Some(mbox0) = mbox0 {
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_MAILBOX0::zeroed().with_value(mbox0),
);
}
if let Some(mbox1) = mbox1 {
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_MAILBOX1::zeroed().with_value(mbox1),
);
@@ -717,21 +712,23 @@ pub(crate) fn write_mailboxes(&self, bar: Bar0<'_>, mbox0: Option<u32>, mbox1: O
}
/// Reads the value from `mbox0` register.
- pub(crate) fn read_mailbox0(&self, bar: Bar0<'_>) -> u32 {
- bar.read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>())
+ pub(crate) fn read_mailbox0(&self) -> u32 {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>())
.value()
}
/// Reads the value from `mbox1` register.
- pub(crate) fn read_mailbox1(&self, bar: Bar0<'_>) -> u32 {
- bar.read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>())
+ pub(crate) fn read_mailbox1(&self) -> u32 {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>())
.value()
}
/// Reads values from both mailbox registers.
- pub(crate) fn read_mailboxes(&self, bar: Bar0<'_>) -> (u32, u32) {
- let mbox0 = self.read_mailbox0(bar);
- let mbox1 = self.read_mailbox1(bar);
+ pub(crate) fn read_mailboxes(&self) -> (u32, u32) {
+ let mbox0 = self.read_mailbox0();
+ let mbox1 = self.read_mailbox1();
(mbox0, mbox1)
}
@@ -743,54 +740,43 @@ pub(crate) fn read_mailboxes(&self, bar: Bar0<'_>) -> (u32, u32) {
///
/// Wait up to two seconds for the firmware to complete, and return its exit status read from
/// the `MBOX0` and `MBOX1` registers.
- pub(crate) fn boot(
- &self,
- bar: Bar0<'_>,
- mbox0: Option<u32>,
- mbox1: Option<u32>,
- ) -> Result<(u32, u32)> {
- self.write_mailboxes(bar, mbox0, mbox1);
- self.start(bar)?;
- self.wait_till_halted(bar)?;
- Ok(self.read_mailboxes(bar))
+ pub(crate) fn boot(&self, mbox0: Option<u32>, mbox1: Option<u32>) -> Result<(u32, u32)> {
+ self.write_mailboxes(mbox0, mbox1);
+ self.start()?;
+ self.wait_till_halted()?;
+ Ok(self.read_mailboxes())
}
/// Returns the fused version of the signature to use in order to run a HS firmware on this
/// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header.
pub(crate) fn signature_reg_fuse_version(
&self,
- bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32> {
self.hal
- .signature_reg_fuse_version(self, bar, engine_id_mask, ucode_id)
+ .signature_reg_fuse_version(self, self.bar, engine_id_mask, ucode_id)
}
/// Check if the RISC-V core is active.
///
/// Returns `true` if the RISC-V core is active, `false` otherwise.
- pub(crate) fn is_riscv_active(&self, bar: Bar0<'_>) -> bool {
- self.hal.is_riscv_active(bar)
+ pub(crate) fn is_riscv_active(&self) -> bool {
+ self.hal.is_riscv_active(self.bar)
}
/// Load a firmware image into Falcon memory, using the preferred method for the current
/// chipset.
- pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
- &self,
- dev: &Device<device::Bound>,
- bar: Bar0<'_>,
- fw: &F,
- ) -> Result {
+ pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
match self.hal.load_method() {
- LoadMethod::Dma => self.dma_load(dev, bar, fw),
- LoadMethod::Pio => self.pio_load(bar, &fw.try_as_pio_loadable()?),
+ LoadMethod::Dma => self.dma_load(fw),
+ LoadMethod::Pio => self.pio_load(&fw.try_as_pio_loadable()?),
}
}
/// Write the application version to the OS register.
- pub(crate) fn write_os_version(&self, bar: Bar0<'_>, app_version: u32) {
- bar.write(
+ pub(crate) fn write_os_version(&self, app_version: u32) {
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_OS::zeroed().with_value(app_version),
);
diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs
index 52cdb84ef0e8..53b1079843ae 100644
--- a/drivers/gpu/nova-core/falcon/fsp.rs
+++ b/drivers/gpu/nova-core/falcon/fsp.rs
@@ -21,7 +21,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
Falcon,
FalconEngine,
@@ -48,18 +47,18 @@ impl RegisterBase<PFalcon2Base> for Fsp {
impl FalconEngine for Fsp {}
-impl Falcon<Fsp> {
+impl<'a> Falcon<'a, Fsp> {
/// Writes `data` to FSP external memory at offset `0`.
///
/// `data` is interpreted as little-endian 32-bit words. Returns `EINVAL`
/// if the `data` length is not 4-byte aligned.
- fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
+ fn write_emem(&mut self, data: &[u8]) -> Result {
if data.len() % 4 != 0 {
return Err(EINVAL);
}
// Begin a write burst at offset `0`, auto-incrementing on each write.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincw(true),
);
@@ -68,7 +67,7 @@ fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
let value = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
// Write the next 32-bit `value`; hardware advances the offset.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMD::zeroed().with_data(value),
);
@@ -81,20 +80,23 @@ fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
///
/// `data` is stored as little-endian 32-bit words. Returns `EINVAL` if
/// the `data` length is not 4-byte aligned.
- fn read_emem(&mut self, bar: Bar0<'_>, data: &mut [u8]) -> Result {
+ fn read_emem(&mut self, data: &mut [u8]) -> Result {
if data.len() % 4 != 0 {
return Err(EINVAL);
}
// Begin a read burst at offset `0`, auto-incrementing on each read.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincr(true),
);
for chunk in data.chunks_exact_mut(4) {
// Read the next 32-bit word; hardware advances the offset.
- let value = bar.read(regs::NV_PFALCON_FALCON_EMEMD::of::<Fsp>()).data();
+ let value = self
+ .bar
+ .read(regs::NV_PFALCON_FALCON_EMEMD::of::<Fsp>())
+ .data();
chunk.copy_from_slice(&value.to_le_bytes());
}
@@ -107,9 +109,9 @@ fn read_emem(&mut self, bar: Bar0<'_>, data: &mut [u8]) -> Result {
///
/// The FSP message queue is not circular. Pointers are reset to 0 after each
/// message exchange, so `tail >= head` is always true when data is present.
- fn poll_msgq(&self, bar: Bar0<'_>) -> u32 {
- let head = bar.read(regs::NV_PFSP_MSGQ_HEAD::at(0)).val();
- let tail = bar.read(regs::NV_PFSP_MSGQ_TAIL::at(0)).val();
+ fn poll_msgq(&self) -> u32 {
+ let head = self.bar.read(regs::NV_PFSP_MSGQ_HEAD::at(0)).val();
+ let tail = self.bar.read(regs::NV_PFSP_MSGQ_TAIL::at(0)).val();
if head == tail {
return 0;
@@ -122,20 +124,20 @@ fn poll_msgq(&self, bar: Bar0<'_>) -> u32 {
/// Writes `packet` to FSP EMEM and updates the queue pointers to notify FSP.
///
/// Returns `EINVAL` if `packet` is empty or its length is not 4-byte aligned.
- pub(crate) fn send_msg(&mut self, bar: Bar0<'_>, packet: &[u8]) -> Result {
+ pub(crate) fn send_msg(&mut self, packet: &[u8]) -> Result {
if packet.is_empty() {
return Err(EINVAL);
}
- self.write_emem(bar, packet)?;
+ self.write_emem(packet)?;
// Update queue pointers. TAIL points at the last DWORD written.
let tail_offset = u32::try_from(packet.len() - 4).map_err(|_| EINVAL)?;
- bar.write(
+ self.bar.write(
Array::at(0),
regs::NV_PFSP_QUEUE_TAIL::zeroed().with_address(tail_offset),
);
- bar.write(
+ self.bar.write(
Array::at(0),
regs::NV_PFSP_QUEUE_HEAD::zeroed().with_address(0),
);
@@ -148,9 +150,9 @@ pub(crate) fn send_msg(&mut self, bar: Bar0<'_>, packet: &[u8]) -> Result {
///
/// Returns `ETIMEDOUT` if no message was available until timeout, or a regular error code if a
/// memory allocation error occurred.
- pub(crate) fn recv_msg(&mut self, bar: Bar0<'_>) -> Result<KVec<u8>> {
+ pub(crate) fn recv_msg(&mut self) -> Result<KVec<u8>> {
let msg_size = read_poll_timeout(
- || Ok(self.poll_msgq(bar)),
+ || Ok(self.poll_msgq()),
|&size| size > 0,
Delta::from_millis(10),
Delta::from_millis(FSP_MSG_TIMEOUT_MS),
@@ -160,11 +162,13 @@ pub(crate) fn recv_msg(&mut self, bar: Bar0<'_>) -> Result<KVec<u8>> {
let mut buffer = KVec::<u8>::new();
buffer.resize(msg_size, 0, GFP_KERNEL)?;
- self.read_emem(bar, &mut buffer)?;
+ self.read_emem(&mut buffer)?;
// Reset message queue pointers after reading.
- bar.write(Array::at(0), regs::NV_PFSP_MSGQ_TAIL::zeroed().with_val(0));
- bar.write(Array::at(0), regs::NV_PFSP_MSGQ_HEAD::zeroed().with_val(0));
+ self.bar
+ .write(Array::at(0), regs::NV_PFSP_MSGQ_TAIL::zeroed().with_val(0));
+ self.bar
+ .write(Array::at(0), regs::NV_PFSP_MSGQ_HEAD::zeroed().with_val(0));
Ok(buffer)
}
diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/falcon/gsp.rs
index f788b87bd951..ae32f401aeb0 100644
--- a/drivers/gpu/nova-core/falcon/gsp.rs
+++ b/drivers/gpu/nova-core/falcon/gsp.rs
@@ -14,7 +14,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
Falcon,
FalconEngine,
@@ -37,20 +36,20 @@ impl RegisterBase<PFalcon2Base> for Gsp {
impl FalconEngine for Gsp {}
-impl Falcon<Gsp> {
+impl<'a> Falcon<'a, Gsp> {
/// Clears the SWGEN0 bit in the Falcon's IRQ status clear register to
/// allow GSP to signal CPU for processing new messages in message queue.
- pub(crate) fn clear_swgen0_intr(&self, bar: Bar0<'_>) {
- bar.write(
+ pub(crate) fn clear_swgen0_intr(&self) {
+ self.bar.write(
WithBase::of::<Gsp>(),
regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true),
);
}
/// Checks if GSP reload/resume has completed during the boot process.
- pub(crate) fn check_reload_completed(&self, bar: Bar0<'_>, timeout: Delta) -> Result<bool> {
+ pub(crate) fn check_reload_completed(&self, timeout: Delta) -> Result<bool> {
read_poll_timeout(
- || Ok(bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)),
+ || Ok(self.bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)),
|val| val.boot_stage_3_handoff(),
Delta::ZERO,
timeout,
@@ -59,19 +58,21 @@ pub(crate) fn check_reload_completed(&self, bar: Bar0<'_>, timeout: Delta) -> Re
}
/// Returns whether the RISC-V branch privilege lockdown bit is set.
- pub(crate) fn riscv_branch_privilege_lockdown(&self, bar: Bar0<'_>) -> bool {
- bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
+ pub(crate) fn riscv_branch_privilege_lockdown(&self) -> bool {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
.riscv_br_priv_lockdown()
}
/// Returns whether GSP registers can be read by the CPU.
- pub(crate) fn priv_target_mask_released(&self, bar: Bar0<'_>) -> bool {
+ pub(crate) fn priv_target_mask_released(&self) -> bool {
/// Pattern returned by GSP register reads while the PRIV target mask still blocks CPU
/// access. The low byte varies; the upper 24 bits are fixed.
const LOCKED_PATTERN: u32 = 0xbadf_4100;
const LOCKED_MASK: u32 = 0xffff_ff00;
- let hwcfg2 = bar
+ let hwcfg2 = self
+ .bar
.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
.into_raw();
diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/falcon/hal.rs
index 89b56823906b..0cb665162c90 100644
--- a/drivers/gpu/nova-core/falcon/hal.rs
+++ b/drivers/gpu/nova-core/falcon/hal.rs
@@ -34,7 +34,7 @@ pub(crate) enum LoadMethod {
/// registers.
pub(crate) trait FalconHal<E: FalconEngine>: Send + Sync {
/// Activates the Falcon core if the engine is a risvc/falcon dual engine.
- fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>) -> Result {
Ok(())
}
@@ -42,14 +42,14 @@ fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
/// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header.
fn signature_reg_fuse_version(
&self,
- falcon: &Falcon<E>,
+ falcon: &Falcon<'_, E>,
bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32>;
/// Program the boot ROM registers prior to starting a secure firmware.
- fn program_brom(&self, falcon: &Falcon<E>, bar: Bar0<'_>, params: &FalconBromParams);
+ fn program_brom(&self, falcon: &Falcon<'_, E>, bar: Bar0<'_>, params: &FalconBromParams);
/// Check if the RISC-V core is active.
/// Returns `true` if the RISC-V core is active, `false` otherwise.
diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs
index cf6ce47e6b25..e45adb0312c0 100644
--- a/drivers/gpu/nova-core/falcon/hal/ga102.rs
+++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs
@@ -115,21 +115,21 @@ pub(super) fn new() -> Self {
}
impl<E: FalconEngine> FalconHal<E> for Ga102<E> {
- fn select_core(&self, _falcon: &Falcon<E>, bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, bar: Bar0<'_>) -> Result {
select_core_ga102::<E>(bar)
}
fn signature_reg_fuse_version(
&self,
- falcon: &Falcon<E>,
+ falcon: &Falcon<'_, E>,
bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32> {
- signature_reg_fuse_version_ga102(&falcon.dev, bar, engine_id_mask, ucode_id)
+ signature_reg_fuse_version_ga102(falcon.dev, bar, engine_id_mask, ucode_id)
}
- fn program_brom(&self, _falcon: &Falcon<E>, bar: Bar0<'_>, params: &FalconBromParams) {
+ fn program_brom(&self, _falcon: &Falcon<'_, E>, bar: Bar0<'_>, params: &FalconBromParams) {
program_brom_ga102::<E>(bar, params);
}
diff --git a/drivers/gpu/nova-core/falcon/hal/tu102.rs b/drivers/gpu/nova-core/falcon/hal/tu102.rs
index 3aaee3869312..de48ded45bbe 100644
--- a/drivers/gpu/nova-core/falcon/hal/tu102.rs
+++ b/drivers/gpu/nova-core/falcon/hal/tu102.rs
@@ -34,13 +34,13 @@ pub(super) fn new() -> Self {
}
impl<E: FalconEngine> FalconHal<E> for Tu102<E> {
- fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>) -> Result {
Ok(())
}
fn signature_reg_fuse_version(
&self,
- _falcon: &Falcon<E>,
+ _falcon: &Falcon<'_, E>,
_bar: Bar0<'_>,
_engine_id_mask: u16,
_ucode_id: u8,
@@ -48,7 +48,7 @@ fn signature_reg_fuse_version(
Ok(0)
}
- fn program_brom(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>, _params: &FalconBromParams) {}
+ fn program_brom(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>, _params: &FalconBromParams) {}
fn is_riscv_active(&self, bar: Bar0<'_>) -> bool {
bar.read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::of::<E>())
diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs
index d9313ac361af..acb7f4d8a532 100644
--- a/drivers/gpu/nova-core/firmware/booter.rs
+++ b/drivers/gpu/nova-core/firmware/booter.rs
@@ -15,7 +15,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
sec2::Sec2,
Falcon,
@@ -293,8 +292,7 @@ pub(crate) fn new(
kind: BooterKind,
chipset: Chipset,
ver: &str,
- falcon: &Falcon<<Self as FalconFirmware>::Target>,
- bar: Bar0<'_>,
+ falcon: &Falcon<'_, <Self as FalconFirmware>::Target>,
) -> Result<Self> {
let fw_name = match kind {
BooterKind::Loader => "booter_load",
@@ -339,11 +337,8 @@ pub(crate) fn new(
} else {
// Obtain the version from the fuse register, and extract the corresponding
// signature.
- let reg_fuse_version = falcon.signature_reg_fuse_version(
- bar,
- brom_params.engine_id_mask,
- brom_params.ucode_id,
- )?;
+ let reg_fuse_version = falcon
+ .signature_reg_fuse_version(brom_params.engine_id_mask, brom_params.ucode_id)?;
// `0` means the last signature should be used.
const FUSE_VERSION_USE_LAST_SIG: u32 = 0;
@@ -405,18 +400,14 @@ pub(crate) fn new(
pub(crate) fn run<T>(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- sec2_falcon: &Falcon<Sec2>,
+ sec2_falcon: &Falcon<'_, Sec2>,
wpr_meta: &Coherent<T>,
) -> Result {
- sec2_falcon.reset(bar)?;
- sec2_falcon.load(dev, bar, self)?;
+ sec2_falcon.reset()?;
+ sec2_falcon.load(self)?;
let wpr_handle = wpr_meta.dma_handle();
- let (mbox0, mbox1) = sec2_falcon.boot(
- bar,
- Some(wpr_handle as u32),
- Some((wpr_handle >> 32) as u32),
- )?;
+ let (mbox0, mbox1) =
+ sec2_falcon.boot(Some(wpr_handle as u32), Some((wpr_handle >> 32) as u32))?;
dev_dbg!(dev, "SEC2 MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
if mbox0 != 0 {
diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs
index 199ae2adb664..95e0dd77746b 100644
--- a/drivers/gpu/nova-core/firmware/fwsec.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec.rs
@@ -27,7 +27,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
gsp::Gsp,
Falcon,
@@ -320,8 +319,7 @@ impl FwsecFirmware {
/// command.
pub(crate) fn new(
dev: &Device<device::Bound>,
- falcon: &Falcon<Gsp>,
- bar: Bar0<'_>,
+ falcon: &Falcon<'_, Gsp>,
bios: &Vbios,
cmd: FwsecCommand,
) -> Result<Self> {
@@ -337,7 +335,7 @@ pub(crate) fn new(
.ok_or(EINVAL)?;
let desc_sig_versions = u32::from(desc.signature_versions());
let reg_fuse_version =
- falcon.signature_reg_fuse_version(bar, desc.engine_id_mask(), desc.ucode_id())?;
+ falcon.signature_reg_fuse_version(desc.engine_id_mask(), desc.ucode_id())?;
dev_dbg!(
dev,
"desc_sig_versions: {:#x}, reg_fuse_version: {}\n",
@@ -390,21 +388,16 @@ pub(crate) fn new(
/// This must only be called on chipsets that do not need the FWSEC bootloader (i.e., where
/// [`Chipset::needs_fwsec_bootloader()`](crate::gpu::Chipset::needs_fwsec_bootloader) returns
/// `false`). On chipsets that do, use [`bootloader::FwsecFirmwareWithBl`] instead.
- pub(crate) fn run(
- &self,
- dev: &Device<device::Bound>,
- falcon: &Falcon<Gsp>,
- bar: Bar0<'_>,
- ) -> Result<()> {
+ pub(crate) fn run(&self, dev: &Device<device::Bound>, falcon: &Falcon<'_, Gsp>) -> Result<()> {
// Reset falcon, load the firmware, and run it.
falcon
- .reset(bar)
+ .reset()
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
falcon
- .load(dev, bar, self)
+ .load(self)
.inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;
let (mbox0, _) = falcon
- .boot(bar, Some(0), None)
+ .boot(Some(0), None)
.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);
diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
index ac1558a83b83..71f5a70a1114 100644
--- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
@@ -12,10 +12,6 @@
Device, //
},
dma::Coherent,
- io::{
- register::WithBase, //
- Io,
- },
prelude::*,
ptr::{
Alignable,
@@ -29,15 +25,12 @@
};
use crate::{
- driver::Bar0,
falcon::{
self,
gsp::Gsp,
Falcon,
FalconBromParams,
FalconDmaLoadable,
- FalconFbifMemType,
- FalconFbifTarget,
FalconFirmware,
FalconPioDmemLoadTarget,
FalconPioImemLoadTarget,
@@ -50,8 +43,7 @@
FIRMWARE_VERSION, //
},
gpu::Chipset,
- num::FromSafeCast,
- regs,
+ num::FromSafeCast, //
};
/// Descriptor used by RM to figure out the requirements of the boot loader.
@@ -275,33 +267,20 @@ 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>,
- bar: Bar0<'_>,
- ) -> Result<()> {
+ pub(crate) fn run(&self, dev: &Device<device::Bound>, falcon: &Falcon<'_, Gsp>) -> Result<()> {
// Reset falcon, load the firmware, and run it.
falcon
- .reset(bar)
+ .reset()
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
falcon
- .pio_load(bar, self)
+ .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.
- bar.update(
- regs::NV_PFALCON_FBIF_TRANSCFG::of::<Gsp>()
- .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)
- },
- );
+ falcon.set_fbif_transcfg_phys_sysmem(self.dmem_desc.ctx_dma)?;
let (mbox0, _) = falcon
- .boot(bar, Some(0), None)
+ .boot(Some(0), None)
.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);
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index 4b97d1fb505e..574e1627e63c 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -224,27 +224,27 @@ pub(crate) fn boot_params_dma_handle(&self) -> u64 {
/// An `Fsp` is produced by [`Fsp::wait_secure_boot`], which only returns once FSP secure boot
/// has completed. It owns the FSP falcon and the FMC firmware, which are used for the subsequent
/// Chain of Trust boot.
-pub(crate) struct Fsp {
- falcon: Falcon<FspEngine>,
+pub(crate) struct Fsp<'a> {
+ falcon: Falcon<'a, FspEngine>,
fsp_fw: FspFirmware,
}
-impl Fsp {
+impl<'a> Fsp<'a> {
/// Waits for FSP secure boot completion, then returns the [`Fsp`] interface.
///
/// Polls the thermal scratch register until FSP signals boot completion or the timeout
/// elapses. Returning an [`Fsp`] only on success guarantees, at the API level, that the
/// interface is not used before secure boot has completed.
pub(crate) fn wait_secure_boot(
- dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
+ dev: &'a device::Device<device::Bound>,
+ bar: Bar0<'a>,
chipset: Chipset,
- ) -> Result<Fsp> {
+ ) -> Result<Fsp<'a>> {
/// FSP secure boot completion timeout in milliseconds.
const FSP_SECURE_BOOT_TIMEOUT_MS: i64 = 5000;
let hal = hal::fsp_hal(chipset).ok_or(ENOTSUPP)?;
- let falcon = Falcon::<FspEngine>::new(dev, chipset)?;
+ let falcon = Falcon::<FspEngine>::new(dev, chipset, bar)?;
let fsp_fw = FspFirmware::new(dev, chipset, FIRMWARE_VERSION)?;
read_poll_timeout(
@@ -262,13 +262,13 @@ pub(crate) fn wait_secure_boot(
/// Sends a message to FSP and waits for the response.
/// Returns the full response buffer on success.
- fn send_sync_fsp<M>(&mut self, dev: &device::Device, bar: Bar0<'_>, msg: &M) -> Result<KVec<u8>>
+ fn send_sync_fsp<M>(&mut self, dev: &device::Device, msg: &M) -> Result<KVec<u8>>
where
M: MessageToFsp,
{
- self.falcon.send_msg(bar, msg.as_bytes())?;
+ self.falcon.send_msg(msg.as_bytes())?;
- let response_buf = self.falcon.recv_msg(bar).inspect_err(|e| {
+ let response_buf = self.falcon.recv_msg().inspect_err(|e| {
dev_err!(dev, "FSP response error: {:?}\n", e);
})?;
@@ -330,7 +330,6 @@ fn send_sync_fsp<M>(&mut self, dev: &device::Device, bar: Bar0<'_>, msg: &M) ->
pub(crate) fn boot_fmc(
&mut self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
fb_layout: &FbLayout,
args: &FmcBootArgs,
) -> Result {
@@ -341,7 +340,7 @@ pub(crate) fn boot_fmc(
GFP_KERNEL,
)?;
- let _response_buf = self.send_sync_fsp(dev, bar, &*msg)?;
+ let _response_buf = self.send_sync_fsp(dev, &*msg)?;
dev_dbg!(dev, "FSP Chain of Trust completed successfully\n");
Ok(())
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 4d76be429e75..43c3f4f8df71 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -273,9 +273,9 @@ struct GspResources<'gpu> {
/// MMIO mapping of PCI BAR 0.
bar: Bar0<'gpu>,
/// GSP falcon instance, used for GSP boot up and cleanup.
- gsp_falcon: Falcon<GspFalcon>,
+ gsp_falcon: Falcon<'gpu, GspFalcon>,
/// SEC2 falcon instance, used for GSP boot up and cleanup.
- sec2_falcon: Falcon<Sec2Falcon>,
+ sec2_falcon: Falcon<'gpu, Sec2Falcon>,
/// GSP runtime data.
#[pin]
gsp: Gsp,
@@ -351,10 +351,11 @@ pub(crate) fn new(
gsp_falcon: Falcon::new(
pdev.as_ref(),
spec.chipset,
+ bar
)
- .inspect(|falcon| falcon.clear_swgen0_intr(bar))?,
+ .inspect(|falcon| falcon.clear_swgen0_intr())?,
- sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
+ sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset, bar)?,
gsp <- Gsp::new(pdev),
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 73e93403601c..b4ac4156056e 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -57,8 +57,8 @@ pub(crate) struct GspBootContext<'a> {
pub(crate) pdev: &'a pci::Device<device::Bound>,
pub(crate) bar: Bar0<'a>,
pub(crate) chipset: Chipset,
- pub(crate) gsp_falcon: &'a Falcon<GspFalcon>,
- pub(crate) sec2_falcon: &'a Falcon<Sec2Falcon>,
+ pub(crate) gsp_falcon: &'a Falcon<'a, GspFalcon>,
+ pub(crate) sec2_falcon: &'a Falcon<'a, Sec2Falcon>,
}
impl<'a> GspBootContext<'a> {
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index bb2000b7a78b..ab0491b57944 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -37,8 +37,8 @@ pub(super) struct BootUnloadArgs<'a> {
gsp: &'a super::Gsp,
dev: &'a device::Device<device::Bound>,
bar: Bar0<'a>,
- gsp_falcon: &'a Falcon<Gsp>,
- sec2_falcon: &'a Falcon<Sec2>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
}
@@ -56,8 +56,8 @@ pub(super) fn new(
gsp: &'a super::Gsp,
dev: &'a device::Device<device::Bound>,
bar: Bar0<'a>,
- gsp_falcon: &'a Falcon<Gsp>,
- sec2_falcon: &'a Falcon<Sec2>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
) -> Self {
Self {
@@ -120,17 +120,17 @@ pub(crate) fn boot(
// Perform the chipset-specific boot sequence, and retrieve the unload bundle.
let unload_guard = hal.boot(&self, &ctx, &fb_layout, &wpr_meta)?;
- gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version);
+ gsp_falcon.write_os_version(gsp_fw.bootloader.app_version);
// Poll for RISC-V to become active before continuing.
read_poll_timeout(
- || Ok(gsp_falcon.is_riscv_active(bar)),
+ || Ok(gsp_falcon.is_riscv_active()),
|val: &bool| *val,
Delta::from_millis(10),
Delta::from_secs(5),
)?;
- dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar),);
+ dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(),);
self.cmdq
.send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?;
@@ -149,7 +149,7 @@ pub(crate) fn boot(
fn shutdown_gsp(
cmdq: &Cmdq,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<Gsp>,
+ gsp_falcon: &Falcon<'_, Gsp>,
mode: commands::PowerStateLevel,
) -> Result {
// Command to shut the GSP down.
@@ -158,7 +158,7 @@ fn shutdown_gsp(
// Wait until GSP signals it is suspended.
const LIBOS_INTERRUPT_PROCESSOR_SUSPENDED: u32 = bits::bit_u32(31);
read_poll_timeout(
- || Ok(gsp_falcon.read_mailbox0(bar)),
+ || Ok(gsp_falcon.read_mailbox0()),
|&mb0| mb0 & LIBOS_INTERRUPT_PROCESSOR_SUSPENDED != 0,
Delta::from_millis(10),
Delta::from_secs(5),
@@ -173,8 +173,8 @@ pub(crate) fn unload(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<Gsp>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, Gsp>,
+ sec2_falcon: &Falcon<'_, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
) -> Result {
// Shut down the GSP. Keep going even in case of error.
diff --git a/drivers/gpu/nova-core/gsp/hal.rs b/drivers/gpu/nova-core/gsp/hal.rs
index 51a277fe97bb..d3e47ef206de 100644
--- a/drivers/gpu/nova-core/gsp/hal.rs
+++ b/drivers/gpu/nova-core/gsp/hal.rs
@@ -42,8 +42,8 @@ fn run(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result;
}
diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
index 2187e11168b2..1d06405a32f6 100644
--- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
+++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
@@ -42,10 +42,10 @@ struct GspMbox {
impl GspMbox {
/// Reads both mailboxes from the GSP falcon.
- fn read(gsp_falcon: &Falcon<GspEngine>, bar: Bar0<'_>) -> Self {
+ fn read(gsp_falcon: &Falcon<'_, GspEngine>) -> Self {
Self {
- mbox0: gsp_falcon.read_mailbox0(bar),
- mbox1: gsp_falcon.read_mailbox1(bar),
+ mbox0: gsp_falcon.read_mailbox0(),
+ mbox1: gsp_falcon.read_mailbox1(),
}
}
@@ -60,8 +60,7 @@ fn combined_addr(&self) -> u64 {
/// either condition should stop the poll loop.
fn lockdown_released_or_error(
&self,
- gsp_falcon: &Falcon<GspEngine>,
- bar: Bar0<'_>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
fmc_boot_params_addr: u64,
) -> bool {
// GSP-FMC normally clears the boot parameters address from the mailboxes early during
@@ -71,15 +70,14 @@ fn lockdown_released_or_error(
return self.combined_addr() != fmc_boot_params_addr;
}
- !gsp_falcon.riscv_branch_privilege_lockdown(bar)
+ !gsp_falcon.riscv_branch_privilege_lockdown()
}
}
/// Waits for GSP lockdown to be released after FSP Chain of Trust.
fn wait_for_gsp_lockdown_release(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
fmc_boot_params_addr: u64,
) -> Result {
dev_dbg!(dev, "Waiting for GSP lockdown release\n");
@@ -88,14 +86,14 @@ fn wait_for_gsp_lockdown_release(
|| {
// While the PRIV target mask is still locked to FSP, GSP register and mailbox reads
// are not meaningful. Wait until HWCFG2 says the CPU can read them.
- Ok(match gsp_falcon.priv_target_mask_released(bar) {
+ Ok(match gsp_falcon.priv_target_mask_released() {
false => None,
- true => Some(GspMbox::read(gsp_falcon, bar)),
+ true => Some(GspMbox::read(gsp_falcon)),
})
},
|mbox| match mbox {
None => false,
- Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, bar, fmc_boot_params_addr),
+ Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, fmc_boot_params_addr),
},
Delta::from_millis(10),
Delta::from_secs(30),
@@ -122,13 +120,13 @@ impl UnloadBundle for FspUnloadBundle {
fn run(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- _sec2_falcon: &Falcon<Sec2>,
+ _bar: Bar0<'_>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ _sec2_falcon: &Falcon<'_, Sec2>,
) -> Result {
// GSP falcon does most of the work of resetting, so just wait for it to finish.
read_poll_timeout(
- || Ok(gsp_falcon.is_riscv_active(bar)),
+ || Ok(gsp_falcon.is_riscv_active()),
|&active| !active,
Delta::from_millis(10),
Delta::from_secs(5),
@@ -176,9 +174,9 @@ fn boot<'a>(
false,
)?;
- fsp.boot_fmc(dev, bar, fb_layout, &args)?;
+ fsp.boot_fmc(dev, fb_layout, &args)?;
- wait_for_gsp_lockdown_release(dev, bar, gsp_falcon, args.boot_params_dma_handle())?;
+ wait_for_gsp_lockdown_release(dev, gsp_falcon, args.boot_params_dma_handle())?;
Ok(unload_guard)
}
diff --git a/drivers/gpu/nova-core/gsp/hal/tu102.rs b/drivers/gpu/nova-core/gsp/hal/tu102.rs
index f8a8541704ee..180d47fb8f4e 100644
--- a/drivers/gpu/nova-core/gsp/hal/tu102.rs
+++ b/drivers/gpu/nova-core/gsp/hal/tu102.rs
@@ -62,12 +62,11 @@ impl FwsecUnloadFirmware {
/// Loads the FWSEC SB firmware, as well as its bootloader if `chipset` requires it.
fn new(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
chipset: Chipset,
bios: &Vbios,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
) -> Result<Self> {
- let fwsec_sb = FwsecFirmware::new(dev, gsp_falcon, bar, bios, FwsecCommand::Sb)?;
+ let fwsec_sb = FwsecFirmware::new(dev, gsp_falcon, bios, FwsecCommand::Sb)?;
Ok(if chipset.needs_fwsec_bootloader() {
Self::WithBl(FwsecFirmwareWithBl::new(fwsec_sb, dev, chipset)?)
@@ -80,12 +79,11 @@ fn new(
fn run(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
) -> Result {
match self {
- Self::WithoutBl(fw) => fw.run(dev, gsp_falcon, bar),
- Self::WithBl(fw) => fw.run(dev, gsp_falcon, bar),
+ Self::WithoutBl(fw) => fw.run(dev, gsp_falcon),
+ Self::WithBl(fw) => fw.run(dev, gsp_falcon),
}
}
}
@@ -101,22 +99,20 @@ impl Sec2UnloadBundle {
/// Load and prepare the resources required to properly reset the GSP after it has been stopped.
fn build(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
chipset: Chipset,
bios: &Vbios,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result<KBox<dyn UnloadBundle>> {
KBox::new(
Self {
- fwsec_sb: FwsecUnloadFirmware::new(dev, bar, chipset, bios, gsp_falcon)?,
+ fwsec_sb: FwsecUnloadFirmware::new(dev, chipset, bios, gsp_falcon)?,
booter_unloader: BooterFirmware::new(
dev,
BooterKind::Unloader,
chipset,
FIRMWARE_VERSION,
sec2_falcon,
- bar,
)?,
},
GFP_KERNEL,
@@ -131,14 +127,14 @@ fn run(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result {
// Run FWSEC-SB to reset the GSP falcon to its pre-libos state.
// Log errors but keep going if it fails.
let fwsec_sb_res = self
.fwsec_sb
- .run(dev, bar, gsp_falcon)
+ .run(dev, gsp_falcon)
.inspect_err(|e| dev_err!(dev, "FWSEC-SB failed to run: {:?}\n", e));
// Remove WPR2 region if set.
@@ -148,13 +144,12 @@ fn run(
return Ok(());
}
- sec2_falcon.reset(bar)?;
- sec2_falcon.load(dev, bar, &self.booter_unloader)?;
+ sec2_falcon.reset()?;
+ sec2_falcon.load(&self.booter_unloader)?;
// Sentinel value to confirm that Booter Unloader has run.
const MAILBOX_SENTINEL: u32 = 0xff;
- let (mbox0, _) =
- sec2_falcon.boot(bar, Some(MAILBOX_SENTINEL), Some(MAILBOX_SENTINEL))?;
+ let (mbox0, _) = sec2_falcon.boot(Some(MAILBOX_SENTINEL), Some(MAILBOX_SENTINEL))?;
if mbox0 != 0 {
dev_err!(dev, "Booter Unloader returned error 0x{:x}\n", mbox0);
return Err(EINVAL);
@@ -183,7 +178,7 @@ fn run(
fn run_fwsec_frts(
dev: &device::Device<device::Bound>,
chipset: Chipset,
- falcon: &Falcon<GspEngine>,
+ falcon: &Falcon<'_, GspEngine>,
bar: Bar0<'_>,
bios: &Vbios,
fb_layout: &FbLayout,
@@ -202,7 +197,6 @@ fn run_fwsec_frts(
let fwsec_frts = FwsecFirmware::new(
dev,
falcon,
- bar,
bios,
FwsecCommand::Frts {
frts_addr: fb_layout.frts.start,
@@ -213,10 +207,10 @@ fn run_fwsec_frts(
if chipset.needs_fwsec_bootloader() {
let fwsec_frts_bl = FwsecFirmwareWithBl::new(fwsec_frts, dev, chipset)?;
// Load and run the bootloader, which will load FWSEC-FRTS and run it.
- fwsec_frts_bl.run(dev, falcon, bar)?;
+ fwsec_frts_bl.run(dev, falcon)?;
} else {
// Load and run FWSEC-FRTS directly.
- fwsec_frts.run(dev, falcon, bar)?;
+ fwsec_frts.run(dev, falcon)?;
}
// SCRATCH_E contains the error code for FWSEC-FRTS.
@@ -286,18 +280,17 @@ fn boot<'a>(
//
// If the unload bundle creation fails, the GPU will need to be reset before the driver can
// be probed again.
- let unload_bundle =
- Sec2UnloadBundle::build(dev, bar, chipset, &bios, gsp_falcon, sec2_falcon)
- .inspect_err(|e| {
- dev_warn!(dev, "Failed to prepare unload firmware: {:?}\n", e);
- dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
- dev_warn!(
- dev,
- "The GPU will need to be reset before the driver can bind again.\n"
- );
- })
- .ok()
- .map(crate::gsp::UnloadBundle);
+ let unload_bundle = Sec2UnloadBundle::build(dev, chipset, &bios, gsp_falcon, sec2_falcon)
+ .inspect_err(|e| {
+ dev_warn!(dev, "Failed to prepare unload firmware: {:?}\n", e);
+ dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
+ dev_warn!(
+ dev,
+ "The GPU will need to be reset before the driver can bind again.\n"
+ );
+ })
+ .ok()
+ .map(crate::gsp::UnloadBundle);
// Wrap the unload bundle into a drop guard so it is automatically run upon failure.
let unload_guard =
@@ -308,13 +301,10 @@ fn boot<'a>(
run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, fb_layout)?;
}
- gsp_falcon.reset(bar)?;
+ gsp_falcon.reset()?;
let libos_handle = gsp.libos.dma_handle();
- let (mbox0, mbox1) = gsp_falcon.boot(
- bar,
- Some(libos_handle as u32),
- Some((libos_handle >> 32) as u32),
- )?;
+ let (mbox0, mbox1) =
+ gsp_falcon.boot(Some(libos_handle as u32), Some((libos_handle >> 32) as u32))?;
dev_dbg!(dev, "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
dev_dbg!(
@@ -328,9 +318,8 @@ fn boot<'a>(
chipset,
FIRMWARE_VERSION,
sec2_falcon,
- bar,
)?
- .run(dev, bar, sec2_falcon, wpr_meta)?;
+ .run(dev, sec2_falcon, wpr_meta)?;
Ok(unload_guard)
}
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index e0850d21adca..13983d42b12b 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -133,9 +133,9 @@ pub(crate) struct GspSequencer<'a> {
/// `Bar0` for register access.
bar: Bar0<'a>,
/// SEC2 falcon for core operations.
- sec2_falcon: &'a Falcon<Sec2>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
/// GSP falcon for core operations.
- gsp_falcon: &'a Falcon<Gsp>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
/// LibOS DMA handle address.
libos_dma_handle: u64,
/// Bootloader application version.
@@ -213,16 +213,16 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
GspSeqCmd::DelayUs(cmd) => cmd.run(seq),
GspSeqCmd::RegStore(cmd) => cmd.run(seq),
GspSeqCmd::CoreReset => {
- seq.gsp_falcon.reset(seq.bar)?;
- seq.gsp_falcon.dma_reset(seq.bar);
+ seq.gsp_falcon.reset()?;
+ seq.gsp_falcon.dma_reset();
Ok(())
}
GspSeqCmd::CoreStart => {
- seq.gsp_falcon.start(seq.bar)?;
+ seq.gsp_falcon.start()?;
Ok(())
}
GspSeqCmd::CoreWaitForHalt => {
- seq.gsp_falcon.wait_till_halted(seq.bar)?;
+ seq.gsp_falcon.wait_till_halted()?;
Ok(())
}
GspSeqCmd::CoreResume => {
@@ -231,35 +231,32 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
// sequencer will start both.
// Reset the GSP to prepare it for resuming.
- seq.gsp_falcon.reset(seq.bar)?;
+ seq.gsp_falcon.reset()?;
// Write the libOS DMA handle to GSP mailboxes.
seq.gsp_falcon.write_mailboxes(
- seq.bar,
Some(seq.libos_dma_handle as u32),
Some((seq.libos_dma_handle >> 32) as u32),
);
// Start the SEC2 falcon which will trigger GSP-RM to resume on the GSP.
- seq.sec2_falcon.start(seq.bar)?;
+ seq.sec2_falcon.start()?;
// Poll until GSP-RM reload/resume has completed (up to 2 seconds).
- seq.gsp_falcon
- .check_reload_completed(seq.bar, Delta::from_secs(2))?;
+ seq.gsp_falcon.check_reload_completed(Delta::from_secs(2))?;
// Verify SEC2 completed successfully by checking its mailbox for errors.
- let mbox0 = seq.sec2_falcon.read_mailbox0(seq.bar);
+ let mbox0 = seq.sec2_falcon.read_mailbox0();
if mbox0 != 0 {
dev_err!(seq.dev, "Sequencer: sec2 errors: {:?}\n", mbox0);
return Err(EIO);
}
// Configure GSP with the bootloader version.
- seq.gsp_falcon
- .write_os_version(seq.bar, seq.bootloader_app_version);
+ seq.gsp_falcon.write_os_version(seq.bootloader_app_version);
// Verify the GSP's RISC-V core is active indicating successful GSP boot.
- if !seq.gsp_falcon.is_riscv_active(seq.bar) {
+ if !seq.gsp_falcon.is_riscv_active() {
dev_err!(seq.dev, "Sequencer: RISC-V core is not active\n");
return Err(EIO);
}
@@ -345,9 +342,9 @@ pub(crate) struct GspSequencerParams<'a> {
/// LibOS DMA handle address.
pub(crate) libos_dma_handle: u64,
/// GSP falcon for core operations.
- pub(crate) gsp_falcon: &'a Falcon<Gsp>,
+ pub(crate) gsp_falcon: &'a Falcon<'a, Gsp>,
/// SEC2 falcon for core operations.
- pub(crate) sec2_falcon: &'a Falcon<Sec2>,
+ pub(crate) sec2_falcon: &'a Falcon<'a, Sec2>,
/// Device for logging.
pub(crate) dev: &'a device::Device,
/// BAR0 for register access.
---
base-commit: 9102e655ea7285c1bc329669865ba8a38cdb69e6
change-id: 20260624-drm-bar-refactor-90435f04c9ea
Best regards,
--
Tim Kovalenko <tim.kovalenko@proton.me>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related
* ✗ Xe.CI.BAT: failure for Couple fdinfo improvements
From: Patchwork @ 2026-06-24 15:52 UTC (permalink / raw)
To: Matthew Auld; +Cc: intel-xe
In-Reply-To: <20260624113837.342961-4-matthew.auld@intel.com>
[-- Attachment #1: Type: text/plain, Size: 4761 bytes --]
== Series Details ==
Series: Couple fdinfo improvements
URL : https://patchwork.freedesktop.org/series/169094/
State : failure
== Summary ==
CI Bug Log - changes from xe-5294-b2817f6a1517bc9ecdef5229b84e8a44d983de82_BAT -> xe-pw-169094v1_BAT
====================================================
Summary
-------
**FAILURE**
Serious unknown changes coming with xe-pw-169094v1_BAT absolutely need to be
verified manually.
If you think the reported changes have nothing to do with the changes
introduced in xe-pw-169094v1_BAT, please notify your bug team (I915-ci-infra@lists.freedesktop.org) to allow them
to document this new failure mode, which will reduce false positives in CI.
Participating hosts (12 -> 13)
------------------------------
Additional (1): bat-ptl-vm
Possible new issues
-------------------
Here are the unknown changes that may have been introduced in xe-pw-169094v1_BAT:
### IGT changes ###
#### Possible regressions ####
* igt@xe_pat@pat-index-auto:
- bat-atsm-2: NOTRUN -> [SKIP][1]
[1]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/bat-atsm-2/igt@xe_pat@pat-index-auto.html
Known issues
------------
Here are the changes found in xe-pw-169094v1_BAT that come from known issues:
### IGT changes ###
#### Issues hit ####
* igt@xe_evict@evict-beng-small-cm:
- bat-ptl-vm: NOTRUN -> [SKIP][2] ([Intel XE#5764]) +10 other tests skip
[2]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/bat-ptl-vm/igt@xe_evict@evict-beng-small-cm.html
* igt@xe_exec_balancer@no-exec-cm-virtual-basic:
- bat-ptl-vm: NOTRUN -> [SKIP][3] ([Intel XE#7482]) +17 other tests skip
[3]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/bat-ptl-vm/igt@xe_exec_balancer@no-exec-cm-virtual-basic.html
* igt@xe_exec_multi_queue@many-queues-preempt-mode-close-fd:
- bat-ptl-vm: NOTRUN -> [SKIP][4] ([Intel XE#8364]) +13 other tests skip
[4]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/bat-ptl-vm/igt@xe_exec_multi_queue@many-queues-preempt-mode-close-fd.html
* igt@xe_live_ktest@xe_migrate@xe_validate_ccs_kunit:
- bat-ptl-vm: NOTRUN -> [SKIP][5] ([Intel XE#5775])
[5]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/bat-ptl-vm/igt@xe_live_ktest@xe_migrate@xe_validate_ccs_kunit.html
* igt@xe_mmap@vram:
- bat-ptl-vm: NOTRUN -> [SKIP][6] ([Intel XE#5776])
[6]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/bat-ptl-vm/igt@xe_mmap@vram.html
* igt@xe_pat@pat-index-auto:
- bat-adlp-7: NOTRUN -> [SKIP][7] ([Intel XE#8434])
[7]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/bat-adlp-7/igt@xe_pat@pat-index-auto.html
* igt@xe_pat@pat-index-xehpc:
- bat-ptl-vm: NOTRUN -> [SKIP][8] ([Intel XE#5777] / [Intel XE#7590])
[8]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/bat-ptl-vm/igt@xe_pat@pat-index-xehpc.html
* igt@xe_pat@pat-index-xelp:
- bat-ptl-vm: NOTRUN -> [SKIP][9] ([Intel XE#5771] / [Intel XE#7590])
[9]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/bat-ptl-vm/igt@xe_pat@pat-index-xelp.html
* igt@xe_pat@pat-index-xelpg:
- bat-ptl-vm: NOTRUN -> [SKIP][10] ([Intel XE#5780] / [Intel XE#7590])
[10]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/bat-ptl-vm/igt@xe_pat@pat-index-xelpg.html
[Intel XE#5764]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5764
[Intel XE#5771]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5771
[Intel XE#5775]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5775
[Intel XE#5776]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5776
[Intel XE#5777]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5777
[Intel XE#5780]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5780
[Intel XE#7482]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7482
[Intel XE#7590]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7590
[Intel XE#8364]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8364
[Intel XE#8434]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8434
Build changes
-------------
* IGT: IGT_8982 -> IGT_8983
* Linux: xe-5294-b2817f6a1517bc9ecdef5229b84e8a44d983de82 -> xe-pw-169094v1
IGT_8982: 48befce9e6b0c0d371c4812bfff34a61319f68f1 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
IGT_8983: f37c260e2c935b4a2885cfd650900c341a7c752b @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
xe-5294-b2817f6a1517bc9ecdef5229b84e8a44d983de82: b2817f6a1517bc9ecdef5229b84e8a44d983de82
xe-pw-169094v1: 169094v1
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-169094v1/index.html
[-- Attachment #2: Type: text/html, Size: 5709 bytes --]
^ permalink raw reply
* [PATCH 2/2] smb/client: fix security flag calculation when setting security descriptors
From: Steve French @ 2026-06-24 15:51 UTC (permalink / raw)
To: linux-cifs; +Cc: Ralph Boehme, Steve French
In-Reply-To: <20260624155124.4121786-1-stfrench@microsoft.com>
From: Ralph Boehme <slow@samba.org>
In id_mode_to_cifs_acl(), aclflag was initialized to CIFS_ACL_DACL by default.
This forced the client to request setting the DACL even when only an ownership
(chown) or group (chgrp) change was being performed.
Let build_sec_desc() do the proper flag calculation by initializing aclflag
to 0. build_sec_desc() sets the appropriate bits (CIFS_ACL_OWNER, CIFS_ACL_GROUP,
or CIFS_ACL_DACL) depending on what actually changed. During ownership transfer,
CIFS_ACL_DACL is only set if replace_sids_and_copy_aces() actually replaces the
SIDs inside any of the DACL's ACEs.
If build_sec_desc() results in aclflag being 0 (meaning no changes were mapped),
exit early to avoid sending an empty security descriptor update to the server.
Signed-off-by: Ralph Boehme <slow@samba.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
---
fs/smb/client/cifsacl.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
index 5bbf73736358..07cf0e578233 100644
--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -1185,7 +1185,8 @@ static void populate_new_aces(char *nacl_base,
static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *pndacl,
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
- struct smb_sid *pnownersid, struct smb_sid *pngrpsid)
+ struct smb_sid *pnownersid, struct smb_sid *pngrpsid,
+ int *aclflag)
{
int i;
u16 size = 0;
@@ -1209,12 +1210,15 @@ static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *p
pntace = (struct smb_ace *) (acl_base + size);
pnntace = (struct smb_ace *) (nacl_base + nsize);
- if (pnownersid && compare_sids(&pntace->sid, pownersid) == 0)
+ if (pnownersid && compare_sids(&pntace->sid, pownersid) == 0) {
ace_size = cifs_copy_ace(pnntace, pntace, pnownersid);
- else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0)
+ *aclflag |= CIFS_ACL_DACL;
+ } else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0) {
ace_size = cifs_copy_ace(pnntace, pntace, pngrpsid);
- else
+ *aclflag |= CIFS_ACL_DACL;
+ } else {
ace_size = cifs_copy_ace(pnntace, pntace, NULL);
+ }
size += le16_to_cpu(pntace->size);
nsize += ace_size;
@@ -1521,7 +1525,8 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
/* Replace ACEs for old owner with new one */
size = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
owner_sid_ptr, group_sid_ptr,
- nowner_sid_ptr, ngroup_sid_ptr);
+ nowner_sid_ptr, ngroup_sid_ptr,
+ aclflag);
ndacl_ptr->size = cpu_to_le16(size);
}
@@ -1738,7 +1743,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
kuid_t uid, kgid_t gid)
{
int rc = 0;
- int aclflag = CIFS_ACL_DACL; /* default flag to set */
+ int aclflag = 0;
__u32 secdesclen = 0;
__u32 nsecdesclen = 0;
__u32 dacloffset = 0;
@@ -1837,6 +1842,11 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
if (rc != 0)
goto id_mode_to_cifs_acl_exit;
+ if (aclflag == 0) {
+ cifs_dbg(FYI, "set_cifs_acl aclflag=0, no change mapped\n");
+ goto id_mode_to_cifs_acl_exit;
+ }
+
if (ops->set_acl == NULL) {
rc = -EOPNOTSUPP;
goto id_mode_to_cifs_acl_exit;
--
2.53.0
^ permalink raw reply related
* [PATCH 1/2] smb: client: refactor ACL setting control flow in id_mode_to_cifs_acl()
From: Steve French @ 2026-06-24 15:51 UTC (permalink / raw)
To: linux-cifs; +Cc: Ralph Boehme, Steve French
From: Ralph Boehme <slow@samba.org>
Refactor the control flow in id_mode_to_cifs_acl() to reduce nesting and
prevent error code overwriting.
Instead of wrapping the call to ops->set_acl() in a conditional block,
introduce early exits (goto id_mode_to_cifs_acl_exit) when build_sec_desc()
fails or ops->set_acl is NULL. This ensures that any actual error returned
by build_sec_desc() is not overwritten with -EOPNOTSUPP.
Signed-off-by: Ralph Boehme <slow@samba.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
---
fs/smb/client/cifsacl.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
index 42a3115359da..5bbf73736358 100644
--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -1834,14 +1834,18 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
- if (ops->set_acl == NULL)
- rc = -EOPNOTSUPP;
+ if (rc != 0)
+ goto id_mode_to_cifs_acl_exit;
- if (!rc) {
- /* Set the security descriptor */
- rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
- cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
+ if (ops->set_acl == NULL) {
+ rc = -EOPNOTSUPP;
+ goto id_mode_to_cifs_acl_exit;
}
+
+ /* Set the security descriptor */
+ rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
+ cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
+
id_mode_to_cifs_acl_exit:
cifs_put_tlink(tlink);
--
2.53.0
^ permalink raw reply related
* [PATCH] gpu: nova-core: falcon: store bar and dev in falcon
From: Tim Kovalenko @ 2026-06-24 15:51 UTC (permalink / raw)
To: Danilo Krummrich, Alexandre Courbot, Alice Ryhl, David Airlie,
Simona Vetter, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti
Cc: nova-gpu, dri-devel, linux-kernel, linux-riscv, Tim Kovalenko
Store the bound device and `BAR0` mapping in `Falcon` instead of passing
them through every `Falcon` operation. This simplifies the `Falcon` API and
removes repeated `dev`/`bar` plumbing from reset, load, boot, mailbox, DMA,
and GSP/FSP-specific Falcon helpers.
Add a named helper for configuring Falcon FBIF transaction slots for
physical coherent system memory, avoiding direct `BAR0` access from the
FWSEC bootloader path without exposing BAR0 publicly.
Future work / questions:
- Focused only on the Falcon for this patch - more to follow.
- Not sure about the FalconHal and if I should modify the Trait
- Could be part of the next patch
- But it could definitively be simplified
- Also, how far should the refactor go and to what extend add new
methods to avoid passing `bar` or `dev` but also not exposing them as
pub. For `dev`, there's a lot of `dev_err` usage that requires us to
pass it as a param.
- I've created the `set_fbif_transcfg_phys_sysmem` method to
address such issue and remove some code duplication but that
method could be made a bit more generic.
- Also, is there a reason why we are not passing the `GspBootContext`
when we need stuff like `bar`, `dev` and both falcons?
Reported-by: Alexandre Courbot <acourbot@nvidia.com>
Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/509436-Nova/topic/Storing.20driver-bound.20references.20into.20sub-devices/near/599137882
Signed-off-by: Tim Kovalenko <tim.kovalenko@proton.me>
---
drivers/gpu/nova-core/falcon.rs | 206 ++++++++++-----------
drivers/gpu/nova-core/falcon/fsp.rs | 44 +++--
drivers/gpu/nova-core/falcon/gsp.rs | 21 ++-
drivers/gpu/nova-core/falcon/hal.rs | 6 +-
drivers/gpu/nova-core/falcon/hal/ga102.rs | 8 +-
drivers/gpu/nova-core/falcon/hal/tu102.rs | 6 +-
drivers/gpu/nova-core/firmware/booter.rs | 25 +--
drivers/gpu/nova-core/firmware/fwsec.rs | 19 +-
drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 33 +---
drivers/gpu/nova-core/fsp.rs | 23 ++-
drivers/gpu/nova-core/gpu.rs | 9 +-
drivers/gpu/nova-core/gsp.rs | 4 +-
drivers/gpu/nova-core/gsp/boot.rs | 22 +--
drivers/gpu/nova-core/gsp/hal.rs | 4 +-
drivers/gpu/nova-core/gsp/hal/gh100.rs | 32 ++--
drivers/gpu/nova-core/gsp/hal/tu102.rs | 75 ++++----
drivers/gpu/nova-core/gsp/sequencer.rs | 31 ++--
17 files changed, 253 insertions(+), 315 deletions(-)
diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 94c7696a6493..ca12cc11a370 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -5,10 +5,7 @@
use hal::FalconHal;
use kernel::{
- device::{
- self,
- Device, //
- },
+ device,
dma::{
Coherent,
CoherentBox,
@@ -24,7 +21,6 @@
Io,
},
prelude::*,
- sync::aref::ARef,
time::Delta,
};
@@ -358,41 +354,47 @@ pub(crate) trait FalconFirmware {
}
/// Contains the base parameters common to all Falcon instances.
-pub(crate) struct Falcon<E: FalconEngine> {
+pub(crate) struct Falcon<'a, E: FalconEngine> {
hal: KBox<dyn FalconHal<E>>,
- dev: ARef<device::Device>,
+ dev: &'a device::Device<device::Bound>,
+ bar: Bar0<'a>,
}
-impl<E: FalconEngine + 'static> Falcon<E> {
+impl<'a, E: FalconEngine + 'static> Falcon<'a, E> {
/// Create a new falcon instance.
- pub(crate) fn new(dev: &device::Device, chipset: Chipset) -> Result<Self> {
+ pub(crate) fn new(
+ dev: &'a device::Device<device::Bound>,
+ chipset: Chipset,
+ bar: Bar0<'a>,
+ ) -> Result<Self> {
Ok(Self {
hal: hal::falcon_hal(chipset)?,
- dev: dev.into(),
+ dev,
+ bar,
})
}
/// Resets DMA-related registers.
- pub(crate) fn dma_reset(&self, bar: Bar0<'_>) {
- bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
+ pub(crate) fn dma_reset(&self) {
+ self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
v.with_allow_phys_no_ctx(true)
});
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMACTL::zeroed(),
);
}
/// Reset the controller, select the falcon core, and wait for memory scrubbing to complete.
- pub(crate) fn reset(&self, bar: Bar0<'_>) -> Result {
- self.hal.reset_eng(bar)?;
- self.hal.select_core(self, bar)?;
- self.hal.reset_wait_mem_scrubbing(bar)?;
+ pub(crate) fn reset(&self) -> Result {
+ self.hal.reset_eng(self.bar)?;
+ self.hal.select_core(self, self.bar)?;
+ self.hal.reset_wait_mem_scrubbing(self.bar)?;
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
- regs::NV_PFALCON_FALCON_RM::from(bar.read(regs::NV_PMC_BOOT_0).into_raw()),
+ regs::NV_PFALCON_FALCON_RM::from(self.bar.read(regs::NV_PMC_BOOT_0).into_raw()),
);
Ok(())
@@ -404,18 +406,14 @@ pub(crate) fn reset(&self, bar: Bar0<'_>) -> Result {
/// Write a slice to Falcon IMEM memory using programmed I/O (PIO).
///
/// Returns `EINVAL` if `img.len()` is not a multiple of 4.
- fn pio_wr_imem_slice(
- &self,
- bar: Bar0<'_>,
- load_offsets: FalconPioImemLoadTarget<'_>,
- ) -> Result {
+ fn pio_wr_imem_slice(&self, load_offsets: FalconPioImemLoadTarget<'_>) -> Result {
// Rejecting misaligned images here allows us to avoid checking
// inside the loops.
if load_offsets.data.len() % 4 != 0 {
return Err(EINVAL);
}
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMC::zeroed()
.with_secure(load_offsets.secure)
@@ -426,13 +424,13 @@ fn pio_wr_imem_slice(
for (n, block) in load_offsets.data.chunks(MEM_BLOCK_ALIGNMENT).enumerate() {
let n = u16::try_from(n)?;
let tag: u16 = load_offsets.start_tag.checked_add(n).ok_or(ERANGE)?;
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMT::zeroed().with_tag(tag),
);
for word in block.chunks_exact(4) {
let w = [word[0], word[1], word[2], word[3]];
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMD::zeroed().with_data(u32::from_le_bytes(w)),
);
@@ -445,18 +443,14 @@ fn pio_wr_imem_slice(
/// Write a slice to Falcon DMEM memory using programmed I/O (PIO).
///
/// Returns `EINVAL` if `img.len()` is not a multiple of 4.
- fn pio_wr_dmem_slice(
- &self,
- bar: Bar0<'_>,
- load_offsets: FalconPioDmemLoadTarget<'_>,
- ) -> Result {
+ fn pio_wr_dmem_slice(&self, load_offsets: FalconPioDmemLoadTarget<'_>) -> Result {
// Rejecting misaligned images here allows us to avoid checking
// inside the loops.
if load_offsets.data.len() % 4 != 0 {
return Err(EINVAL);
}
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_DMEMC::zeroed()
.with_aincw(true)
@@ -465,7 +459,7 @@ fn pio_wr_dmem_slice(
for word in load_offsets.data.chunks_exact(4) {
let w = [word[0], word[1], word[2], word[3]];
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_DMEMD::zeroed().with_data(u32::from_le_bytes(w)),
);
@@ -477,29 +471,28 @@ fn pio_wr_dmem_slice(
/// Perform a PIO copy into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
pub(crate) fn pio_load<F: FalconFirmware<Target = E> + FalconPioLoadable>(
&self,
- bar: Bar0<'_>,
fw: &F,
) -> Result {
- bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
+ self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
v.with_allow_phys_no_ctx(true)
});
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMACTL::zeroed(),
);
if let Some(imem_ns) = fw.imem_ns_load_params() {
- self.pio_wr_imem_slice(bar, imem_ns)?;
+ self.pio_wr_imem_slice(imem_ns)?;
}
if let Some(imem_sec) = fw.imem_sec_load_params() {
- self.pio_wr_imem_slice(bar, imem_sec)?;
+ self.pio_wr_imem_slice(imem_sec)?;
}
- self.pio_wr_dmem_slice(bar, fw.dmem_load_params())?;
+ self.pio_wr_dmem_slice(fw.dmem_load_params())?;
- self.hal.program_brom(self, bar, &fw.brom_params());
+ self.hal.program_brom(self, self.bar, &fw.brom_params());
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()),
);
@@ -513,7 +506,6 @@ pub(crate) fn pio_load<F: FalconFirmware<Target = E> + FalconPioLoadable>(
/// `sec` is set if the loaded firmware is expected to run in secure mode.
fn dma_wr(
&self,
- bar: Bar0<'_>,
dma_obj: &Coherent<[u8]>,
target_mem: FalconMem,
load_offsets: FalconDmaLoadTarget,
@@ -571,7 +563,7 @@ fn dma_wr(
// Set up the base source DMA address.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_base(
// CAST: `as u32` is used on purpose since we do want to strip the upper bits,
@@ -579,7 +571,7 @@ fn dma_wr(
(dma_start >> 8) as u32,
),
);
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed().try_with_base(dma_start >> 40)?,
);
@@ -590,23 +582,23 @@ fn dma_wr(
for pos in (0..num_transfers).map(|i| i * DMA_LEN) {
// Perform a transfer of size `DMA_LEN`.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed()
.try_with_offs(load_offsets.dst_start + pos)?,
);
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(src_start + pos),
);
- bar.write(WithBase::of::<E>(), cmd);
+ self.bar.write(WithBase::of::<E>(), cmd);
// Wait for the transfer to complete.
// TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories
// should ever take that long.
read_poll_timeout(
- || Ok(bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())),
+ || Ok(self.bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())),
|r| r.idle(),
Delta::ZERO,
Delta::from_secs(2),
@@ -617,12 +609,7 @@ fn dma_wr(
}
/// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
- fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
- &self,
- dev: &Device<device::Bound>,
- bar: Bar0<'_>,
- fw: &F,
- ) -> Result {
+ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
// DMA object with firmware content as the source of the DMA engine.
let dma_obj = {
let fw_slice = fw.as_slice();
@@ -630,7 +617,7 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
// DMA copies are done in chunks of `MEM_BLOCK_ALIGNMENT`, so pad the length
// accordingly and fill with `0`.
let mut dma_obj = CoherentBox::zeroed_slice(
- dev,
+ self.dev,
fw_slice.len().next_multiple_of(MEM_BLOCK_ALIGNMENT),
GFP_KERNEL,
)?;
@@ -642,24 +629,16 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
dma_obj.into()
};
- self.dma_reset(bar);
- bar.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| {
- v.with_target(FalconFbifTarget::CoherentSysmem)
- .with_mem_type(FalconFbifMemType::Physical)
- });
+ self.dma_reset();
+ self.set_fbif_transcfg_phys_sysmem(0)?;
- self.dma_wr(
- bar,
- &dma_obj,
- FalconMem::ImemSecure,
- fw.imem_sec_load_params(),
- )?;
- self.dma_wr(bar, &dma_obj, FalconMem::Dmem, fw.dmem_load_params())?;
+ self.dma_wr(&dma_obj, FalconMem::ImemSecure, fw.imem_sec_load_params())?;
+ self.dma_wr(&dma_obj, FalconMem::Dmem, fw.dmem_load_params())?;
- self.hal.program_brom(self, bar, &fw.brom_params());
+ self.hal.program_brom(self, self.bar, &fw.brom_params());
// Set `BootVec` to start of non-secure code.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()),
);
@@ -667,11 +646,26 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
Ok(())
}
+ /// Configure a Falcon FBIF transaction slot to access physical coherent system memory.
+ pub(crate) fn set_fbif_transcfg_phys_sysmem(&self, dmaidx: u32) -> Result {
+ self.bar.update(
+ regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>()
+ .try_at(usize::from_safe_cast(dmaidx))
+ .ok_or(EINVAL)?,
+ |v| {
+ v.with_target(FalconFbifTarget::CoherentSysmem)
+ .with_mem_type(FalconFbifMemType::Physical)
+ },
+ );
+
+ Ok(())
+ }
+
/// Wait until the falcon CPU is halted.
- pub(crate) fn wait_till_halted(&self, bar: Bar0<'_>) -> Result<()> {
+ pub(crate) fn wait_till_halted(&self) -> Result<()> {
// TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds.
read_poll_timeout(
- || Ok(bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())),
+ || Ok(self.bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())),
|r| r.halted(),
Delta::ZERO,
Delta::from_secs(2),
@@ -681,16 +675,17 @@ pub(crate) fn wait_till_halted(&self, bar: Bar0<'_>) -> Result<()> {
}
/// Start the falcon CPU.
- pub(crate) fn start(&self, bar: Bar0<'_>) -> Result<()> {
- match bar
+ pub(crate) fn start(&self) -> Result<()> {
+ match self
+ .bar
.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())
.alias_en()
{
- true => bar.write(
+ true => self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed().with_startcpu(true),
),
- false => bar.write(
+ false => self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_CPUCTL::zeroed().with_startcpu(true),
),
@@ -700,16 +695,16 @@ pub(crate) fn start(&self, bar: Bar0<'_>) -> Result<()> {
}
/// Writes values to the mailbox registers if provided.
- pub(crate) fn write_mailboxes(&self, bar: Bar0<'_>, mbox0: Option<u32>, mbox1: Option<u32>) {
+ pub(crate) fn write_mailboxes(&self, mbox0: Option<u32>, mbox1: Option<u32>) {
if let Some(mbox0) = mbox0 {
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_MAILBOX0::zeroed().with_value(mbox0),
);
}
if let Some(mbox1) = mbox1 {
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_MAILBOX1::zeroed().with_value(mbox1),
);
@@ -717,21 +712,23 @@ pub(crate) fn write_mailboxes(&self, bar: Bar0<'_>, mbox0: Option<u32>, mbox1: O
}
/// Reads the value from `mbox0` register.
- pub(crate) fn read_mailbox0(&self, bar: Bar0<'_>) -> u32 {
- bar.read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>())
+ pub(crate) fn read_mailbox0(&self) -> u32 {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>())
.value()
}
/// Reads the value from `mbox1` register.
- pub(crate) fn read_mailbox1(&self, bar: Bar0<'_>) -> u32 {
- bar.read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>())
+ pub(crate) fn read_mailbox1(&self) -> u32 {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>())
.value()
}
/// Reads values from both mailbox registers.
- pub(crate) fn read_mailboxes(&self, bar: Bar0<'_>) -> (u32, u32) {
- let mbox0 = self.read_mailbox0(bar);
- let mbox1 = self.read_mailbox1(bar);
+ pub(crate) fn read_mailboxes(&self) -> (u32, u32) {
+ let mbox0 = self.read_mailbox0();
+ let mbox1 = self.read_mailbox1();
(mbox0, mbox1)
}
@@ -743,54 +740,43 @@ pub(crate) fn read_mailboxes(&self, bar: Bar0<'_>) -> (u32, u32) {
///
/// Wait up to two seconds for the firmware to complete, and return its exit status read from
/// the `MBOX0` and `MBOX1` registers.
- pub(crate) fn boot(
- &self,
- bar: Bar0<'_>,
- mbox0: Option<u32>,
- mbox1: Option<u32>,
- ) -> Result<(u32, u32)> {
- self.write_mailboxes(bar, mbox0, mbox1);
- self.start(bar)?;
- self.wait_till_halted(bar)?;
- Ok(self.read_mailboxes(bar))
+ pub(crate) fn boot(&self, mbox0: Option<u32>, mbox1: Option<u32>) -> Result<(u32, u32)> {
+ self.write_mailboxes(mbox0, mbox1);
+ self.start()?;
+ self.wait_till_halted()?;
+ Ok(self.read_mailboxes())
}
/// Returns the fused version of the signature to use in order to run a HS firmware on this
/// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header.
pub(crate) fn signature_reg_fuse_version(
&self,
- bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32> {
self.hal
- .signature_reg_fuse_version(self, bar, engine_id_mask, ucode_id)
+ .signature_reg_fuse_version(self, self.bar, engine_id_mask, ucode_id)
}
/// Check if the RISC-V core is active.
///
/// Returns `true` if the RISC-V core is active, `false` otherwise.
- pub(crate) fn is_riscv_active(&self, bar: Bar0<'_>) -> bool {
- self.hal.is_riscv_active(bar)
+ pub(crate) fn is_riscv_active(&self) -> bool {
+ self.hal.is_riscv_active(self.bar)
}
/// Load a firmware image into Falcon memory, using the preferred method for the current
/// chipset.
- pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
- &self,
- dev: &Device<device::Bound>,
- bar: Bar0<'_>,
- fw: &F,
- ) -> Result {
+ pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
match self.hal.load_method() {
- LoadMethod::Dma => self.dma_load(dev, bar, fw),
- LoadMethod::Pio => self.pio_load(bar, &fw.try_as_pio_loadable()?),
+ LoadMethod::Dma => self.dma_load(fw),
+ LoadMethod::Pio => self.pio_load(&fw.try_as_pio_loadable()?),
}
}
/// Write the application version to the OS register.
- pub(crate) fn write_os_version(&self, bar: Bar0<'_>, app_version: u32) {
- bar.write(
+ pub(crate) fn write_os_version(&self, app_version: u32) {
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_OS::zeroed().with_value(app_version),
);
diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs
index 52cdb84ef0e8..53b1079843ae 100644
--- a/drivers/gpu/nova-core/falcon/fsp.rs
+++ b/drivers/gpu/nova-core/falcon/fsp.rs
@@ -21,7 +21,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
Falcon,
FalconEngine,
@@ -48,18 +47,18 @@ impl RegisterBase<PFalcon2Base> for Fsp {
impl FalconEngine for Fsp {}
-impl Falcon<Fsp> {
+impl<'a> Falcon<'a, Fsp> {
/// Writes `data` to FSP external memory at offset `0`.
///
/// `data` is interpreted as little-endian 32-bit words. Returns `EINVAL`
/// if the `data` length is not 4-byte aligned.
- fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
+ fn write_emem(&mut self, data: &[u8]) -> Result {
if data.len() % 4 != 0 {
return Err(EINVAL);
}
// Begin a write burst at offset `0`, auto-incrementing on each write.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincw(true),
);
@@ -68,7 +67,7 @@ fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
let value = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
// Write the next 32-bit `value`; hardware advances the offset.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMD::zeroed().with_data(value),
);
@@ -81,20 +80,23 @@ fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
///
/// `data` is stored as little-endian 32-bit words. Returns `EINVAL` if
/// the `data` length is not 4-byte aligned.
- fn read_emem(&mut self, bar: Bar0<'_>, data: &mut [u8]) -> Result {
+ fn read_emem(&mut self, data: &mut [u8]) -> Result {
if data.len() % 4 != 0 {
return Err(EINVAL);
}
// Begin a read burst at offset `0`, auto-incrementing on each read.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincr(true),
);
for chunk in data.chunks_exact_mut(4) {
// Read the next 32-bit word; hardware advances the offset.
- let value = bar.read(regs::NV_PFALCON_FALCON_EMEMD::of::<Fsp>()).data();
+ let value = self
+ .bar
+ .read(regs::NV_PFALCON_FALCON_EMEMD::of::<Fsp>())
+ .data();
chunk.copy_from_slice(&value.to_le_bytes());
}
@@ -107,9 +109,9 @@ fn read_emem(&mut self, bar: Bar0<'_>, data: &mut [u8]) -> Result {
///
/// The FSP message queue is not circular. Pointers are reset to 0 after each
/// message exchange, so `tail >= head` is always true when data is present.
- fn poll_msgq(&self, bar: Bar0<'_>) -> u32 {
- let head = bar.read(regs::NV_PFSP_MSGQ_HEAD::at(0)).val();
- let tail = bar.read(regs::NV_PFSP_MSGQ_TAIL::at(0)).val();
+ fn poll_msgq(&self) -> u32 {
+ let head = self.bar.read(regs::NV_PFSP_MSGQ_HEAD::at(0)).val();
+ let tail = self.bar.read(regs::NV_PFSP_MSGQ_TAIL::at(0)).val();
if head == tail {
return 0;
@@ -122,20 +124,20 @@ fn poll_msgq(&self, bar: Bar0<'_>) -> u32 {
/// Writes `packet` to FSP EMEM and updates the queue pointers to notify FSP.
///
/// Returns `EINVAL` if `packet` is empty or its length is not 4-byte aligned.
- pub(crate) fn send_msg(&mut self, bar: Bar0<'_>, packet: &[u8]) -> Result {
+ pub(crate) fn send_msg(&mut self, packet: &[u8]) -> Result {
if packet.is_empty() {
return Err(EINVAL);
}
- self.write_emem(bar, packet)?;
+ self.write_emem(packet)?;
// Update queue pointers. TAIL points at the last DWORD written.
let tail_offset = u32::try_from(packet.len() - 4).map_err(|_| EINVAL)?;
- bar.write(
+ self.bar.write(
Array::at(0),
regs::NV_PFSP_QUEUE_TAIL::zeroed().with_address(tail_offset),
);
- bar.write(
+ self.bar.write(
Array::at(0),
regs::NV_PFSP_QUEUE_HEAD::zeroed().with_address(0),
);
@@ -148,9 +150,9 @@ pub(crate) fn send_msg(&mut self, bar: Bar0<'_>, packet: &[u8]) -> Result {
///
/// Returns `ETIMEDOUT` if no message was available until timeout, or a regular error code if a
/// memory allocation error occurred.
- pub(crate) fn recv_msg(&mut self, bar: Bar0<'_>) -> Result<KVec<u8>> {
+ pub(crate) fn recv_msg(&mut self) -> Result<KVec<u8>> {
let msg_size = read_poll_timeout(
- || Ok(self.poll_msgq(bar)),
+ || Ok(self.poll_msgq()),
|&size| size > 0,
Delta::from_millis(10),
Delta::from_millis(FSP_MSG_TIMEOUT_MS),
@@ -160,11 +162,13 @@ pub(crate) fn recv_msg(&mut self, bar: Bar0<'_>) -> Result<KVec<u8>> {
let mut buffer = KVec::<u8>::new();
buffer.resize(msg_size, 0, GFP_KERNEL)?;
- self.read_emem(bar, &mut buffer)?;
+ self.read_emem(&mut buffer)?;
// Reset message queue pointers after reading.
- bar.write(Array::at(0), regs::NV_PFSP_MSGQ_TAIL::zeroed().with_val(0));
- bar.write(Array::at(0), regs::NV_PFSP_MSGQ_HEAD::zeroed().with_val(0));
+ self.bar
+ .write(Array::at(0), regs::NV_PFSP_MSGQ_TAIL::zeroed().with_val(0));
+ self.bar
+ .write(Array::at(0), regs::NV_PFSP_MSGQ_HEAD::zeroed().with_val(0));
Ok(buffer)
}
diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/falcon/gsp.rs
index f788b87bd951..ae32f401aeb0 100644
--- a/drivers/gpu/nova-core/falcon/gsp.rs
+++ b/drivers/gpu/nova-core/falcon/gsp.rs
@@ -14,7 +14,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
Falcon,
FalconEngine,
@@ -37,20 +36,20 @@ impl RegisterBase<PFalcon2Base> for Gsp {
impl FalconEngine for Gsp {}
-impl Falcon<Gsp> {
+impl<'a> Falcon<'a, Gsp> {
/// Clears the SWGEN0 bit in the Falcon's IRQ status clear register to
/// allow GSP to signal CPU for processing new messages in message queue.
- pub(crate) fn clear_swgen0_intr(&self, bar: Bar0<'_>) {
- bar.write(
+ pub(crate) fn clear_swgen0_intr(&self) {
+ self.bar.write(
WithBase::of::<Gsp>(),
regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true),
);
}
/// Checks if GSP reload/resume has completed during the boot process.
- pub(crate) fn check_reload_completed(&self, bar: Bar0<'_>, timeout: Delta) -> Result<bool> {
+ pub(crate) fn check_reload_completed(&self, timeout: Delta) -> Result<bool> {
read_poll_timeout(
- || Ok(bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)),
+ || Ok(self.bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)),
|val| val.boot_stage_3_handoff(),
Delta::ZERO,
timeout,
@@ -59,19 +58,21 @@ pub(crate) fn check_reload_completed(&self, bar: Bar0<'_>, timeout: Delta) -> Re
}
/// Returns whether the RISC-V branch privilege lockdown bit is set.
- pub(crate) fn riscv_branch_privilege_lockdown(&self, bar: Bar0<'_>) -> bool {
- bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
+ pub(crate) fn riscv_branch_privilege_lockdown(&self) -> bool {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
.riscv_br_priv_lockdown()
}
/// Returns whether GSP registers can be read by the CPU.
- pub(crate) fn priv_target_mask_released(&self, bar: Bar0<'_>) -> bool {
+ pub(crate) fn priv_target_mask_released(&self) -> bool {
/// Pattern returned by GSP register reads while the PRIV target mask still blocks CPU
/// access. The low byte varies; the upper 24 bits are fixed.
const LOCKED_PATTERN: u32 = 0xbadf_4100;
const LOCKED_MASK: u32 = 0xffff_ff00;
- let hwcfg2 = bar
+ let hwcfg2 = self
+ .bar
.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
.into_raw();
diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/falcon/hal.rs
index 89b56823906b..0cb665162c90 100644
--- a/drivers/gpu/nova-core/falcon/hal.rs
+++ b/drivers/gpu/nova-core/falcon/hal.rs
@@ -34,7 +34,7 @@ pub(crate) enum LoadMethod {
/// registers.
pub(crate) trait FalconHal<E: FalconEngine>: Send + Sync {
/// Activates the Falcon core if the engine is a risvc/falcon dual engine.
- fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>) -> Result {
Ok(())
}
@@ -42,14 +42,14 @@ fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
/// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header.
fn signature_reg_fuse_version(
&self,
- falcon: &Falcon<E>,
+ falcon: &Falcon<'_, E>,
bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32>;
/// Program the boot ROM registers prior to starting a secure firmware.
- fn program_brom(&self, falcon: &Falcon<E>, bar: Bar0<'_>, params: &FalconBromParams);
+ fn program_brom(&self, falcon: &Falcon<'_, E>, bar: Bar0<'_>, params: &FalconBromParams);
/// Check if the RISC-V core is active.
/// Returns `true` if the RISC-V core is active, `false` otherwise.
diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs
index cf6ce47e6b25..e45adb0312c0 100644
--- a/drivers/gpu/nova-core/falcon/hal/ga102.rs
+++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs
@@ -115,21 +115,21 @@ pub(super) fn new() -> Self {
}
impl<E: FalconEngine> FalconHal<E> for Ga102<E> {
- fn select_core(&self, _falcon: &Falcon<E>, bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, bar: Bar0<'_>) -> Result {
select_core_ga102::<E>(bar)
}
fn signature_reg_fuse_version(
&self,
- falcon: &Falcon<E>,
+ falcon: &Falcon<'_, E>,
bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32> {
- signature_reg_fuse_version_ga102(&falcon.dev, bar, engine_id_mask, ucode_id)
+ signature_reg_fuse_version_ga102(falcon.dev, bar, engine_id_mask, ucode_id)
}
- fn program_brom(&self, _falcon: &Falcon<E>, bar: Bar0<'_>, params: &FalconBromParams) {
+ fn program_brom(&self, _falcon: &Falcon<'_, E>, bar: Bar0<'_>, params: &FalconBromParams) {
program_brom_ga102::<E>(bar, params);
}
diff --git a/drivers/gpu/nova-core/falcon/hal/tu102.rs b/drivers/gpu/nova-core/falcon/hal/tu102.rs
index 3aaee3869312..de48ded45bbe 100644
--- a/drivers/gpu/nova-core/falcon/hal/tu102.rs
+++ b/drivers/gpu/nova-core/falcon/hal/tu102.rs
@@ -34,13 +34,13 @@ pub(super) fn new() -> Self {
}
impl<E: FalconEngine> FalconHal<E> for Tu102<E> {
- fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>) -> Result {
Ok(())
}
fn signature_reg_fuse_version(
&self,
- _falcon: &Falcon<E>,
+ _falcon: &Falcon<'_, E>,
_bar: Bar0<'_>,
_engine_id_mask: u16,
_ucode_id: u8,
@@ -48,7 +48,7 @@ fn signature_reg_fuse_version(
Ok(0)
}
- fn program_brom(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>, _params: &FalconBromParams) {}
+ fn program_brom(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>, _params: &FalconBromParams) {}
fn is_riscv_active(&self, bar: Bar0<'_>) -> bool {
bar.read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::of::<E>())
diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs
index d9313ac361af..acb7f4d8a532 100644
--- a/drivers/gpu/nova-core/firmware/booter.rs
+++ b/drivers/gpu/nova-core/firmware/booter.rs
@@ -15,7 +15,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
sec2::Sec2,
Falcon,
@@ -293,8 +292,7 @@ pub(crate) fn new(
kind: BooterKind,
chipset: Chipset,
ver: &str,
- falcon: &Falcon<<Self as FalconFirmware>::Target>,
- bar: Bar0<'_>,
+ falcon: &Falcon<'_, <Self as FalconFirmware>::Target>,
) -> Result<Self> {
let fw_name = match kind {
BooterKind::Loader => "booter_load",
@@ -339,11 +337,8 @@ pub(crate) fn new(
} else {
// Obtain the version from the fuse register, and extract the corresponding
// signature.
- let reg_fuse_version = falcon.signature_reg_fuse_version(
- bar,
- brom_params.engine_id_mask,
- brom_params.ucode_id,
- )?;
+ let reg_fuse_version = falcon
+ .signature_reg_fuse_version(brom_params.engine_id_mask, brom_params.ucode_id)?;
// `0` means the last signature should be used.
const FUSE_VERSION_USE_LAST_SIG: u32 = 0;
@@ -405,18 +400,14 @@ pub(crate) fn new(
pub(crate) fn run<T>(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- sec2_falcon: &Falcon<Sec2>,
+ sec2_falcon: &Falcon<'_, Sec2>,
wpr_meta: &Coherent<T>,
) -> Result {
- sec2_falcon.reset(bar)?;
- sec2_falcon.load(dev, bar, self)?;
+ sec2_falcon.reset()?;
+ sec2_falcon.load(self)?;
let wpr_handle = wpr_meta.dma_handle();
- let (mbox0, mbox1) = sec2_falcon.boot(
- bar,
- Some(wpr_handle as u32),
- Some((wpr_handle >> 32) as u32),
- )?;
+ let (mbox0, mbox1) =
+ sec2_falcon.boot(Some(wpr_handle as u32), Some((wpr_handle >> 32) as u32))?;
dev_dbg!(dev, "SEC2 MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
if mbox0 != 0 {
diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs
index 199ae2adb664..95e0dd77746b 100644
--- a/drivers/gpu/nova-core/firmware/fwsec.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec.rs
@@ -27,7 +27,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
gsp::Gsp,
Falcon,
@@ -320,8 +319,7 @@ impl FwsecFirmware {
/// command.
pub(crate) fn new(
dev: &Device<device::Bound>,
- falcon: &Falcon<Gsp>,
- bar: Bar0<'_>,
+ falcon: &Falcon<'_, Gsp>,
bios: &Vbios,
cmd: FwsecCommand,
) -> Result<Self> {
@@ -337,7 +335,7 @@ pub(crate) fn new(
.ok_or(EINVAL)?;
let desc_sig_versions = u32::from(desc.signature_versions());
let reg_fuse_version =
- falcon.signature_reg_fuse_version(bar, desc.engine_id_mask(), desc.ucode_id())?;
+ falcon.signature_reg_fuse_version(desc.engine_id_mask(), desc.ucode_id())?;
dev_dbg!(
dev,
"desc_sig_versions: {:#x}, reg_fuse_version: {}\n",
@@ -390,21 +388,16 @@ pub(crate) fn new(
/// This must only be called on chipsets that do not need the FWSEC bootloader (i.e., where
/// [`Chipset::needs_fwsec_bootloader()`](crate::gpu::Chipset::needs_fwsec_bootloader) returns
/// `false`). On chipsets that do, use [`bootloader::FwsecFirmwareWithBl`] instead.
- pub(crate) fn run(
- &self,
- dev: &Device<device::Bound>,
- falcon: &Falcon<Gsp>,
- bar: Bar0<'_>,
- ) -> Result<()> {
+ pub(crate) fn run(&self, dev: &Device<device::Bound>, falcon: &Falcon<'_, Gsp>) -> Result<()> {
// Reset falcon, load the firmware, and run it.
falcon
- .reset(bar)
+ .reset()
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
falcon
- .load(dev, bar, self)
+ .load(self)
.inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;
let (mbox0, _) = falcon
- .boot(bar, Some(0), None)
+ .boot(Some(0), None)
.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);
diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
index ac1558a83b83..71f5a70a1114 100644
--- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
@@ -12,10 +12,6 @@
Device, //
},
dma::Coherent,
- io::{
- register::WithBase, //
- Io,
- },
prelude::*,
ptr::{
Alignable,
@@ -29,15 +25,12 @@
};
use crate::{
- driver::Bar0,
falcon::{
self,
gsp::Gsp,
Falcon,
FalconBromParams,
FalconDmaLoadable,
- FalconFbifMemType,
- FalconFbifTarget,
FalconFirmware,
FalconPioDmemLoadTarget,
FalconPioImemLoadTarget,
@@ -50,8 +43,7 @@
FIRMWARE_VERSION, //
},
gpu::Chipset,
- num::FromSafeCast,
- regs,
+ num::FromSafeCast, //
};
/// Descriptor used by RM to figure out the requirements of the boot loader.
@@ -275,33 +267,20 @@ 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>,
- bar: Bar0<'_>,
- ) -> Result<()> {
+ pub(crate) fn run(&self, dev: &Device<device::Bound>, falcon: &Falcon<'_, Gsp>) -> Result<()> {
// Reset falcon, load the firmware, and run it.
falcon
- .reset(bar)
+ .reset()
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
falcon
- .pio_load(bar, self)
+ .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.
- bar.update(
- regs::NV_PFALCON_FBIF_TRANSCFG::of::<Gsp>()
- .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)
- },
- );
+ falcon.set_fbif_transcfg_phys_sysmem(self.dmem_desc.ctx_dma)?;
let (mbox0, _) = falcon
- .boot(bar, Some(0), None)
+ .boot(Some(0), None)
.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);
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index 4b97d1fb505e..574e1627e63c 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -224,27 +224,27 @@ pub(crate) fn boot_params_dma_handle(&self) -> u64 {
/// An `Fsp` is produced by [`Fsp::wait_secure_boot`], which only returns once FSP secure boot
/// has completed. It owns the FSP falcon and the FMC firmware, which are used for the subsequent
/// Chain of Trust boot.
-pub(crate) struct Fsp {
- falcon: Falcon<FspEngine>,
+pub(crate) struct Fsp<'a> {
+ falcon: Falcon<'a, FspEngine>,
fsp_fw: FspFirmware,
}
-impl Fsp {
+impl<'a> Fsp<'a> {
/// Waits for FSP secure boot completion, then returns the [`Fsp`] interface.
///
/// Polls the thermal scratch register until FSP signals boot completion or the timeout
/// elapses. Returning an [`Fsp`] only on success guarantees, at the API level, that the
/// interface is not used before secure boot has completed.
pub(crate) fn wait_secure_boot(
- dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
+ dev: &'a device::Device<device::Bound>,
+ bar: Bar0<'a>,
chipset: Chipset,
- ) -> Result<Fsp> {
+ ) -> Result<Fsp<'a>> {
/// FSP secure boot completion timeout in milliseconds.
const FSP_SECURE_BOOT_TIMEOUT_MS: i64 = 5000;
let hal = hal::fsp_hal(chipset).ok_or(ENOTSUPP)?;
- let falcon = Falcon::<FspEngine>::new(dev, chipset)?;
+ let falcon = Falcon::<FspEngine>::new(dev, chipset, bar)?;
let fsp_fw = FspFirmware::new(dev, chipset, FIRMWARE_VERSION)?;
read_poll_timeout(
@@ -262,13 +262,13 @@ pub(crate) fn wait_secure_boot(
/// Sends a message to FSP and waits for the response.
/// Returns the full response buffer on success.
- fn send_sync_fsp<M>(&mut self, dev: &device::Device, bar: Bar0<'_>, msg: &M) -> Result<KVec<u8>>
+ fn send_sync_fsp<M>(&mut self, dev: &device::Device, msg: &M) -> Result<KVec<u8>>
where
M: MessageToFsp,
{
- self.falcon.send_msg(bar, msg.as_bytes())?;
+ self.falcon.send_msg(msg.as_bytes())?;
- let response_buf = self.falcon.recv_msg(bar).inspect_err(|e| {
+ let response_buf = self.falcon.recv_msg().inspect_err(|e| {
dev_err!(dev, "FSP response error: {:?}\n", e);
})?;
@@ -330,7 +330,6 @@ fn send_sync_fsp<M>(&mut self, dev: &device::Device, bar: Bar0<'_>, msg: &M) ->
pub(crate) fn boot_fmc(
&mut self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
fb_layout: &FbLayout,
args: &FmcBootArgs,
) -> Result {
@@ -341,7 +340,7 @@ pub(crate) fn boot_fmc(
GFP_KERNEL,
)?;
- let _response_buf = self.send_sync_fsp(dev, bar, &*msg)?;
+ let _response_buf = self.send_sync_fsp(dev, &*msg)?;
dev_dbg!(dev, "FSP Chain of Trust completed successfully\n");
Ok(())
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 4d76be429e75..43c3f4f8df71 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -273,9 +273,9 @@ struct GspResources<'gpu> {
/// MMIO mapping of PCI BAR 0.
bar: Bar0<'gpu>,
/// GSP falcon instance, used for GSP boot up and cleanup.
- gsp_falcon: Falcon<GspFalcon>,
+ gsp_falcon: Falcon<'gpu, GspFalcon>,
/// SEC2 falcon instance, used for GSP boot up and cleanup.
- sec2_falcon: Falcon<Sec2Falcon>,
+ sec2_falcon: Falcon<'gpu, Sec2Falcon>,
/// GSP runtime data.
#[pin]
gsp: Gsp,
@@ -351,10 +351,11 @@ pub(crate) fn new(
gsp_falcon: Falcon::new(
pdev.as_ref(),
spec.chipset,
+ bar
)
- .inspect(|falcon| falcon.clear_swgen0_intr(bar))?,
+ .inspect(|falcon| falcon.clear_swgen0_intr())?,
- sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
+ sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset, bar)?,
gsp <- Gsp::new(pdev),
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 73e93403601c..b4ac4156056e 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -57,8 +57,8 @@ pub(crate) struct GspBootContext<'a> {
pub(crate) pdev: &'a pci::Device<device::Bound>,
pub(crate) bar: Bar0<'a>,
pub(crate) chipset: Chipset,
- pub(crate) gsp_falcon: &'a Falcon<GspFalcon>,
- pub(crate) sec2_falcon: &'a Falcon<Sec2Falcon>,
+ pub(crate) gsp_falcon: &'a Falcon<'a, GspFalcon>,
+ pub(crate) sec2_falcon: &'a Falcon<'a, Sec2Falcon>,
}
impl<'a> GspBootContext<'a> {
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index bb2000b7a78b..ab0491b57944 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -37,8 +37,8 @@ pub(super) struct BootUnloadArgs<'a> {
gsp: &'a super::Gsp,
dev: &'a device::Device<device::Bound>,
bar: Bar0<'a>,
- gsp_falcon: &'a Falcon<Gsp>,
- sec2_falcon: &'a Falcon<Sec2>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
}
@@ -56,8 +56,8 @@ pub(super) fn new(
gsp: &'a super::Gsp,
dev: &'a device::Device<device::Bound>,
bar: Bar0<'a>,
- gsp_falcon: &'a Falcon<Gsp>,
- sec2_falcon: &'a Falcon<Sec2>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
) -> Self {
Self {
@@ -120,17 +120,17 @@ pub(crate) fn boot(
// Perform the chipset-specific boot sequence, and retrieve the unload bundle.
let unload_guard = hal.boot(&self, &ctx, &fb_layout, &wpr_meta)?;
- gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version);
+ gsp_falcon.write_os_version(gsp_fw.bootloader.app_version);
// Poll for RISC-V to become active before continuing.
read_poll_timeout(
- || Ok(gsp_falcon.is_riscv_active(bar)),
+ || Ok(gsp_falcon.is_riscv_active()),
|val: &bool| *val,
Delta::from_millis(10),
Delta::from_secs(5),
)?;
- dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar),);
+ dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(),);
self.cmdq
.send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?;
@@ -149,7 +149,7 @@ pub(crate) fn boot(
fn shutdown_gsp(
cmdq: &Cmdq,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<Gsp>,
+ gsp_falcon: &Falcon<'_, Gsp>,
mode: commands::PowerStateLevel,
) -> Result {
// Command to shut the GSP down.
@@ -158,7 +158,7 @@ fn shutdown_gsp(
// Wait until GSP signals it is suspended.
const LIBOS_INTERRUPT_PROCESSOR_SUSPENDED: u32 = bits::bit_u32(31);
read_poll_timeout(
- || Ok(gsp_falcon.read_mailbox0(bar)),
+ || Ok(gsp_falcon.read_mailbox0()),
|&mb0| mb0 & LIBOS_INTERRUPT_PROCESSOR_SUSPENDED != 0,
Delta::from_millis(10),
Delta::from_secs(5),
@@ -173,8 +173,8 @@ pub(crate) fn unload(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<Gsp>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, Gsp>,
+ sec2_falcon: &Falcon<'_, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
) -> Result {
// Shut down the GSP. Keep going even in case of error.
diff --git a/drivers/gpu/nova-core/gsp/hal.rs b/drivers/gpu/nova-core/gsp/hal.rs
index 51a277fe97bb..d3e47ef206de 100644
--- a/drivers/gpu/nova-core/gsp/hal.rs
+++ b/drivers/gpu/nova-core/gsp/hal.rs
@@ -42,8 +42,8 @@ fn run(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result;
}
diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
index 2187e11168b2..1d06405a32f6 100644
--- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
+++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
@@ -42,10 +42,10 @@ struct GspMbox {
impl GspMbox {
/// Reads both mailboxes from the GSP falcon.
- fn read(gsp_falcon: &Falcon<GspEngine>, bar: Bar0<'_>) -> Self {
+ fn read(gsp_falcon: &Falcon<'_, GspEngine>) -> Self {
Self {
- mbox0: gsp_falcon.read_mailbox0(bar),
- mbox1: gsp_falcon.read_mailbox1(bar),
+ mbox0: gsp_falcon.read_mailbox0(),
+ mbox1: gsp_falcon.read_mailbox1(),
}
}
@@ -60,8 +60,7 @@ fn combined_addr(&self) -> u64 {
/// either condition should stop the poll loop.
fn lockdown_released_or_error(
&self,
- gsp_falcon: &Falcon<GspEngine>,
- bar: Bar0<'_>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
fmc_boot_params_addr: u64,
) -> bool {
// GSP-FMC normally clears the boot parameters address from the mailboxes early during
@@ -71,15 +70,14 @@ fn lockdown_released_or_error(
return self.combined_addr() != fmc_boot_params_addr;
}
- !gsp_falcon.riscv_branch_privilege_lockdown(bar)
+ !gsp_falcon.riscv_branch_privilege_lockdown()
}
}
/// Waits for GSP lockdown to be released after FSP Chain of Trust.
fn wait_for_gsp_lockdown_release(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
fmc_boot_params_addr: u64,
) -> Result {
dev_dbg!(dev, "Waiting for GSP lockdown release\n");
@@ -88,14 +86,14 @@ fn wait_for_gsp_lockdown_release(
|| {
// While the PRIV target mask is still locked to FSP, GSP register and mailbox reads
// are not meaningful. Wait until HWCFG2 says the CPU can read them.
- Ok(match gsp_falcon.priv_target_mask_released(bar) {
+ Ok(match gsp_falcon.priv_target_mask_released() {
false => None,
- true => Some(GspMbox::read(gsp_falcon, bar)),
+ true => Some(GspMbox::read(gsp_falcon)),
})
},
|mbox| match mbox {
None => false,
- Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, bar, fmc_boot_params_addr),
+ Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, fmc_boot_params_addr),
},
Delta::from_millis(10),
Delta::from_secs(30),
@@ -122,13 +120,13 @@ impl UnloadBundle for FspUnloadBundle {
fn run(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- _sec2_falcon: &Falcon<Sec2>,
+ _bar: Bar0<'_>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ _sec2_falcon: &Falcon<'_, Sec2>,
) -> Result {
// GSP falcon does most of the work of resetting, so just wait for it to finish.
read_poll_timeout(
- || Ok(gsp_falcon.is_riscv_active(bar)),
+ || Ok(gsp_falcon.is_riscv_active()),
|&active| !active,
Delta::from_millis(10),
Delta::from_secs(5),
@@ -176,9 +174,9 @@ fn boot<'a>(
false,
)?;
- fsp.boot_fmc(dev, bar, fb_layout, &args)?;
+ fsp.boot_fmc(dev, fb_layout, &args)?;
- wait_for_gsp_lockdown_release(dev, bar, gsp_falcon, args.boot_params_dma_handle())?;
+ wait_for_gsp_lockdown_release(dev, gsp_falcon, args.boot_params_dma_handle())?;
Ok(unload_guard)
}
diff --git a/drivers/gpu/nova-core/gsp/hal/tu102.rs b/drivers/gpu/nova-core/gsp/hal/tu102.rs
index f8a8541704ee..180d47fb8f4e 100644
--- a/drivers/gpu/nova-core/gsp/hal/tu102.rs
+++ b/drivers/gpu/nova-core/gsp/hal/tu102.rs
@@ -62,12 +62,11 @@ impl FwsecUnloadFirmware {
/// Loads the FWSEC SB firmware, as well as its bootloader if `chipset` requires it.
fn new(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
chipset: Chipset,
bios: &Vbios,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
) -> Result<Self> {
- let fwsec_sb = FwsecFirmware::new(dev, gsp_falcon, bar, bios, FwsecCommand::Sb)?;
+ let fwsec_sb = FwsecFirmware::new(dev, gsp_falcon, bios, FwsecCommand::Sb)?;
Ok(if chipset.needs_fwsec_bootloader() {
Self::WithBl(FwsecFirmwareWithBl::new(fwsec_sb, dev, chipset)?)
@@ -80,12 +79,11 @@ fn new(
fn run(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
) -> Result {
match self {
- Self::WithoutBl(fw) => fw.run(dev, gsp_falcon, bar),
- Self::WithBl(fw) => fw.run(dev, gsp_falcon, bar),
+ Self::WithoutBl(fw) => fw.run(dev, gsp_falcon),
+ Self::WithBl(fw) => fw.run(dev, gsp_falcon),
}
}
}
@@ -101,22 +99,20 @@ impl Sec2UnloadBundle {
/// Load and prepare the resources required to properly reset the GSP after it has been stopped.
fn build(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
chipset: Chipset,
bios: &Vbios,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result<KBox<dyn UnloadBundle>> {
KBox::new(
Self {
- fwsec_sb: FwsecUnloadFirmware::new(dev, bar, chipset, bios, gsp_falcon)?,
+ fwsec_sb: FwsecUnloadFirmware::new(dev, chipset, bios, gsp_falcon)?,
booter_unloader: BooterFirmware::new(
dev,
BooterKind::Unloader,
chipset,
FIRMWARE_VERSION,
sec2_falcon,
- bar,
)?,
},
GFP_KERNEL,
@@ -131,14 +127,14 @@ fn run(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result {
// Run FWSEC-SB to reset the GSP falcon to its pre-libos state.
// Log errors but keep going if it fails.
let fwsec_sb_res = self
.fwsec_sb
- .run(dev, bar, gsp_falcon)
+ .run(dev, gsp_falcon)
.inspect_err(|e| dev_err!(dev, "FWSEC-SB failed to run: {:?}\n", e));
// Remove WPR2 region if set.
@@ -148,13 +144,12 @@ fn run(
return Ok(());
}
- sec2_falcon.reset(bar)?;
- sec2_falcon.load(dev, bar, &self.booter_unloader)?;
+ sec2_falcon.reset()?;
+ sec2_falcon.load(&self.booter_unloader)?;
// Sentinel value to confirm that Booter Unloader has run.
const MAILBOX_SENTINEL: u32 = 0xff;
- let (mbox0, _) =
- sec2_falcon.boot(bar, Some(MAILBOX_SENTINEL), Some(MAILBOX_SENTINEL))?;
+ let (mbox0, _) = sec2_falcon.boot(Some(MAILBOX_SENTINEL), Some(MAILBOX_SENTINEL))?;
if mbox0 != 0 {
dev_err!(dev, "Booter Unloader returned error 0x{:x}\n", mbox0);
return Err(EINVAL);
@@ -183,7 +178,7 @@ fn run(
fn run_fwsec_frts(
dev: &device::Device<device::Bound>,
chipset: Chipset,
- falcon: &Falcon<GspEngine>,
+ falcon: &Falcon<'_, GspEngine>,
bar: Bar0<'_>,
bios: &Vbios,
fb_layout: &FbLayout,
@@ -202,7 +197,6 @@ fn run_fwsec_frts(
let fwsec_frts = FwsecFirmware::new(
dev,
falcon,
- bar,
bios,
FwsecCommand::Frts {
frts_addr: fb_layout.frts.start,
@@ -213,10 +207,10 @@ fn run_fwsec_frts(
if chipset.needs_fwsec_bootloader() {
let fwsec_frts_bl = FwsecFirmwareWithBl::new(fwsec_frts, dev, chipset)?;
// Load and run the bootloader, which will load FWSEC-FRTS and run it.
- fwsec_frts_bl.run(dev, falcon, bar)?;
+ fwsec_frts_bl.run(dev, falcon)?;
} else {
// Load and run FWSEC-FRTS directly.
- fwsec_frts.run(dev, falcon, bar)?;
+ fwsec_frts.run(dev, falcon)?;
}
// SCRATCH_E contains the error code for FWSEC-FRTS.
@@ -286,18 +280,17 @@ fn boot<'a>(
//
// If the unload bundle creation fails, the GPU will need to be reset before the driver can
// be probed again.
- let unload_bundle =
- Sec2UnloadBundle::build(dev, bar, chipset, &bios, gsp_falcon, sec2_falcon)
- .inspect_err(|e| {
- dev_warn!(dev, "Failed to prepare unload firmware: {:?}\n", e);
- dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
- dev_warn!(
- dev,
- "The GPU will need to be reset before the driver can bind again.\n"
- );
- })
- .ok()
- .map(crate::gsp::UnloadBundle);
+ let unload_bundle = Sec2UnloadBundle::build(dev, chipset, &bios, gsp_falcon, sec2_falcon)
+ .inspect_err(|e| {
+ dev_warn!(dev, "Failed to prepare unload firmware: {:?}\n", e);
+ dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
+ dev_warn!(
+ dev,
+ "The GPU will need to be reset before the driver can bind again.\n"
+ );
+ })
+ .ok()
+ .map(crate::gsp::UnloadBundle);
// Wrap the unload bundle into a drop guard so it is automatically run upon failure.
let unload_guard =
@@ -308,13 +301,10 @@ fn boot<'a>(
run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, fb_layout)?;
}
- gsp_falcon.reset(bar)?;
+ gsp_falcon.reset()?;
let libos_handle = gsp.libos.dma_handle();
- let (mbox0, mbox1) = gsp_falcon.boot(
- bar,
- Some(libos_handle as u32),
- Some((libos_handle >> 32) as u32),
- )?;
+ let (mbox0, mbox1) =
+ gsp_falcon.boot(Some(libos_handle as u32), Some((libos_handle >> 32) as u32))?;
dev_dbg!(dev, "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
dev_dbg!(
@@ -328,9 +318,8 @@ fn boot<'a>(
chipset,
FIRMWARE_VERSION,
sec2_falcon,
- bar,
)?
- .run(dev, bar, sec2_falcon, wpr_meta)?;
+ .run(dev, sec2_falcon, wpr_meta)?;
Ok(unload_guard)
}
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index e0850d21adca..13983d42b12b 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -133,9 +133,9 @@ pub(crate) struct GspSequencer<'a> {
/// `Bar0` for register access.
bar: Bar0<'a>,
/// SEC2 falcon for core operations.
- sec2_falcon: &'a Falcon<Sec2>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
/// GSP falcon for core operations.
- gsp_falcon: &'a Falcon<Gsp>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
/// LibOS DMA handle address.
libos_dma_handle: u64,
/// Bootloader application version.
@@ -213,16 +213,16 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
GspSeqCmd::DelayUs(cmd) => cmd.run(seq),
GspSeqCmd::RegStore(cmd) => cmd.run(seq),
GspSeqCmd::CoreReset => {
- seq.gsp_falcon.reset(seq.bar)?;
- seq.gsp_falcon.dma_reset(seq.bar);
+ seq.gsp_falcon.reset()?;
+ seq.gsp_falcon.dma_reset();
Ok(())
}
GspSeqCmd::CoreStart => {
- seq.gsp_falcon.start(seq.bar)?;
+ seq.gsp_falcon.start()?;
Ok(())
}
GspSeqCmd::CoreWaitForHalt => {
- seq.gsp_falcon.wait_till_halted(seq.bar)?;
+ seq.gsp_falcon.wait_till_halted()?;
Ok(())
}
GspSeqCmd::CoreResume => {
@@ -231,35 +231,32 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
// sequencer will start both.
// Reset the GSP to prepare it for resuming.
- seq.gsp_falcon.reset(seq.bar)?;
+ seq.gsp_falcon.reset()?;
// Write the libOS DMA handle to GSP mailboxes.
seq.gsp_falcon.write_mailboxes(
- seq.bar,
Some(seq.libos_dma_handle as u32),
Some((seq.libos_dma_handle >> 32) as u32),
);
// Start the SEC2 falcon which will trigger GSP-RM to resume on the GSP.
- seq.sec2_falcon.start(seq.bar)?;
+ seq.sec2_falcon.start()?;
// Poll until GSP-RM reload/resume has completed (up to 2 seconds).
- seq.gsp_falcon
- .check_reload_completed(seq.bar, Delta::from_secs(2))?;
+ seq.gsp_falcon.check_reload_completed(Delta::from_secs(2))?;
// Verify SEC2 completed successfully by checking its mailbox for errors.
- let mbox0 = seq.sec2_falcon.read_mailbox0(seq.bar);
+ let mbox0 = seq.sec2_falcon.read_mailbox0();
if mbox0 != 0 {
dev_err!(seq.dev, "Sequencer: sec2 errors: {:?}\n", mbox0);
return Err(EIO);
}
// Configure GSP with the bootloader version.
- seq.gsp_falcon
- .write_os_version(seq.bar, seq.bootloader_app_version);
+ seq.gsp_falcon.write_os_version(seq.bootloader_app_version);
// Verify the GSP's RISC-V core is active indicating successful GSP boot.
- if !seq.gsp_falcon.is_riscv_active(seq.bar) {
+ if !seq.gsp_falcon.is_riscv_active() {
dev_err!(seq.dev, "Sequencer: RISC-V core is not active\n");
return Err(EIO);
}
@@ -345,9 +342,9 @@ pub(crate) struct GspSequencerParams<'a> {
/// LibOS DMA handle address.
pub(crate) libos_dma_handle: u64,
/// GSP falcon for core operations.
- pub(crate) gsp_falcon: &'a Falcon<Gsp>,
+ pub(crate) gsp_falcon: &'a Falcon<'a, Gsp>,
/// SEC2 falcon for core operations.
- pub(crate) sec2_falcon: &'a Falcon<Sec2>,
+ pub(crate) sec2_falcon: &'a Falcon<'a, Sec2>,
/// Device for logging.
pub(crate) dev: &'a device::Device,
/// BAR0 for register access.
---
base-commit: 9102e655ea7285c1bc329669865ba8a38cdb69e6
change-id: 20260624-drm-bar-refactor-90435f04c9ea
Best regards,
--
Tim Kovalenko <tim.kovalenko@proton.me>
^ permalink raw reply related
* Re: [PATCH V9 02/17] iothread: introduce iothread_ref/unref to track attached devices
From: Stefan Hajnoczi @ 2026-06-24 15:51 UTC (permalink / raw)
To: Zhang Chen
Cc: qemu-devel, Dr . David Alan Gilbert, Eric Blake,
Markus Armbruster, Michael S . Tsirkin, Paolo Bonzini, Kevin Wolf,
Jason Wang, Fam Zheng
In-Reply-To: <20260624070851.13342-3-zhangckid@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 3529 bytes --]
On Wed, Jun 24, 2026 at 03:08:36PM +0800, Zhang Chen wrote:
> Currently, IOThreads do not maintain a record of which devices are
> associated with them. This makes it difficult to monitor the
> workload distribution of IOThreads, especially in complex
> hotplug scenarios involving multiple virtio-blk or virtio-scsi devices.
>
> This patch introduces a reference counting and tracking mechanism
> within the IOThread object:
>
> - iothread_ref(): Prepends the device's IOThreadHolder to a list.
> - iothread_unref(): Searches for the IOThreadHolder using a custom
> string comparison (g_strcmp0), releases the associated memory
> upon a successful match.
> - holders: A GList storing the IOThreadHolder of attached devices
> for runtime introspection.
>
> A later commit will add QMP commands to let management applications
> query the attachment status of IOThreads.
>
> Signed-off-by: Zhang Chen <zhangckid@gmail.com>
> ---
> include/system/iothread.h | 5 +++
> iothread.c | 94 +++++++++++++++++++++++++++++++++++++++
> qapi/misc.json | 61 +++++++++++++++++++++++++
> 3 files changed, 160 insertions(+)
Minor comments below. This patch looks good overall:
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> diff --git a/include/system/iothread.h b/include/system/iothread.h
> index a1ef7696cb..b9207ad829 100644
> --- a/include/system/iothread.h
> +++ b/include/system/iothread.h
> @@ -50,6 +50,11 @@ struct IOThread {
> bool stopping; /* has iothread_stop() been called? */
> bool running; /* should iothread_run() continue? */
> int thread_id;
> + /*
> + * The list elements are of type IOThreadHolder, which can
> + * represent either a QOM path or a block node name.
This comment duplicates the IOThreadHolder types and will become
outdated easily. It might already be outdated (there are 3 types, not
just the 2 mentioned in the comment). I suggest replacing it with
something like:
/* List of iothread_ref() holders (elements are of type IOThreadHolder) */
> +static int iothread_holder_compare(gconstpointer a, gconstpointer b)
> +{
> + const IOThreadHolder *holder_a = a;
> + const IOThreadHolder *holder_b = b;
> + const char *name_a, *name_b;
> +
> + if (holder_a->type != holder_b->type) {
> + return -1;
> + }
> +
> + switch (holder_a->type) {
> + case IO_THREAD_HOLDER_KIND_QOM_OBJECT:
> + name_a = holder_a->u.qom_object.qom_path;
> + name_b = holder_b->u.qom_object.qom_path;
> + break;
> + case IO_THREAD_HOLDER_KIND_BLOCK_NODE:
> + name_a = holder_a->u.block_node.node_name;
> + name_b = holder_b->u.block_node.node_name;
> + break;
> + case IO_THREAD_HOLDER_KIND_MONITOR_NAME:
> + name_a = holder_a->u.monitor_name.monitor_name;
> + name_b = holder_b->u.monitor_name.monitor_name;
> + break;
> + default:
> + /*
> + * This should not happen. If it does, name_a/b remains
> + * NULL and g_strcmp0 will handle it safely.
> + */
> + name_a = NULL;
> + name_b = NULL;
return -1 would be simpler and safer. g_strcmp0(NULL, NULL) returns 0,
so callers will think they have found a match and proceed with their
operation - it will likely result in undefined behavior since memory is
probably corrupted if we got here. It's safer to fail the comparison so
the caller does not proceed.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH bpf 2/2] selftests/bpf: Verify no non-zeroed kernel heap memory exposure
From: Leon Hwang @ 2026-06-24 15:51 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Shuah Khan, Leon Hwang, linux-kernel,
linux-kselftest, kernel-patches-bot
In-Reply-To: <20260624155115.85196-1-leon.hwang@linux.dev>
When lookup element from those per-CPU maps, which have special field
in their values and their value size is not equal to roundup(value_sz, 8),
the padding size of temporary non-zeroed kernel heap memory allocated by
kvmalloc should not be exposed to user space.
Without the fix:
test_map_uninit_mem_exposure:FAIL:zeroed tail bytes unexpected memory mismatch
actual:
2B 2B 2B 2B
expected:
00 00 00 00
Assisted-by: Codex:gpt-5.5
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
.../bpf/prog_tests/test_map_uninit.c | 68 +++++++++++++++++++
tools/testing/selftests/bpf/progs/map_kptr.c | 12 ++++
2 files changed, 80 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/test_map_uninit.c
diff --git a/tools/testing/selftests/bpf/prog_tests/test_map_uninit.c b/tools/testing/selftests/bpf/prog_tests/test_map_uninit.c
new file mode 100644
index 000000000000..d0ba2ca587b0
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/test_map_uninit.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+
+#include "map_kptr.skel.h"
+
+void test_map_uninit_mem_exposure(void)
+{
+ size_t value_sz, slot_sz, lookup_sz, tail_sz;
+ int err, key, nr_cpus, cpu, map_fd;
+ __u8 *value = NULL, *zero = NULL;
+ struct bpf_program *prog;
+ struct map_kptr *skel;
+
+ nr_cpus = libbpf_num_possible_cpus();
+ if (!ASSERT_GT(nr_cpus, 0, "libbpf_num_possible_cpus"))
+ return;
+
+ skel = map_kptr__open();
+ if (!ASSERT_OK_PTR(skel, "map_kptr__open"))
+ return;
+
+ bpf_object__for_each_program(prog, skel->obj) {
+ err = bpf_program__set_autoload(prog, false);
+ if (!ASSERT_OK(err, "bpf_program__set_autoload"))
+ goto out;
+ }
+
+ err = map_kptr__load(skel);
+ if (!ASSERT_OK(err, "map_kptr__load"))
+ goto out;
+
+ value_sz = bpf_map__value_size((skel)->maps.pcpu_array);
+ slot_sz = roundup(value_sz, 8);
+ tail_sz = slot_sz - value_sz;
+ if (!ASSERT_NEQ(tail_sz, 0, "tail_sz"))
+ goto out;
+
+ lookup_sz = slot_sz * nr_cpus;
+ map_fd = bpf_map__fd(skel->maps.pcpu_array);
+
+ value = malloc(lookup_sz);
+ zero = calloc(1, tail_sz);
+ if (!ASSERT_OK_PTR(value, "malloc value") || !ASSERT_OK_PTR(zero, "calloc zero"))
+ goto out;
+
+ key = 0;
+ memset(value, 0x2B, lookup_sz);
+ err = bpf_map_update_elem(map_fd, &key, value, BPF_ANY);
+ if (!ASSERT_OK(err, "bpf_map_update_elem"))
+ goto out;
+
+ memset(value, 0xFF, lookup_sz);
+ err = bpf_map_lookup_elem(map_fd, &key, value);
+ if (!ASSERT_OK(err, "bpf_map_lookup_elem"))
+ goto out;
+
+ for (cpu = 0; cpu < nr_cpus; cpu++) {
+ __u8 *tail = value + cpu * slot_sz + value_sz;
+
+ if (!ASSERT_MEMEQ(tail, zero, tail_sz, "zeroed tail bytes"))
+ goto out;
+ }
+
+out:
+ free(zero);
+ free(value);
+ map_kptr__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/progs/map_kptr.c b/tools/testing/selftests/bpf/progs/map_kptr.c
index 3fbefc568e0a..0d87c97dac99 100644
--- a/tools/testing/selftests/bpf/progs/map_kptr.c
+++ b/tools/testing/selftests/bpf/progs/map_kptr.c
@@ -4,6 +4,18 @@
#include <bpf/bpf_helpers.h>
#include "../test_kmods/bpf_testmod_kfunc.h"
+struct map_uninit_value {
+ struct prog_test_ref_kfunc __kptr_untrusted *unref_ptr;
+ __u32 data;
+} __attribute__((packed));
+
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, int);
+ __type(value, struct map_uninit_value);
+ __uint(max_entries, 1);
+} pcpu_array SEC(".maps");
+
struct map_value {
struct prog_test_ref_kfunc __kptr_untrusted *unref_ptr;
struct prog_test_ref_kfunc __kptr *ref_ptr;
--
2.54.0
^ permalink raw reply related
* [PATCH bpf 1/2] bpf: Copy per-CPU map value padding in copy_map_value_long()
From: Leon Hwang @ 2026-06-24 15:51 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Shuah Khan, Leon Hwang, linux-kernel,
linux-kselftest, kernel-patches-bot
In-Reply-To: <20260624155115.85196-1-leon.hwang@linux.dev>
In kernel, per-CPU map elements are stored with
round_up(map->value_size, 8) bytes. On UAPI lookup paths, it copies the
rounded size for each CPU into a temporary buffer.
However, copy_map_value_long() passes 'map->value_size' to
bpf_obj_memcpy(). When the map has special fields, bpf_obj_memcpy() copies
around those fields with memcpy(), and does not copy the tail padding
between 'map->value_size' and round_up(map->value_size, 8).
The temporary UAPI lookup buffers are allocated without __GFP_ZERO. As a
result, when the per-CPU map's value size is not equal to
round_up(map->value_size, 8), UAPI LOOKUP_ELEM and its variants can return
stale heap contents from that padding to user space. The same issue
applies to bpf_iter for per-CPU maps.
Pass round_up(map->value_size, 8) to bpf_obj_memcpy() from
copy_map_value_long(), so per-CPU maps both with and without special
fields copy the entire per-CPU slot. Remove the now redundant round_up()
from bpf_obj_memcpy()'s long_memcpy path.
Fixes: 448325199f57 ("bpf: Add copy_map_value_long to copy to remote percpu memory")
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
include/linux/bpf.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 7719f6528445..ba09795e0bfd 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -570,7 +570,7 @@ static inline void bpf_obj_memcpy(struct btf_record *rec,
if (IS_ERR_OR_NULL(rec)) {
if (long_memcpy)
- bpf_long_memcpy(dst, src, round_up(size, 8));
+ bpf_long_memcpy(dst, src, size);
else
memcpy(dst, src, size);
return;
@@ -593,7 +593,7 @@ static inline void copy_map_value(struct bpf_map *map, void *dst, void *src)
static inline void copy_map_value_long(struct bpf_map *map, void *dst, void *src)
{
- bpf_obj_memcpy(map->record, dst, src, map->value_size, true);
+ bpf_obj_memcpy(map->record, dst, src, round_up(map->value_size, 8), true);
}
static inline void bpf_obj_swap_uptrs(const struct btf_record *rec, void *dst, void *src)
--
2.54.0
^ permalink raw reply related
* Re: [Buildroot] [PATCH] package/libxkbcommon: provide xkbregistry when libxml2 is enabled
From: Romain Naour via buildroot @ 2026-06-24 15:51 UTC (permalink / raw)
To: Raphaël Gallais-Pou, buildroot; +Cc: Thomas Petazzoni
In-Reply-To: <20260527-master-v1-1-0d975f3b3f0d@gmail.com>
Hello Raphaël,
Le 27/05/2026 à 21:53, Raphaël Gallais-Pou a écrit :
> xkbregistry is disabled by default. Yet, it only needs libxml2 to be
> built, which is already supported.
>
> Add the compile flags to build xkbregistry when possible.
>
> Signed-off-by: Raphaël Gallais-Pou <rgallaispou@gmail.com>
> ---
> package/libxkbcommon/libxkbcommon.mk | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/package/libxkbcommon/libxkbcommon.mk b/package/libxkbcommon/libxkbcommon.mk
> index 21a2b937ef02..98154369b419 100644
> --- a/package/libxkbcommon/libxkbcommon.mk
> +++ b/package/libxkbcommon/libxkbcommon.mk
> @@ -12,8 +12,7 @@ LIBXKBCOMMON_CPE_ID_VENDOR = xkbcommon
> LIBXKBCOMMON_INSTALL_STAGING = YES
> LIBXKBCOMMON_DEPENDENCIES = host-bison host-flex
> LIBXKBCOMMON_CONF_OPTS = \
> - -Denable-docs=false \
> - -Denable-xkbregistry=false
xkbregistry has been disabled on purpose when libxkbcommon has been updated to
1.0.1 [1].
It seems to requires xkeyboard-config at runtime [2], can you verify?
[1]
https://gitlab.com/buildroot.org/buildroot/-/commit/1791bc30a5b19bb52366375d03e66348242ff25a
[2]
https://github.com/xkbcommon/libxkbcommon/blob/2c295b10aa87e9bd8c11954adcf7e92b031b92f9/PACKAGING#L61
Best regards,
Romain
> + -Denable-docs=false
>
> ifeq ($(BR2_PACKAGE_XORG7),y)
> LIBXKBCOMMON_CONF_OPTS += -Denable-x11=true
> @@ -22,6 +21,13 @@ else
> LIBXKBCOMMON_CONF_OPTS += -Denable-x11=false
> endif
>
> +ifeq ($(BR2_PACKAGE_LIBXML2),y)
> +LIBXKBCOMMON_CONF_OPTS += -Denable-xkbregistry=true
> +LIBXKBCOMMON_DEPENDENCIES += libxml2
> +else
> +LIBXKBCOMMON_CONF_OPTS += -Denable-xkbregistry=false
> +endif
> +
> ifeq ($(BR2_PACKAGE_LIBXKBCOMMON_TOOLS),y)
> LIBXKBCOMMON_CONF_OPTS += -Denable-tools=true
> else
>
> ---
> base-commit: 08f3757b0f2133b0ed50e1ef3d7a5a1d9c80de1c
> change-id: 20260527-master-2e5299aaa8ca
>
> Best regards,
> --
> Raphaël Gallais-Pou <rgallaispou@gmail.com>
>
> _______________________________________________
> buildroot mailing list
> buildroot@buildroot.org
> https://lists.buildroot.org/mailman/listinfo/buildroot
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply
* [PATCH bpf 0/2] bpf: Copy per-CPU map value padding in copy_map_value_long()
From: Leon Hwang @ 2026-06-24 15:51 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, John Fastabend,
Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Shuah Khan, Leon Hwang, linux-kernel,
linux-kselftest, kernel-patches-bot
Sashiko reported [1]:
This is a pre-existing issue, but does iterating over per-CPU maps expose
uninitialized kernel heap memory?
When working with per-CPU maps, temporary buffers are allocated using kmalloc
without the __GFP_ZERO flag in functions like bpf_iter_init_array_map in
kernel/bpf/arraymap.c:
kernel/bpf/arraymap.c:bpf_iter_init_array_map() {
...
value_buf = kmalloc(buf_size, GFP_USER | __GFP_NOWARN);
...
}
This is also done in kernel/bpf/hashtab.c:bpf_iter_init_hash_map().
If the map contains a BTF record, bpf_obj_memcpy in include/linux/bpf.h
explicitly stops at map->value_size instead of filling the entire rounded-up
size:
include/linux/bpf.h:bpf_obj_memcpy() {
...
memcpy(dst + curr_off, src + curr_off, size - curr_off);
...
}
This fails to overwrite the padding bytes up to round_up(map->value_size, 8).
[1] https://lore.kernel.org/bpf/20260622150844.28C551F000E9@smtp.kernel.org/
===
For example,
struct map_uninit_value {
struct prog_test_ref_kfunc __kptr_untrusted *unref_ptr;
__u32 data;
} __attribute__((packed));
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__type(key, int);
__type(value, struct map_uninit_value);
__uint(max_entries, 1);
} pcpu_array SEC(".maps");
There are 4 padding bytes in the kernel percpu_array map elements.
When lookup element from 'pcpu_array' map, for each CPU, the 4 padding
bytes memory allocated by syscall.c::map_lookup_elem():kvmalloc() could
be exposed to user space.
Without the fix, the selftest could fail with:
test_map_uninit_mem_exposure:FAIL:zeroed tail bytes unexpected memory
mismatch
actual:
2B 2B 2B 2B
expected:
00 00 00 00
Leon Hwang (2):
bpf: Copy per-CPU map value padding in copy_map_value_long()
selftests/bpf: Verify no non-zeroed kernel heap memory exposure
include/linux/bpf.h | 4 +-
.../bpf/prog_tests/test_map_uninit.c | 68 +++++++++++++++++++
tools/testing/selftests/bpf/progs/map_kptr.c | 12 ++++
3 files changed, 82 insertions(+), 2 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/test_map_uninit.c
--
2.54.0
^ permalink raw reply
* Re: [PATCH-next v5 0/6] cgroup/cpuset: Support multiple source/destination cpusets for cpuset_*attach()
From: Michal Koutný @ 2026-06-24 15:51 UTC (permalink / raw)
To: Waiman Long
Cc: Chen Ridong, Tejun Heo, Johannes Weiner, Peter Zijlstra, cgroups,
linux-kernel, Aaron Tomlin, Guopeng Zhang
In-Reply-To: <20260602023203.248077-1-longman@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 9453 bytes --]
On Mon, Jun 01, 2026 at 10:31:57PM -0400, Waiman Long <longman@redhat.com> wrote:
> Patch 6 makes the necessary changes to enable the support of multiple
> source and destination cpusets by keeping all the source and destination
> cpusets found during task iterations in two singly linked lists for
> source and destination cpusets respectively.
Thanks for looking into this!
I've played with a coding assistant and produced the following selftest
(it (expectedly) fails on my machine), feel free to include in the
series (if it validates the fix).
-- 8< --
From ed4e6cf91413bb4b64befb1c15412c8cfd205d73 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20Koutn=C3=BD?= <mkoutny@suse.com>
Date: Wed, 24 Jun 2026 16:39:30 +0200
Subject: [PATCH] selftests/cgroup: Add test for cpuset affinity on controller
disable
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add a new selftest that exposes a bug in cpuset_attach() where thread
CPU affinity is not properly updated when the cpuset controller is
disabled in a threaded cgroup hierarchy.
The test creates a threaded cgroup hierarchy with two child cgroups
(A and B) having different cpuset.cpus constraints:
- Parent: cpuset.cpus=0-1
- Child A: cpuset.cpus=0-1
- Child B: cpuset.cpus=1 (restricted to CPU 1 only)
A multithreaded process is created with threads placed in different
cgroups. When the cpuset controller is disabled on the parent, thread
affinities should be updated to match the parent's cpuset.
Expected behavior:
- thread_a affinity: {0-1} before and after (unchanged)
- thread_b affinity: {1} before, {0-1} after (expanded)
Current buggy behavior:
- thread_b affinity remains {1} after controller disable
Assisted-by: Claude:claude-sonnet-4-5
Signed-off-by: Michal Koutný <mkoutny@suse.com>
---
tools/testing/selftests/cgroup/test_cpuset.c | 243 +++++++++++++++++++
1 file changed, 243 insertions(+)
diff --git a/tools/testing/selftests/cgroup/test_cpuset.c b/tools/testing/selftests/cgroup/test_cpuset.c
index c5cf8b56ceb8f..1d72a199ca552 100644
--- a/tools/testing/selftests/cgroup/test_cpuset.c
+++ b/tools/testing/selftests/cgroup/test_cpuset.c
@@ -1,7 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <assert.h>
#include <linux/limits.h>
+#include <pthread.h>
+#include <sched.h>
#include <signal.h>
+#include <sys/syscall.h>
+#include <unistd.h>
#include "kselftest.h"
#include "cgroup_util.h"
@@ -232,6 +238,242 @@ static int test_cpuset_perms_subtree(const char *root)
return ret;
}
+static int get_cpu_affinity(cpu_set_t *mask)
+{
+ CPU_ZERO(mask);
+ return sched_getaffinity(0, sizeof(*mask), mask);
+}
+
+static int cpu_set_equal(cpu_set_t *dst, unsigned long mask)
+{
+ cpu_set_t expected;
+
+ CPU_ZERO(&expected);
+ assert(sizeof(mask) < CPU_SETSIZE);
+
+ for (int cpu = 0; cpu < sizeof(mask); ++cpu)
+ if ((1UL << cpu) & mask)
+ CPU_SET(cpu, &expected);
+
+ return CPU_EQUAL(&expected, dst);
+}
+
+enum test_phase {
+ AFFINITY_SETUP,
+ AFFINITY_THREAD_A_READY,
+ AFFINITY_THREADS_READY,
+ AFFINITY_CONTROLLER_DISABLED,
+ AFFINITY_COMPLETE,
+ AFFINITY_ERROR
+};
+
+struct thread_args {
+ const char *cgroup;
+ cpu_set_t *affinity_before;
+ cpu_set_t *affinity_after;
+ enum test_phase ready_phase;
+};
+
+static pthread_mutex_t test_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t test_cond = PTHREAD_COND_INITIALIZER;
+static enum test_phase test_phase;
+
+static void *affinity_thread_fn(void *arg)
+{
+ struct thread_args *args = (struct thread_args *)arg;
+
+ if (cg_enter_current_thread(args->cgroup))
+ goto fail;
+
+ if (get_cpu_affinity(args->affinity_before) != 0)
+ goto fail;
+
+ pthread_mutex_lock(&test_mutex);
+ if (test_phase < args->ready_phase)
+ test_phase = args->ready_phase;
+ pthread_cond_broadcast(&test_cond);
+
+ while (test_phase < AFFINITY_CONTROLLER_DISABLED)
+ pthread_cond_wait(&test_cond, &test_mutex);
+ pthread_mutex_unlock(&test_mutex);
+
+ if (get_cpu_affinity(args->affinity_after) != 0)
+ goto fail;
+
+
+ return NULL;
+
+fail:
+ pthread_mutex_lock(&test_mutex);
+ test_phase = AFFINITY_ERROR;
+ pthread_cond_broadcast(&test_cond);
+ pthread_mutex_unlock(&test_mutex);
+ return NULL;
+}
+
+/*
+ * Test that disabling cpuset controller properly updates thread affinity.
+ *
+ * This test exposes a bug in cpuset_attach() where threads in child cgroups
+ * don't get their affinity updated when the cpuset controller is disabled.
+ *
+ * Setup:
+ * - Create parent cgroup with cpuset.cpus=0-1
+ * - Create child A with cpuset.cpus=0-1
+ * - Create child B with cpuset.cpus=1
+ * - Place multithreaded process: group leader + thread_a in A, thread_b in B
+ * - Disable cpuset controller on parent
+ *
+ * Expected: thread_b's affinity should expand from {1} to {0-1}
+ * Buggy: thread_b's affinity remains {1}
+ */
+static int test_cpuset_affinity_on_controller_disable(const char *root)
+{
+ char *parent = NULL, *child_a = NULL, *child_b = NULL;
+ pthread_t thread_a, thread_b;
+ int thread_a_created = 0, thread_b_created = 0;
+ cpu_set_t affinity_a_before, affinity_a_after;
+ cpu_set_t affinity_b_before, affinity_b_after;
+ int ret = KSFT_FAIL;
+
+ parent = cg_name(root, "cpuset_affinity_test");
+ if (!parent)
+ goto cleanup;
+ if (cg_create(parent))
+ goto cleanup;
+ if (cg_write(parent, "cgroup.type", "threaded"))
+ goto cleanup;
+
+ child_a = cg_name(parent, "A");
+ if (!child_a)
+ goto cleanup;
+ if (cg_create(child_a))
+ goto cleanup;
+ if (cg_write(child_a, "cgroup.type", "threaded"))
+ goto cleanup;
+
+ child_b = cg_name(parent, "B");
+ if (!child_b)
+ goto cleanup;
+ if (cg_create(child_b))
+ goto cleanup;
+ if (cg_write(child_b, "cgroup.type", "threaded"))
+ goto cleanup;
+
+ /* Now enable cpuset controller in parent */
+ if (cg_write(parent, "cgroup.subtree_control", "+cpuset")) {
+ ret = KSFT_SKIP;
+ goto cleanup;
+ }
+
+ /* Set CPU affinity constraints */
+ if (cg_write(parent, "cpuset.cpus", "0-1"))
+ goto cleanup;
+ if (cg_write(child_a, "cpuset.cpus", "0-1"))
+ goto cleanup;
+ if (cg_write(child_b, "cpuset.cpus", "1"))
+ goto cleanup;
+
+ /* Move group leader (main thread) to child A */
+ if (cg_enter_current(child_a))
+ goto cleanup;
+
+ /* Create threads - they will move themselves to their respective cgroups */
+ test_phase = AFFINITY_SETUP;
+
+ struct thread_args args_a = {
+ .cgroup = child_a,
+ .affinity_before = &affinity_a_before,
+ .affinity_after = &affinity_a_after,
+ .ready_phase = AFFINITY_THREAD_A_READY,
+ };
+ if (pthread_create(&thread_a, NULL, affinity_thread_fn, &args_a))
+ goto cleanup;
+ thread_a_created = 1;
+
+ struct thread_args args_b = {
+ .cgroup = child_b,
+ .affinity_before = &affinity_b_before,
+ .affinity_after = &affinity_b_after,
+ .ready_phase = AFFINITY_THREADS_READY,
+ };
+ if (pthread_create(&thread_b, NULL, affinity_thread_fn, &args_b))
+ goto cleanup_threads;
+ thread_b_created = 1;
+
+ pthread_mutex_lock(&test_mutex);
+ while (test_phase < AFFINITY_THREADS_READY)
+ pthread_cond_wait(&test_cond, &test_mutex);
+
+ /* If a thread failed during setup, bail out */
+ if (test_phase == AFFINITY_ERROR) {
+ pthread_mutex_unlock(&test_mutex);
+ goto cleanup_threads;
+ }
+ pthread_mutex_unlock(&test_mutex);
+
+ if (!cpu_set_equal(&affinity_a_before, 0x3)) {
+ ksft_print_msg("FAIL: thread_a initial affinity incorrect\n");
+ goto cleanup_threads;
+ }
+
+ if (!cpu_set_equal(&affinity_b_before, 0x2)) {
+ ksft_print_msg("FAIL: thread_b initial affinity incorrect\n");
+ goto cleanup_threads;
+ }
+
+ /* Disable cpuset controller - this should trigger affinity update */
+ if (cg_write(parent, "cgroup.subtree_control", "-cpuset"))
+ goto cleanup_threads;
+
+ /* Signal threads to save their final affinity and exit */
+ pthread_mutex_lock(&test_mutex);
+ test_phase = AFFINITY_CONTROLLER_DISABLED;
+ pthread_cond_broadcast(&test_cond);
+ pthread_mutex_unlock(&test_mutex);
+
+ pthread_join(thread_a, NULL);
+ pthread_join(thread_b, NULL);
+
+ /* Verify thread affinities AFTER disabling controller */
+ if (!cpu_set_equal(&affinity_a_after, 0x3)) {
+ ksft_print_msg("FAIL: thread_a final affinity incorrect\n");
+ goto cleanup;
+ }
+
+ if (!cpu_set_equal(&affinity_b_after, 0x3)) {
+ ksft_print_msg("FAIL: thread_b affinity did not expand to {0-1}\n");
+ goto cleanup;
+ }
+
+ ret = KSFT_PASS;
+ goto cleanup;
+
+cleanup_threads:
+ pthread_mutex_lock(&test_mutex);
+ test_phase = AFFINITY_COMPLETE;
+ pthread_cond_broadcast(&test_cond);
+ pthread_mutex_unlock(&test_mutex);
+
+ if (thread_a_created)
+ pthread_join(thread_a, NULL);
+ if (thread_b_created)
+ pthread_join(thread_b, NULL);
+
+cleanup:
+ /* Move back to root before cleanup */
+ cg_enter_current(root);
+
+ cg_destroy(child_b);
+ free(child_b);
+ cg_destroy(child_a);
+ free(child_a);
+ cg_destroy(parent);
+ free(parent);
+
+ return ret;
+}
+
#define T(x) { x, #x }
struct cpuset_test {
@@ -241,6 +483,7 @@ struct cpuset_test {
T(test_cpuset_perms_object_allow),
T(test_cpuset_perms_object_deny),
T(test_cpuset_perms_subtree),
+ T(test_cpuset_affinity_on_controller_disable),
};
#undef T
--
2.54.0
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]
^ permalink raw reply related
* Re: [RFC net-next 08/15] ipxlat: add translation engine and dispatch core
From: Ralf Lici @ 2026-06-24 15:43 UTC (permalink / raw)
To: Beniamino Galvani
Cc: Toke Høiland-Jørgensen, netdev, Daniel Gröber,
Antonio Quartulli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <ajo-MgpZ8jA8YDwi@tp>
On Tue, 23 Jun 2026 10:05:06 +0200, Beniamino Galvani <bgalvani@redhat.com> wrote:
> On Mon, Jun 22, 2026 at 05:56:11PM +0200, Ralf Lici wrote:
> > While reading the BPF programs, two things stood out that would help
> > shape v2. On addressing, both implementations use a single NAT64/PLAT
> > prefix for destinations plus an explicit local_v4<>local_v6 mapping for
> > the host itself. ipxlat today maps both source and destination through
> > one RFC 6052 prefix, so this suggests v2 should probably support
> > explicit 1:1 address mappings (EAM, RFC 7757) alongside prefix
> > embedding. Is a single local mapping enough for your case, or do you
> > foresee needing several?
>
> Based on these:
>
> https://datatracker.ietf.org/doc/html/rfc6877#section-6.3
> https://www.ietf.org/archive/id/draft-ietf-v6ops-claton-14.html#name-obtaining-clat-ipv6-address
>
> there are two cases to consider for CLAT.
>
> If the node doing CLAT extends the IPv4 connectivity downstream, it
> should acquire a dedicated prefix via DHCPv6-PD for the downstream
> network, and use this prefix to generate IPv4-Embedded IPv6 Addresses
> (RFC 6052 2.2) for downlink hosts. In this case, the ipxlat device
> would need to be configured with two prefixes: one is the NAT64 prefix
> used to synthesize IPv6 destinations for IPv4 Internet addresses, and
> the other is the delegated prefix used to synthesize IPv6 source
> addresses for hosts on the downstream IPv4 network. Ideally, the
> ipxlat device should also be aware of the address range of the
> downstream IPv4 network, and check that the source addresses of
> packets belong to that network.
>
> If the node doing CLAT does not extend IPv4 connectivity downstream
> (or it does, but it also uses NAT44), the "downstream network" is
> basically just one host. The CLAT only needs to map a single
> locally-generated IPv4 address (usually in the 192.0.0.0/29 range) to
> a single SLAAC IPv6 address reserved for the CLAT. In this case, the
> ipxlat device would need to know the CLAT IPv4 address, the CLAT IPv6
> address and the NAT64 prefix.
>
> Currently, NetworkManager only uses a single IPv4 address and doesn't
> request a dedicated prefix via DHCPv6-PD for the CLAT. If it needs to
> provide downstream connectivity, it does IPv4 masquerading so that the
> traffic originates from a single IPv4 address. I think the ipxlat
> implementation should also support the delegated-prefix case, as this
> architecture is described in the standards.
>
I see. Your CLAT breakdown makes it clear that the single-prefix model
in this RFC is too narrow for v2. What I am currently thinking is to
shape the config as a far-side prefix plus an optional near-side map.
The 2 CLAT cases then can be represented roughly as:
remote-prefix6 64:ff9b::/96
local-map 192.0.0.1/32 2001:db8:1:2::1234/128
for the single-host CLAT case (which is an explicit 1:1 mapping), and:
remote-prefix6 64:ff9b::/96
local-map 192.0.2.0/24 2001:db8:100:64::/96
for the downstream/delegated-prefix case.
The idea is that remote-prefix6 is the RFC 6052 prefix used for the
NAT64/PLAT side, while local-map optionally describes the near-side
mapping. If local-map is omitted, the translator falls back to the
symmetric v1 behavior where the same RFC 6052 prefix is used for both
source and destination.
On the source-range check you mentioned: it falls out of the near-side
map for free. In the 4->6 direction the source is resolved through
local-map only, so a source outside its IPv4 domain (the /32 or the /24
above) simply has no near-side mapping and is dropped, so no separate
anti-spoofing knob should be needed. Anything broader than "is this a
valid near-side source" I'd leave to routing/nft rather than bake into
the translator.
Names and exact attribute shape are still WIP, but does this capture the
two CLAT cases you had in mind?
> > On the consumer side, is there anything in how NM models a connection
> > that would make a particular kernel model awkward to drive, e.g. needing
> > to attach to an already-managed interface, or conversely being able to
> > create and own a dedicated device? We're still settling the
> > kernel-facing model for v2, so consumer input here is genuinely
> > valuable.
>
> Any of the solutions mentioned in the thread (dedicated device,
> netfilter, LWT) would be fine from NetworkManager's point of
> view. Compared to what we are doing now, they would be a great
> simplification ;)
>
Nice, thanks for confirming!
--
Ralf Lici
Mandelbit Srl
^ permalink raw reply
* Re: [PATCH v6 6/8] Documentation: bootconfig: document build-time cmdline rendering
From: Breno Leitao @ 2026-06-24 15:50 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Andrew Morton, Nathan Chancellor, paulmck, Nicolas Schier,
Nick Desaulniers, Bill Wendling, Justin Stitt, Jonathan Corbet,
Shuah Khan, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, linux-kernel,
linux-trace-kernel, linux-kbuild, bpf, llvm, linux-doc,
kernel-team
In-Reply-To: <20260624174737.a4862dcd86f3d746b788d197@kernel.org>
On Wed, Jun 24, 2026 at 05:47:37PM +0900, Masami Hiramatsu wrote:
> On Tue, 23 Jun 2026 09:15:33 -0700
> >
> > +The option requires ``CONFIG_BOOT_CONFIG_EMBED=y``, a non-empty
> > +``CONFIG_BOOT_CONFIG_EMBED_FILE``, and an architecture that selects
> > +``CONFIG_ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG``. Currently only x86
> > +selects it; on other architectures the embedded bootconfig still works,
> > +but only through the late runtime parser.
>
> As commented by Sashiko, here we need to mention that this option requires
> CONFIG_CMDLINE to be empty. This means user can NOT set both option
> at once (This also means user doesn't have to worry about configuration
> conflicts.)
Ack! I will update.
--breno
^ permalink raw reply
* Re: [PATCH 06/27] tests/tcg/meson.build: introduce test_name
From: Alex Bennée @ 2026-06-24 15:50 UTC (permalink / raw)
To: Manos Pitsidianakis
Cc: Pierrick Bouvier, qemu-devel, Thomas Huth, Paolo Bonzini,
Daniel P . Berrangé, Philippe Mathieu-Daudé, qemu-arm,
Richard Henderson, Alexandre Iooss, Peter Maydell, Gustavo Romero
In-Reply-To: <tgemmc.ymcxyhiodn9w@linaro.org>
Manos Pitsidianakis <manos.pitsidianakis@linaro.org> writes:
> On Wed, 10 Jun 2026 00:47, Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> wrote:
>>We add possibility to duplicate a test for a given src. This allows to
>>declare several tests that still share the same executable, thus saving
>>space and compile time.
>>
>>A side note to mention that meson perfectly supports declaring several
>>tests with the same name. However, we prevent that to force dev to
>>clarify what is the intent of each individual test.
>>
>>Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
>>---
>> tests/tcg/meson.build | 14 ++++++++++----
>> 1 file changed, 10 insertions(+), 4 deletions(-)
>>
>>diff --git a/tests/tcg/meson.build b/tests/tcg/meson.build
>>index 2c6d85c586a..bb0184732fd 100644
>>--- a/tests/tcg/meson.build
>>+++ b/tests/tcg/meson.build
>>@@ -12,6 +12,7 @@ tcg_tests = {}
>> # {
>> # 'src_file': {
>> # 'exe_name': ['provide an alternative binary name'],
>>+# 'test_name': ['provide an alternative test name'],
>> # }
>> # },
>> # ...
>>@@ -21,8 +22,8 @@ tcg_tests = {}
>> #
>> # Every test executable, identified by 'exe_name' is built only once.
>> # Tests for a given src use the same executable by default, and their definition
>>-# is guaranteed to be unique also.
>>-# Default name is derived from src if 'exe_name' is omitted.
>>+# is guaranteed to be unique also. They can be duplicated by setting 'test_name'.
>
> While it's clear in the patch description, it might be a good idea to
> explain that "duplication" means using the same executable here, for
> clarity, if you respin this series.
additional versions of the test can be added by setting 'test_name'?
>
>>+# Default name is derived from src if 'exe_name' and 'test_name' are omitted.
>> # plugins come first, as we need to build the list
>> subdir('plugins')
>>@@ -51,7 +52,7 @@ foreach target, plan: tcg_tests
>> # return a clear error if user mispell a setup entry
>> foreach key, _ : setup
>> if key not in [
>>- 'exe_name',
>>+ 'exe_name', 'test_name',
>> ]
>> error('unknown tcg setup entry \'' + key + '\' for test ' + src)
>
>
> Unrelated to this patch, but you could refactor the ['exe_name',
> 'test_name'] etc key set outside and print the list of valid keys in
> the error message as well for UX.
>
>> endif
>>@@ -66,8 +67,13 @@ foreach target, plan: tcg_tests
>> exe_name = setup['exe_name']
>> endif
>> - exe_name = target + '-' + exe_name
>> test_name = exe_name
>>+ if 'test_name' in setup
>>+ test_name = setup['test_name']
>>+ endif
>>+
>>+ exe_name = target + '-' + exe_name
>>+ test_name = target + '-' + test_name
>> if test_name in added_tests
>> error('test ' + test_name + ' was already added: ' +
>> -- 2.43.0
>>
>
>
> LGTM (feel free to ignore the comments)
>
> Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply
* [PATCH v2] accel/tcg: Remove per-vCPU ignore_memory_transaction_failures flag
From: Philippe Mathieu-Daudé @ 2026-06-24 15:49 UTC (permalink / raw)
To: qemu-devel
Cc: Richard Henderson, Zhao Liu, Paolo Bonzini,
Philippe Mathieu-Daudé, Philippe Mathieu-Daudé
The %ignore_memory_transaction_failures flag is meant for legacy
machines, and is defined once per machine. It is applied to all
vCPUs such machine creates, to be eventually only used by the TCG
SoftMMU layer.
We can decouple it of the vCPU layer by making it a TCG-specific
global, setting it once when the machine is initialized (via the
per-accelerator init_machine callback), allowing to remove machine
code in the common vCPU layer.
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
accel/tcg/internal-common.h | 2 ++
include/hw/core/cpu.h | 2 --
accel/tcg/cputlb.c | 8 ++++++--
accel/tcg/tcg-all.c | 3 +++
hw/core/cpu-common.c | 15 ---------------
5 files changed, 11 insertions(+), 19 deletions(-)
diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h
index 9e7be2d78df..cd8896bafd5 100644
--- a/accel/tcg/internal-common.h
+++ b/accel/tcg/internal-common.h
@@ -21,6 +21,8 @@ extern bool one_insn_per_tb;
extern bool icount_align_option;
+extern bool tlb_ignore_memory_transaction_failures;
+
/*
* Return true if CS is not running in parallel with other cpus, either
* because there are no other cpus or we are within an exclusive context.
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 59d601465b4..72666189774 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -575,8 +575,6 @@ struct CPUState {
*/
int64_t throttle_us_per_full;
- bool ignore_memory_transaction_failures;
-
/* Used for user-only emulation of prctl(PR_SET_UNALIGN). */
bool prctl_unalign_sigbus;
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 6e66f3c6e93..9028f386965 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -90,6 +90,8 @@
*/
QEMU_BUILD_BUG_ON(sizeof(vaddr) > sizeof(run_on_cpu_data));
+bool tlb_ignore_memory_transaction_failures;
+
#define ALL_MMUIDX_BITS ((1 << NB_MMU_MODES) - 1)
static inline size_t tlb_n_entries(CPUTLBDescFast *fast)
@@ -1291,8 +1293,10 @@ static void io_failed(CPUState *cpu, CPUTLBEntryFull *full, vaddr addr,
unsigned size, MMUAccessType access_type, int mmu_idx,
MemTxResult response, uintptr_t retaddr)
{
- if (!cpu->ignore_memory_transaction_failures
- && cpu->cc->tcg_ops->do_transaction_failed) {
+ if (unlikely(tlb_ignore_memory_transaction_failures)) {
+ return;
+ }
+ if (cpu->cc->tcg_ops->do_transaction_failed) {
hwaddr physaddr = full->phys_addr | (addr & ~TARGET_PAGE_MASK);
cpu->cc->tcg_ops->do_transaction_failed(cpu, physaddr, addr, size,
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
index 8eb4a6b89e8..1b1ac0dbab6 100644
--- a/accel/tcg/tcg-all.c
+++ b/accel/tcg/tcg-all.c
@@ -107,9 +107,12 @@ static int tcg_init_machine(AccelState *as, MachineState *ms)
unsigned max_threads = 1;
#ifndef CONFIG_USER_ONLY
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
CPUClass *cc = CPU_CLASS(object_class_by_name(target_cpu_type()));
bool mttcg_supported = cc->tcg_ops->mttcg_supported;
+ tlb_ignore_memory_transaction_failures = mc->ignore_memory_transaction_failures;
+
switch (s->mttcg_enabled) {
case ON_OFF_AUTO_AUTO:
/*
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index e314f916f84..b74a39c96ac 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -32,7 +32,6 @@
#include "exec/log.h"
#include "exec/gdbstub.h"
#include "system/tcg.h"
-#include "hw/core/boards.h"
#include "hw/core/qdev-properties.h"
#include "trace.h"
#ifdef CONFIG_PLUGIN
@@ -247,20 +246,6 @@ bool cpu_exec_realizefn(CPUState *cpu, Error **errp)
static void cpu_common_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cpu = CPU(dev);
- Object *machine = qdev_get_machine();
-
- /* qdev_get_machine() can return something that's not TYPE_MACHINE
- * if this is one of the user-only emulators; in that case there's
- * no need to check the ignore_memory_transaction_failures board flag.
- */
- if (object_dynamic_cast(machine, TYPE_MACHINE)) {
- MachineClass *mc = MACHINE_GET_CLASS(machine);
-
- if (mc) {
- cpu->ignore_memory_transaction_failures =
- mc->ignore_memory_transaction_failures;
- }
- }
if (dev->hotplugged) {
cpu_synchronize_post_init(cpu);
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v2 3/5] vhost: reset vhost devices for CPR
From: Andrey Drobyshev @ 2026-06-24 15:49 UTC (permalink / raw)
To: Maciej S. Szmigiero
Cc: mst, sgarzare, farosas, qemu-devel, peterx, dongli.zhang, bchaney,
mark.kanda, den
In-Reply-To: <d258f5fc-5c67-456a-be2e-49b0c7e1f4aa@maciej.szmigiero.name>
On 6/23/26 9:27 PM, Maciej S. Szmigiero wrote:
> On 19.06.2026 12:55, Andrey Drobyshev wrote:
>> When preserving a vhost fd using CPR, call VHOST_RESET_OWNER prior to CPR
>> in old QEMU. Otherwise, new QEMU will fail when it calls VHOST_SET_OWNER
>> during vhost_dev_init.
>>
>> This patch is a rework of the change originally proposed by Steve, Ben
>> and Mark at [0].
>>
>> [0] https://lore.kernel.org/qemu-devel/20260128-cpr-tap-v4-0-48e334d4216b@akamai.com
>>
>> Originally-by: Mark Kanda <mark.kanda@oracle.com>
>> Originally-by: Steve Sistare <steven.sistare@oracle.com>
>> Originally-by: Ben Chaney <bchaney@akamai.com>
>> Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
>> ---
>> hw/virtio/vhost-kernel.c | 6 ++++++
>> hw/virtio/vhost.c | 33 +++++++++++++++++++++++++++++++
>> include/hw/virtio/vhost-backend.h | 1 +
>> include/hw/virtio/vhost.h | 1 +
>> 4 files changed, 41 insertions(+)
>>
>> diff --git a/hw/virtio/vhost-kernel.c b/hw/virtio/vhost-kernel.c
>> index 3390b48c6f1..55d316b88e9 100644
>> --- a/hw/virtio/vhost-kernel.c
>> +++ b/hw/virtio/vhost-kernel.c
>> @@ -261,6 +261,11 @@ static int vhost_kernel_set_owner(struct vhost_dev *dev)
>> return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL);
>> }
>>
>> +static int vhost_kernel_reset_owner(struct vhost_dev *dev)
>> +{
>> + return vhost_kernel_call(dev, VHOST_RESET_OWNER, NULL);
>> +}
>> +
>> static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
>> {
>> assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
>> @@ -385,6 +390,7 @@ const VhostOps kernel_ops = {
>> .vhost_get_features_ex = vhost_kernel_get_features,
>> .vhost_set_backend_cap = vhost_kernel_set_backend_cap,
>> .vhost_set_owner = vhost_kernel_set_owner,
>> + .vhost_reset_owner = vhost_kernel_reset_owner,
>> .vhost_get_vq_index = vhost_kernel_get_vq_index,
>> .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid,
>> .vhost_vsock_set_running = vhost_kernel_vsock_set_running,
>> diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
>> index af41841b529..1521b50cbff 100644
>> --- a/hw/virtio/vhost.c
>> +++ b/hw/virtio/vhost.c
>> @@ -24,6 +24,7 @@
>> #include "standard-headers/linux/vhost_types.h"
>> #include "hw/virtio/virtio-bus.h"
>> #include "hw/mem/memory-device.h"
>> +#include "migration/misc.h"
>> #include "migration/blocker.h"
>> #include "migration/qemu-file-types.h"
>> #include "system/dma.h"
>> @@ -1667,6 +1668,32 @@ static int vhost_dev_init_features(struct vhost_dev *hdev)
>> return r;
>> }
>>
>> +static int vhost_cpr_notifier(NotifierWithReturn *notifier,
>> + MigrationEvent *e, Error **errp)
>> +{
>> + struct vhost_dev *dev;
>> + int r;
>> +
>> + dev = container_of(notifier, struct vhost_dev, cpr_notifier);
>> +
>> + if (dev->vhost_ops->backend_type != VHOST_BACKEND_TYPE_KERNEL) {
>> + return 0;
>> + }
>> +
>> + if (e->type == MIG_EVENT_SETUP) {
>> + r = dev->vhost_ops->vhost_reset_owner(dev);
>> + if (r < 0) {
>> + VHOST_OPS_DEBUG(r, "vhost_reset_owner failed");
>
> Shouldn't we abort the migration attempt here?
>
Hmm yes, I think you're right. We shouldn't proceed and should do
error_setg_errno() and return r < 0 instead.
>> + }
>> + } else if (e->type == MIG_EVENT_FAILED) {
>> + r = dev->vhost_ops->vhost_set_owner(dev);
>> + if (r < 0) {
>> + VHOST_OPS_DEBUG(r, "vhost_set_owner failed");
>
> What would be the impact on the guest of this failure?
>
> Shouldn't we *at least* unconditionally print error here?
> Maybe even more if guest would be unsafe in this condition?
Agreed. Should report error as well. The only catch is we might also
get into this branch after unsuccessful qmp_migrate() -> SETUP ->
vhost_reset_owner() -> migration_connect_error_propagate() -> FAILED.
Then we'll attempt set_owner for a device whose owner we didn't reset.
So we should probably add some bool flag which would signalize whether
device has its owner currently set or not, and only attempt set_owner if
reset_owner took place.
But you got me doubtful about what can happen to the guest if on FAILED
we couldn't restore owner. Realistically enough, we can at least get
-ENOMEM during high memory pressure, which is likely to leave vsock dead.
WDYT?
>> + }
>> + }
>> + return 0;
>> +}
>> +
> Thanks,
> Maciej
>
^ permalink raw reply
* Re: [PATCH v3] dt-bindings: interrupt-controller: ti,irq-crossbar: Convert to DT schema
From: Rob Herring @ 2026-06-24 15:49 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Bhargav Joshi, simona.toaca, Krzysztof Kozlowski, m-chawdhry,
daniel.baluta, Thomas Gleixner, Sricharan R, linux-kernel,
devicetree, Conor Dooley, goledhruva
In-Reply-To: <42760292-3a29-4600-8676-6a79d3b5d7a4@kernel.org>
On Wed, Jun 24, 2026 at 6:22 AM Konrad Dybcio <konradybcio@kernel.org> wrote:
>
> On 6/15/26 11:01 PM, Rob Herring (Arm) wrote:
> >
> > On Fri, 12 Jun 2026 02:42:29 +0530, Bhargav Joshi wrote:
> >> Convert TI irq-crossbar binding from text format to DT schema.
> >>
> >> As part of conversion following changes are made:
> >> - Add '#interrupt-cells' as a required property which was missing in
> >> text binding
> >> - As irq-crossbar is interrupt-controller. Move binding from
> >> bindings/arm/omap to bindings/interrupt-controller
> >>
> >> Signed-off-by: Bhargav Joshi <j.bhargav.u@gmail.com>
> >> ---
> >> Changes in v3:
> >> - Fixed typo in property description
> >> - Link to v2: https://lore.kernel.org/r/20260611-crossbar-v2-1-231d4f88298e@gmail.com
> >>
> >> Changes in v2:
> >> - Dropped property name change and driver updates.
> >> - Link to v1: https://lore.kernel.org/r/20260606-crossbar-v1-0-f67f7cb9ee50@gmail.com
> >> ---
> >> .../devicetree/bindings/arm/omap/crossbar.txt | 55 -------------
> >> .../interrupt-controller/ti,irq-crossbar.yaml | 96 ++++++++++++++++++++++
> >> 2 files changed, 96 insertions(+), 55 deletions(-)
> >>
> >
> > Applied, thanks!
>
> With:
>
> $ dt-validate --version
> 2026.4
There is 2026.6 now which fixes this.
>
> on next-20260623
>
> I'm getting:
>
> $ LC_ALL=C make ARCH=arm64 LLVM=1 -j24 dt_binding_check
> SCHEMA Documentation/devicetree/bindings/processed-schema.json
> Traceback (most recent call last):
> File "/home/konrad/.local/bin/dt-mk-schema", line 6, in <module>
> sys.exit(main())
> ~~~~^^
> File "/home/konrad/.local/share/pipx/venvs/dtschema/lib/python3.14/site-packages/dtschema/mk_schema.py", line 28, in main
> schemas = dtschema.DTValidator(args.schemas).schemas
> ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
> File "/home/konrad/.local/share/pipx/venvs/dtschema/lib/python3.14/site-packages/dtschema/validator.py", line 399, in __init__
> self.make_property_type_cache()
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
> File "/home/konrad/.local/share/pipx/venvs/dtschema/lib/python3.14/site-packages/dtschema/validator.py", line 528, in make_property_type_cache
> self.check_duplicate_property_types()
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
> File "/home/konrad/.local/share/pipx/venvs/dtschema/lib/python3.14/site-packages/dtschema/validator.py", line 522, in check_duplicate_property_types
> print(f"{self.schemas[sch_id]['$filename']}: {p}: multiple incompatible types: {v['type']}", file=sys.stderr)
> ~~~~~~~~~~~~^^^^^^^^
> KeyError: 'http://devicetree.org/schemas/interrupt-controller/ti,irq-crossbar.yaml#'
> make[2]: *** [Documentation/devicetree/bindings/Makefile:75: Documentation/devicetree/bindings/processed-schema.json] Błąd 1
> make[2]: *** Kasuję plik 'Documentation/devicetree/bindings/processed-schema.json'
> make[1]: *** [<snip>/linux/Makefile:1672: dt_binding_schemas] Błąd 2
> make: *** [Makefile:248: __sub-make] Error 2
We should fix this to avoid the splat, but that would still be a new
tool version.
So we either need to revert this and delay adding this schema or force
people to upgrade.
Rob
^ permalink raw reply
* [PATCH] gpu: nova-core: falcon: store bar and dev in falcon
From: Tim Kovalenko @ 2026-06-24 15:49 UTC (permalink / raw)
Cc: nova-gpu, dri-devel, linux-kernel, linux-riscv, Tim Kovalenko
Store the bound device and `BAR0` mapping in `Falcon` instead of passing
them through every `Falcon` operation. This simplifies the `Falcon` API and
removes repeated `dev`/`bar` plumbing from reset, load, boot, mailbox, DMA,
and GSP/FSP-specific Falcon helpers.
Add a named helper for configuring Falcon FBIF transaction slots for
physical coherent system memory, avoiding direct `BAR0` access from the
FWSEC bootloader path without exposing BAR0 publicly.
Future work / questions:
- Focused only on the Falcon for this patch - more to follow.
- Not sure about the FalconHal and if I should modify the Trait
- Could be part of the next patch
- But it could definitively be simplified
- Also, how far should the refactor go and to what extend add new
methods to avoid passing `bar` or `dev` but also not exposing them as
pub. For `dev`, there's a lot of `dev_err` usage that requires us to
pass it as a param.
- I've created the `set_fbif_transcfg_phys_sysmem` method to
address such issue and remove some code duplication but that
method could be made a bit more generic.
- Also, is there a reason why we are not passing the `GspBootContext`
when we need stuff like `bar`, `dev` and both falcons?
Reported-by: Alexandre Courbot <acourbot@nvidia.com>
Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/509436-Nova/topic/Storing.20driver-bound.20references.20into.20sub-devices/near/599137882
Signed-off-by: Tim Kovalenko <tim.kovalenko@proton.me>
---
drivers/gpu/nova-core/falcon.rs | 206 ++++++++++-----------
drivers/gpu/nova-core/falcon/fsp.rs | 44 +++--
drivers/gpu/nova-core/falcon/gsp.rs | 21 ++-
drivers/gpu/nova-core/falcon/hal.rs | 6 +-
drivers/gpu/nova-core/falcon/hal/ga102.rs | 8 +-
drivers/gpu/nova-core/falcon/hal/tu102.rs | 6 +-
drivers/gpu/nova-core/firmware/booter.rs | 25 +--
drivers/gpu/nova-core/firmware/fwsec.rs | 19 +-
drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 33 +---
drivers/gpu/nova-core/fsp.rs | 23 ++-
drivers/gpu/nova-core/gpu.rs | 9 +-
drivers/gpu/nova-core/gsp.rs | 4 +-
drivers/gpu/nova-core/gsp/boot.rs | 22 +--
drivers/gpu/nova-core/gsp/hal.rs | 4 +-
drivers/gpu/nova-core/gsp/hal/gh100.rs | 32 ++--
drivers/gpu/nova-core/gsp/hal/tu102.rs | 75 ++++----
drivers/gpu/nova-core/gsp/sequencer.rs | 31 ++--
17 files changed, 253 insertions(+), 315 deletions(-)
diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 94c7696a6493..ca12cc11a370 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -5,10 +5,7 @@
use hal::FalconHal;
use kernel::{
- device::{
- self,
- Device, //
- },
+ device,
dma::{
Coherent,
CoherentBox,
@@ -24,7 +21,6 @@
Io,
},
prelude::*,
- sync::aref::ARef,
time::Delta,
};
@@ -358,41 +354,47 @@ pub(crate) trait FalconFirmware {
}
/// Contains the base parameters common to all Falcon instances.
-pub(crate) struct Falcon<E: FalconEngine> {
+pub(crate) struct Falcon<'a, E: FalconEngine> {
hal: KBox<dyn FalconHal<E>>,
- dev: ARef<device::Device>,
+ dev: &'a device::Device<device::Bound>,
+ bar: Bar0<'a>,
}
-impl<E: FalconEngine + 'static> Falcon<E> {
+impl<'a, E: FalconEngine + 'static> Falcon<'a, E> {
/// Create a new falcon instance.
- pub(crate) fn new(dev: &device::Device, chipset: Chipset) -> Result<Self> {
+ pub(crate) fn new(
+ dev: &'a device::Device<device::Bound>,
+ chipset: Chipset,
+ bar: Bar0<'a>,
+ ) -> Result<Self> {
Ok(Self {
hal: hal::falcon_hal(chipset)?,
- dev: dev.into(),
+ dev,
+ bar,
})
}
/// Resets DMA-related registers.
- pub(crate) fn dma_reset(&self, bar: Bar0<'_>) {
- bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
+ pub(crate) fn dma_reset(&self) {
+ self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
v.with_allow_phys_no_ctx(true)
});
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMACTL::zeroed(),
);
}
/// Reset the controller, select the falcon core, and wait for memory scrubbing to complete.
- pub(crate) fn reset(&self, bar: Bar0<'_>) -> Result {
- self.hal.reset_eng(bar)?;
- self.hal.select_core(self, bar)?;
- self.hal.reset_wait_mem_scrubbing(bar)?;
+ pub(crate) fn reset(&self) -> Result {
+ self.hal.reset_eng(self.bar)?;
+ self.hal.select_core(self, self.bar)?;
+ self.hal.reset_wait_mem_scrubbing(self.bar)?;
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
- regs::NV_PFALCON_FALCON_RM::from(bar.read(regs::NV_PMC_BOOT_0).into_raw()),
+ regs::NV_PFALCON_FALCON_RM::from(self.bar.read(regs::NV_PMC_BOOT_0).into_raw()),
);
Ok(())
@@ -404,18 +406,14 @@ pub(crate) fn reset(&self, bar: Bar0<'_>) -> Result {
/// Write a slice to Falcon IMEM memory using programmed I/O (PIO).
///
/// Returns `EINVAL` if `img.len()` is not a multiple of 4.
- fn pio_wr_imem_slice(
- &self,
- bar: Bar0<'_>,
- load_offsets: FalconPioImemLoadTarget<'_>,
- ) -> Result {
+ fn pio_wr_imem_slice(&self, load_offsets: FalconPioImemLoadTarget<'_>) -> Result {
// Rejecting misaligned images here allows us to avoid checking
// inside the loops.
if load_offsets.data.len() % 4 != 0 {
return Err(EINVAL);
}
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMC::zeroed()
.with_secure(load_offsets.secure)
@@ -426,13 +424,13 @@ fn pio_wr_imem_slice(
for (n, block) in load_offsets.data.chunks(MEM_BLOCK_ALIGNMENT).enumerate() {
let n = u16::try_from(n)?;
let tag: u16 = load_offsets.start_tag.checked_add(n).ok_or(ERANGE)?;
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMT::zeroed().with_tag(tag),
);
for word in block.chunks_exact(4) {
let w = [word[0], word[1], word[2], word[3]];
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMD::zeroed().with_data(u32::from_le_bytes(w)),
);
@@ -445,18 +443,14 @@ fn pio_wr_imem_slice(
/// Write a slice to Falcon DMEM memory using programmed I/O (PIO).
///
/// Returns `EINVAL` if `img.len()` is not a multiple of 4.
- fn pio_wr_dmem_slice(
- &self,
- bar: Bar0<'_>,
- load_offsets: FalconPioDmemLoadTarget<'_>,
- ) -> Result {
+ fn pio_wr_dmem_slice(&self, load_offsets: FalconPioDmemLoadTarget<'_>) -> Result {
// Rejecting misaligned images here allows us to avoid checking
// inside the loops.
if load_offsets.data.len() % 4 != 0 {
return Err(EINVAL);
}
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_DMEMC::zeroed()
.with_aincw(true)
@@ -465,7 +459,7 @@ fn pio_wr_dmem_slice(
for word in load_offsets.data.chunks_exact(4) {
let w = [word[0], word[1], word[2], word[3]];
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_DMEMD::zeroed().with_data(u32::from_le_bytes(w)),
);
@@ -477,29 +471,28 @@ fn pio_wr_dmem_slice(
/// Perform a PIO copy into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
pub(crate) fn pio_load<F: FalconFirmware<Target = E> + FalconPioLoadable>(
&self,
- bar: Bar0<'_>,
fw: &F,
) -> Result {
- bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
+ self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
v.with_allow_phys_no_ctx(true)
});
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMACTL::zeroed(),
);
if let Some(imem_ns) = fw.imem_ns_load_params() {
- self.pio_wr_imem_slice(bar, imem_ns)?;
+ self.pio_wr_imem_slice(imem_ns)?;
}
if let Some(imem_sec) = fw.imem_sec_load_params() {
- self.pio_wr_imem_slice(bar, imem_sec)?;
+ self.pio_wr_imem_slice(imem_sec)?;
}
- self.pio_wr_dmem_slice(bar, fw.dmem_load_params())?;
+ self.pio_wr_dmem_slice(fw.dmem_load_params())?;
- self.hal.program_brom(self, bar, &fw.brom_params());
+ self.hal.program_brom(self, self.bar, &fw.brom_params());
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()),
);
@@ -513,7 +506,6 @@ pub(crate) fn pio_load<F: FalconFirmware<Target = E> + FalconPioLoadable>(
/// `sec` is set if the loaded firmware is expected to run in secure mode.
fn dma_wr(
&self,
- bar: Bar0<'_>,
dma_obj: &Coherent<[u8]>,
target_mem: FalconMem,
load_offsets: FalconDmaLoadTarget,
@@ -571,7 +563,7 @@ fn dma_wr(
// Set up the base source DMA address.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_base(
// CAST: `as u32` is used on purpose since we do want to strip the upper bits,
@@ -579,7 +571,7 @@ fn dma_wr(
(dma_start >> 8) as u32,
),
);
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed().try_with_base(dma_start >> 40)?,
);
@@ -590,23 +582,23 @@ fn dma_wr(
for pos in (0..num_transfers).map(|i| i * DMA_LEN) {
// Perform a transfer of size `DMA_LEN`.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed()
.try_with_offs(load_offsets.dst_start + pos)?,
);
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(src_start + pos),
);
- bar.write(WithBase::of::<E>(), cmd);
+ self.bar.write(WithBase::of::<E>(), cmd);
// Wait for the transfer to complete.
// TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories
// should ever take that long.
read_poll_timeout(
- || Ok(bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())),
+ || Ok(self.bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())),
|r| r.idle(),
Delta::ZERO,
Delta::from_secs(2),
@@ -617,12 +609,7 @@ fn dma_wr(
}
/// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
- fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
- &self,
- dev: &Device<device::Bound>,
- bar: Bar0<'_>,
- fw: &F,
- ) -> Result {
+ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
// DMA object with firmware content as the source of the DMA engine.
let dma_obj = {
let fw_slice = fw.as_slice();
@@ -630,7 +617,7 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
// DMA copies are done in chunks of `MEM_BLOCK_ALIGNMENT`, so pad the length
// accordingly and fill with `0`.
let mut dma_obj = CoherentBox::zeroed_slice(
- dev,
+ self.dev,
fw_slice.len().next_multiple_of(MEM_BLOCK_ALIGNMENT),
GFP_KERNEL,
)?;
@@ -642,24 +629,16 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
dma_obj.into()
};
- self.dma_reset(bar);
- bar.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| {
- v.with_target(FalconFbifTarget::CoherentSysmem)
- .with_mem_type(FalconFbifMemType::Physical)
- });
+ self.dma_reset();
+ self.set_fbif_transcfg_phys_sysmem(0)?;
- self.dma_wr(
- bar,
- &dma_obj,
- FalconMem::ImemSecure,
- fw.imem_sec_load_params(),
- )?;
- self.dma_wr(bar, &dma_obj, FalconMem::Dmem, fw.dmem_load_params())?;
+ self.dma_wr(&dma_obj, FalconMem::ImemSecure, fw.imem_sec_load_params())?;
+ self.dma_wr(&dma_obj, FalconMem::Dmem, fw.dmem_load_params())?;
- self.hal.program_brom(self, bar, &fw.brom_params());
+ self.hal.program_brom(self, self.bar, &fw.brom_params());
// Set `BootVec` to start of non-secure code.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()),
);
@@ -667,11 +646,26 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
Ok(())
}
+ /// Configure a Falcon FBIF transaction slot to access physical coherent system memory.
+ pub(crate) fn set_fbif_transcfg_phys_sysmem(&self, dmaidx: u32) -> Result {
+ self.bar.update(
+ regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>()
+ .try_at(usize::from_safe_cast(dmaidx))
+ .ok_or(EINVAL)?,
+ |v| {
+ v.with_target(FalconFbifTarget::CoherentSysmem)
+ .with_mem_type(FalconFbifMemType::Physical)
+ },
+ );
+
+ Ok(())
+ }
+
/// Wait until the falcon CPU is halted.
- pub(crate) fn wait_till_halted(&self, bar: Bar0<'_>) -> Result<()> {
+ pub(crate) fn wait_till_halted(&self) -> Result<()> {
// TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds.
read_poll_timeout(
- || Ok(bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())),
+ || Ok(self.bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())),
|r| r.halted(),
Delta::ZERO,
Delta::from_secs(2),
@@ -681,16 +675,17 @@ pub(crate) fn wait_till_halted(&self, bar: Bar0<'_>) -> Result<()> {
}
/// Start the falcon CPU.
- pub(crate) fn start(&self, bar: Bar0<'_>) -> Result<()> {
- match bar
+ pub(crate) fn start(&self) -> Result<()> {
+ match self
+ .bar
.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())
.alias_en()
{
- true => bar.write(
+ true => self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed().with_startcpu(true),
),
- false => bar.write(
+ false => self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_CPUCTL::zeroed().with_startcpu(true),
),
@@ -700,16 +695,16 @@ pub(crate) fn start(&self, bar: Bar0<'_>) -> Result<()> {
}
/// Writes values to the mailbox registers if provided.
- pub(crate) fn write_mailboxes(&self, bar: Bar0<'_>, mbox0: Option<u32>, mbox1: Option<u32>) {
+ pub(crate) fn write_mailboxes(&self, mbox0: Option<u32>, mbox1: Option<u32>) {
if let Some(mbox0) = mbox0 {
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_MAILBOX0::zeroed().with_value(mbox0),
);
}
if let Some(mbox1) = mbox1 {
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_MAILBOX1::zeroed().with_value(mbox1),
);
@@ -717,21 +712,23 @@ pub(crate) fn write_mailboxes(&self, bar: Bar0<'_>, mbox0: Option<u32>, mbox1: O
}
/// Reads the value from `mbox0` register.
- pub(crate) fn read_mailbox0(&self, bar: Bar0<'_>) -> u32 {
- bar.read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>())
+ pub(crate) fn read_mailbox0(&self) -> u32 {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>())
.value()
}
/// Reads the value from `mbox1` register.
- pub(crate) fn read_mailbox1(&self, bar: Bar0<'_>) -> u32 {
- bar.read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>())
+ pub(crate) fn read_mailbox1(&self) -> u32 {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>())
.value()
}
/// Reads values from both mailbox registers.
- pub(crate) fn read_mailboxes(&self, bar: Bar0<'_>) -> (u32, u32) {
- let mbox0 = self.read_mailbox0(bar);
- let mbox1 = self.read_mailbox1(bar);
+ pub(crate) fn read_mailboxes(&self) -> (u32, u32) {
+ let mbox0 = self.read_mailbox0();
+ let mbox1 = self.read_mailbox1();
(mbox0, mbox1)
}
@@ -743,54 +740,43 @@ pub(crate) fn read_mailboxes(&self, bar: Bar0<'_>) -> (u32, u32) {
///
/// Wait up to two seconds for the firmware to complete, and return its exit status read from
/// the `MBOX0` and `MBOX1` registers.
- pub(crate) fn boot(
- &self,
- bar: Bar0<'_>,
- mbox0: Option<u32>,
- mbox1: Option<u32>,
- ) -> Result<(u32, u32)> {
- self.write_mailboxes(bar, mbox0, mbox1);
- self.start(bar)?;
- self.wait_till_halted(bar)?;
- Ok(self.read_mailboxes(bar))
+ pub(crate) fn boot(&self, mbox0: Option<u32>, mbox1: Option<u32>) -> Result<(u32, u32)> {
+ self.write_mailboxes(mbox0, mbox1);
+ self.start()?;
+ self.wait_till_halted()?;
+ Ok(self.read_mailboxes())
}
/// Returns the fused version of the signature to use in order to run a HS firmware on this
/// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header.
pub(crate) fn signature_reg_fuse_version(
&self,
- bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32> {
self.hal
- .signature_reg_fuse_version(self, bar, engine_id_mask, ucode_id)
+ .signature_reg_fuse_version(self, self.bar, engine_id_mask, ucode_id)
}
/// Check if the RISC-V core is active.
///
/// Returns `true` if the RISC-V core is active, `false` otherwise.
- pub(crate) fn is_riscv_active(&self, bar: Bar0<'_>) -> bool {
- self.hal.is_riscv_active(bar)
+ pub(crate) fn is_riscv_active(&self) -> bool {
+ self.hal.is_riscv_active(self.bar)
}
/// Load a firmware image into Falcon memory, using the preferred method for the current
/// chipset.
- pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
- &self,
- dev: &Device<device::Bound>,
- bar: Bar0<'_>,
- fw: &F,
- ) -> Result {
+ pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
match self.hal.load_method() {
- LoadMethod::Dma => self.dma_load(dev, bar, fw),
- LoadMethod::Pio => self.pio_load(bar, &fw.try_as_pio_loadable()?),
+ LoadMethod::Dma => self.dma_load(fw),
+ LoadMethod::Pio => self.pio_load(&fw.try_as_pio_loadable()?),
}
}
/// Write the application version to the OS register.
- pub(crate) fn write_os_version(&self, bar: Bar0<'_>, app_version: u32) {
- bar.write(
+ pub(crate) fn write_os_version(&self, app_version: u32) {
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_OS::zeroed().with_value(app_version),
);
diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs
index 52cdb84ef0e8..53b1079843ae 100644
--- a/drivers/gpu/nova-core/falcon/fsp.rs
+++ b/drivers/gpu/nova-core/falcon/fsp.rs
@@ -21,7 +21,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
Falcon,
FalconEngine,
@@ -48,18 +47,18 @@ impl RegisterBase<PFalcon2Base> for Fsp {
impl FalconEngine for Fsp {}
-impl Falcon<Fsp> {
+impl<'a> Falcon<'a, Fsp> {
/// Writes `data` to FSP external memory at offset `0`.
///
/// `data` is interpreted as little-endian 32-bit words. Returns `EINVAL`
/// if the `data` length is not 4-byte aligned.
- fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
+ fn write_emem(&mut self, data: &[u8]) -> Result {
if data.len() % 4 != 0 {
return Err(EINVAL);
}
// Begin a write burst at offset `0`, auto-incrementing on each write.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincw(true),
);
@@ -68,7 +67,7 @@ fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
let value = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
// Write the next 32-bit `value`; hardware advances the offset.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMD::zeroed().with_data(value),
);
@@ -81,20 +80,23 @@ fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
///
/// `data` is stored as little-endian 32-bit words. Returns `EINVAL` if
/// the `data` length is not 4-byte aligned.
- fn read_emem(&mut self, bar: Bar0<'_>, data: &mut [u8]) -> Result {
+ fn read_emem(&mut self, data: &mut [u8]) -> Result {
if data.len() % 4 != 0 {
return Err(EINVAL);
}
// Begin a read burst at offset `0`, auto-incrementing on each read.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincr(true),
);
for chunk in data.chunks_exact_mut(4) {
// Read the next 32-bit word; hardware advances the offset.
- let value = bar.read(regs::NV_PFALCON_FALCON_EMEMD::of::<Fsp>()).data();
+ let value = self
+ .bar
+ .read(regs::NV_PFALCON_FALCON_EMEMD::of::<Fsp>())
+ .data();
chunk.copy_from_slice(&value.to_le_bytes());
}
@@ -107,9 +109,9 @@ fn read_emem(&mut self, bar: Bar0<'_>, data: &mut [u8]) -> Result {
///
/// The FSP message queue is not circular. Pointers are reset to 0 after each
/// message exchange, so `tail >= head` is always true when data is present.
- fn poll_msgq(&self, bar: Bar0<'_>) -> u32 {
- let head = bar.read(regs::NV_PFSP_MSGQ_HEAD::at(0)).val();
- let tail = bar.read(regs::NV_PFSP_MSGQ_TAIL::at(0)).val();
+ fn poll_msgq(&self) -> u32 {
+ let head = self.bar.read(regs::NV_PFSP_MSGQ_HEAD::at(0)).val();
+ let tail = self.bar.read(regs::NV_PFSP_MSGQ_TAIL::at(0)).val();
if head == tail {
return 0;
@@ -122,20 +124,20 @@ fn poll_msgq(&self, bar: Bar0<'_>) -> u32 {
/// Writes `packet` to FSP EMEM and updates the queue pointers to notify FSP.
///
/// Returns `EINVAL` if `packet` is empty or its length is not 4-byte aligned.
- pub(crate) fn send_msg(&mut self, bar: Bar0<'_>, packet: &[u8]) -> Result {
+ pub(crate) fn send_msg(&mut self, packet: &[u8]) -> Result {
if packet.is_empty() {
return Err(EINVAL);
}
- self.write_emem(bar, packet)?;
+ self.write_emem(packet)?;
// Update queue pointers. TAIL points at the last DWORD written.
let tail_offset = u32::try_from(packet.len() - 4).map_err(|_| EINVAL)?;
- bar.write(
+ self.bar.write(
Array::at(0),
regs::NV_PFSP_QUEUE_TAIL::zeroed().with_address(tail_offset),
);
- bar.write(
+ self.bar.write(
Array::at(0),
regs::NV_PFSP_QUEUE_HEAD::zeroed().with_address(0),
);
@@ -148,9 +150,9 @@ pub(crate) fn send_msg(&mut self, bar: Bar0<'_>, packet: &[u8]) -> Result {
///
/// Returns `ETIMEDOUT` if no message was available until timeout, or a regular error code if a
/// memory allocation error occurred.
- pub(crate) fn recv_msg(&mut self, bar: Bar0<'_>) -> Result<KVec<u8>> {
+ pub(crate) fn recv_msg(&mut self) -> Result<KVec<u8>> {
let msg_size = read_poll_timeout(
- || Ok(self.poll_msgq(bar)),
+ || Ok(self.poll_msgq()),
|&size| size > 0,
Delta::from_millis(10),
Delta::from_millis(FSP_MSG_TIMEOUT_MS),
@@ -160,11 +162,13 @@ pub(crate) fn recv_msg(&mut self, bar: Bar0<'_>) -> Result<KVec<u8>> {
let mut buffer = KVec::<u8>::new();
buffer.resize(msg_size, 0, GFP_KERNEL)?;
- self.read_emem(bar, &mut buffer)?;
+ self.read_emem(&mut buffer)?;
// Reset message queue pointers after reading.
- bar.write(Array::at(0), regs::NV_PFSP_MSGQ_TAIL::zeroed().with_val(0));
- bar.write(Array::at(0), regs::NV_PFSP_MSGQ_HEAD::zeroed().with_val(0));
+ self.bar
+ .write(Array::at(0), regs::NV_PFSP_MSGQ_TAIL::zeroed().with_val(0));
+ self.bar
+ .write(Array::at(0), regs::NV_PFSP_MSGQ_HEAD::zeroed().with_val(0));
Ok(buffer)
}
diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/falcon/gsp.rs
index f788b87bd951..ae32f401aeb0 100644
--- a/drivers/gpu/nova-core/falcon/gsp.rs
+++ b/drivers/gpu/nova-core/falcon/gsp.rs
@@ -14,7 +14,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
Falcon,
FalconEngine,
@@ -37,20 +36,20 @@ impl RegisterBase<PFalcon2Base> for Gsp {
impl FalconEngine for Gsp {}
-impl Falcon<Gsp> {
+impl<'a> Falcon<'a, Gsp> {
/// Clears the SWGEN0 bit in the Falcon's IRQ status clear register to
/// allow GSP to signal CPU for processing new messages in message queue.
- pub(crate) fn clear_swgen0_intr(&self, bar: Bar0<'_>) {
- bar.write(
+ pub(crate) fn clear_swgen0_intr(&self) {
+ self.bar.write(
WithBase::of::<Gsp>(),
regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true),
);
}
/// Checks if GSP reload/resume has completed during the boot process.
- pub(crate) fn check_reload_completed(&self, bar: Bar0<'_>, timeout: Delta) -> Result<bool> {
+ pub(crate) fn check_reload_completed(&self, timeout: Delta) -> Result<bool> {
read_poll_timeout(
- || Ok(bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)),
+ || Ok(self.bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)),
|val| val.boot_stage_3_handoff(),
Delta::ZERO,
timeout,
@@ -59,19 +58,21 @@ pub(crate) fn check_reload_completed(&self, bar: Bar0<'_>, timeout: Delta) -> Re
}
/// Returns whether the RISC-V branch privilege lockdown bit is set.
- pub(crate) fn riscv_branch_privilege_lockdown(&self, bar: Bar0<'_>) -> bool {
- bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
+ pub(crate) fn riscv_branch_privilege_lockdown(&self) -> bool {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
.riscv_br_priv_lockdown()
}
/// Returns whether GSP registers can be read by the CPU.
- pub(crate) fn priv_target_mask_released(&self, bar: Bar0<'_>) -> bool {
+ pub(crate) fn priv_target_mask_released(&self) -> bool {
/// Pattern returned by GSP register reads while the PRIV target mask still blocks CPU
/// access. The low byte varies; the upper 24 bits are fixed.
const LOCKED_PATTERN: u32 = 0xbadf_4100;
const LOCKED_MASK: u32 = 0xffff_ff00;
- let hwcfg2 = bar
+ let hwcfg2 = self
+ .bar
.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
.into_raw();
diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/falcon/hal.rs
index 89b56823906b..0cb665162c90 100644
--- a/drivers/gpu/nova-core/falcon/hal.rs
+++ b/drivers/gpu/nova-core/falcon/hal.rs
@@ -34,7 +34,7 @@ pub(crate) enum LoadMethod {
/// registers.
pub(crate) trait FalconHal<E: FalconEngine>: Send + Sync {
/// Activates the Falcon core if the engine is a risvc/falcon dual engine.
- fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>) -> Result {
Ok(())
}
@@ -42,14 +42,14 @@ fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
/// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header.
fn signature_reg_fuse_version(
&self,
- falcon: &Falcon<E>,
+ falcon: &Falcon<'_, E>,
bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32>;
/// Program the boot ROM registers prior to starting a secure firmware.
- fn program_brom(&self, falcon: &Falcon<E>, bar: Bar0<'_>, params: &FalconBromParams);
+ fn program_brom(&self, falcon: &Falcon<'_, E>, bar: Bar0<'_>, params: &FalconBromParams);
/// Check if the RISC-V core is active.
/// Returns `true` if the RISC-V core is active, `false` otherwise.
diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs
index cf6ce47e6b25..e45adb0312c0 100644
--- a/drivers/gpu/nova-core/falcon/hal/ga102.rs
+++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs
@@ -115,21 +115,21 @@ pub(super) fn new() -> Self {
}
impl<E: FalconEngine> FalconHal<E> for Ga102<E> {
- fn select_core(&self, _falcon: &Falcon<E>, bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, bar: Bar0<'_>) -> Result {
select_core_ga102::<E>(bar)
}
fn signature_reg_fuse_version(
&self,
- falcon: &Falcon<E>,
+ falcon: &Falcon<'_, E>,
bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32> {
- signature_reg_fuse_version_ga102(&falcon.dev, bar, engine_id_mask, ucode_id)
+ signature_reg_fuse_version_ga102(falcon.dev, bar, engine_id_mask, ucode_id)
}
- fn program_brom(&self, _falcon: &Falcon<E>, bar: Bar0<'_>, params: &FalconBromParams) {
+ fn program_brom(&self, _falcon: &Falcon<'_, E>, bar: Bar0<'_>, params: &FalconBromParams) {
program_brom_ga102::<E>(bar, params);
}
diff --git a/drivers/gpu/nova-core/falcon/hal/tu102.rs b/drivers/gpu/nova-core/falcon/hal/tu102.rs
index 3aaee3869312..de48ded45bbe 100644
--- a/drivers/gpu/nova-core/falcon/hal/tu102.rs
+++ b/drivers/gpu/nova-core/falcon/hal/tu102.rs
@@ -34,13 +34,13 @@ pub(super) fn new() -> Self {
}
impl<E: FalconEngine> FalconHal<E> for Tu102<E> {
- fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>) -> Result {
Ok(())
}
fn signature_reg_fuse_version(
&self,
- _falcon: &Falcon<E>,
+ _falcon: &Falcon<'_, E>,
_bar: Bar0<'_>,
_engine_id_mask: u16,
_ucode_id: u8,
@@ -48,7 +48,7 @@ fn signature_reg_fuse_version(
Ok(0)
}
- fn program_brom(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>, _params: &FalconBromParams) {}
+ fn program_brom(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>, _params: &FalconBromParams) {}
fn is_riscv_active(&self, bar: Bar0<'_>) -> bool {
bar.read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::of::<E>())
diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs
index d9313ac361af..acb7f4d8a532 100644
--- a/drivers/gpu/nova-core/firmware/booter.rs
+++ b/drivers/gpu/nova-core/firmware/booter.rs
@@ -15,7 +15,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
sec2::Sec2,
Falcon,
@@ -293,8 +292,7 @@ pub(crate) fn new(
kind: BooterKind,
chipset: Chipset,
ver: &str,
- falcon: &Falcon<<Self as FalconFirmware>::Target>,
- bar: Bar0<'_>,
+ falcon: &Falcon<'_, <Self as FalconFirmware>::Target>,
) -> Result<Self> {
let fw_name = match kind {
BooterKind::Loader => "booter_load",
@@ -339,11 +337,8 @@ pub(crate) fn new(
} else {
// Obtain the version from the fuse register, and extract the corresponding
// signature.
- let reg_fuse_version = falcon.signature_reg_fuse_version(
- bar,
- brom_params.engine_id_mask,
- brom_params.ucode_id,
- )?;
+ let reg_fuse_version = falcon
+ .signature_reg_fuse_version(brom_params.engine_id_mask, brom_params.ucode_id)?;
// `0` means the last signature should be used.
const FUSE_VERSION_USE_LAST_SIG: u32 = 0;
@@ -405,18 +400,14 @@ pub(crate) fn new(
pub(crate) fn run<T>(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- sec2_falcon: &Falcon<Sec2>,
+ sec2_falcon: &Falcon<'_, Sec2>,
wpr_meta: &Coherent<T>,
) -> Result {
- sec2_falcon.reset(bar)?;
- sec2_falcon.load(dev, bar, self)?;
+ sec2_falcon.reset()?;
+ sec2_falcon.load(self)?;
let wpr_handle = wpr_meta.dma_handle();
- let (mbox0, mbox1) = sec2_falcon.boot(
- bar,
- Some(wpr_handle as u32),
- Some((wpr_handle >> 32) as u32),
- )?;
+ let (mbox0, mbox1) =
+ sec2_falcon.boot(Some(wpr_handle as u32), Some((wpr_handle >> 32) as u32))?;
dev_dbg!(dev, "SEC2 MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
if mbox0 != 0 {
diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs
index 199ae2adb664..95e0dd77746b 100644
--- a/drivers/gpu/nova-core/firmware/fwsec.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec.rs
@@ -27,7 +27,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
gsp::Gsp,
Falcon,
@@ -320,8 +319,7 @@ impl FwsecFirmware {
/// command.
pub(crate) fn new(
dev: &Device<device::Bound>,
- falcon: &Falcon<Gsp>,
- bar: Bar0<'_>,
+ falcon: &Falcon<'_, Gsp>,
bios: &Vbios,
cmd: FwsecCommand,
) -> Result<Self> {
@@ -337,7 +335,7 @@ pub(crate) fn new(
.ok_or(EINVAL)?;
let desc_sig_versions = u32::from(desc.signature_versions());
let reg_fuse_version =
- falcon.signature_reg_fuse_version(bar, desc.engine_id_mask(), desc.ucode_id())?;
+ falcon.signature_reg_fuse_version(desc.engine_id_mask(), desc.ucode_id())?;
dev_dbg!(
dev,
"desc_sig_versions: {:#x}, reg_fuse_version: {}\n",
@@ -390,21 +388,16 @@ pub(crate) fn new(
/// This must only be called on chipsets that do not need the FWSEC bootloader (i.e., where
/// [`Chipset::needs_fwsec_bootloader()`](crate::gpu::Chipset::needs_fwsec_bootloader) returns
/// `false`). On chipsets that do, use [`bootloader::FwsecFirmwareWithBl`] instead.
- pub(crate) fn run(
- &self,
- dev: &Device<device::Bound>,
- falcon: &Falcon<Gsp>,
- bar: Bar0<'_>,
- ) -> Result<()> {
+ pub(crate) fn run(&self, dev: &Device<device::Bound>, falcon: &Falcon<'_, Gsp>) -> Result<()> {
// Reset falcon, load the firmware, and run it.
falcon
- .reset(bar)
+ .reset()
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
falcon
- .load(dev, bar, self)
+ .load(self)
.inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;
let (mbox0, _) = falcon
- .boot(bar, Some(0), None)
+ .boot(Some(0), None)
.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);
diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
index ac1558a83b83..71f5a70a1114 100644
--- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
@@ -12,10 +12,6 @@
Device, //
},
dma::Coherent,
- io::{
- register::WithBase, //
- Io,
- },
prelude::*,
ptr::{
Alignable,
@@ -29,15 +25,12 @@
};
use crate::{
- driver::Bar0,
falcon::{
self,
gsp::Gsp,
Falcon,
FalconBromParams,
FalconDmaLoadable,
- FalconFbifMemType,
- FalconFbifTarget,
FalconFirmware,
FalconPioDmemLoadTarget,
FalconPioImemLoadTarget,
@@ -50,8 +43,7 @@
FIRMWARE_VERSION, //
},
gpu::Chipset,
- num::FromSafeCast,
- regs,
+ num::FromSafeCast, //
};
/// Descriptor used by RM to figure out the requirements of the boot loader.
@@ -275,33 +267,20 @@ 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>,
- bar: Bar0<'_>,
- ) -> Result<()> {
+ pub(crate) fn run(&self, dev: &Device<device::Bound>, falcon: &Falcon<'_, Gsp>) -> Result<()> {
// Reset falcon, load the firmware, and run it.
falcon
- .reset(bar)
+ .reset()
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
falcon
- .pio_load(bar, self)
+ .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.
- bar.update(
- regs::NV_PFALCON_FBIF_TRANSCFG::of::<Gsp>()
- .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)
- },
- );
+ falcon.set_fbif_transcfg_phys_sysmem(self.dmem_desc.ctx_dma)?;
let (mbox0, _) = falcon
- .boot(bar, Some(0), None)
+ .boot(Some(0), None)
.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);
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index 4b97d1fb505e..574e1627e63c 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -224,27 +224,27 @@ pub(crate) fn boot_params_dma_handle(&self) -> u64 {
/// An `Fsp` is produced by [`Fsp::wait_secure_boot`], which only returns once FSP secure boot
/// has completed. It owns the FSP falcon and the FMC firmware, which are used for the subsequent
/// Chain of Trust boot.
-pub(crate) struct Fsp {
- falcon: Falcon<FspEngine>,
+pub(crate) struct Fsp<'a> {
+ falcon: Falcon<'a, FspEngine>,
fsp_fw: FspFirmware,
}
-impl Fsp {
+impl<'a> Fsp<'a> {
/// Waits for FSP secure boot completion, then returns the [`Fsp`] interface.
///
/// Polls the thermal scratch register until FSP signals boot completion or the timeout
/// elapses. Returning an [`Fsp`] only on success guarantees, at the API level, that the
/// interface is not used before secure boot has completed.
pub(crate) fn wait_secure_boot(
- dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
+ dev: &'a device::Device<device::Bound>,
+ bar: Bar0<'a>,
chipset: Chipset,
- ) -> Result<Fsp> {
+ ) -> Result<Fsp<'a>> {
/// FSP secure boot completion timeout in milliseconds.
const FSP_SECURE_BOOT_TIMEOUT_MS: i64 = 5000;
let hal = hal::fsp_hal(chipset).ok_or(ENOTSUPP)?;
- let falcon = Falcon::<FspEngine>::new(dev, chipset)?;
+ let falcon = Falcon::<FspEngine>::new(dev, chipset, bar)?;
let fsp_fw = FspFirmware::new(dev, chipset, FIRMWARE_VERSION)?;
read_poll_timeout(
@@ -262,13 +262,13 @@ pub(crate) fn wait_secure_boot(
/// Sends a message to FSP and waits for the response.
/// Returns the full response buffer on success.
- fn send_sync_fsp<M>(&mut self, dev: &device::Device, bar: Bar0<'_>, msg: &M) -> Result<KVec<u8>>
+ fn send_sync_fsp<M>(&mut self, dev: &device::Device, msg: &M) -> Result<KVec<u8>>
where
M: MessageToFsp,
{
- self.falcon.send_msg(bar, msg.as_bytes())?;
+ self.falcon.send_msg(msg.as_bytes())?;
- let response_buf = self.falcon.recv_msg(bar).inspect_err(|e| {
+ let response_buf = self.falcon.recv_msg().inspect_err(|e| {
dev_err!(dev, "FSP response error: {:?}\n", e);
})?;
@@ -330,7 +330,6 @@ fn send_sync_fsp<M>(&mut self, dev: &device::Device, bar: Bar0<'_>, msg: &M) ->
pub(crate) fn boot_fmc(
&mut self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
fb_layout: &FbLayout,
args: &FmcBootArgs,
) -> Result {
@@ -341,7 +340,7 @@ pub(crate) fn boot_fmc(
GFP_KERNEL,
)?;
- let _response_buf = self.send_sync_fsp(dev, bar, &*msg)?;
+ let _response_buf = self.send_sync_fsp(dev, &*msg)?;
dev_dbg!(dev, "FSP Chain of Trust completed successfully\n");
Ok(())
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 4d76be429e75..43c3f4f8df71 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -273,9 +273,9 @@ struct GspResources<'gpu> {
/// MMIO mapping of PCI BAR 0.
bar: Bar0<'gpu>,
/// GSP falcon instance, used for GSP boot up and cleanup.
- gsp_falcon: Falcon<GspFalcon>,
+ gsp_falcon: Falcon<'gpu, GspFalcon>,
/// SEC2 falcon instance, used for GSP boot up and cleanup.
- sec2_falcon: Falcon<Sec2Falcon>,
+ sec2_falcon: Falcon<'gpu, Sec2Falcon>,
/// GSP runtime data.
#[pin]
gsp: Gsp,
@@ -351,10 +351,11 @@ pub(crate) fn new(
gsp_falcon: Falcon::new(
pdev.as_ref(),
spec.chipset,
+ bar
)
- .inspect(|falcon| falcon.clear_swgen0_intr(bar))?,
+ .inspect(|falcon| falcon.clear_swgen0_intr())?,
- sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
+ sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset, bar)?,
gsp <- Gsp::new(pdev),
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 73e93403601c..b4ac4156056e 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -57,8 +57,8 @@ pub(crate) struct GspBootContext<'a> {
pub(crate) pdev: &'a pci::Device<device::Bound>,
pub(crate) bar: Bar0<'a>,
pub(crate) chipset: Chipset,
- pub(crate) gsp_falcon: &'a Falcon<GspFalcon>,
- pub(crate) sec2_falcon: &'a Falcon<Sec2Falcon>,
+ pub(crate) gsp_falcon: &'a Falcon<'a, GspFalcon>,
+ pub(crate) sec2_falcon: &'a Falcon<'a, Sec2Falcon>,
}
impl<'a> GspBootContext<'a> {
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index bb2000b7a78b..ab0491b57944 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -37,8 +37,8 @@ pub(super) struct BootUnloadArgs<'a> {
gsp: &'a super::Gsp,
dev: &'a device::Device<device::Bound>,
bar: Bar0<'a>,
- gsp_falcon: &'a Falcon<Gsp>,
- sec2_falcon: &'a Falcon<Sec2>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
}
@@ -56,8 +56,8 @@ pub(super) fn new(
gsp: &'a super::Gsp,
dev: &'a device::Device<device::Bound>,
bar: Bar0<'a>,
- gsp_falcon: &'a Falcon<Gsp>,
- sec2_falcon: &'a Falcon<Sec2>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
) -> Self {
Self {
@@ -120,17 +120,17 @@ pub(crate) fn boot(
// Perform the chipset-specific boot sequence, and retrieve the unload bundle.
let unload_guard = hal.boot(&self, &ctx, &fb_layout, &wpr_meta)?;
- gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version);
+ gsp_falcon.write_os_version(gsp_fw.bootloader.app_version);
// Poll for RISC-V to become active before continuing.
read_poll_timeout(
- || Ok(gsp_falcon.is_riscv_active(bar)),
+ || Ok(gsp_falcon.is_riscv_active()),
|val: &bool| *val,
Delta::from_millis(10),
Delta::from_secs(5),
)?;
- dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar),);
+ dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(),);
self.cmdq
.send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?;
@@ -149,7 +149,7 @@ pub(crate) fn boot(
fn shutdown_gsp(
cmdq: &Cmdq,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<Gsp>,
+ gsp_falcon: &Falcon<'_, Gsp>,
mode: commands::PowerStateLevel,
) -> Result {
// Command to shut the GSP down.
@@ -158,7 +158,7 @@ fn shutdown_gsp(
// Wait until GSP signals it is suspended.
const LIBOS_INTERRUPT_PROCESSOR_SUSPENDED: u32 = bits::bit_u32(31);
read_poll_timeout(
- || Ok(gsp_falcon.read_mailbox0(bar)),
+ || Ok(gsp_falcon.read_mailbox0()),
|&mb0| mb0 & LIBOS_INTERRUPT_PROCESSOR_SUSPENDED != 0,
Delta::from_millis(10),
Delta::from_secs(5),
@@ -173,8 +173,8 @@ pub(crate) fn unload(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<Gsp>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, Gsp>,
+ sec2_falcon: &Falcon<'_, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
) -> Result {
// Shut down the GSP. Keep going even in case of error.
diff --git a/drivers/gpu/nova-core/gsp/hal.rs b/drivers/gpu/nova-core/gsp/hal.rs
index 51a277fe97bb..d3e47ef206de 100644
--- a/drivers/gpu/nova-core/gsp/hal.rs
+++ b/drivers/gpu/nova-core/gsp/hal.rs
@@ -42,8 +42,8 @@ fn run(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result;
}
diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
index 2187e11168b2..1d06405a32f6 100644
--- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
+++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
@@ -42,10 +42,10 @@ struct GspMbox {
impl GspMbox {
/// Reads both mailboxes from the GSP falcon.
- fn read(gsp_falcon: &Falcon<GspEngine>, bar: Bar0<'_>) -> Self {
+ fn read(gsp_falcon: &Falcon<'_, GspEngine>) -> Self {
Self {
- mbox0: gsp_falcon.read_mailbox0(bar),
- mbox1: gsp_falcon.read_mailbox1(bar),
+ mbox0: gsp_falcon.read_mailbox0(),
+ mbox1: gsp_falcon.read_mailbox1(),
}
}
@@ -60,8 +60,7 @@ fn combined_addr(&self) -> u64 {
/// either condition should stop the poll loop.
fn lockdown_released_or_error(
&self,
- gsp_falcon: &Falcon<GspEngine>,
- bar: Bar0<'_>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
fmc_boot_params_addr: u64,
) -> bool {
// GSP-FMC normally clears the boot parameters address from the mailboxes early during
@@ -71,15 +70,14 @@ fn lockdown_released_or_error(
return self.combined_addr() != fmc_boot_params_addr;
}
- !gsp_falcon.riscv_branch_privilege_lockdown(bar)
+ !gsp_falcon.riscv_branch_privilege_lockdown()
}
}
/// Waits for GSP lockdown to be released after FSP Chain of Trust.
fn wait_for_gsp_lockdown_release(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
fmc_boot_params_addr: u64,
) -> Result {
dev_dbg!(dev, "Waiting for GSP lockdown release\n");
@@ -88,14 +86,14 @@ fn wait_for_gsp_lockdown_release(
|| {
// While the PRIV target mask is still locked to FSP, GSP register and mailbox reads
// are not meaningful. Wait until HWCFG2 says the CPU can read them.
- Ok(match gsp_falcon.priv_target_mask_released(bar) {
+ Ok(match gsp_falcon.priv_target_mask_released() {
false => None,
- true => Some(GspMbox::read(gsp_falcon, bar)),
+ true => Some(GspMbox::read(gsp_falcon)),
})
},
|mbox| match mbox {
None => false,
- Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, bar, fmc_boot_params_addr),
+ Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, fmc_boot_params_addr),
},
Delta::from_millis(10),
Delta::from_secs(30),
@@ -122,13 +120,13 @@ impl UnloadBundle for FspUnloadBundle {
fn run(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- _sec2_falcon: &Falcon<Sec2>,
+ _bar: Bar0<'_>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ _sec2_falcon: &Falcon<'_, Sec2>,
) -> Result {
// GSP falcon does most of the work of resetting, so just wait for it to finish.
read_poll_timeout(
- || Ok(gsp_falcon.is_riscv_active(bar)),
+ || Ok(gsp_falcon.is_riscv_active()),
|&active| !active,
Delta::from_millis(10),
Delta::from_secs(5),
@@ -176,9 +174,9 @@ fn boot<'a>(
false,
)?;
- fsp.boot_fmc(dev, bar, fb_layout, &args)?;
+ fsp.boot_fmc(dev, fb_layout, &args)?;
- wait_for_gsp_lockdown_release(dev, bar, gsp_falcon, args.boot_params_dma_handle())?;
+ wait_for_gsp_lockdown_release(dev, gsp_falcon, args.boot_params_dma_handle())?;
Ok(unload_guard)
}
diff --git a/drivers/gpu/nova-core/gsp/hal/tu102.rs b/drivers/gpu/nova-core/gsp/hal/tu102.rs
index f8a8541704ee..180d47fb8f4e 100644
--- a/drivers/gpu/nova-core/gsp/hal/tu102.rs
+++ b/drivers/gpu/nova-core/gsp/hal/tu102.rs
@@ -62,12 +62,11 @@ impl FwsecUnloadFirmware {
/// Loads the FWSEC SB firmware, as well as its bootloader if `chipset` requires it.
fn new(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
chipset: Chipset,
bios: &Vbios,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
) -> Result<Self> {
- let fwsec_sb = FwsecFirmware::new(dev, gsp_falcon, bar, bios, FwsecCommand::Sb)?;
+ let fwsec_sb = FwsecFirmware::new(dev, gsp_falcon, bios, FwsecCommand::Sb)?;
Ok(if chipset.needs_fwsec_bootloader() {
Self::WithBl(FwsecFirmwareWithBl::new(fwsec_sb, dev, chipset)?)
@@ -80,12 +79,11 @@ fn new(
fn run(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
) -> Result {
match self {
- Self::WithoutBl(fw) => fw.run(dev, gsp_falcon, bar),
- Self::WithBl(fw) => fw.run(dev, gsp_falcon, bar),
+ Self::WithoutBl(fw) => fw.run(dev, gsp_falcon),
+ Self::WithBl(fw) => fw.run(dev, gsp_falcon),
}
}
}
@@ -101,22 +99,20 @@ impl Sec2UnloadBundle {
/// Load and prepare the resources required to properly reset the GSP after it has been stopped.
fn build(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
chipset: Chipset,
bios: &Vbios,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result<KBox<dyn UnloadBundle>> {
KBox::new(
Self {
- fwsec_sb: FwsecUnloadFirmware::new(dev, bar, chipset, bios, gsp_falcon)?,
+ fwsec_sb: FwsecUnloadFirmware::new(dev, chipset, bios, gsp_falcon)?,
booter_unloader: BooterFirmware::new(
dev,
BooterKind::Unloader,
chipset,
FIRMWARE_VERSION,
sec2_falcon,
- bar,
)?,
},
GFP_KERNEL,
@@ -131,14 +127,14 @@ fn run(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result {
// Run FWSEC-SB to reset the GSP falcon to its pre-libos state.
// Log errors but keep going if it fails.
let fwsec_sb_res = self
.fwsec_sb
- .run(dev, bar, gsp_falcon)
+ .run(dev, gsp_falcon)
.inspect_err(|e| dev_err!(dev, "FWSEC-SB failed to run: {:?}\n", e));
// Remove WPR2 region if set.
@@ -148,13 +144,12 @@ fn run(
return Ok(());
}
- sec2_falcon.reset(bar)?;
- sec2_falcon.load(dev, bar, &self.booter_unloader)?;
+ sec2_falcon.reset()?;
+ sec2_falcon.load(&self.booter_unloader)?;
// Sentinel value to confirm that Booter Unloader has run.
const MAILBOX_SENTINEL: u32 = 0xff;
- let (mbox0, _) =
- sec2_falcon.boot(bar, Some(MAILBOX_SENTINEL), Some(MAILBOX_SENTINEL))?;
+ let (mbox0, _) = sec2_falcon.boot(Some(MAILBOX_SENTINEL), Some(MAILBOX_SENTINEL))?;
if mbox0 != 0 {
dev_err!(dev, "Booter Unloader returned error 0x{:x}\n", mbox0);
return Err(EINVAL);
@@ -183,7 +178,7 @@ fn run(
fn run_fwsec_frts(
dev: &device::Device<device::Bound>,
chipset: Chipset,
- falcon: &Falcon<GspEngine>,
+ falcon: &Falcon<'_, GspEngine>,
bar: Bar0<'_>,
bios: &Vbios,
fb_layout: &FbLayout,
@@ -202,7 +197,6 @@ fn run_fwsec_frts(
let fwsec_frts = FwsecFirmware::new(
dev,
falcon,
- bar,
bios,
FwsecCommand::Frts {
frts_addr: fb_layout.frts.start,
@@ -213,10 +207,10 @@ fn run_fwsec_frts(
if chipset.needs_fwsec_bootloader() {
let fwsec_frts_bl = FwsecFirmwareWithBl::new(fwsec_frts, dev, chipset)?;
// Load and run the bootloader, which will load FWSEC-FRTS and run it.
- fwsec_frts_bl.run(dev, falcon, bar)?;
+ fwsec_frts_bl.run(dev, falcon)?;
} else {
// Load and run FWSEC-FRTS directly.
- fwsec_frts.run(dev, falcon, bar)?;
+ fwsec_frts.run(dev, falcon)?;
}
// SCRATCH_E contains the error code for FWSEC-FRTS.
@@ -286,18 +280,17 @@ fn boot<'a>(
//
// If the unload bundle creation fails, the GPU will need to be reset before the driver can
// be probed again.
- let unload_bundle =
- Sec2UnloadBundle::build(dev, bar, chipset, &bios, gsp_falcon, sec2_falcon)
- .inspect_err(|e| {
- dev_warn!(dev, "Failed to prepare unload firmware: {:?}\n", e);
- dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
- dev_warn!(
- dev,
- "The GPU will need to be reset before the driver can bind again.\n"
- );
- })
- .ok()
- .map(crate::gsp::UnloadBundle);
+ let unload_bundle = Sec2UnloadBundle::build(dev, chipset, &bios, gsp_falcon, sec2_falcon)
+ .inspect_err(|e| {
+ dev_warn!(dev, "Failed to prepare unload firmware: {:?}\n", e);
+ dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
+ dev_warn!(
+ dev,
+ "The GPU will need to be reset before the driver can bind again.\n"
+ );
+ })
+ .ok()
+ .map(crate::gsp::UnloadBundle);
// Wrap the unload bundle into a drop guard so it is automatically run upon failure.
let unload_guard =
@@ -308,13 +301,10 @@ fn boot<'a>(
run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, fb_layout)?;
}
- gsp_falcon.reset(bar)?;
+ gsp_falcon.reset()?;
let libos_handle = gsp.libos.dma_handle();
- let (mbox0, mbox1) = gsp_falcon.boot(
- bar,
- Some(libos_handle as u32),
- Some((libos_handle >> 32) as u32),
- )?;
+ let (mbox0, mbox1) =
+ gsp_falcon.boot(Some(libos_handle as u32), Some((libos_handle >> 32) as u32))?;
dev_dbg!(dev, "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
dev_dbg!(
@@ -328,9 +318,8 @@ fn boot<'a>(
chipset,
FIRMWARE_VERSION,
sec2_falcon,
- bar,
)?
- .run(dev, bar, sec2_falcon, wpr_meta)?;
+ .run(dev, sec2_falcon, wpr_meta)?;
Ok(unload_guard)
}
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index e0850d21adca..13983d42b12b 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -133,9 +133,9 @@ pub(crate) struct GspSequencer<'a> {
/// `Bar0` for register access.
bar: Bar0<'a>,
/// SEC2 falcon for core operations.
- sec2_falcon: &'a Falcon<Sec2>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
/// GSP falcon for core operations.
- gsp_falcon: &'a Falcon<Gsp>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
/// LibOS DMA handle address.
libos_dma_handle: u64,
/// Bootloader application version.
@@ -213,16 +213,16 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
GspSeqCmd::DelayUs(cmd) => cmd.run(seq),
GspSeqCmd::RegStore(cmd) => cmd.run(seq),
GspSeqCmd::CoreReset => {
- seq.gsp_falcon.reset(seq.bar)?;
- seq.gsp_falcon.dma_reset(seq.bar);
+ seq.gsp_falcon.reset()?;
+ seq.gsp_falcon.dma_reset();
Ok(())
}
GspSeqCmd::CoreStart => {
- seq.gsp_falcon.start(seq.bar)?;
+ seq.gsp_falcon.start()?;
Ok(())
}
GspSeqCmd::CoreWaitForHalt => {
- seq.gsp_falcon.wait_till_halted(seq.bar)?;
+ seq.gsp_falcon.wait_till_halted()?;
Ok(())
}
GspSeqCmd::CoreResume => {
@@ -231,35 +231,32 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
// sequencer will start both.
// Reset the GSP to prepare it for resuming.
- seq.gsp_falcon.reset(seq.bar)?;
+ seq.gsp_falcon.reset()?;
// Write the libOS DMA handle to GSP mailboxes.
seq.gsp_falcon.write_mailboxes(
- seq.bar,
Some(seq.libos_dma_handle as u32),
Some((seq.libos_dma_handle >> 32) as u32),
);
// Start the SEC2 falcon which will trigger GSP-RM to resume on the GSP.
- seq.sec2_falcon.start(seq.bar)?;
+ seq.sec2_falcon.start()?;
// Poll until GSP-RM reload/resume has completed (up to 2 seconds).
- seq.gsp_falcon
- .check_reload_completed(seq.bar, Delta::from_secs(2))?;
+ seq.gsp_falcon.check_reload_completed(Delta::from_secs(2))?;
// Verify SEC2 completed successfully by checking its mailbox for errors.
- let mbox0 = seq.sec2_falcon.read_mailbox0(seq.bar);
+ let mbox0 = seq.sec2_falcon.read_mailbox0();
if mbox0 != 0 {
dev_err!(seq.dev, "Sequencer: sec2 errors: {:?}\n", mbox0);
return Err(EIO);
}
// Configure GSP with the bootloader version.
- seq.gsp_falcon
- .write_os_version(seq.bar, seq.bootloader_app_version);
+ seq.gsp_falcon.write_os_version(seq.bootloader_app_version);
// Verify the GSP's RISC-V core is active indicating successful GSP boot.
- if !seq.gsp_falcon.is_riscv_active(seq.bar) {
+ if !seq.gsp_falcon.is_riscv_active() {
dev_err!(seq.dev, "Sequencer: RISC-V core is not active\n");
return Err(EIO);
}
@@ -345,9 +342,9 @@ pub(crate) struct GspSequencerParams<'a> {
/// LibOS DMA handle address.
pub(crate) libos_dma_handle: u64,
/// GSP falcon for core operations.
- pub(crate) gsp_falcon: &'a Falcon<Gsp>,
+ pub(crate) gsp_falcon: &'a Falcon<'a, Gsp>,
/// SEC2 falcon for core operations.
- pub(crate) sec2_falcon: &'a Falcon<Sec2>,
+ pub(crate) sec2_falcon: &'a Falcon<'a, Sec2>,
/// Device for logging.
pub(crate) dev: &'a device::Device,
/// BAR0 for register access.
---
base-commit: 9102e655ea7285c1bc329669865ba8a38cdb69e6
change-id: 20260624-drm-bar-refactor-90435f04c9ea
Best regards,
--
Tim Kovalenko <tim.kovalenko@proton.me>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related
* Re: [PATCH 1/2] drm/connector: Introduce "min bpc" connector property
From: Harry Wentland @ 2026-06-24 15:49 UTC (permalink / raw)
To: Nicolas Frattaroli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Xaver Hugl,
Michel Dänzer, Mario Kleiner, Pekka Paalanen,
Ville Syrjälä, Daniel Stone
Cc: dri-devel, linux-kernel, kernel, wayland-devel
In-Reply-To: <20260612-min-bpc-v1-1-bba88c2c4836@collabora.com>
On 2026-06-12 11:34, Nicolas Frattaroli wrote:
> Add a new KMS connector property called "min bpc". Its purpose is to
> allow userspace to mandate that the output bit depth ends up greater
> than or equal to a specified depth, or else have the commit fail. This
> is useful for checking for output depth degradation in combination with
> atomic test commits.
>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Despite your statement in the cover letter, this does still need a
userspace implementation before merging, as well as an IGT test.
But I like this definition and your documentation and think we have
something quite workable, even long-term.
Harry
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 4 ++
> drivers/gpu/drm/drm_atomic_uapi.c | 4 ++
> drivers/gpu/drm/drm_connector.c | 77 +++++++++++++++++++++++++++++++++++++
> include/drm/drm_connector.h | 13 +++++++
> 4 files changed, 98 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 285aac3554df..613a674ace87 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -739,6 +739,10 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> new_connector_state->max_requested_bpc)
> new_crtc_state->connectors_changed = true;
>
> + if (old_connector_state->min_requested_bpc !=
> + new_connector_state->min_requested_bpc)
> + new_crtc_state->connectors_changed = true;
> +
> if (old_connector_state->color_format !=
> new_connector_state->color_format)
> new_crtc_state->connectors_changed = true;
> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> index 1050dddadb17..0440cb63f786 100644
> --- a/drivers/gpu/drm/drm_atomic_uapi.c
> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> @@ -956,6 +956,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> fence_ptr);
> } else if (property == connector->max_bpc_property) {
> state->max_requested_bpc = val;
> + } else if (property == connector->min_bpc_property) {
> + state->min_requested_bpc = val;
> } else if (property == connector->privacy_screen_sw_state_property) {
> state->privacy_screen_sw_state = val;
> } else if (property == connector->broadcast_rgb_property) {
> @@ -1043,6 +1045,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> *val = 0;
> } else if (property == connector->max_bpc_property) {
> *val = state->max_requested_bpc;
> + } else if (property == connector->min_bpc_property) {
> + *val = state->min_requested_bpc;
> } else if (property == connector->privacy_screen_sw_state_property) {
> *val = state->privacy_screen_sw_state;
> } else if (property == connector->broadcast_rgb_property) {
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index cbb067d02cb9..dcf53cc113b0 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -1738,6 +1738,46 @@ EXPORT_SYMBOL(drm_hdmi_connector_get_output_format_name);
> * drm_connector_attach_max_bpc_property() to create and attach the
> * property to the connector during initialization.
> *
> + * min bpc:
> + * This range property is used by userspace to set a minimum bit depth that
> + * the driver must reach on the connector for a given atomic state. If it
> + * cannot do so, the atomic commit fails.
> + *
> + * The precise definition of minimum bit depth used for the "min bpc"
> + * property must align with the definition a given driver uses for the
> + * "max bpc" property, such that when "min bpc" and "max bpc" are set to
> + * the same value, the allowable range of bit depths is a single set point.
> + *
> + * Drivers should ideally use a definition of bit depth that refers to a
> + * perceptual optical bit depth, meaning it is equivalent to an
> + * uncompressed optical bit depth for a variety of content to the median
> + * human eyeball in a variety of viewing environments. The display link's
> + * actual optical bit depth to represent the data on the wire may be lower
> + * due to compression techniques, or even higher due to padding. In
> + * concrete terms, userspace should not need to know how to implement DSC
> + * compression in order to set a minimum bit depth to the appropriate
> + * value, and should not need to perform display-protocol-specific
> + * calculations to set the right on-the-wire format.
> + *
> + * Userspace may use the "min bpc" property in combination with performing
> + * atomic test commits in order to enumerate the possible output bit depths
> + * for a given configuration. This way, userspace compositors can make
> + * use-case and content-specific tradeoffs to reach a desired output bit
> + * depth, such as by using chroma subsampling, or by choosing a lower
> + * refresh rate mode.
> + *
> + * Userspace may use the "min bpc" property in combination with the
> + * "max bpc" property to know what output bit depth a successful atomic
> + * commit is using. By setting "min bpc" and "max bpc" to the same value,
> + * a successful commit will be using an output bit depth of said value.
> + *
> + * When "min bpc" is set to a non-zero value, any bit depth degradation
> + * logic below "min bpc" must be implemented by userspace (through lowering
> + * "min bpc"), rather than by kernel drivers. For a driver to degrade to an
> + * uncompressed optical output bit depth below "min bpc" is always a bug no
> + * matter how good the intentions are, since it renders the property
> + * useless as an oracle.
> + *
> * Connectors also have one standardized atomic property:
> *
> * CRTC_ID:
> @@ -2892,6 +2932,43 @@ int drm_connector_attach_max_bpc_property(struct drm_connector *connector,
> }
> EXPORT_SYMBOL(drm_connector_attach_max_bpc_property);
>
> +/**
> + * drm_connector_attach_min_bpc_property - attach "min bpc" property
> + * @connector: connector to attach min bpc property on.
> + * @max: The maximum bit depth supported by the connector.
> + *
> + * Create and attach the "min bpc" connector property, which is used by
> + * userspace to require that a certain minimum bit depth is reached by the
> + * connector on atomic commit.
> + *
> + * Returns:
> + * Zero on success, negative errno on failure.
> + */
> +int drm_connector_attach_min_bpc_property(struct drm_connector *connector,
> + unsigned int max)
> +{
> + struct drm_device *dev = connector->dev;
> + struct drm_property *prop;
> +
> + if (max > U8_MAX)
> + return -ERANGE;
> +
> + prop = connector->min_bpc_property;
> + if (!prop) {
> + prop = drm_property_create_range(dev, 0, "min bpc", 0, max);
> + if (!prop)
> + return -ENOMEM;
> +
> + connector->min_bpc_property = prop;
> + }
> +
> + drm_object_attach_property(&connector->base, prop, 0);
> + connector->state->min_requested_bpc = 0;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_connector_attach_min_bpc_property);
> +
> /**
> * drm_connector_attach_hdr_output_metadata_property - attach "HDR_OUTPUT_METADATA" property
> * @connector: connector to attach the property on.
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index 4317166562cf..63d6ac85b3ec 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -1261,6 +1261,11 @@ struct drm_connector_state {
> */
> u8 max_requested_bpc;
>
> + /**
> + * @min_requested_bpc: Minimum output bit depth requested by userspace
> + */
> + u8 min_requested_bpc;
> +
> /**
> * @max_bpc: Connector max_bpc based on the requested max_bpc property
> * and the connector bpc limitations obtained from edid.
> @@ -2291,6 +2296,12 @@ struct drm_connector {
> */
> struct drm_property *max_bpc_property;
>
> + /**
> + * @min_bpc_property: Default connector property for the minimum bit
> + * depth for the output to reach, or the commit to fail otherwise.
> + */
> + struct drm_property *min_bpc_property;
> +
> /** @privacy_screen: drm_privacy_screen for this connector, or NULL. */
> struct drm_privacy_screen *privacy_screen;
>
> @@ -2697,6 +2708,8 @@ int drm_connector_set_orientation_from_panel(
> struct drm_panel *panel);
> int drm_connector_attach_max_bpc_property(struct drm_connector *connector,
> int min, int max);
> +int drm_connector_attach_min_bpc_property(struct drm_connector *connector,
> + unsigned int max);
> void drm_connector_create_privacy_screen_properties(struct drm_connector *conn);
> void drm_connector_attach_privacy_screen_properties(struct drm_connector *conn);
> void drm_connector_attach_privacy_screen_provider(
>
^ permalink raw reply
* [PATCH] gpu: nova-core: falcon: store bar and dev in falcon
From: Tim Kovalenko @ 2026-06-24 15:49 UTC (permalink / raw)
Cc: nova-gpu, dri-devel, linux-kernel, linux-riscv, Tim Kovalenko
Store the bound device and `BAR0` mapping in `Falcon` instead of passing
them through every `Falcon` operation. This simplifies the `Falcon` API and
removes repeated `dev`/`bar` plumbing from reset, load, boot, mailbox, DMA,
and GSP/FSP-specific Falcon helpers.
Add a named helper for configuring Falcon FBIF transaction slots for
physical coherent system memory, avoiding direct `BAR0` access from the
FWSEC bootloader path without exposing BAR0 publicly.
Future work / questions:
- Focused only on the Falcon for this patch - more to follow.
- Not sure about the FalconHal and if I should modify the Trait
- Could be part of the next patch
- But it could definitively be simplified
- Also, how far should the refactor go and to what extend add new
methods to avoid passing `bar` or `dev` but also not exposing them as
pub. For `dev`, there's a lot of `dev_err` usage that requires us to
pass it as a param.
- I've created the `set_fbif_transcfg_phys_sysmem` method to
address such issue and remove some code duplication but that
method could be made a bit more generic.
- Also, is there a reason why we are not passing the `GspBootContext`
when we need stuff like `bar`, `dev` and both falcons?
Reported-by: Alexandre Courbot <acourbot@nvidia.com>
Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/509436-Nova/topic/Storing.20driver-bound.20references.20into.20sub-devices/near/599137882
Signed-off-by: Tim Kovalenko <tim.kovalenko@proton.me>
---
drivers/gpu/nova-core/falcon.rs | 206 ++++++++++-----------
drivers/gpu/nova-core/falcon/fsp.rs | 44 +++--
drivers/gpu/nova-core/falcon/gsp.rs | 21 ++-
drivers/gpu/nova-core/falcon/hal.rs | 6 +-
drivers/gpu/nova-core/falcon/hal/ga102.rs | 8 +-
drivers/gpu/nova-core/falcon/hal/tu102.rs | 6 +-
drivers/gpu/nova-core/firmware/booter.rs | 25 +--
drivers/gpu/nova-core/firmware/fwsec.rs | 19 +-
drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 33 +---
drivers/gpu/nova-core/fsp.rs | 23 ++-
drivers/gpu/nova-core/gpu.rs | 9 +-
drivers/gpu/nova-core/gsp.rs | 4 +-
drivers/gpu/nova-core/gsp/boot.rs | 22 +--
drivers/gpu/nova-core/gsp/hal.rs | 4 +-
drivers/gpu/nova-core/gsp/hal/gh100.rs | 32 ++--
drivers/gpu/nova-core/gsp/hal/tu102.rs | 75 ++++----
drivers/gpu/nova-core/gsp/sequencer.rs | 31 ++--
17 files changed, 253 insertions(+), 315 deletions(-)
diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 94c7696a6493..ca12cc11a370 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -5,10 +5,7 @@
use hal::FalconHal;
use kernel::{
- device::{
- self,
- Device, //
- },
+ device,
dma::{
Coherent,
CoherentBox,
@@ -24,7 +21,6 @@
Io,
},
prelude::*,
- sync::aref::ARef,
time::Delta,
};
@@ -358,41 +354,47 @@ pub(crate) trait FalconFirmware {
}
/// Contains the base parameters common to all Falcon instances.
-pub(crate) struct Falcon<E: FalconEngine> {
+pub(crate) struct Falcon<'a, E: FalconEngine> {
hal: KBox<dyn FalconHal<E>>,
- dev: ARef<device::Device>,
+ dev: &'a device::Device<device::Bound>,
+ bar: Bar0<'a>,
}
-impl<E: FalconEngine + 'static> Falcon<E> {
+impl<'a, E: FalconEngine + 'static> Falcon<'a, E> {
/// Create a new falcon instance.
- pub(crate) fn new(dev: &device::Device, chipset: Chipset) -> Result<Self> {
+ pub(crate) fn new(
+ dev: &'a device::Device<device::Bound>,
+ chipset: Chipset,
+ bar: Bar0<'a>,
+ ) -> Result<Self> {
Ok(Self {
hal: hal::falcon_hal(chipset)?,
- dev: dev.into(),
+ dev,
+ bar,
})
}
/// Resets DMA-related registers.
- pub(crate) fn dma_reset(&self, bar: Bar0<'_>) {
- bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
+ pub(crate) fn dma_reset(&self) {
+ self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
v.with_allow_phys_no_ctx(true)
});
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMACTL::zeroed(),
);
}
/// Reset the controller, select the falcon core, and wait for memory scrubbing to complete.
- pub(crate) fn reset(&self, bar: Bar0<'_>) -> Result {
- self.hal.reset_eng(bar)?;
- self.hal.select_core(self, bar)?;
- self.hal.reset_wait_mem_scrubbing(bar)?;
+ pub(crate) fn reset(&self) -> Result {
+ self.hal.reset_eng(self.bar)?;
+ self.hal.select_core(self, self.bar)?;
+ self.hal.reset_wait_mem_scrubbing(self.bar)?;
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
- regs::NV_PFALCON_FALCON_RM::from(bar.read(regs::NV_PMC_BOOT_0).into_raw()),
+ regs::NV_PFALCON_FALCON_RM::from(self.bar.read(regs::NV_PMC_BOOT_0).into_raw()),
);
Ok(())
@@ -404,18 +406,14 @@ pub(crate) fn reset(&self, bar: Bar0<'_>) -> Result {
/// Write a slice to Falcon IMEM memory using programmed I/O (PIO).
///
/// Returns `EINVAL` if `img.len()` is not a multiple of 4.
- fn pio_wr_imem_slice(
- &self,
- bar: Bar0<'_>,
- load_offsets: FalconPioImemLoadTarget<'_>,
- ) -> Result {
+ fn pio_wr_imem_slice(&self, load_offsets: FalconPioImemLoadTarget<'_>) -> Result {
// Rejecting misaligned images here allows us to avoid checking
// inside the loops.
if load_offsets.data.len() % 4 != 0 {
return Err(EINVAL);
}
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMC::zeroed()
.with_secure(load_offsets.secure)
@@ -426,13 +424,13 @@ fn pio_wr_imem_slice(
for (n, block) in load_offsets.data.chunks(MEM_BLOCK_ALIGNMENT).enumerate() {
let n = u16::try_from(n)?;
let tag: u16 = load_offsets.start_tag.checked_add(n).ok_or(ERANGE)?;
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMT::zeroed().with_tag(tag),
);
for word in block.chunks_exact(4) {
let w = [word[0], word[1], word[2], word[3]];
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_IMEMD::zeroed().with_data(u32::from_le_bytes(w)),
);
@@ -445,18 +443,14 @@ fn pio_wr_imem_slice(
/// Write a slice to Falcon DMEM memory using programmed I/O (PIO).
///
/// Returns `EINVAL` if `img.len()` is not a multiple of 4.
- fn pio_wr_dmem_slice(
- &self,
- bar: Bar0<'_>,
- load_offsets: FalconPioDmemLoadTarget<'_>,
- ) -> Result {
+ fn pio_wr_dmem_slice(&self, load_offsets: FalconPioDmemLoadTarget<'_>) -> Result {
// Rejecting misaligned images here allows us to avoid checking
// inside the loops.
if load_offsets.data.len() % 4 != 0 {
return Err(EINVAL);
}
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_DMEMC::zeroed()
.with_aincw(true)
@@ -465,7 +459,7 @@ fn pio_wr_dmem_slice(
for word in load_offsets.data.chunks_exact(4) {
let w = [word[0], word[1], word[2], word[3]];
- bar.write(
+ self.bar.write(
WithBase::of::<E>().at(Self::PIO_PORT),
regs::NV_PFALCON_FALCON_DMEMD::zeroed().with_data(u32::from_le_bytes(w)),
);
@@ -477,29 +471,28 @@ fn pio_wr_dmem_slice(
/// Perform a PIO copy into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
pub(crate) fn pio_load<F: FalconFirmware<Target = E> + FalconPioLoadable>(
&self,
- bar: Bar0<'_>,
fw: &F,
) -> Result {
- bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
+ self.bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| {
v.with_allow_phys_no_ctx(true)
});
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMACTL::zeroed(),
);
if let Some(imem_ns) = fw.imem_ns_load_params() {
- self.pio_wr_imem_slice(bar, imem_ns)?;
+ self.pio_wr_imem_slice(imem_ns)?;
}
if let Some(imem_sec) = fw.imem_sec_load_params() {
- self.pio_wr_imem_slice(bar, imem_sec)?;
+ self.pio_wr_imem_slice(imem_sec)?;
}
- self.pio_wr_dmem_slice(bar, fw.dmem_load_params())?;
+ self.pio_wr_dmem_slice(fw.dmem_load_params())?;
- self.hal.program_brom(self, bar, &fw.brom_params());
+ self.hal.program_brom(self, self.bar, &fw.brom_params());
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()),
);
@@ -513,7 +506,6 @@ pub(crate) fn pio_load<F: FalconFirmware<Target = E> + FalconPioLoadable>(
/// `sec` is set if the loaded firmware is expected to run in secure mode.
fn dma_wr(
&self,
- bar: Bar0<'_>,
dma_obj: &Coherent<[u8]>,
target_mem: FalconMem,
load_offsets: FalconDmaLoadTarget,
@@ -571,7 +563,7 @@ fn dma_wr(
// Set up the base source DMA address.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_base(
// CAST: `as u32` is used on purpose since we do want to strip the upper bits,
@@ -579,7 +571,7 @@ fn dma_wr(
(dma_start >> 8) as u32,
),
);
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed().try_with_base(dma_start >> 40)?,
);
@@ -590,23 +582,23 @@ fn dma_wr(
for pos in (0..num_transfers).map(|i| i * DMA_LEN) {
// Perform a transfer of size `DMA_LEN`.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed()
.try_with_offs(load_offsets.dst_start + pos)?,
);
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(src_start + pos),
);
- bar.write(WithBase::of::<E>(), cmd);
+ self.bar.write(WithBase::of::<E>(), cmd);
// Wait for the transfer to complete.
// TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories
// should ever take that long.
read_poll_timeout(
- || Ok(bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())),
+ || Ok(self.bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())),
|r| r.idle(),
Delta::ZERO,
Delta::from_secs(2),
@@ -617,12 +609,7 @@ fn dma_wr(
}
/// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it.
- fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
- &self,
- dev: &Device<device::Bound>,
- bar: Bar0<'_>,
- fw: &F,
- ) -> Result {
+ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
// DMA object with firmware content as the source of the DMA engine.
let dma_obj = {
let fw_slice = fw.as_slice();
@@ -630,7 +617,7 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
// DMA copies are done in chunks of `MEM_BLOCK_ALIGNMENT`, so pad the length
// accordingly and fill with `0`.
let mut dma_obj = CoherentBox::zeroed_slice(
- dev,
+ self.dev,
fw_slice.len().next_multiple_of(MEM_BLOCK_ALIGNMENT),
GFP_KERNEL,
)?;
@@ -642,24 +629,16 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
dma_obj.into()
};
- self.dma_reset(bar);
- bar.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| {
- v.with_target(FalconFbifTarget::CoherentSysmem)
- .with_mem_type(FalconFbifMemType::Physical)
- });
+ self.dma_reset();
+ self.set_fbif_transcfg_phys_sysmem(0)?;
- self.dma_wr(
- bar,
- &dma_obj,
- FalconMem::ImemSecure,
- fw.imem_sec_load_params(),
- )?;
- self.dma_wr(bar, &dma_obj, FalconMem::Dmem, fw.dmem_load_params())?;
+ self.dma_wr(&dma_obj, FalconMem::ImemSecure, fw.imem_sec_load_params())?;
+ self.dma_wr(&dma_obj, FalconMem::Dmem, fw.dmem_load_params())?;
- self.hal.program_brom(self, bar, &fw.brom_params());
+ self.hal.program_brom(self, self.bar, &fw.brom_params());
// Set `BootVec` to start of non-secure code.
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()),
);
@@ -667,11 +646,26 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
Ok(())
}
+ /// Configure a Falcon FBIF transaction slot to access physical coherent system memory.
+ pub(crate) fn set_fbif_transcfg_phys_sysmem(&self, dmaidx: u32) -> Result {
+ self.bar.update(
+ regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>()
+ .try_at(usize::from_safe_cast(dmaidx))
+ .ok_or(EINVAL)?,
+ |v| {
+ v.with_target(FalconFbifTarget::CoherentSysmem)
+ .with_mem_type(FalconFbifMemType::Physical)
+ },
+ );
+
+ Ok(())
+ }
+
/// Wait until the falcon CPU is halted.
- pub(crate) fn wait_till_halted(&self, bar: Bar0<'_>) -> Result<()> {
+ pub(crate) fn wait_till_halted(&self) -> Result<()> {
// TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds.
read_poll_timeout(
- || Ok(bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())),
+ || Ok(self.bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())),
|r| r.halted(),
Delta::ZERO,
Delta::from_secs(2),
@@ -681,16 +675,17 @@ pub(crate) fn wait_till_halted(&self, bar: Bar0<'_>) -> Result<()> {
}
/// Start the falcon CPU.
- pub(crate) fn start(&self, bar: Bar0<'_>) -> Result<()> {
- match bar
+ pub(crate) fn start(&self) -> Result<()> {
+ match self
+ .bar
.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())
.alias_en()
{
- true => bar.write(
+ true => self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed().with_startcpu(true),
),
- false => bar.write(
+ false => self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_CPUCTL::zeroed().with_startcpu(true),
),
@@ -700,16 +695,16 @@ pub(crate) fn start(&self, bar: Bar0<'_>) -> Result<()> {
}
/// Writes values to the mailbox registers if provided.
- pub(crate) fn write_mailboxes(&self, bar: Bar0<'_>, mbox0: Option<u32>, mbox1: Option<u32>) {
+ pub(crate) fn write_mailboxes(&self, mbox0: Option<u32>, mbox1: Option<u32>) {
if let Some(mbox0) = mbox0 {
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_MAILBOX0::zeroed().with_value(mbox0),
);
}
if let Some(mbox1) = mbox1 {
- bar.write(
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_MAILBOX1::zeroed().with_value(mbox1),
);
@@ -717,21 +712,23 @@ pub(crate) fn write_mailboxes(&self, bar: Bar0<'_>, mbox0: Option<u32>, mbox1: O
}
/// Reads the value from `mbox0` register.
- pub(crate) fn read_mailbox0(&self, bar: Bar0<'_>) -> u32 {
- bar.read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>())
+ pub(crate) fn read_mailbox0(&self) -> u32 {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>())
.value()
}
/// Reads the value from `mbox1` register.
- pub(crate) fn read_mailbox1(&self, bar: Bar0<'_>) -> u32 {
- bar.read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>())
+ pub(crate) fn read_mailbox1(&self) -> u32 {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>())
.value()
}
/// Reads values from both mailbox registers.
- pub(crate) fn read_mailboxes(&self, bar: Bar0<'_>) -> (u32, u32) {
- let mbox0 = self.read_mailbox0(bar);
- let mbox1 = self.read_mailbox1(bar);
+ pub(crate) fn read_mailboxes(&self) -> (u32, u32) {
+ let mbox0 = self.read_mailbox0();
+ let mbox1 = self.read_mailbox1();
(mbox0, mbox1)
}
@@ -743,54 +740,43 @@ pub(crate) fn read_mailboxes(&self, bar: Bar0<'_>) -> (u32, u32) {
///
/// Wait up to two seconds for the firmware to complete, and return its exit status read from
/// the `MBOX0` and `MBOX1` registers.
- pub(crate) fn boot(
- &self,
- bar: Bar0<'_>,
- mbox0: Option<u32>,
- mbox1: Option<u32>,
- ) -> Result<(u32, u32)> {
- self.write_mailboxes(bar, mbox0, mbox1);
- self.start(bar)?;
- self.wait_till_halted(bar)?;
- Ok(self.read_mailboxes(bar))
+ pub(crate) fn boot(&self, mbox0: Option<u32>, mbox1: Option<u32>) -> Result<(u32, u32)> {
+ self.write_mailboxes(mbox0, mbox1);
+ self.start()?;
+ self.wait_till_halted()?;
+ Ok(self.read_mailboxes())
}
/// Returns the fused version of the signature to use in order to run a HS firmware on this
/// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header.
pub(crate) fn signature_reg_fuse_version(
&self,
- bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32> {
self.hal
- .signature_reg_fuse_version(self, bar, engine_id_mask, ucode_id)
+ .signature_reg_fuse_version(self, self.bar, engine_id_mask, ucode_id)
}
/// Check if the RISC-V core is active.
///
/// Returns `true` if the RISC-V core is active, `false` otherwise.
- pub(crate) fn is_riscv_active(&self, bar: Bar0<'_>) -> bool {
- self.hal.is_riscv_active(bar)
+ pub(crate) fn is_riscv_active(&self) -> bool {
+ self.hal.is_riscv_active(self.bar)
}
/// Load a firmware image into Falcon memory, using the preferred method for the current
/// chipset.
- pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
- &self,
- dev: &Device<device::Bound>,
- bar: Bar0<'_>,
- fw: &F,
- ) -> Result {
+ pub(crate) fn load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(&self, fw: &F) -> Result {
match self.hal.load_method() {
- LoadMethod::Dma => self.dma_load(dev, bar, fw),
- LoadMethod::Pio => self.pio_load(bar, &fw.try_as_pio_loadable()?),
+ LoadMethod::Dma => self.dma_load(fw),
+ LoadMethod::Pio => self.pio_load(&fw.try_as_pio_loadable()?),
}
}
/// Write the application version to the OS register.
- pub(crate) fn write_os_version(&self, bar: Bar0<'_>, app_version: u32) {
- bar.write(
+ pub(crate) fn write_os_version(&self, app_version: u32) {
+ self.bar.write(
WithBase::of::<E>(),
regs::NV_PFALCON_FALCON_OS::zeroed().with_value(app_version),
);
diff --git a/drivers/gpu/nova-core/falcon/fsp.rs b/drivers/gpu/nova-core/falcon/fsp.rs
index 52cdb84ef0e8..53b1079843ae 100644
--- a/drivers/gpu/nova-core/falcon/fsp.rs
+++ b/drivers/gpu/nova-core/falcon/fsp.rs
@@ -21,7 +21,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
Falcon,
FalconEngine,
@@ -48,18 +47,18 @@ impl RegisterBase<PFalcon2Base> for Fsp {
impl FalconEngine for Fsp {}
-impl Falcon<Fsp> {
+impl<'a> Falcon<'a, Fsp> {
/// Writes `data` to FSP external memory at offset `0`.
///
/// `data` is interpreted as little-endian 32-bit words. Returns `EINVAL`
/// if the `data` length is not 4-byte aligned.
- fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
+ fn write_emem(&mut self, data: &[u8]) -> Result {
if data.len() % 4 != 0 {
return Err(EINVAL);
}
// Begin a write burst at offset `0`, auto-incrementing on each write.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincw(true),
);
@@ -68,7 +67,7 @@ fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
let value = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
// Write the next 32-bit `value`; hardware advances the offset.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMD::zeroed().with_data(value),
);
@@ -81,20 +80,23 @@ fn write_emem(&mut self, bar: Bar0<'_>, data: &[u8]) -> Result {
///
/// `data` is stored as little-endian 32-bit words. Returns `EINVAL` if
/// the `data` length is not 4-byte aligned.
- fn read_emem(&mut self, bar: Bar0<'_>, data: &mut [u8]) -> Result {
+ fn read_emem(&mut self, data: &mut [u8]) -> Result {
if data.len() % 4 != 0 {
return Err(EINVAL);
}
// Begin a read burst at offset `0`, auto-incrementing on each read.
- bar.write(
+ self.bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincr(true),
);
for chunk in data.chunks_exact_mut(4) {
// Read the next 32-bit word; hardware advances the offset.
- let value = bar.read(regs::NV_PFALCON_FALCON_EMEMD::of::<Fsp>()).data();
+ let value = self
+ .bar
+ .read(regs::NV_PFALCON_FALCON_EMEMD::of::<Fsp>())
+ .data();
chunk.copy_from_slice(&value.to_le_bytes());
}
@@ -107,9 +109,9 @@ fn read_emem(&mut self, bar: Bar0<'_>, data: &mut [u8]) -> Result {
///
/// The FSP message queue is not circular. Pointers are reset to 0 after each
/// message exchange, so `tail >= head` is always true when data is present.
- fn poll_msgq(&self, bar: Bar0<'_>) -> u32 {
- let head = bar.read(regs::NV_PFSP_MSGQ_HEAD::at(0)).val();
- let tail = bar.read(regs::NV_PFSP_MSGQ_TAIL::at(0)).val();
+ fn poll_msgq(&self) -> u32 {
+ let head = self.bar.read(regs::NV_PFSP_MSGQ_HEAD::at(0)).val();
+ let tail = self.bar.read(regs::NV_PFSP_MSGQ_TAIL::at(0)).val();
if head == tail {
return 0;
@@ -122,20 +124,20 @@ fn poll_msgq(&self, bar: Bar0<'_>) -> u32 {
/// Writes `packet` to FSP EMEM and updates the queue pointers to notify FSP.
///
/// Returns `EINVAL` if `packet` is empty or its length is not 4-byte aligned.
- pub(crate) fn send_msg(&mut self, bar: Bar0<'_>, packet: &[u8]) -> Result {
+ pub(crate) fn send_msg(&mut self, packet: &[u8]) -> Result {
if packet.is_empty() {
return Err(EINVAL);
}
- self.write_emem(bar, packet)?;
+ self.write_emem(packet)?;
// Update queue pointers. TAIL points at the last DWORD written.
let tail_offset = u32::try_from(packet.len() - 4).map_err(|_| EINVAL)?;
- bar.write(
+ self.bar.write(
Array::at(0),
regs::NV_PFSP_QUEUE_TAIL::zeroed().with_address(tail_offset),
);
- bar.write(
+ self.bar.write(
Array::at(0),
regs::NV_PFSP_QUEUE_HEAD::zeroed().with_address(0),
);
@@ -148,9 +150,9 @@ pub(crate) fn send_msg(&mut self, bar: Bar0<'_>, packet: &[u8]) -> Result {
///
/// Returns `ETIMEDOUT` if no message was available until timeout, or a regular error code if a
/// memory allocation error occurred.
- pub(crate) fn recv_msg(&mut self, bar: Bar0<'_>) -> Result<KVec<u8>> {
+ pub(crate) fn recv_msg(&mut self) -> Result<KVec<u8>> {
let msg_size = read_poll_timeout(
- || Ok(self.poll_msgq(bar)),
+ || Ok(self.poll_msgq()),
|&size| size > 0,
Delta::from_millis(10),
Delta::from_millis(FSP_MSG_TIMEOUT_MS),
@@ -160,11 +162,13 @@ pub(crate) fn recv_msg(&mut self, bar: Bar0<'_>) -> Result<KVec<u8>> {
let mut buffer = KVec::<u8>::new();
buffer.resize(msg_size, 0, GFP_KERNEL)?;
- self.read_emem(bar, &mut buffer)?;
+ self.read_emem(&mut buffer)?;
// Reset message queue pointers after reading.
- bar.write(Array::at(0), regs::NV_PFSP_MSGQ_TAIL::zeroed().with_val(0));
- bar.write(Array::at(0), regs::NV_PFSP_MSGQ_HEAD::zeroed().with_val(0));
+ self.bar
+ .write(Array::at(0), regs::NV_PFSP_MSGQ_TAIL::zeroed().with_val(0));
+ self.bar
+ .write(Array::at(0), regs::NV_PFSP_MSGQ_HEAD::zeroed().with_val(0));
Ok(buffer)
}
diff --git a/drivers/gpu/nova-core/falcon/gsp.rs b/drivers/gpu/nova-core/falcon/gsp.rs
index f788b87bd951..ae32f401aeb0 100644
--- a/drivers/gpu/nova-core/falcon/gsp.rs
+++ b/drivers/gpu/nova-core/falcon/gsp.rs
@@ -14,7 +14,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
Falcon,
FalconEngine,
@@ -37,20 +36,20 @@ impl RegisterBase<PFalcon2Base> for Gsp {
impl FalconEngine for Gsp {}
-impl Falcon<Gsp> {
+impl<'a> Falcon<'a, Gsp> {
/// Clears the SWGEN0 bit in the Falcon's IRQ status clear register to
/// allow GSP to signal CPU for processing new messages in message queue.
- pub(crate) fn clear_swgen0_intr(&self, bar: Bar0<'_>) {
- bar.write(
+ pub(crate) fn clear_swgen0_intr(&self) {
+ self.bar.write(
WithBase::of::<Gsp>(),
regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true),
);
}
/// Checks if GSP reload/resume has completed during the boot process.
- pub(crate) fn check_reload_completed(&self, bar: Bar0<'_>, timeout: Delta) -> Result<bool> {
+ pub(crate) fn check_reload_completed(&self, timeout: Delta) -> Result<bool> {
read_poll_timeout(
- || Ok(bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)),
+ || Ok(self.bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)),
|val| val.boot_stage_3_handoff(),
Delta::ZERO,
timeout,
@@ -59,19 +58,21 @@ pub(crate) fn check_reload_completed(&self, bar: Bar0<'_>, timeout: Delta) -> Re
}
/// Returns whether the RISC-V branch privilege lockdown bit is set.
- pub(crate) fn riscv_branch_privilege_lockdown(&self, bar: Bar0<'_>) -> bool {
- bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
+ pub(crate) fn riscv_branch_privilege_lockdown(&self) -> bool {
+ self.bar
+ .read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
.riscv_br_priv_lockdown()
}
/// Returns whether GSP registers can be read by the CPU.
- pub(crate) fn priv_target_mask_released(&self, bar: Bar0<'_>) -> bool {
+ pub(crate) fn priv_target_mask_released(&self) -> bool {
/// Pattern returned by GSP register reads while the PRIV target mask still blocks CPU
/// access. The low byte varies; the upper 24 bits are fixed.
const LOCKED_PATTERN: u32 = 0xbadf_4100;
const LOCKED_MASK: u32 = 0xffff_ff00;
- let hwcfg2 = bar
+ let hwcfg2 = self
+ .bar
.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<Gsp>())
.into_raw();
diff --git a/drivers/gpu/nova-core/falcon/hal.rs b/drivers/gpu/nova-core/falcon/hal.rs
index 89b56823906b..0cb665162c90 100644
--- a/drivers/gpu/nova-core/falcon/hal.rs
+++ b/drivers/gpu/nova-core/falcon/hal.rs
@@ -34,7 +34,7 @@ pub(crate) enum LoadMethod {
/// registers.
pub(crate) trait FalconHal<E: FalconEngine>: Send + Sync {
/// Activates the Falcon core if the engine is a risvc/falcon dual engine.
- fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>) -> Result {
Ok(())
}
@@ -42,14 +42,14 @@ fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
/// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header.
fn signature_reg_fuse_version(
&self,
- falcon: &Falcon<E>,
+ falcon: &Falcon<'_, E>,
bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32>;
/// Program the boot ROM registers prior to starting a secure firmware.
- fn program_brom(&self, falcon: &Falcon<E>, bar: Bar0<'_>, params: &FalconBromParams);
+ fn program_brom(&self, falcon: &Falcon<'_, E>, bar: Bar0<'_>, params: &FalconBromParams);
/// Check if the RISC-V core is active.
/// Returns `true` if the RISC-V core is active, `false` otherwise.
diff --git a/drivers/gpu/nova-core/falcon/hal/ga102.rs b/drivers/gpu/nova-core/falcon/hal/ga102.rs
index cf6ce47e6b25..e45adb0312c0 100644
--- a/drivers/gpu/nova-core/falcon/hal/ga102.rs
+++ b/drivers/gpu/nova-core/falcon/hal/ga102.rs
@@ -115,21 +115,21 @@ pub(super) fn new() -> Self {
}
impl<E: FalconEngine> FalconHal<E> for Ga102<E> {
- fn select_core(&self, _falcon: &Falcon<E>, bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, bar: Bar0<'_>) -> Result {
select_core_ga102::<E>(bar)
}
fn signature_reg_fuse_version(
&self,
- falcon: &Falcon<E>,
+ falcon: &Falcon<'_, E>,
bar: Bar0<'_>,
engine_id_mask: u16,
ucode_id: u8,
) -> Result<u32> {
- signature_reg_fuse_version_ga102(&falcon.dev, bar, engine_id_mask, ucode_id)
+ signature_reg_fuse_version_ga102(falcon.dev, bar, engine_id_mask, ucode_id)
}
- fn program_brom(&self, _falcon: &Falcon<E>, bar: Bar0<'_>, params: &FalconBromParams) {
+ fn program_brom(&self, _falcon: &Falcon<'_, E>, bar: Bar0<'_>, params: &FalconBromParams) {
program_brom_ga102::<E>(bar, params);
}
diff --git a/drivers/gpu/nova-core/falcon/hal/tu102.rs b/drivers/gpu/nova-core/falcon/hal/tu102.rs
index 3aaee3869312..de48ded45bbe 100644
--- a/drivers/gpu/nova-core/falcon/hal/tu102.rs
+++ b/drivers/gpu/nova-core/falcon/hal/tu102.rs
@@ -34,13 +34,13 @@ pub(super) fn new() -> Self {
}
impl<E: FalconEngine> FalconHal<E> for Tu102<E> {
- fn select_core(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>) -> Result {
+ fn select_core(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>) -> Result {
Ok(())
}
fn signature_reg_fuse_version(
&self,
- _falcon: &Falcon<E>,
+ _falcon: &Falcon<'_, E>,
_bar: Bar0<'_>,
_engine_id_mask: u16,
_ucode_id: u8,
@@ -48,7 +48,7 @@ fn signature_reg_fuse_version(
Ok(0)
}
- fn program_brom(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>, _params: &FalconBromParams) {}
+ fn program_brom(&self, _falcon: &Falcon<'_, E>, _bar: Bar0<'_>, _params: &FalconBromParams) {}
fn is_riscv_active(&self, bar: Bar0<'_>) -> bool {
bar.read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::of::<E>())
diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs
index d9313ac361af..acb7f4d8a532 100644
--- a/drivers/gpu/nova-core/firmware/booter.rs
+++ b/drivers/gpu/nova-core/firmware/booter.rs
@@ -15,7 +15,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
sec2::Sec2,
Falcon,
@@ -293,8 +292,7 @@ pub(crate) fn new(
kind: BooterKind,
chipset: Chipset,
ver: &str,
- falcon: &Falcon<<Self as FalconFirmware>::Target>,
- bar: Bar0<'_>,
+ falcon: &Falcon<'_, <Self as FalconFirmware>::Target>,
) -> Result<Self> {
let fw_name = match kind {
BooterKind::Loader => "booter_load",
@@ -339,11 +337,8 @@ pub(crate) fn new(
} else {
// Obtain the version from the fuse register, and extract the corresponding
// signature.
- let reg_fuse_version = falcon.signature_reg_fuse_version(
- bar,
- brom_params.engine_id_mask,
- brom_params.ucode_id,
- )?;
+ let reg_fuse_version = falcon
+ .signature_reg_fuse_version(brom_params.engine_id_mask, brom_params.ucode_id)?;
// `0` means the last signature should be used.
const FUSE_VERSION_USE_LAST_SIG: u32 = 0;
@@ -405,18 +400,14 @@ pub(crate) fn new(
pub(crate) fn run<T>(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- sec2_falcon: &Falcon<Sec2>,
+ sec2_falcon: &Falcon<'_, Sec2>,
wpr_meta: &Coherent<T>,
) -> Result {
- sec2_falcon.reset(bar)?;
- sec2_falcon.load(dev, bar, self)?;
+ sec2_falcon.reset()?;
+ sec2_falcon.load(self)?;
let wpr_handle = wpr_meta.dma_handle();
- let (mbox0, mbox1) = sec2_falcon.boot(
- bar,
- Some(wpr_handle as u32),
- Some((wpr_handle >> 32) as u32),
- )?;
+ let (mbox0, mbox1) =
+ sec2_falcon.boot(Some(wpr_handle as u32), Some((wpr_handle >> 32) as u32))?;
dev_dbg!(dev, "SEC2 MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
if mbox0 != 0 {
diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs
index 199ae2adb664..95e0dd77746b 100644
--- a/drivers/gpu/nova-core/firmware/fwsec.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec.rs
@@ -27,7 +27,6 @@
};
use crate::{
- driver::Bar0,
falcon::{
gsp::Gsp,
Falcon,
@@ -320,8 +319,7 @@ impl FwsecFirmware {
/// command.
pub(crate) fn new(
dev: &Device<device::Bound>,
- falcon: &Falcon<Gsp>,
- bar: Bar0<'_>,
+ falcon: &Falcon<'_, Gsp>,
bios: &Vbios,
cmd: FwsecCommand,
) -> Result<Self> {
@@ -337,7 +335,7 @@ pub(crate) fn new(
.ok_or(EINVAL)?;
let desc_sig_versions = u32::from(desc.signature_versions());
let reg_fuse_version =
- falcon.signature_reg_fuse_version(bar, desc.engine_id_mask(), desc.ucode_id())?;
+ falcon.signature_reg_fuse_version(desc.engine_id_mask(), desc.ucode_id())?;
dev_dbg!(
dev,
"desc_sig_versions: {:#x}, reg_fuse_version: {}\n",
@@ -390,21 +388,16 @@ pub(crate) fn new(
/// This must only be called on chipsets that do not need the FWSEC bootloader (i.e., where
/// [`Chipset::needs_fwsec_bootloader()`](crate::gpu::Chipset::needs_fwsec_bootloader) returns
/// `false`). On chipsets that do, use [`bootloader::FwsecFirmwareWithBl`] instead.
- pub(crate) fn run(
- &self,
- dev: &Device<device::Bound>,
- falcon: &Falcon<Gsp>,
- bar: Bar0<'_>,
- ) -> Result<()> {
+ pub(crate) fn run(&self, dev: &Device<device::Bound>, falcon: &Falcon<'_, Gsp>) -> Result<()> {
// Reset falcon, load the firmware, and run it.
falcon
- .reset(bar)
+ .reset()
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
falcon
- .load(dev, bar, self)
+ .load(self)
.inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;
let (mbox0, _) = falcon
- .boot(bar, Some(0), None)
+ .boot(Some(0), None)
.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);
diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
index ac1558a83b83..71f5a70a1114 100644
--- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
@@ -12,10 +12,6 @@
Device, //
},
dma::Coherent,
- io::{
- register::WithBase, //
- Io,
- },
prelude::*,
ptr::{
Alignable,
@@ -29,15 +25,12 @@
};
use crate::{
- driver::Bar0,
falcon::{
self,
gsp::Gsp,
Falcon,
FalconBromParams,
FalconDmaLoadable,
- FalconFbifMemType,
- FalconFbifTarget,
FalconFirmware,
FalconPioDmemLoadTarget,
FalconPioImemLoadTarget,
@@ -50,8 +43,7 @@
FIRMWARE_VERSION, //
},
gpu::Chipset,
- num::FromSafeCast,
- regs,
+ num::FromSafeCast, //
};
/// Descriptor used by RM to figure out the requirements of the boot loader.
@@ -275,33 +267,20 @@ 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>,
- bar: Bar0<'_>,
- ) -> Result<()> {
+ pub(crate) fn run(&self, dev: &Device<device::Bound>, falcon: &Falcon<'_, Gsp>) -> Result<()> {
// Reset falcon, load the firmware, and run it.
falcon
- .reset(bar)
+ .reset()
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
falcon
- .pio_load(bar, self)
+ .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.
- bar.update(
- regs::NV_PFALCON_FBIF_TRANSCFG::of::<Gsp>()
- .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)
- },
- );
+ falcon.set_fbif_transcfg_phys_sysmem(self.dmem_desc.ctx_dma)?;
let (mbox0, _) = falcon
- .boot(bar, Some(0), None)
+ .boot(Some(0), None)
.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);
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index 4b97d1fb505e..574e1627e63c 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -224,27 +224,27 @@ pub(crate) fn boot_params_dma_handle(&self) -> u64 {
/// An `Fsp` is produced by [`Fsp::wait_secure_boot`], which only returns once FSP secure boot
/// has completed. It owns the FSP falcon and the FMC firmware, which are used for the subsequent
/// Chain of Trust boot.
-pub(crate) struct Fsp {
- falcon: Falcon<FspEngine>,
+pub(crate) struct Fsp<'a> {
+ falcon: Falcon<'a, FspEngine>,
fsp_fw: FspFirmware,
}
-impl Fsp {
+impl<'a> Fsp<'a> {
/// Waits for FSP secure boot completion, then returns the [`Fsp`] interface.
///
/// Polls the thermal scratch register until FSP signals boot completion or the timeout
/// elapses. Returning an [`Fsp`] only on success guarantees, at the API level, that the
/// interface is not used before secure boot has completed.
pub(crate) fn wait_secure_boot(
- dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
+ dev: &'a device::Device<device::Bound>,
+ bar: Bar0<'a>,
chipset: Chipset,
- ) -> Result<Fsp> {
+ ) -> Result<Fsp<'a>> {
/// FSP secure boot completion timeout in milliseconds.
const FSP_SECURE_BOOT_TIMEOUT_MS: i64 = 5000;
let hal = hal::fsp_hal(chipset).ok_or(ENOTSUPP)?;
- let falcon = Falcon::<FspEngine>::new(dev, chipset)?;
+ let falcon = Falcon::<FspEngine>::new(dev, chipset, bar)?;
let fsp_fw = FspFirmware::new(dev, chipset, FIRMWARE_VERSION)?;
read_poll_timeout(
@@ -262,13 +262,13 @@ pub(crate) fn wait_secure_boot(
/// Sends a message to FSP and waits for the response.
/// Returns the full response buffer on success.
- fn send_sync_fsp<M>(&mut self, dev: &device::Device, bar: Bar0<'_>, msg: &M) -> Result<KVec<u8>>
+ fn send_sync_fsp<M>(&mut self, dev: &device::Device, msg: &M) -> Result<KVec<u8>>
where
M: MessageToFsp,
{
- self.falcon.send_msg(bar, msg.as_bytes())?;
+ self.falcon.send_msg(msg.as_bytes())?;
- let response_buf = self.falcon.recv_msg(bar).inspect_err(|e| {
+ let response_buf = self.falcon.recv_msg().inspect_err(|e| {
dev_err!(dev, "FSP response error: {:?}\n", e);
})?;
@@ -330,7 +330,6 @@ fn send_sync_fsp<M>(&mut self, dev: &device::Device, bar: Bar0<'_>, msg: &M) ->
pub(crate) fn boot_fmc(
&mut self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
fb_layout: &FbLayout,
args: &FmcBootArgs,
) -> Result {
@@ -341,7 +340,7 @@ pub(crate) fn boot_fmc(
GFP_KERNEL,
)?;
- let _response_buf = self.send_sync_fsp(dev, bar, &*msg)?;
+ let _response_buf = self.send_sync_fsp(dev, &*msg)?;
dev_dbg!(dev, "FSP Chain of Trust completed successfully\n");
Ok(())
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 4d76be429e75..43c3f4f8df71 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -273,9 +273,9 @@ struct GspResources<'gpu> {
/// MMIO mapping of PCI BAR 0.
bar: Bar0<'gpu>,
/// GSP falcon instance, used for GSP boot up and cleanup.
- gsp_falcon: Falcon<GspFalcon>,
+ gsp_falcon: Falcon<'gpu, GspFalcon>,
/// SEC2 falcon instance, used for GSP boot up and cleanup.
- sec2_falcon: Falcon<Sec2Falcon>,
+ sec2_falcon: Falcon<'gpu, Sec2Falcon>,
/// GSP runtime data.
#[pin]
gsp: Gsp,
@@ -351,10 +351,11 @@ pub(crate) fn new(
gsp_falcon: Falcon::new(
pdev.as_ref(),
spec.chipset,
+ bar
)
- .inspect(|falcon| falcon.clear_swgen0_intr(bar))?,
+ .inspect(|falcon| falcon.clear_swgen0_intr())?,
- sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
+ sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset, bar)?,
gsp <- Gsp::new(pdev),
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 73e93403601c..b4ac4156056e 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -57,8 +57,8 @@ pub(crate) struct GspBootContext<'a> {
pub(crate) pdev: &'a pci::Device<device::Bound>,
pub(crate) bar: Bar0<'a>,
pub(crate) chipset: Chipset,
- pub(crate) gsp_falcon: &'a Falcon<GspFalcon>,
- pub(crate) sec2_falcon: &'a Falcon<Sec2Falcon>,
+ pub(crate) gsp_falcon: &'a Falcon<'a, GspFalcon>,
+ pub(crate) sec2_falcon: &'a Falcon<'a, Sec2Falcon>,
}
impl<'a> GspBootContext<'a> {
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index bb2000b7a78b..ab0491b57944 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -37,8 +37,8 @@ pub(super) struct BootUnloadArgs<'a> {
gsp: &'a super::Gsp,
dev: &'a device::Device<device::Bound>,
bar: Bar0<'a>,
- gsp_falcon: &'a Falcon<Gsp>,
- sec2_falcon: &'a Falcon<Sec2>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
}
@@ -56,8 +56,8 @@ pub(super) fn new(
gsp: &'a super::Gsp,
dev: &'a device::Device<device::Bound>,
bar: Bar0<'a>,
- gsp_falcon: &'a Falcon<Gsp>,
- sec2_falcon: &'a Falcon<Sec2>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
) -> Self {
Self {
@@ -120,17 +120,17 @@ pub(crate) fn boot(
// Perform the chipset-specific boot sequence, and retrieve the unload bundle.
let unload_guard = hal.boot(&self, &ctx, &fb_layout, &wpr_meta)?;
- gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version);
+ gsp_falcon.write_os_version(gsp_fw.bootloader.app_version);
// Poll for RISC-V to become active before continuing.
read_poll_timeout(
- || Ok(gsp_falcon.is_riscv_active(bar)),
+ || Ok(gsp_falcon.is_riscv_active()),
|val: &bool| *val,
Delta::from_millis(10),
Delta::from_secs(5),
)?;
- dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar),);
+ dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(),);
self.cmdq
.send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?;
@@ -149,7 +149,7 @@ pub(crate) fn boot(
fn shutdown_gsp(
cmdq: &Cmdq,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<Gsp>,
+ gsp_falcon: &Falcon<'_, Gsp>,
mode: commands::PowerStateLevel,
) -> Result {
// Command to shut the GSP down.
@@ -158,7 +158,7 @@ fn shutdown_gsp(
// Wait until GSP signals it is suspended.
const LIBOS_INTERRUPT_PROCESSOR_SUSPENDED: u32 = bits::bit_u32(31);
read_poll_timeout(
- || Ok(gsp_falcon.read_mailbox0(bar)),
+ || Ok(gsp_falcon.read_mailbox0()),
|&mb0| mb0 & LIBOS_INTERRUPT_PROCESSOR_SUSPENDED != 0,
Delta::from_millis(10),
Delta::from_secs(5),
@@ -173,8 +173,8 @@ pub(crate) fn unload(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<Gsp>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, Gsp>,
+ sec2_falcon: &Falcon<'_, Sec2>,
unload_bundle: Option<super::UnloadBundle>,
) -> Result {
// Shut down the GSP. Keep going even in case of error.
diff --git a/drivers/gpu/nova-core/gsp/hal.rs b/drivers/gpu/nova-core/gsp/hal.rs
index 51a277fe97bb..d3e47ef206de 100644
--- a/drivers/gpu/nova-core/gsp/hal.rs
+++ b/drivers/gpu/nova-core/gsp/hal.rs
@@ -42,8 +42,8 @@ fn run(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result;
}
diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
index 2187e11168b2..1d06405a32f6 100644
--- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
+++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
@@ -42,10 +42,10 @@ struct GspMbox {
impl GspMbox {
/// Reads both mailboxes from the GSP falcon.
- fn read(gsp_falcon: &Falcon<GspEngine>, bar: Bar0<'_>) -> Self {
+ fn read(gsp_falcon: &Falcon<'_, GspEngine>) -> Self {
Self {
- mbox0: gsp_falcon.read_mailbox0(bar),
- mbox1: gsp_falcon.read_mailbox1(bar),
+ mbox0: gsp_falcon.read_mailbox0(),
+ mbox1: gsp_falcon.read_mailbox1(),
}
}
@@ -60,8 +60,7 @@ fn combined_addr(&self) -> u64 {
/// either condition should stop the poll loop.
fn lockdown_released_or_error(
&self,
- gsp_falcon: &Falcon<GspEngine>,
- bar: Bar0<'_>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
fmc_boot_params_addr: u64,
) -> bool {
// GSP-FMC normally clears the boot parameters address from the mailboxes early during
@@ -71,15 +70,14 @@ fn lockdown_released_or_error(
return self.combined_addr() != fmc_boot_params_addr;
}
- !gsp_falcon.riscv_branch_privilege_lockdown(bar)
+ !gsp_falcon.riscv_branch_privilege_lockdown()
}
}
/// Waits for GSP lockdown to be released after FSP Chain of Trust.
fn wait_for_gsp_lockdown_release(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
fmc_boot_params_addr: u64,
) -> Result {
dev_dbg!(dev, "Waiting for GSP lockdown release\n");
@@ -88,14 +86,14 @@ fn wait_for_gsp_lockdown_release(
|| {
// While the PRIV target mask is still locked to FSP, GSP register and mailbox reads
// are not meaningful. Wait until HWCFG2 says the CPU can read them.
- Ok(match gsp_falcon.priv_target_mask_released(bar) {
+ Ok(match gsp_falcon.priv_target_mask_released() {
false => None,
- true => Some(GspMbox::read(gsp_falcon, bar)),
+ true => Some(GspMbox::read(gsp_falcon)),
})
},
|mbox| match mbox {
None => false,
- Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, bar, fmc_boot_params_addr),
+ Some(mbox) => mbox.lockdown_released_or_error(gsp_falcon, fmc_boot_params_addr),
},
Delta::from_millis(10),
Delta::from_secs(30),
@@ -122,13 +120,13 @@ impl UnloadBundle for FspUnloadBundle {
fn run(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- _sec2_falcon: &Falcon<Sec2>,
+ _bar: Bar0<'_>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ _sec2_falcon: &Falcon<'_, Sec2>,
) -> Result {
// GSP falcon does most of the work of resetting, so just wait for it to finish.
read_poll_timeout(
- || Ok(gsp_falcon.is_riscv_active(bar)),
+ || Ok(gsp_falcon.is_riscv_active()),
|&active| !active,
Delta::from_millis(10),
Delta::from_secs(5),
@@ -176,9 +174,9 @@ fn boot<'a>(
false,
)?;
- fsp.boot_fmc(dev, bar, fb_layout, &args)?;
+ fsp.boot_fmc(dev, fb_layout, &args)?;
- wait_for_gsp_lockdown_release(dev, bar, gsp_falcon, args.boot_params_dma_handle())?;
+ wait_for_gsp_lockdown_release(dev, gsp_falcon, args.boot_params_dma_handle())?;
Ok(unload_guard)
}
diff --git a/drivers/gpu/nova-core/gsp/hal/tu102.rs b/drivers/gpu/nova-core/gsp/hal/tu102.rs
index f8a8541704ee..180d47fb8f4e 100644
--- a/drivers/gpu/nova-core/gsp/hal/tu102.rs
+++ b/drivers/gpu/nova-core/gsp/hal/tu102.rs
@@ -62,12 +62,11 @@ impl FwsecUnloadFirmware {
/// Loads the FWSEC SB firmware, as well as its bootloader if `chipset` requires it.
fn new(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
chipset: Chipset,
bios: &Vbios,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
) -> Result<Self> {
- let fwsec_sb = FwsecFirmware::new(dev, gsp_falcon, bar, bios, FwsecCommand::Sb)?;
+ let fwsec_sb = FwsecFirmware::new(dev, gsp_falcon, bios, FwsecCommand::Sb)?;
Ok(if chipset.needs_fwsec_bootloader() {
Self::WithBl(FwsecFirmwareWithBl::new(fwsec_sb, dev, chipset)?)
@@ -80,12 +79,11 @@ fn new(
fn run(
&self,
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
) -> Result {
match self {
- Self::WithoutBl(fw) => fw.run(dev, gsp_falcon, bar),
- Self::WithBl(fw) => fw.run(dev, gsp_falcon, bar),
+ Self::WithoutBl(fw) => fw.run(dev, gsp_falcon),
+ Self::WithBl(fw) => fw.run(dev, gsp_falcon),
}
}
}
@@ -101,22 +99,20 @@ impl Sec2UnloadBundle {
/// Load and prepare the resources required to properly reset the GSP after it has been stopped.
fn build(
dev: &device::Device<device::Bound>,
- bar: Bar0<'_>,
chipset: Chipset,
bios: &Vbios,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result<KBox<dyn UnloadBundle>> {
KBox::new(
Self {
- fwsec_sb: FwsecUnloadFirmware::new(dev, bar, chipset, bios, gsp_falcon)?,
+ fwsec_sb: FwsecUnloadFirmware::new(dev, chipset, bios, gsp_falcon)?,
booter_unloader: BooterFirmware::new(
dev,
BooterKind::Unloader,
chipset,
FIRMWARE_VERSION,
sec2_falcon,
- bar,
)?,
},
GFP_KERNEL,
@@ -131,14 +127,14 @@ fn run(
&self,
dev: &device::Device<device::Bound>,
bar: Bar0<'_>,
- gsp_falcon: &Falcon<GspEngine>,
- sec2_falcon: &Falcon<Sec2>,
+ gsp_falcon: &Falcon<'_, GspEngine>,
+ sec2_falcon: &Falcon<'_, Sec2>,
) -> Result {
// Run FWSEC-SB to reset the GSP falcon to its pre-libos state.
// Log errors but keep going if it fails.
let fwsec_sb_res = self
.fwsec_sb
- .run(dev, bar, gsp_falcon)
+ .run(dev, gsp_falcon)
.inspect_err(|e| dev_err!(dev, "FWSEC-SB failed to run: {:?}\n", e));
// Remove WPR2 region if set.
@@ -148,13 +144,12 @@ fn run(
return Ok(());
}
- sec2_falcon.reset(bar)?;
- sec2_falcon.load(dev, bar, &self.booter_unloader)?;
+ sec2_falcon.reset()?;
+ sec2_falcon.load(&self.booter_unloader)?;
// Sentinel value to confirm that Booter Unloader has run.
const MAILBOX_SENTINEL: u32 = 0xff;
- let (mbox0, _) =
- sec2_falcon.boot(bar, Some(MAILBOX_SENTINEL), Some(MAILBOX_SENTINEL))?;
+ let (mbox0, _) = sec2_falcon.boot(Some(MAILBOX_SENTINEL), Some(MAILBOX_SENTINEL))?;
if mbox0 != 0 {
dev_err!(dev, "Booter Unloader returned error 0x{:x}\n", mbox0);
return Err(EINVAL);
@@ -183,7 +178,7 @@ fn run(
fn run_fwsec_frts(
dev: &device::Device<device::Bound>,
chipset: Chipset,
- falcon: &Falcon<GspEngine>,
+ falcon: &Falcon<'_, GspEngine>,
bar: Bar0<'_>,
bios: &Vbios,
fb_layout: &FbLayout,
@@ -202,7 +197,6 @@ fn run_fwsec_frts(
let fwsec_frts = FwsecFirmware::new(
dev,
falcon,
- bar,
bios,
FwsecCommand::Frts {
frts_addr: fb_layout.frts.start,
@@ -213,10 +207,10 @@ fn run_fwsec_frts(
if chipset.needs_fwsec_bootloader() {
let fwsec_frts_bl = FwsecFirmwareWithBl::new(fwsec_frts, dev, chipset)?;
// Load and run the bootloader, which will load FWSEC-FRTS and run it.
- fwsec_frts_bl.run(dev, falcon, bar)?;
+ fwsec_frts_bl.run(dev, falcon)?;
} else {
// Load and run FWSEC-FRTS directly.
- fwsec_frts.run(dev, falcon, bar)?;
+ fwsec_frts.run(dev, falcon)?;
}
// SCRATCH_E contains the error code for FWSEC-FRTS.
@@ -286,18 +280,17 @@ fn boot<'a>(
//
// If the unload bundle creation fails, the GPU will need to be reset before the driver can
// be probed again.
- let unload_bundle =
- Sec2UnloadBundle::build(dev, bar, chipset, &bios, gsp_falcon, sec2_falcon)
- .inspect_err(|e| {
- dev_warn!(dev, "Failed to prepare unload firmware: {:?}\n", e);
- dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
- dev_warn!(
- dev,
- "The GPU will need to be reset before the driver can bind again.\n"
- );
- })
- .ok()
- .map(crate::gsp::UnloadBundle);
+ let unload_bundle = Sec2UnloadBundle::build(dev, chipset, &bios, gsp_falcon, sec2_falcon)
+ .inspect_err(|e| {
+ dev_warn!(dev, "Failed to prepare unload firmware: {:?}\n", e);
+ dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
+ dev_warn!(
+ dev,
+ "The GPU will need to be reset before the driver can bind again.\n"
+ );
+ })
+ .ok()
+ .map(crate::gsp::UnloadBundle);
// Wrap the unload bundle into a drop guard so it is automatically run upon failure.
let unload_guard =
@@ -308,13 +301,10 @@ fn boot<'a>(
run_fwsec_frts(dev, chipset, gsp_falcon, bar, &bios, fb_layout)?;
}
- gsp_falcon.reset(bar)?;
+ gsp_falcon.reset()?;
let libos_handle = gsp.libos.dma_handle();
- let (mbox0, mbox1) = gsp_falcon.boot(
- bar,
- Some(libos_handle as u32),
- Some((libos_handle >> 32) as u32),
- )?;
+ let (mbox0, mbox1) =
+ gsp_falcon.boot(Some(libos_handle as u32), Some((libos_handle >> 32) as u32))?;
dev_dbg!(dev, "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
dev_dbg!(
@@ -328,9 +318,8 @@ fn boot<'a>(
chipset,
FIRMWARE_VERSION,
sec2_falcon,
- bar,
)?
- .run(dev, bar, sec2_falcon, wpr_meta)?;
+ .run(dev, sec2_falcon, wpr_meta)?;
Ok(unload_guard)
}
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index e0850d21adca..13983d42b12b 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -133,9 +133,9 @@ pub(crate) struct GspSequencer<'a> {
/// `Bar0` for register access.
bar: Bar0<'a>,
/// SEC2 falcon for core operations.
- sec2_falcon: &'a Falcon<Sec2>,
+ sec2_falcon: &'a Falcon<'a, Sec2>,
/// GSP falcon for core operations.
- gsp_falcon: &'a Falcon<Gsp>,
+ gsp_falcon: &'a Falcon<'a, Gsp>,
/// LibOS DMA handle address.
libos_dma_handle: u64,
/// Bootloader application version.
@@ -213,16 +213,16 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
GspSeqCmd::DelayUs(cmd) => cmd.run(seq),
GspSeqCmd::RegStore(cmd) => cmd.run(seq),
GspSeqCmd::CoreReset => {
- seq.gsp_falcon.reset(seq.bar)?;
- seq.gsp_falcon.dma_reset(seq.bar);
+ seq.gsp_falcon.reset()?;
+ seq.gsp_falcon.dma_reset();
Ok(())
}
GspSeqCmd::CoreStart => {
- seq.gsp_falcon.start(seq.bar)?;
+ seq.gsp_falcon.start()?;
Ok(())
}
GspSeqCmd::CoreWaitForHalt => {
- seq.gsp_falcon.wait_till_halted(seq.bar)?;
+ seq.gsp_falcon.wait_till_halted()?;
Ok(())
}
GspSeqCmd::CoreResume => {
@@ -231,35 +231,32 @@ fn run(&self, seq: &GspSequencer<'_>) -> Result {
// sequencer will start both.
// Reset the GSP to prepare it for resuming.
- seq.gsp_falcon.reset(seq.bar)?;
+ seq.gsp_falcon.reset()?;
// Write the libOS DMA handle to GSP mailboxes.
seq.gsp_falcon.write_mailboxes(
- seq.bar,
Some(seq.libos_dma_handle as u32),
Some((seq.libos_dma_handle >> 32) as u32),
);
// Start the SEC2 falcon which will trigger GSP-RM to resume on the GSP.
- seq.sec2_falcon.start(seq.bar)?;
+ seq.sec2_falcon.start()?;
// Poll until GSP-RM reload/resume has completed (up to 2 seconds).
- seq.gsp_falcon
- .check_reload_completed(seq.bar, Delta::from_secs(2))?;
+ seq.gsp_falcon.check_reload_completed(Delta::from_secs(2))?;
// Verify SEC2 completed successfully by checking its mailbox for errors.
- let mbox0 = seq.sec2_falcon.read_mailbox0(seq.bar);
+ let mbox0 = seq.sec2_falcon.read_mailbox0();
if mbox0 != 0 {
dev_err!(seq.dev, "Sequencer: sec2 errors: {:?}\n", mbox0);
return Err(EIO);
}
// Configure GSP with the bootloader version.
- seq.gsp_falcon
- .write_os_version(seq.bar, seq.bootloader_app_version);
+ seq.gsp_falcon.write_os_version(seq.bootloader_app_version);
// Verify the GSP's RISC-V core is active indicating successful GSP boot.
- if !seq.gsp_falcon.is_riscv_active(seq.bar) {
+ if !seq.gsp_falcon.is_riscv_active() {
dev_err!(seq.dev, "Sequencer: RISC-V core is not active\n");
return Err(EIO);
}
@@ -345,9 +342,9 @@ pub(crate) struct GspSequencerParams<'a> {
/// LibOS DMA handle address.
pub(crate) libos_dma_handle: u64,
/// GSP falcon for core operations.
- pub(crate) gsp_falcon: &'a Falcon<Gsp>,
+ pub(crate) gsp_falcon: &'a Falcon<'a, Gsp>,
/// SEC2 falcon for core operations.
- pub(crate) sec2_falcon: &'a Falcon<Sec2>,
+ pub(crate) sec2_falcon: &'a Falcon<'a, Sec2>,
/// Device for logging.
pub(crate) dev: &'a device::Device,
/// BAR0 for register access.
---
base-commit: 9102e655ea7285c1bc329669865ba8a38cdb69e6
change-id: 20260624-drm-bar-refactor-90435f04c9ea
Best regards,
--
Tim Kovalenko <tim.kovalenko@proton.me>
^ permalink raw reply related
* Re: [PATCH v2] PCI/ASPM: Mask ASPM states based on Devicetree properties
From: kernel test robot @ 2026-06-24 15:48 UTC (permalink / raw)
To: Krishna Chaitanya Chundru, Bjorn Helgaas
Cc: oe-kbuild-all, linux-pci, linux-kernel, mani,
Krishna Chaitanya Chundru
In-Reply-To: <20260624-aspm-v2-1-800a4151ba3a@oss.qualcomm.com>
Hi Krishna,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 840ef6c78e6a2f694b578ecb9063241c992aaa9e]
url: https://github.com/intel-lab-lkp/linux/commits/Krishna-Chaitanya-Chundru/PCI-ASPM-Mask-ASPM-states-based-on-Devicetree-properties/20260624-181628
base: 840ef6c78e6a2f694b578ecb9063241c992aaa9e
patch link: https://lore.kernel.org/r/20260624-aspm-v2-1-800a4151ba3a%40oss.qualcomm.com
patch subject: [PATCH v2] PCI/ASPM: Mask ASPM states based on Devicetree properties
config: x86_64-buildonly-randconfig-006-20260624 (https://download.01.org/0day-ci/archive/20260624/202606242330.Ab9bKFmk-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260624/202606242330.Ab9bKFmk-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606242330.Ab9bKFmk-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/pci/pcie/aspm.c:30:13: warning: 'pcie_config_aspm_l1ss' declared 'static' but never defined [-Wunused-function]
30 | static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state);
| ^~~~~~~~~~~~~~~~~~~~~
vim +30 drivers/pci/pcie/aspm.c
29
> 30 static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state);
31
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* ✓ i915.CI.BAT: success for drm/{i915,xe}: unify runtime pm calls (rev2)
From: Patchwork @ 2026-06-24 15:48 UTC (permalink / raw)
To: Jani Nikula; +Cc: intel-gfx
In-Reply-To: <cover.1782311749.git.jani.nikula@intel.com>
[-- Attachment #1: Type: text/plain, Size: 1094 bytes --]
== Series Details ==
Series: drm/{i915,xe}: unify runtime pm calls (rev2)
URL : https://patchwork.freedesktop.org/series/168520/
State : success
== Summary ==
CI Bug Log - changes from CI_DRM_18716 -> Patchwork_168520v2
====================================================
Summary
-------
**SUCCESS**
No regressions found.
External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_168520v2/index.html
Participating hosts (42 -> 40)
------------------------------
Missing (2): bat-dg2-13 fi-snb-2520m
Changes
-------
No changes found
Build changes
-------------
* Linux: CI_DRM_18716 -> Patchwork_168520v2
CI-20190529: 20190529
CI_DRM_18716: 4e1cbe14a45bd66fe75e0d08febddb9bab0405b1 @ git://anongit.freedesktop.org/gfx-ci/linux
IGT_8985: d5fe8732b8547454c38fdd220b55f6f0cc841a3b @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
Patchwork_168520v2: 4e1cbe14a45bd66fe75e0d08febddb9bab0405b1 @ git://anongit.freedesktop.org/gfx-ci/linux
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_168520v2/index.html
[-- Attachment #2: Type: text/html, Size: 1659 bytes --]
^ permalink raw reply
* Re: [PATCH v3 2/2] tracing: Remove trace_printk.h from kernel.h
From: David Laight @ 2026-06-24 15:48 UTC (permalink / raw)
To: Steven Rostedt
Cc: linux-kernel, linux-trace-kernel, Masami Hiramatsu, Mark Rutland,
Mathieu Desnoyers, Andrew Morton, Linus Torvalds,
Sebastian Andrzej Siewior, John Ogness, Thomas Gleixner,
Peter Zijlstra, Julia Lawall, Yury Norov
In-Reply-To: <20260624103225.77116713@fedora>
On Wed, 24 Jun 2026 10:32:25 -0400
Steven Rostedt <rostedt@kernel.org> wrote:
> On Wed, 24 Jun 2026 11:11:52 +0100
> David Laight <david.laight.linux@gmail.com> wrote:
>
> > That is all about changes to the file causing everything to be rebuilt,
> > not the contents of the file slowing down builds.
>
> I guess I should say it better. It causes more build time if that file
> changes. That's what I meant. I update the wording to say:
>
> There have been complaints about trace_printk.h causing more build time
> for being in kernel.h it if changes. There is also an effort to clean up
> kernel.h to have it not include unneeded header files. Move trace_printk.h
> out of kernel.h and place it in the headers and C files that use it.
> >
> > The part you are moving out of normal builds is just a few #defines.
> > They won't have a significant effect on build times either.
> >
> > So there is no point splitting out trace_controls.h.
>
> That is a completely different reason. trace_printk.h is about
> trace_printk() usage. The stuff split out into trace_controls.h have
> nothing to do with trace_printk()s.
True, but every header file costs extra time to open.
That could easily be more that the cost of parsing it (ok hand waving!).
With a long list of -I parameters just finding a file costs because of
all the failed opens.
I've just knocked it out of kernel.h, had to fix:
rcu.h
linux/ftrace.h
to make my 'normal' kernel build.
Lots of stuff includes the latter.
David
>
> -- Steve
>
^ permalink raw reply
* Re: [PATCH net] dt-bindings: net: renesas,ether: Drop example "ethernet-phy-ieee802.3-c22" fallback
From: Andrew Lunn @ 2026-06-24 15:47 UTC (permalink / raw)
To: Rob Herring (Arm)
Cc: Niklas Söderlund, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Krzysztof Kozlowski, Conor Dooley,
Geert Uytterhoeven, Magnus Damm, Sergei Shtylyov, netdev,
linux-renesas-soc, devicetree, linux-kernel
In-Reply-To: <20260624150250.131966-2-robh@kernel.org>
On Wed, Jun 24, 2026 at 10:02:50AM -0500, Rob Herring (Arm) wrote:
> Fix the Micrel PHY in the example which shouldn't have the
> fallback "ethernet-phy-ieee802.3-c22" compatible:
>
> Documentation/devicetree/bindings/net/renesas,ether.example.dtb: ethernet-phy@1 \
> (ethernet-phy-id0022.1537): compatible: ['ethernet-phy-id0022.1537', 'ethernet-phy-ieee802.3-c22'] is too long
> from schema $id: http://devicetree.org/schemas/net/micrel.yaml
>
> Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
Fixes: 37a2fce09001 ("dt-bindings: sh_eth convert bindings to json-schema")
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.