Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2
3use kernel::{
4 device,
5 dma::CoherentAllocation,
6 dma_write,
7 io::poll::read_poll_timeout,
8 pci,
9 prelude::*,
10 time::Delta, //
11};
12
13use crate::{
14 driver::Bar0,
15 falcon::{
16 gsp::Gsp,
17 sec2::Sec2,
18 Falcon, //
19 },
20 fb::FbLayout,
21 firmware::{
22 booter::{
23 BooterFirmware,
24 BooterKind, //
25 },
26 fwsec::{
27 FwsecCommand,
28 FwsecFirmware, //
29 },
30 gsp::GspFirmware,
31 FIRMWARE_VERSION, //
32 },
33 gpu::Chipset,
34 gsp::{
35 commands,
36 sequencer::{
37 GspSequencer,
38 GspSequencerParams, //
39 },
40 GspFwWprMeta, //
41 },
42 regs,
43 vbios::Vbios,
44};
45
46impl super::Gsp {
47 /// Helper function to load and run the FWSEC-FRTS firmware and confirm that it has properly
48 /// created the WPR2 region.
49 fn run_fwsec_frts(
50 dev: &device::Device<device::Bound>,
51 falcon: &Falcon<Gsp>,
52 bar: &Bar0,
53 bios: &Vbios,
54 fb_layout: &FbLayout,
55 ) -> Result<()> {
56 // Check that the WPR2 region does not already exists - if it does, we cannot run
57 // FWSEC-FRTS until the GPU is reset.
58 if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != 0 {
59 dev_err!(
60 dev,
61 "WPR2 region already exists - GPU needs to be reset to proceed\n"
62 );
63 return Err(EBUSY);
64 }
65
66 let fwsec_frts = FwsecFirmware::new(
67 dev,
68 falcon,
69 bar,
70 bios,
71 FwsecCommand::Frts {
72 frts_addr: fb_layout.frts.start,
73 frts_size: fb_layout.frts.end - fb_layout.frts.start,
74 },
75 )?;
76
77 // Run FWSEC-FRTS to create the WPR2 region.
78 fwsec_frts.run(dev, falcon, bar)?;
79
80 // SCRATCH_E contains the error code for FWSEC-FRTS.
81 let frts_status = regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar).frts_err_code();
82 if frts_status != 0 {
83 dev_err!(
84 dev,
85 "FWSEC-FRTS returned with error code {:#x}",
86 frts_status
87 );
88
89 return Err(EIO);
90 }
91
92 // Check that the WPR2 region has been created as we requested.
93 let (wpr2_lo, wpr2_hi) = (
94 regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(),
95 regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(),
96 );
97
98 match (wpr2_lo, wpr2_hi) {
99 (_, 0) => {
100 dev_err!(dev, "WPR2 region not created after running FWSEC-FRTS\n");
101
102 Err(EIO)
103 }
104 (wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => {
105 dev_err!(
106 dev,
107 "WPR2 region created at unexpected address {:#x}; expected {:#x}\n",
108 wpr2_lo,
109 fb_layout.frts.start,
110 );
111
112 Err(EIO)
113 }
114 (wpr2_lo, wpr2_hi) => {
115 dev_dbg!(dev, "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi);
116 dev_dbg!(dev, "GPU instance built\n");
117
118 Ok(())
119 }
120 }
121 }
122
123 /// Attempt to boot the GSP.
124 ///
125 /// This is a GPU-dependent and complex procedure that involves loading firmware files from
126 /// user-space, patching them with signatures, and building firmware-specific intricate data
127 /// structures that the GSP will use at runtime.
128 ///
129 /// Upon return, the GSP is up and running, and its runtime object given as return value.
130 pub(crate) fn boot(
131 mut self: Pin<&mut Self>,
132 pdev: &pci::Device<device::Bound>,
133 bar: &Bar0,
134 chipset: Chipset,
135 gsp_falcon: &Falcon<Gsp>,
136 sec2_falcon: &Falcon<Sec2>,
137 ) -> Result {
138 let dev = pdev.as_ref();
139
140 let bios = Vbios::new(dev, bar)?;
141
142 let gsp_fw = KBox::pin_init(
143 GspFirmware::new(dev, chipset, FIRMWARE_VERSION)?,
144 GFP_KERNEL,
145 )?;
146
147 let fb_layout = FbLayout::new(chipset, bar, &gsp_fw)?;
148 dev_dbg!(dev, "{:#x?}\n", fb_layout);
149
150 Self::run_fwsec_frts(dev, gsp_falcon, bar, &bios, &fb_layout)?;
151
152 let booter_loader = BooterFirmware::new(
153 dev,
154 BooterKind::Loader,
155 chipset,
156 FIRMWARE_VERSION,
157 sec2_falcon,
158 bar,
159 )?;
160
161 let wpr_meta =
162 CoherentAllocation::<GspFwWprMeta>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?;
163 dma_write!(wpr_meta[0] = GspFwWprMeta::new(&gsp_fw, &fb_layout))?;
164
165 self.cmdq
166 .send_command(bar, commands::SetSystemInfo::new(pdev))?;
167 self.cmdq.send_command(bar, commands::SetRegistry::new())?;
168
169 gsp_falcon.reset(bar)?;
170 let libos_handle = self.libos.dma_handle();
171 let (mbox0, mbox1) = gsp_falcon.boot(
172 bar,
173 Some(libos_handle as u32),
174 Some((libos_handle >> 32) as u32),
175 )?;
176 dev_dbg!(
177 pdev.as_ref(),
178 "GSP MBOX0: {:#x}, MBOX1: {:#x}\n",
179 mbox0,
180 mbox1
181 );
182
183 dev_dbg!(
184 pdev.as_ref(),
185 "Using SEC2 to load and run the booter_load firmware...\n"
186 );
187
188 sec2_falcon.reset(bar)?;
189 sec2_falcon.dma_load(bar, &booter_loader)?;
190 let wpr_handle = wpr_meta.dma_handle();
191 let (mbox0, mbox1) = sec2_falcon.boot(
192 bar,
193 Some(wpr_handle as u32),
194 Some((wpr_handle >> 32) as u32),
195 )?;
196 dev_dbg!(
197 pdev.as_ref(),
198 "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n",
199 mbox0,
200 mbox1
201 );
202
203 if mbox0 != 0 {
204 dev_err!(
205 pdev.as_ref(),
206 "Booter-load failed with error {:#x}\n",
207 mbox0
208 );
209 return Err(ENODEV);
210 }
211
212 gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version);
213
214 // Poll for RISC-V to become active before running sequencer
215 read_poll_timeout(
216 || Ok(gsp_falcon.is_riscv_active(bar)),
217 |val: &bool| *val,
218 Delta::from_millis(10),
219 Delta::from_secs(5),
220 )?;
221
222 dev_dbg!(
223 pdev.as_ref(),
224 "RISC-V active? {}\n",
225 gsp_falcon.is_riscv_active(bar),
226 );
227
228 // Create and run the GSP sequencer.
229 let seq_params = GspSequencerParams {
230 bootloader_app_version: gsp_fw.bootloader.app_version,
231 libos_dma_handle: libos_handle,
232 gsp_falcon,
233 sec2_falcon,
234 dev: pdev.as_ref().into(),
235 bar,
236 };
237 GspSequencer::run(&mut self.cmdq, seq_params)?;
238
239 // Wait until GSP is fully initialized.
240 commands::wait_gsp_init_done(&mut self.cmdq)?;
241
242 // Obtain and display basic GPU information.
243 let info = commands::get_gsp_info(&mut self.cmdq, bar)?;
244 dev_info!(
245 pdev.as_ref(),
246 "GPU name: {}\n",
247 info.gpu_name().unwrap_or("invalid GPU name")
248 );
249
250 Ok(())
251 }
252}