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