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 gsp::{ 21 cmdq::{ 22 Cmdq, 23 CommandToGsp, 24 MessageFromGsp, // 25 }, 26 fw::{ 27 commands::*, 28 MsgFunction, // 29 }, 30 }, 31 sbuffer::SBufferIter, 32 }; 33 34 /// The `GspSetSystemInfo` command. 35 pub(crate) struct SetSystemInfo<'a> { 36 pdev: &'a pci::Device<device::Bound>, 37 } 38 39 impl<'a> SetSystemInfo<'a> { 40 /// Creates a new `GspSetSystemInfo` command using the parameters of `pdev`. 41 pub(crate) fn new(pdev: &'a pci::Device<device::Bound>) -> Self { 42 Self { pdev } 43 } 44 } 45 46 impl<'a> CommandToGsp for SetSystemInfo<'a> { 47 const FUNCTION: MsgFunction = MsgFunction::GspSetSystemInfo; 48 type Command = GspSetSystemInfo; 49 type InitError = Error; 50 51 fn init(&self) -> impl Init<Self::Command, Self::InitError> { 52 GspSetSystemInfo::init(self.pdev) 53 } 54 } 55 56 struct RegistryEntry { 57 key: &'static str, 58 value: u32, 59 } 60 61 /// The `SetRegistry` command. 62 pub(crate) struct SetRegistry { 63 entries: [RegistryEntry; Self::NUM_ENTRIES], 64 } 65 66 impl SetRegistry { 67 // For now we hard-code the registry entries. Future work will allow others to 68 // be added as module parameters. 69 const NUM_ENTRIES: usize = 3; 70 71 /// Creates a new `SetRegistry` command, using a set of hardcoded entries. 72 pub(crate) fn new() -> Self { 73 Self { 74 entries: [ 75 // RMSecBusResetEnable - enables PCI secondary bus reset 76 RegistryEntry { 77 key: "RMSecBusResetEnable", 78 value: 1, 79 }, 80 // RMForcePcieConfigSave - forces GSP-RM to preserve PCI configuration registers on 81 // any PCI reset. 82 RegistryEntry { 83 key: "RMForcePcieConfigSave", 84 value: 1, 85 }, 86 // RMDevidCheckIgnore - allows GSP-RM to boot even if the PCI dev ID is not found 87 // in the internal product name database. 88 RegistryEntry { 89 key: "RMDevidCheckIgnore", 90 value: 1, 91 }, 92 ], 93 } 94 } 95 } 96 97 impl CommandToGsp for SetRegistry { 98 const FUNCTION: MsgFunction = MsgFunction::SetRegistry; 99 type Command = PackedRegistryTable; 100 type InitError = Infallible; 101 102 fn init(&self) -> impl Init<Self::Command, Self::InitError> { 103 PackedRegistryTable::init(Self::NUM_ENTRIES as u32, self.variable_payload_len() as u32) 104 } 105 106 fn variable_payload_len(&self) -> usize { 107 let mut key_size = 0; 108 for i in 0..Self::NUM_ENTRIES { 109 key_size += self.entries[i].key.len() + 1; // +1 for NULL terminator 110 } 111 Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>() + key_size 112 } 113 114 fn init_variable_payload( 115 &self, 116 dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>, 117 ) -> Result { 118 let string_data_start_offset = 119 size_of::<PackedRegistryTable>() + Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>(); 120 121 // Array for string data. 122 let mut string_data = KVec::new(); 123 124 for entry in self.entries.iter().take(Self::NUM_ENTRIES) { 125 dst.write_all( 126 PackedRegistryEntry::new( 127 (string_data_start_offset + string_data.len()) as u32, 128 entry.value, 129 ) 130 .as_bytes(), 131 )?; 132 133 let key_bytes = entry.key.as_bytes(); 134 string_data.extend_from_slice(key_bytes, GFP_KERNEL)?; 135 string_data.push(0, GFP_KERNEL)?; 136 } 137 138 dst.write_all(string_data.as_slice()) 139 } 140 } 141 142 /// Message type for GSP initialization done notification. 143 struct GspInitDone {} 144 145 // SAFETY: `GspInitDone` is a zero-sized type with no bytes, therefore it 146 // trivially has no uninitialized bytes. 147 unsafe impl FromBytes for GspInitDone {} 148 149 impl MessageFromGsp for GspInitDone { 150 const FUNCTION: MsgFunction = MsgFunction::GspInitDone; 151 type InitError = Infallible; 152 type Message = GspInitDone; 153 154 fn read( 155 _msg: &Self::Message, 156 _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>, 157 ) -> Result<Self, Self::InitError> { 158 Ok(GspInitDone {}) 159 } 160 } 161 162 /// Waits for GSP initialization to complete. 163 pub(crate) fn wait_gsp_init_done(cmdq: &mut Cmdq) -> Result { 164 loop { 165 match cmdq.receive_msg::<GspInitDone>(Delta::from_secs(10)) { 166 Ok(_) => break Ok(()), 167 Err(ERANGE) => continue, 168 Err(e) => break Err(e), 169 } 170 } 171 } 172