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