With all the required pieces in place, load FWSEC-FRTS onto the GSP falcon, run it, and check that it successfully carved out the WPR2 region out of framebuffer memory.
Reviewed-by: Lyude Paul <ly...@redhat.com> Signed-off-by: Alexandre Courbot <acour...@nvidia.com> --- drivers/gpu/nova-core/falcon.rs | 3 -- drivers/gpu/nova-core/gpu.rs | 63 ++++++++++++++++++++++++++++++++++++++++- drivers/gpu/nova-core/regs.rs | 15 ++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs index 25ed8ee30def3abcc43bcba965eb62f49d532604..486be64895a0250ae4263de708784a8fdf1d54b5 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -2,9 +2,6 @@ //! Falcon microprocessor base support -// To be removed when all code is used. -#![expect(dead_code)] - use core::ops::Deref; use core::time::Duration; use hal::FalconHal; diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index b0bc390b972b5e75538797acd6abffd013a8a159..7af35ffa1d2f900e0117a55ec41312d16d718f67 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -226,7 +226,7 @@ pub(crate) fn new( let bios = Vbios::new(pdev, bar)?; - let _fwsec_frts = FwsecFirmware::new( + let fwsec_frts = FwsecFirmware::new( &gsp_falcon, pdev.as_ref(), bar, @@ -237,6 +237,67 @@ pub(crate) fn new( }, )?; + // Check that the WPR2 region does not already exists - if it does, the GPU needs to be + // reset. + if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).hi_val() != 0 { + dev_err!( + pdev.as_ref(), + "WPR2 region already exists - GPU needs to be reset to proceed\n" + ); + return Err(EBUSY); + } + + // Reset falcon, load FWSEC-FRTS, and run it. + gsp_falcon + .reset(bar) + .inspect_err(|e| dev_err!(pdev.as_ref(), "Failed to reset GSP falcon: {:?}\n", e))?; + gsp_falcon + .dma_load(bar, &fwsec_frts) + .inspect_err(|e| dev_err!(pdev.as_ref(), "Failed to load FWSEC-FRTS: {:?}\n", e))?; + let (mbox0, _) = gsp_falcon + .boot(bar, Some(0), None) + .inspect_err(|e| dev_err!(pdev.as_ref(), "Failed to boot FWSEC-FRTS: {:?}\n", e))?; + if mbox0 != 0 { + dev_err!(pdev.as_ref(), "FWSEC firmware returned error {}\n", mbox0); + return Err(EIO); + } + + // SCRATCH_E contains FWSEC-FRTS' error code, if any. + let frts_status = regs::NV_PBUS_SW_SCRATCH_0E::read(bar).frts_err_code(); + if frts_status != 0 { + dev_err!( + pdev.as_ref(), + "FWSEC-FRTS returned with error code {:#x}", + frts_status + ); + return Err(EIO); + } + + // Check the WPR2 has been created as we requested. + let (wpr2_lo, wpr2_hi) = ( + (regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lo_val() as u64) << 12, + (regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).hi_val() as u64) << 12, + ); + if wpr2_hi == 0 { + dev_err!( + pdev.as_ref(), + "WPR2 region not created after running FWSEC-FRTS\n" + ); + + return Err(EIO); + } else if wpr2_lo != fb_layout.frts.start { + dev_err!( + pdev.as_ref(), + "WPR2 region created at unexpected address {:#x}; expected {:#x}\n", + wpr2_lo, + fb_layout.frts.start, + ); + return Err(EIO); + } + + dev_dbg!(pdev.as_ref(), "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi); + dev_dbg!(pdev.as_ref(), "GPU instance built\n"); + Ok(pin_init!(Self { spec, bar: devres_bar, diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 54d4d37d6bf2c31947b965258d2733009c293a18..2a2d5610e552780957bcf00e0da1ec4cd3ac85d2 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -42,6 +42,13 @@ pub(crate) fn chipset(self) -> Result<Chipset> { } } +/* PBUS */ + +// TODO: this is an array of registers. +register!(NV_PBUS_SW_SCRATCH_0E@0x00001438 { + 31:16 frts_err_code as u16; +}); + /* PFB */ register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR @ 0x00100c10 { @@ -73,6 +80,14 @@ pub(crate) fn usable_fb_size(self) -> u64 { } } +register!(NV_PFB_PRI_MMU_WPR2_ADDR_LO@0x001fa824 { + 31:4 lo_val as u32; +}); + +register!(NV_PFB_PRI_MMU_WPR2_ADDR_HI@0x001fa828 { + 31:4 hi_val as u32; +}); + /* PGC6 */ register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK @ 0x00118128 { -- 2.49.0