1 // SPDX-License-Identifier: GPL-2.0 2 3 use core::convert::Infallible; 4 5 use kernel::{ 6 device, 7 pci, 8 prelude::*, 9 transmute::AsBytes, // 10 }; 11 12 use crate::{ 13 gsp::{ 14 cmdq::CommandToGsp, 15 fw::{ 16 commands::*, 17 MsgFunction, // 18 }, 19 }, 20 sbuffer::SBufferIter, 21 }; 22 23 /// The `GspSetSystemInfo` command. 24 pub(crate) struct SetSystemInfo<'a> { 25 pdev: &'a pci::Device<device::Bound>, 26 } 27 28 impl<'a> SetSystemInfo<'a> { 29 /// Creates a new `GspSetSystemInfo` command using the parameters of `pdev`. 30 pub(crate) fn new(pdev: &'a pci::Device<device::Bound>) -> Self { 31 Self { pdev } 32 } 33 } 34 35 impl<'a> CommandToGsp for SetSystemInfo<'a> { 36 const FUNCTION: MsgFunction = MsgFunction::GspSetSystemInfo; 37 type Command = GspSetSystemInfo; 38 type InitError = Error; 39 40 fn init(&self) -> impl Init<Self::Command, Self::InitError> { 41 GspSetSystemInfo::init(self.pdev) 42 } 43 } 44 45 struct RegistryEntry { 46 key: &'static str, 47 value: u32, 48 } 49 50 /// The `SetRegistry` command. 51 pub(crate) struct SetRegistry { 52 entries: [RegistryEntry; Self::NUM_ENTRIES], 53 } 54 55 impl SetRegistry { 56 // For now we hard-code the registry entries. Future work will allow others to 57 // be added as module parameters. 58 const NUM_ENTRIES: usize = 3; 59 60 /// Creates a new `SetRegistry` command, using a set of hardcoded entries. 61 pub(crate) fn new() -> Self { 62 Self { 63 entries: [ 64 // RMSecBusResetEnable - enables PCI secondary bus reset 65 RegistryEntry { 66 key: "RMSecBusResetEnable", 67 value: 1, 68 }, 69 // RMForcePcieConfigSave - forces GSP-RM to preserve PCI configuration registers on 70 // any PCI reset. 71 RegistryEntry { 72 key: "RMForcePcieConfigSave", 73 value: 1, 74 }, 75 // RMDevidCheckIgnore - allows GSP-RM to boot even if the PCI dev ID is not found 76 // in the internal product name database. 77 RegistryEntry { 78 key: "RMDevidCheckIgnore", 79 value: 1, 80 }, 81 ], 82 } 83 } 84 } 85 86 impl CommandToGsp for SetRegistry { 87 const FUNCTION: MsgFunction = MsgFunction::SetRegistry; 88 type Command = PackedRegistryTable; 89 type InitError = Infallible; 90 91 fn init(&self) -> impl Init<Self::Command, Self::InitError> { 92 PackedRegistryTable::init(Self::NUM_ENTRIES as u32, self.variable_payload_len() as u32) 93 } 94 95 fn variable_payload_len(&self) -> usize { 96 let mut key_size = 0; 97 for i in 0..Self::NUM_ENTRIES { 98 key_size += self.entries[i].key.len() + 1; // +1 for NULL terminator 99 } 100 Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>() + key_size 101 } 102 103 fn init_variable_payload( 104 &self, 105 dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>, 106 ) -> Result { 107 let string_data_start_offset = 108 size_of::<PackedRegistryTable>() + Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>(); 109 110 // Array for string data. 111 let mut string_data = KVec::new(); 112 113 for entry in self.entries.iter().take(Self::NUM_ENTRIES) { 114 dst.write_all( 115 PackedRegistryEntry::new( 116 (string_data_start_offset + string_data.len()) as u32, 117 entry.value, 118 ) 119 .as_bytes(), 120 )?; 121 122 let key_bytes = entry.key.as_bytes(); 123 string_data.extend_from_slice(key_bytes, GFP_KERNEL)?; 124 string_data.push(0, GFP_KERNEL)?; 125 } 126 127 dst.write_all(string_data.as_slice()) 128 } 129 } 130