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