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