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