xref: /linux/drivers/gpu/nova-core/gsp/commands.rs (revision f77be04d00d8ce403ecaf547f1515a844bbde060)
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