xref: /linux/drivers/gpu/nova-core/gsp/boot.rs (revision e7c96980ea4d93e79b43b07c5489d700207b0055)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 use kernel::device;
4 use kernel::pci;
5 use kernel::prelude::*;
6 
7 use crate::driver::Bar0;
8 use crate::falcon::{gsp::Gsp, sec2::Sec2, Falcon};
9 use crate::fb::FbLayout;
10 use crate::firmware::fwsec::{FwsecCommand, FwsecFirmware};
11 use crate::gpu::Chipset;
12 use crate::regs;
13 use crate::vbios::Vbios;
14 
15 impl super::Gsp {
16     /// Helper function to load and run the FWSEC-FRTS firmware and confirm that it has properly
17     /// created the WPR2 region.
18     fn run_fwsec_frts(
19         dev: &device::Device<device::Bound>,
20         falcon: &Falcon<Gsp>,
21         bar: &Bar0,
22         bios: &Vbios,
23         fb_layout: &FbLayout,
24     ) -> Result<()> {
25         // Check that the WPR2 region does not already exists - if it does, we cannot run
26         // FWSEC-FRTS until the GPU is reset.
27         if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != 0 {
28             dev_err!(
29                 dev,
30                 "WPR2 region already exists - GPU needs to be reset to proceed\n"
31             );
32             return Err(EBUSY);
33         }
34 
35         let fwsec_frts = FwsecFirmware::new(
36             dev,
37             falcon,
38             bar,
39             bios,
40             FwsecCommand::Frts {
41                 frts_addr: fb_layout.frts.start,
42                 frts_size: fb_layout.frts.end - fb_layout.frts.start,
43             },
44         )?;
45 
46         // Run FWSEC-FRTS to create the WPR2 region.
47         fwsec_frts.run(dev, falcon, bar)?;
48 
49         // SCRATCH_E contains the error code for FWSEC-FRTS.
50         let frts_status = regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar).frts_err_code();
51         if frts_status != 0 {
52             dev_err!(
53                 dev,
54                 "FWSEC-FRTS returned with error code {:#x}",
55                 frts_status
56             );
57 
58             return Err(EIO);
59         }
60 
61         // Check that the WPR2 region has been created as we requested.
62         let (wpr2_lo, wpr2_hi) = (
63             regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(),
64             regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(),
65         );
66 
67         match (wpr2_lo, wpr2_hi) {
68             (_, 0) => {
69                 dev_err!(dev, "WPR2 region not created after running FWSEC-FRTS\n");
70 
71                 Err(EIO)
72             }
73             (wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => {
74                 dev_err!(
75                     dev,
76                     "WPR2 region created at unexpected address {:#x}; expected {:#x}\n",
77                     wpr2_lo,
78                     fb_layout.frts.start,
79                 );
80 
81                 Err(EIO)
82             }
83             (wpr2_lo, wpr2_hi) => {
84                 dev_dbg!(dev, "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi);
85                 dev_dbg!(dev, "GPU instance built\n");
86 
87                 Ok(())
88             }
89         }
90     }
91 
92     /// Attempt to boot the GSP.
93     ///
94     /// This is a GPU-dependent and complex procedure that involves loading firmware files from
95     /// user-space, patching them with signatures, and building firmware-specific intricate data
96     /// structures that the GSP will use at runtime.
97     ///
98     /// Upon return, the GSP is up and running, and its runtime object given as return value.
99     pub(crate) fn boot(
100         self: Pin<&mut Self>,
101         pdev: &pci::Device<device::Bound>,
102         bar: &Bar0,
103         chipset: Chipset,
104         gsp_falcon: &Falcon<Gsp>,
105         _sec2_falcon: &Falcon<Sec2>,
106     ) -> Result {
107         let dev = pdev.as_ref();
108 
109         let bios = Vbios::new(dev, bar)?;
110 
111         let fb_layout = FbLayout::new(chipset, bar)?;
112         dev_dbg!(dev, "{:#x?}\n", fb_layout);
113 
114         Self::run_fwsec_frts(dev, gsp_falcon, bar, &bios, &fb_layout)?;
115 
116         Ok(())
117     }
118 }
119