Skip to content

Commit 859aa3d

Browse files
GnurouDanilo Krummrich
authored andcommitted
gpu: nova-core: load and run FWSEC-FRTS
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 <[email protected]> Signed-off-by: Alexandre Courbot <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Danilo Krummrich <[email protected]>
1 parent 31f0fee commit 859aa3d

File tree

4 files changed

+136
-13
lines changed

4 files changed

+136
-13
lines changed

drivers/gpu/nova-core/falcon.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22

33
//! Falcon microprocessor base support
44
5-
// To be removed when all code is used.
6-
#![expect(dead_code)]
7-
85
use core::ops::Deref;
96
use core::time::Duration;
107
use hal::FalconHal;

drivers/gpu/nova-core/firmware/fwsec.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,4 +395,29 @@ impl FwsecFirmware {
395395
ucode: ucode_signed,
396396
})
397397
}
398+
399+
/// Loads the FWSEC firmware into `falcon` and execute it.
400+
pub(crate) fn run(
401+
&self,
402+
dev: &Device<device::Bound>,
403+
falcon: &Falcon<Gsp>,
404+
bar: &Bar0,
405+
) -> Result<()> {
406+
// Reset falcon, load the firmware, and run it.
407+
falcon
408+
.reset(bar)
409+
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
410+
falcon
411+
.dma_load(bar, self)
412+
.inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;
413+
let (mbox0, _) = falcon
414+
.boot(bar, Some(0), None)
415+
.inspect_err(|e| dev_err!(dev, "Failed to boot FWSEC firmware: {:?}\n", e))?;
416+
if mbox0 != 0 {
417+
dev_err!(dev, "FWSEC firmware returned error {}\n", mbox0);
418+
Err(EIO)
419+
} else {
420+
Ok(())
421+
}
422+
}
398423
}

drivers/gpu/nova-core/gpu.rs

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,85 @@ impl PinnedDrop for Gpu {
184184
}
185185

186186
impl Gpu {
187+
/// Helper function to load and run the FWSEC-FRTS firmware and confirm that it has properly
188+
/// created the WPR2 region.
189+
///
190+
/// TODO: this needs to be moved into a larger type responsible for booting the whole GSP
191+
/// (`GspBooter`?).
192+
fn run_fwsec_frts(
193+
dev: &device::Device<device::Bound>,
194+
falcon: &Falcon<Gsp>,
195+
bar: &Bar0,
196+
bios: &Vbios,
197+
fb_layout: &FbLayout,
198+
) -> Result<()> {
199+
// Check that the WPR2 region does not already exists - if it does, we cannot run
200+
// FWSEC-FRTS until the GPU is reset.
201+
if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != 0 {
202+
dev_err!(
203+
dev,
204+
"WPR2 region already exists - GPU needs to be reset to proceed\n"
205+
);
206+
return Err(EBUSY);
207+
}
208+
209+
let fwsec_frts = FwsecFirmware::new(
210+
dev,
211+
falcon,
212+
bar,
213+
bios,
214+
FwsecCommand::Frts {
215+
frts_addr: fb_layout.frts.start,
216+
frts_size: fb_layout.frts.end - fb_layout.frts.start,
217+
},
218+
)?;
219+
220+
// Run FWSEC-FRTS to create the WPR2 region.
221+
fwsec_frts.run(dev, falcon, bar)?;
222+
223+
// SCRATCH_E contains the error code for FWSEC-FRTS.
224+
let frts_status = regs::NV_PBUS_SW_SCRATCH_0E::read(bar).frts_err_code();
225+
if frts_status != 0 {
226+
dev_err!(
227+
dev,
228+
"FWSEC-FRTS returned with error code {:#x}",
229+
frts_status
230+
);
231+
232+
return Err(EIO);
233+
}
234+
235+
// Check that the WPR2 region has been created as we requested.
236+
let (wpr2_lo, wpr2_hi) = (
237+
regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(),
238+
regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(),
239+
);
240+
241+
match (wpr2_lo, wpr2_hi) {
242+
(_, 0) => {
243+
dev_err!(dev, "WPR2 region not created after running FWSEC-FRTS\n");
244+
245+
Err(EIO)
246+
}
247+
(wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => {
248+
dev_err!(
249+
dev,
250+
"WPR2 region created at unexpected address {:#x}; expected {:#x}\n",
251+
wpr2_lo,
252+
fb_layout.frts.start,
253+
);
254+
255+
Err(EIO)
256+
}
257+
(wpr2_lo, wpr2_hi) => {
258+
dev_dbg!(dev, "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi);
259+
dev_dbg!(dev, "GPU instance built\n");
260+
261+
Ok(())
262+
}
263+
}
264+
}
265+
187266
pub(crate) fn new(
188267
pdev: &pci::Device<device::Bound>,
189268
devres_bar: Devres<Bar0>,
@@ -222,16 +301,7 @@ impl Gpu {
222301

223302
let bios = Vbios::new(pdev, bar)?;
224303

225-
let _fwsec_frts = FwsecFirmware::new(
226-
pdev.as_ref(),
227-
&gsp_falcon,
228-
bar,
229-
&bios,
230-
FwsecCommand::Frts {
231-
frts_addr: fb_layout.frts.start,
232-
frts_size: fb_layout.frts.end - fb_layout.frts.start,
233-
},
234-
)?;
304+
Self::run_fwsec_frts(pdev.as_ref(), &gsp_falcon, bar, &bios, &fb_layout)?;
235305

236306
Ok(pin_init!(Self {
237307
spec,

drivers/gpu/nova-core/regs.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ impl NV_PMC_BOOT_0 {
4242
}
4343
}
4444

45+
/* PBUS */
46+
47+
// TODO: this is an array of registers.
48+
register!(NV_PBUS_SW_SCRATCH_0E@0x00001438 {
49+
31:16 frts_err_code as u16;
50+
});
51+
4552
/* PFB */
4653

4754
register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR @ 0x00100c10 {
@@ -73,6 +80,30 @@ impl NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE {
7380
}
7481
}
7582

83+
register!(NV_PFB_PRI_MMU_WPR2_ADDR_LO@0x001fa824 {
84+
31:4 lo_val as u32, "Bits 12..40 of the lower (inclusive) bound of the WPR2 region";
85+
});
86+
87+
impl NV_PFB_PRI_MMU_WPR2_ADDR_LO {
88+
/// Returns the lower (inclusive) bound of the WPR2 region.
89+
pub(crate) fn lower_bound(self) -> u64 {
90+
(self.lo_val() as u64) << 12
91+
}
92+
}
93+
94+
register!(NV_PFB_PRI_MMU_WPR2_ADDR_HI@0x001fa828 {
95+
31:4 hi_val as u32, "Bits 12..40 of the higher (exclusive) bound of the WPR2 region";
96+
});
97+
98+
impl NV_PFB_PRI_MMU_WPR2_ADDR_HI {
99+
/// Returns the higher (exclusive) bound of the WPR2 region.
100+
///
101+
/// A value of zero means the WPR2 region is not set.
102+
pub(crate) fn higher_bound(self) -> u64 {
103+
(self.hi_val() as u64) << 12
104+
}
105+
}
106+
76107
/* PGC6 */
77108

78109
register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK @ 0x00118128 {

0 commit comments

Comments
 (0)