Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/nova-core/gsp/boot.rs
49213 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
use kernel::{
4
device,
5
dma::CoherentAllocation,
6
dma_write,
7
io::poll::read_poll_timeout,
8
pci,
9
prelude::*,
10
time::Delta, //
11
};
12
13
use 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
46
impl 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
}
253
254