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