Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/nova-core/gsp/commands.rs
122941 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
use core::{
4
array,
5
convert::Infallible,
6
ffi::FromBytesUntilNulError,
7
str::Utf8Error, //
8
};
9
10
use kernel::{
11
device,
12
pci,
13
prelude::*,
14
time::Delta,
15
transmute::{
16
AsBytes,
17
FromBytes, //
18
}, //
19
};
20
21
use crate::{
22
driver::Bar0,
23
gsp::{
24
cmdq::{
25
Cmdq,
26
CommandToGsp,
27
MessageFromGsp, //
28
},
29
fw::{
30
commands::*,
31
MsgFunction, //
32
},
33
},
34
sbuffer::SBufferIter,
35
};
36
37
/// The `GspSetSystemInfo` command.
38
pub(crate) struct SetSystemInfo<'a> {
39
pdev: &'a pci::Device<device::Bound>,
40
}
41
42
impl<'a> SetSystemInfo<'a> {
43
/// Creates a new `GspSetSystemInfo` command using the parameters of `pdev`.
44
pub(crate) fn new(pdev: &'a pci::Device<device::Bound>) -> Self {
45
Self { pdev }
46
}
47
}
48
49
impl<'a> CommandToGsp for SetSystemInfo<'a> {
50
const FUNCTION: MsgFunction = MsgFunction::GspSetSystemInfo;
51
type Command = GspSetSystemInfo;
52
type InitError = Error;
53
54
fn init(&self) -> impl Init<Self::Command, Self::InitError> {
55
GspSetSystemInfo::init(self.pdev)
56
}
57
}
58
59
struct RegistryEntry {
60
key: &'static str,
61
value: u32,
62
}
63
64
/// The `SetRegistry` command.
65
pub(crate) struct SetRegistry {
66
entries: [RegistryEntry; Self::NUM_ENTRIES],
67
}
68
69
impl SetRegistry {
70
// For now we hard-code the registry entries. Future work will allow others to
71
// be added as module parameters.
72
const NUM_ENTRIES: usize = 3;
73
74
/// Creates a new `SetRegistry` command, using a set of hardcoded entries.
75
pub(crate) fn new() -> Self {
76
Self {
77
entries: [
78
// RMSecBusResetEnable - enables PCI secondary bus reset
79
RegistryEntry {
80
key: "RMSecBusResetEnable",
81
value: 1,
82
},
83
// RMForcePcieConfigSave - forces GSP-RM to preserve PCI configuration registers on
84
// any PCI reset.
85
RegistryEntry {
86
key: "RMForcePcieConfigSave",
87
value: 1,
88
},
89
// RMDevidCheckIgnore - allows GSP-RM to boot even if the PCI dev ID is not found
90
// in the internal product name database.
91
RegistryEntry {
92
key: "RMDevidCheckIgnore",
93
value: 1,
94
},
95
],
96
}
97
}
98
}
99
100
impl CommandToGsp for SetRegistry {
101
const FUNCTION: MsgFunction = MsgFunction::SetRegistry;
102
type Command = PackedRegistryTable;
103
type InitError = Infallible;
104
105
fn init(&self) -> impl Init<Self::Command, Self::InitError> {
106
PackedRegistryTable::init(Self::NUM_ENTRIES as u32, self.variable_payload_len() as u32)
107
}
108
109
fn variable_payload_len(&self) -> usize {
110
let mut key_size = 0;
111
for i in 0..Self::NUM_ENTRIES {
112
key_size += self.entries[i].key.len() + 1; // +1 for NULL terminator
113
}
114
Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>() + key_size
115
}
116
117
fn init_variable_payload(
118
&self,
119
dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,
120
) -> Result {
121
let string_data_start_offset =
122
size_of::<PackedRegistryTable>() + Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>();
123
124
// Array for string data.
125
let mut string_data = KVec::new();
126
127
for entry in self.entries.iter().take(Self::NUM_ENTRIES) {
128
dst.write_all(
129
PackedRegistryEntry::new(
130
(string_data_start_offset + string_data.len()) as u32,
131
entry.value,
132
)
133
.as_bytes(),
134
)?;
135
136
let key_bytes = entry.key.as_bytes();
137
string_data.extend_from_slice(key_bytes, GFP_KERNEL)?;
138
string_data.push(0, GFP_KERNEL)?;
139
}
140
141
dst.write_all(string_data.as_slice())
142
}
143
}
144
145
/// Message type for GSP initialization done notification.
146
struct GspInitDone;
147
148
// SAFETY: `GspInitDone` is a zero-sized type with no bytes, therefore it
149
// trivially has no uninitialized bytes.
150
unsafe impl FromBytes for GspInitDone {}
151
152
impl MessageFromGsp for GspInitDone {
153
const FUNCTION: MsgFunction = MsgFunction::GspInitDone;
154
type InitError = Infallible;
155
type Message = ();
156
157
fn read(
158
_msg: &Self::Message,
159
_sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
160
) -> Result<Self, Self::InitError> {
161
Ok(GspInitDone)
162
}
163
}
164
165
/// Waits for GSP initialization to complete.
166
pub(crate) fn wait_gsp_init_done(cmdq: &mut Cmdq) -> Result {
167
loop {
168
match cmdq.receive_msg::<GspInitDone>(Delta::from_secs(10)) {
169
Ok(_) => break Ok(()),
170
Err(ERANGE) => continue,
171
Err(e) => break Err(e),
172
}
173
}
174
}
175
176
/// The `GetGspStaticInfo` command.
177
struct GetGspStaticInfo;
178
179
impl CommandToGsp for GetGspStaticInfo {
180
const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
181
type Command = GspStaticConfigInfo;
182
type InitError = Infallible;
183
184
fn init(&self) -> impl Init<Self::Command, Self::InitError> {
185
GspStaticConfigInfo::init_zeroed()
186
}
187
}
188
189
/// The reply from the GSP to the [`GetGspInfo`] command.
190
pub(crate) struct GetGspStaticInfoReply {
191
gpu_name: [u8; 64],
192
}
193
194
impl MessageFromGsp for GetGspStaticInfoReply {
195
const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
196
type Message = GspStaticConfigInfo;
197
type InitError = Infallible;
198
199
fn read(
200
msg: &Self::Message,
201
_sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
202
) -> Result<Self, Self::InitError> {
203
Ok(GetGspStaticInfoReply {
204
gpu_name: msg.gpu_name_str(),
205
})
206
}
207
}
208
209
/// Error type for [`GetGspStaticInfoReply::gpu_name`].
210
#[derive(Debug)]
211
pub(crate) enum GpuNameError {
212
/// The GPU name string does not contain a null terminator.
213
NoNullTerminator(FromBytesUntilNulError),
214
215
/// The GPU name string contains invalid UTF-8.
216
#[expect(dead_code)]
217
InvalidUtf8(Utf8Error),
218
}
219
220
impl GetGspStaticInfoReply {
221
/// Returns the name of the GPU as a string.
222
///
223
/// Returns an error if the string given by the GSP does not contain a null terminator or
224
/// contains invalid UTF-8.
225
pub(crate) fn gpu_name(&self) -> core::result::Result<&str, GpuNameError> {
226
CStr::from_bytes_until_nul(&self.gpu_name)
227
.map_err(GpuNameError::NoNullTerminator)?
228
.to_str()
229
.map_err(GpuNameError::InvalidUtf8)
230
}
231
}
232
233
/// Send the [`GetGspInfo`] command and awaits for its reply.
234
pub(crate) fn get_gsp_info(cmdq: &mut Cmdq, bar: &Bar0) -> Result<GetGspStaticInfoReply> {
235
cmdq.send_command(bar, GetGspStaticInfo)?;
236
237
loop {
238
match cmdq.receive_msg::<GetGspStaticInfoReply>(Delta::from_secs(5)) {
239
Ok(info) => return Ok(info),
240
Err(ERANGE) => continue,
241
Err(e) => return Err(e),
242
}
243
}
244
}
245
246