mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
gpu: nova-core: falcon: store bar and dev in falcon
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. `FalconHal` now receives a reference to a `Falcon` and uses its methods and members instead of passing them individually. Suggested-by: Alexandre Courbot <acourbot@nvidia.com> Link: 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> Acked-by: Danilo Krummrich <dakr@kernel.org> Link: https://patch.msgid.link/20260625-drm-bar-refactor-v2-1-9db6b890d92e@proton.me Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
This commit is contained in:
parent
f1bd7119ac
commit
23d66dbab8
|
|
@ -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)?;
|
||||
self.hal.select_core(self)?;
|
||||
self.hal.reset_wait_mem_scrubbing(self)?;
|
||||
|
||||
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, &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,20 @@ 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.bar
|
||||
.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| {
|
||||
v.with_target(FalconFbifTarget::CoherentSysmem)
|
||||
.with_mem_type(FalconFbifMemType::Physical)
|
||||
});
|
||||
|
||||
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, &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()),
|
||||
);
|
||||
|
|
@ -668,10 +651,10 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
|
|||
}
|
||||
|
||||
/// 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 +664,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 +684,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 +701,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 +729,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, 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)
|
||||
}
|
||||
|
||||
/// 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),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
use kernel::prelude::*;
|
||||
|
||||
use crate::{
|
||||
driver::Bar0,
|
||||
falcon::{
|
||||
Falcon,
|
||||
FalconBromParams,
|
||||
|
|
@ -34,7 +33,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>) -> Result {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -42,24 +41,23 @@ 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>,
|
||||
bar: Bar0<'_>,
|
||||
falcon: &Falcon<'_, E>,
|
||||
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>, params: &FalconBromParams);
|
||||
|
||||
/// Check if the RISC-V core is active.
|
||||
/// Returns `true` if the RISC-V core is active, `false` otherwise.
|
||||
fn is_riscv_active(&self, bar: Bar0<'_>) -> bool;
|
||||
fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool;
|
||||
|
||||
/// Wait for memory scrubbing to complete.
|
||||
fn reset_wait_mem_scrubbing(&self, bar: Bar0<'_>) -> Result;
|
||||
fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result;
|
||||
|
||||
/// Reset the falcon engine.
|
||||
fn reset_eng(&self, bar: Bar0<'_>) -> Result;
|
||||
fn reset_eng(&self, falcon: &Falcon<'_, E>) -> Result;
|
||||
|
||||
/// Returns the method used to load data into the falcon's memory.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -115,33 +115,34 @@ pub(super) fn new() -> Self {
|
|||
}
|
||||
|
||||
impl<E: FalconEngine> FalconHal<E> for Ga102<E> {
|
||||
fn select_core(&self, _falcon: &Falcon<E>, bar: Bar0<'_>) -> Result {
|
||||
select_core_ga102::<E>(bar)
|
||||
fn select_core(&self, falcon: &Falcon<'_, E>) -> Result {
|
||||
select_core_ga102::<E>(falcon.bar)
|
||||
}
|
||||
|
||||
fn signature_reg_fuse_version(
|
||||
&self,
|
||||
falcon: &Falcon<E>,
|
||||
bar: Bar0<'_>,
|
||||
falcon: &Falcon<'_, E>,
|
||||
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, falcon.bar, engine_id_mask, ucode_id)
|
||||
}
|
||||
|
||||
fn program_brom(&self, _falcon: &Falcon<E>, bar: Bar0<'_>, params: &FalconBromParams) {
|
||||
program_brom_ga102::<E>(bar, params);
|
||||
fn program_brom(&self, falcon: &Falcon<'_, E>, params: &FalconBromParams) {
|
||||
program_brom_ga102::<E>(falcon.bar, params);
|
||||
}
|
||||
|
||||
fn is_riscv_active(&self, bar: Bar0<'_>) -> bool {
|
||||
bar.read(regs::NV_PRISCV_RISCV_CPUCTL::of::<E>())
|
||||
fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool {
|
||||
falcon
|
||||
.bar
|
||||
.read(regs::NV_PRISCV_RISCV_CPUCTL::of::<E>())
|
||||
.active_stat()
|
||||
}
|
||||
|
||||
fn reset_wait_mem_scrubbing(&self, bar: Bar0<'_>) -> Result {
|
||||
fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result {
|
||||
// TIMEOUT: memory scrubbing should complete in less than 20ms.
|
||||
read_poll_timeout(
|
||||
|| Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())),
|
||||
|| Ok(falcon.bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())),
|
||||
|r| r.mem_scrubbing_done(),
|
||||
Delta::ZERO,
|
||||
Delta::from_millis(20),
|
||||
|
|
@ -149,7 +150,9 @@ fn reset_wait_mem_scrubbing(&self, bar: Bar0<'_>) -> Result {
|
|||
.map(|_| ())
|
||||
}
|
||||
|
||||
fn reset_eng(&self, bar: Bar0<'_>) -> Result {
|
||||
fn reset_eng(&self, falcon: &Falcon<'_, E>) -> Result {
|
||||
let bar = falcon.bar;
|
||||
|
||||
let _ = bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>());
|
||||
|
||||
// According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set
|
||||
|
|
@ -162,7 +165,7 @@ fn reset_eng(&self, bar: Bar0<'_>) -> Result {
|
|||
);
|
||||
|
||||
regs::NV_PFALCON_FALCON_ENGINE::reset_engine::<E>(bar);
|
||||
self.reset_wait_mem_scrubbing(bar)?;
|
||||
self.reset_wait_mem_scrubbing(falcon)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
};
|
||||
|
||||
use crate::{
|
||||
driver::Bar0,
|
||||
falcon::{
|
||||
hal::LoadMethod,
|
||||
Falcon,
|
||||
|
|
@ -34,31 +33,32 @@ 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>) -> Result {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn signature_reg_fuse_version(
|
||||
&self,
|
||||
_falcon: &Falcon<E>,
|
||||
_bar: Bar0<'_>,
|
||||
_falcon: &Falcon<'_, E>,
|
||||
_engine_id_mask: u16,
|
||||
_ucode_id: u8,
|
||||
) -> Result<u32> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn program_brom(&self, _falcon: &Falcon<E>, _bar: Bar0<'_>, _params: &FalconBromParams) {}
|
||||
fn program_brom(&self, _falcon: &Falcon<'_, E>, _params: &FalconBromParams) {}
|
||||
|
||||
fn is_riscv_active(&self, bar: Bar0<'_>) -> bool {
|
||||
bar.read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::of::<E>())
|
||||
fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool {
|
||||
falcon
|
||||
.bar
|
||||
.read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::of::<E>())
|
||||
.active_stat()
|
||||
}
|
||||
|
||||
fn reset_wait_mem_scrubbing(&self, bar: Bar0<'_>) -> Result {
|
||||
fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result {
|
||||
// TIMEOUT: memory scrubbing should complete in less than 10ms.
|
||||
read_poll_timeout(
|
||||
|| Ok(bar.read(regs::NV_PFALCON_FALCON_DMACTL::of::<E>())),
|
||||
|| Ok(falcon.bar.read(regs::NV_PFALCON_FALCON_DMACTL::of::<E>())),
|
||||
|r| r.mem_scrubbing_done(),
|
||||
Delta::ZERO,
|
||||
Delta::from_millis(10),
|
||||
|
|
@ -66,9 +66,9 @@ fn reset_wait_mem_scrubbing(&self, bar: Bar0<'_>) -> Result {
|
|||
.map(|_| ())
|
||||
}
|
||||
|
||||
fn reset_eng(&self, bar: Bar0<'_>) -> Result {
|
||||
regs::NV_PFALCON_FALCON_ENGINE::reset_engine::<E>(bar);
|
||||
self.reset_wait_mem_scrubbing(bar)?;
|
||||
fn reset_eng(&self, falcon: &Falcon<'_, E>) -> Result {
|
||||
regs::NV_PFALCON_FALCON_ENGINE::reset_engine::<E>(falcon.bar);
|
||||
self.reset_wait_mem_scrubbing(falcon)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -12,10 +12,7 @@
|
|||
Device, //
|
||||
},
|
||||
dma::Coherent,
|
||||
io::{
|
||||
register::WithBase, //
|
||||
Io,
|
||||
},
|
||||
io::{register::WithBase, Io},
|
||||
prelude::*,
|
||||
ptr::{
|
||||
Alignable,
|
||||
|
|
@ -50,7 +47,7 @@
|
|||
FIRMWARE_VERSION, //
|
||||
},
|
||||
gpu::Chipset,
|
||||
num::FromSafeCast,
|
||||
num::FromSafeCast, //
|
||||
regs,
|
||||
};
|
||||
|
||||
|
|
@ -278,15 +275,15 @@ pub(crate) fn new(
|
|||
pub(crate) fn run(
|
||||
&self,
|
||||
dev: &Device<device::Bound>,
|
||||
falcon: &Falcon<Gsp>,
|
||||
falcon: &Falcon<'_, Gsp>,
|
||||
bar: Bar0<'_>,
|
||||
) -> 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.
|
||||
|
|
@ -301,7 +298,7 @@ pub(crate) fn run(
|
|||
);
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)?)
|
||||
|
|
@ -81,10 +80,10 @@ 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::WithoutBl(fw) => fw.run(dev, gsp_falcon),
|
||||
Self::WithBl(fw) => fw.run(dev, gsp_falcon, bar),
|
||||
}
|
||||
}
|
||||
|
|
@ -101,22 +100,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,8 +128,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 {
|
||||
// Run FWSEC-SB to reset the GSP falcon to its pre-libos state.
|
||||
// Log errors but keep going if it fails.
|
||||
|
|
@ -148,13 +145,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 +179,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 +198,6 @@ fn run_fwsec_frts(
|
|||
let fwsec_frts = FwsecFirmware::new(
|
||||
dev,
|
||||
falcon,
|
||||
bar,
|
||||
bios,
|
||||
FwsecCommand::Frts {
|
||||
frts_addr: fb_layout.frts.start,
|
||||
|
|
@ -216,7 +211,7 @@ fn run_fwsec_frts(
|
|||
fwsec_frts_bl.run(dev, falcon, bar)?;
|
||||
} 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 +281,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 +302,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 +319,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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user