Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/nova-core/gsp/boot.rs
29281 views
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
139