|
3 | 3 | use kernel::{device, devres::Devres, error::code::*, pci, prelude::*, sync::Arc}; |
4 | 4 |
|
5 | 5 | use crate::driver::Bar0; |
6 | | -use crate::falcon::{gsp::Gsp, sec2::Sec2, Falcon}; |
7 | | -use crate::fb::FbLayout; |
| 6 | +use crate::falcon::{gsp::Gsp as GspFalcon, sec2::Sec2 as Sec2Falcon, Falcon}; |
8 | 7 | use crate::fb::SysmemFlush; |
9 | | -use crate::firmware::fwsec::{FwsecCommand, FwsecFirmware}; |
10 | 8 | use crate::firmware::{Firmware, FIRMWARE_VERSION}; |
11 | 9 | use crate::gfw; |
| 10 | +use crate::gsp::Gsp; |
12 | 11 | use crate::regs; |
13 | 12 | use crate::util; |
14 | | -use crate::vbios::Vbios; |
15 | 13 | use core::fmt; |
16 | 14 |
|
17 | 15 | macro_rules! define_chipset { |
@@ -172,133 +170,58 @@ pub(crate) struct Gpu { |
172 | 170 | /// System memory page required for flushing all pending GPU-side memory writes done through |
173 | 171 | /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation). |
174 | 172 | sysmem_flush: SysmemFlush, |
| 173 | + /// GSP falcon instance, used for GSP boot up and cleanup. |
| 174 | + gsp_falcon: Falcon<GspFalcon>, |
| 175 | + /// SEC2 falcon instance, used for GSP boot up and cleanup. |
| 176 | + sec2_falcon: Falcon<Sec2Falcon>, |
| 177 | + /// GSP runtime data. Temporarily an empty placeholder. |
| 178 | + #[pin] |
| 179 | + gsp: Gsp, |
175 | 180 | } |
176 | 181 |
|
177 | 182 | impl Gpu { |
178 | | - /// Helper function to load and run the FWSEC-FRTS firmware and confirm that it has properly |
179 | | - /// created the WPR2 region. |
180 | | - /// |
181 | | - /// TODO: this needs to be moved into a larger type responsible for booting the whole GSP |
182 | | - /// (`GspBooter`?). |
183 | | - fn run_fwsec_frts( |
184 | | - dev: &device::Device<device::Bound>, |
185 | | - falcon: &Falcon<Gsp>, |
186 | | - bar: &Bar0, |
187 | | - bios: &Vbios, |
188 | | - fb_layout: &FbLayout, |
189 | | - ) -> Result<()> { |
190 | | - // Check that the WPR2 region does not already exists - if it does, we cannot run |
191 | | - // FWSEC-FRTS until the GPU is reset. |
192 | | - if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != 0 { |
193 | | - dev_err!( |
194 | | - dev, |
195 | | - "WPR2 region already exists - GPU needs to be reset to proceed\n" |
196 | | - ); |
197 | | - return Err(EBUSY); |
198 | | - } |
199 | | - |
200 | | - let fwsec_frts = FwsecFirmware::new( |
201 | | - dev, |
202 | | - falcon, |
203 | | - bar, |
204 | | - bios, |
205 | | - FwsecCommand::Frts { |
206 | | - frts_addr: fb_layout.frts.start, |
207 | | - frts_size: fb_layout.frts.end - fb_layout.frts.start, |
208 | | - }, |
209 | | - )?; |
210 | | - |
211 | | - // Run FWSEC-FRTS to create the WPR2 region. |
212 | | - fwsec_frts.run(dev, falcon, bar)?; |
213 | | - |
214 | | - // SCRATCH_E contains the error code for FWSEC-FRTS. |
215 | | - let frts_status = regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar).frts_err_code(); |
216 | | - if frts_status != 0 { |
217 | | - dev_err!( |
218 | | - dev, |
219 | | - "FWSEC-FRTS returned with error code {:#x}", |
220 | | - frts_status |
221 | | - ); |
222 | | - |
223 | | - return Err(EIO); |
224 | | - } |
225 | | - |
226 | | - // Check that the WPR2 region has been created as we requested. |
227 | | - let (wpr2_lo, wpr2_hi) = ( |
228 | | - regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(), |
229 | | - regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(), |
230 | | - ); |
231 | | - |
232 | | - match (wpr2_lo, wpr2_hi) { |
233 | | - (_, 0) => { |
234 | | - dev_err!(dev, "WPR2 region not created after running FWSEC-FRTS\n"); |
235 | | - |
236 | | - Err(EIO) |
237 | | - } |
238 | | - (wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => { |
239 | | - dev_err!( |
240 | | - dev, |
241 | | - "WPR2 region created at unexpected address {:#x}; expected {:#x}\n", |
242 | | - wpr2_lo, |
243 | | - fb_layout.frts.start, |
244 | | - ); |
245 | | - |
246 | | - Err(EIO) |
247 | | - } |
248 | | - (wpr2_lo, wpr2_hi) => { |
249 | | - dev_dbg!(dev, "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi); |
250 | | - dev_dbg!(dev, "GPU instance built\n"); |
251 | | - |
252 | | - Ok(()) |
253 | | - } |
254 | | - } |
255 | | - } |
256 | | - |
257 | | - pub(crate) fn new( |
258 | | - pdev: &pci::Device<device::Bound>, |
| 183 | + pub(crate) fn new<'a>( |
| 184 | + pdev: &'a pci::Device<device::Bound>, |
259 | 185 | devres_bar: Arc<Devres<Bar0>>, |
260 | | - ) -> Result<impl PinInit<Self>> { |
261 | | - let bar = devres_bar.access(pdev.as_ref())?; |
262 | | - let spec = Spec::new(bar)?; |
263 | | - let fw = Firmware::new(pdev.as_ref(), spec.chipset, FIRMWARE_VERSION)?; |
264 | | - |
265 | | - dev_info!( |
266 | | - pdev.as_ref(), |
267 | | - "NVIDIA (Chipset: {}, Architecture: {:?}, Revision: {})\n", |
268 | | - spec.chipset, |
269 | | - spec.chipset.arch(), |
270 | | - spec.revision |
271 | | - ); |
| 186 | + bar: &'a Bar0, |
| 187 | + ) -> impl PinInit<Self, Error> + 'a { |
| 188 | + try_pin_init!(Self { |
| 189 | + spec: Spec::new(bar).inspect(|spec| { |
| 190 | + dev_info!( |
| 191 | + pdev.as_ref(), |
| 192 | + "NVIDIA (Chipset: {}, Architecture: {:?}, Revision: {})\n", |
| 193 | + spec.chipset, |
| 194 | + spec.chipset.arch(), |
| 195 | + spec.revision |
| 196 | + ); |
| 197 | + })?, |
272 | 198 |
|
273 | | - // We must wait for GFW_BOOT completion before doing any significant setup on the GPU. |
274 | | - gfw::wait_gfw_boot_completion(bar) |
275 | | - .inspect_err(|_| dev_err!(pdev.as_ref(), "GFW boot did not complete"))?; |
| 199 | + // We must wait for GFW_BOOT completion before doing any significant setup on the GPU. |
| 200 | + _: { |
| 201 | + gfw::wait_gfw_boot_completion(bar) |
| 202 | + .inspect_err(|_| dev_err!(pdev.as_ref(), "GFW boot did not complete"))?; |
| 203 | + }, |
276 | 204 |
|
277 | | - let sysmem_flush = SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?; |
| 205 | + fw <- Firmware::new(pdev.as_ref(), spec.chipset, FIRMWARE_VERSION)?, |
278 | 206 |
|
279 | | - let gsp_falcon = Falcon::<Gsp>::new( |
280 | | - pdev.as_ref(), |
281 | | - spec.chipset, |
282 | | - bar, |
283 | | - spec.chipset > Chipset::GA100, |
284 | | - )?; |
285 | | - gsp_falcon.clear_swgen0_intr(bar); |
| 207 | + sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?, |
286 | 208 |
|
287 | | - let _sec2_falcon = Falcon::<Sec2>::new(pdev.as_ref(), spec.chipset, bar, true)?; |
| 209 | + gsp_falcon: Falcon::new( |
| 210 | + pdev.as_ref(), |
| 211 | + spec.chipset, |
| 212 | + bar, |
| 213 | + spec.chipset > Chipset::GA100, |
| 214 | + ) |
| 215 | + .inspect(|falcon| falcon.clear_swgen0_intr(bar))?, |
288 | 216 |
|
289 | | - let fb_layout = FbLayout::new(spec.chipset, bar)?; |
290 | | - dev_dbg!(pdev.as_ref(), "{:#x?}\n", fb_layout); |
| 217 | + sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset, bar, true)?, |
291 | 218 |
|
292 | | - let bios = Vbios::new(pdev.as_ref(), bar)?; |
| 219 | + gsp <- Gsp::new(), |
293 | 220 |
|
294 | | - Self::run_fwsec_frts(pdev.as_ref(), &gsp_falcon, bar, &bios, &fb_layout)?; |
| 221 | + _: { gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)? }, |
295 | 222 |
|
296 | | - Ok(pin_init!(Self { |
297 | | - spec, |
298 | 223 | bar: devres_bar, |
299 | | - fw, |
300 | | - sysmem_flush, |
301 | | - })) |
| 224 | + }) |
302 | 225 | } |
303 | 226 |
|
304 | 227 | /// Called when the corresponding [`Device`](device::Device) is unbound. |
|
0 commit comments