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