File Index
Files and directories
Sign in
FILE

commands.rs

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/nova-core/gsp/commands.rs RUST
  1// SPDX-License-Identifier: GPL-2.0
  2
  3use core::{
  4    array,
  5    convert::Infallible, //
  6};
  7
  8use kernel::{
  9    device,
 10    pci,
 11    prelude::*,
 12    time::Delta,
 13    transmute::{
 14        AsBytes,
 15        FromBytes, //
 16    }, //
 17};
 18
 19use 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.
 37pub(crate) struct SetSystemInfo<'a> {
 38    pdev: &'a pci::Device<device::Bound>,
 39}
 40
 41impl<'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
 48impl<'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
 58struct RegistryEntry {
 59    key: &'static str,
 60    value: u32,
 61}
 62
 63/// The `SetRegistry` command.
 64pub(crate) struct SetRegistry {
 65    entries: [RegistryEntry; Self::NUM_ENTRIES],
 66}
 67
 68impl 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
 99impl 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.
145struct GspInitDone {}
146
147// SAFETY: `GspInitDone` is a zero-sized type with no bytes, therefore it
148// trivially has no uninitialized bytes.
149unsafe impl FromBytes for GspInitDone {}
150
151impl 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.
165pub(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.
176struct GetGspStaticInfo;
177
178impl 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.
189pub(crate) struct GetGspStaticInfoReply {
190    gpu_name: [u8; 64],
191}
192
193impl 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
208impl 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.
217pub(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}
~/ Read-only file preview.