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