Path: blob/master/drivers/gpu/nova-core/gsp/commands.rs
38186 views
// SPDX-License-Identifier: GPL-2.012use core::{3array,4convert::Infallible, //5};67use kernel::{8device,9pci,10prelude::*,11time::Delta,12transmute::{13AsBytes,14FromBytes, //15}, //16};1718use crate::{19driver::Bar0,20gsp::{21cmdq::{22Cmdq,23CommandToGsp,24MessageFromGsp, //25},26fw::{27commands::*,28MsgFunction, //29},30},31sbuffer::SBufferIter,32util,33};3435/// The `GspSetSystemInfo` command.36pub(crate) struct SetSystemInfo<'a> {37pdev: &'a pci::Device<device::Bound>,38}3940impl<'a> SetSystemInfo<'a> {41/// Creates a new `GspSetSystemInfo` command using the parameters of `pdev`.42pub(crate) fn new(pdev: &'a pci::Device<device::Bound>) -> Self {43Self { pdev }44}45}4647impl<'a> CommandToGsp for SetSystemInfo<'a> {48const FUNCTION: MsgFunction = MsgFunction::GspSetSystemInfo;49type Command = GspSetSystemInfo;50type InitError = Error;5152fn init(&self) -> impl Init<Self::Command, Self::InitError> {53GspSetSystemInfo::init(self.pdev)54}55}5657struct RegistryEntry {58key: &'static str,59value: u32,60}6162/// The `SetRegistry` command.63pub(crate) struct SetRegistry {64entries: [RegistryEntry; Self::NUM_ENTRIES],65}6667impl SetRegistry {68// For now we hard-code the registry entries. Future work will allow others to69// be added as module parameters.70const NUM_ENTRIES: usize = 3;7172/// Creates a new `SetRegistry` command, using a set of hardcoded entries.73pub(crate) fn new() -> Self {74Self {75entries: [76// RMSecBusResetEnable - enables PCI secondary bus reset77RegistryEntry {78key: "RMSecBusResetEnable",79value: 1,80},81// RMForcePcieConfigSave - forces GSP-RM to preserve PCI configuration registers on82// any PCI reset.83RegistryEntry {84key: "RMForcePcieConfigSave",85value: 1,86},87// RMDevidCheckIgnore - allows GSP-RM to boot even if the PCI dev ID is not found88// in the internal product name database.89RegistryEntry {90key: "RMDevidCheckIgnore",91value: 1,92},93],94}95}96}9798impl CommandToGsp for SetRegistry {99const FUNCTION: MsgFunction = MsgFunction::SetRegistry;100type Command = PackedRegistryTable;101type InitError = Infallible;102103fn init(&self) -> impl Init<Self::Command, Self::InitError> {104PackedRegistryTable::init(Self::NUM_ENTRIES as u32, self.variable_payload_len() as u32)105}106107fn variable_payload_len(&self) -> usize {108let mut key_size = 0;109for i in 0..Self::NUM_ENTRIES {110key_size += self.entries[i].key.len() + 1; // +1 for NULL terminator111}112Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>() + key_size113}114115fn init_variable_payload(116&self,117dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,118) -> Result {119let string_data_start_offset =120size_of::<PackedRegistryTable>() + Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>();121122// Array for string data.123let mut string_data = KVec::new();124125for entry in self.entries.iter().take(Self::NUM_ENTRIES) {126dst.write_all(127PackedRegistryEntry::new(128(string_data_start_offset + string_data.len()) as u32,129entry.value,130)131.as_bytes(),132)?;133134let key_bytes = entry.key.as_bytes();135string_data.extend_from_slice(key_bytes, GFP_KERNEL)?;136string_data.push(0, GFP_KERNEL)?;137}138139dst.write_all(string_data.as_slice())140}141}142143/// Message type for GSP initialization done notification.144struct GspInitDone {}145146// SAFETY: `GspInitDone` is a zero-sized type with no bytes, therefore it147// trivially has no uninitialized bytes.148unsafe impl FromBytes for GspInitDone {}149150impl MessageFromGsp for GspInitDone {151const FUNCTION: MsgFunction = MsgFunction::GspInitDone;152type InitError = Infallible;153type Message = GspInitDone;154155fn read(156_msg: &Self::Message,157_sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,158) -> Result<Self, Self::InitError> {159Ok(GspInitDone {})160}161}162163/// Waits for GSP initialization to complete.164pub(crate) fn wait_gsp_init_done(cmdq: &mut Cmdq) -> Result {165loop {166match cmdq.receive_msg::<GspInitDone>(Delta::from_secs(10)) {167Ok(_) => break Ok(()),168Err(ERANGE) => continue,169Err(e) => break Err(e),170}171}172}173174/// The `GetGspStaticInfo` command.175struct GetGspStaticInfo;176177impl CommandToGsp for GetGspStaticInfo {178const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;179type Command = GspStaticConfigInfo;180type InitError = Infallible;181182fn init(&self) -> impl Init<Self::Command, Self::InitError> {183GspStaticConfigInfo::init_zeroed()184}185}186187/// The reply from the GSP to the [`GetGspInfo`] command.188pub(crate) struct GetGspStaticInfoReply {189gpu_name: [u8; 64],190}191192impl MessageFromGsp for GetGspStaticInfoReply {193const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;194type Message = GspStaticConfigInfo;195type InitError = Infallible;196197fn read(198msg: &Self::Message,199_sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,200) -> Result<Self, Self::InitError> {201Ok(GetGspStaticInfoReply {202gpu_name: msg.gpu_name_str(),203})204}205}206207impl GetGspStaticInfoReply {208/// Returns the name of the GPU as a string, or `None` if the string given by the GSP was209/// invalid.210pub(crate) fn gpu_name(&self) -> Option<&str> {211util::str_from_null_terminated(&self.gpu_name)212}213}214215/// Send the [`GetGspInfo`] command and awaits for its reply.216pub(crate) fn get_gsp_info(cmdq: &mut Cmdq, bar: &Bar0) -> Result<GetGspStaticInfoReply> {217cmdq.send_command(bar, GetGspStaticInfo)?;218219loop {220match cmdq.receive_msg::<GetGspStaticInfoReply>(Delta::from_secs(5)) {221Ok(info) => return Ok(info),222Err(ERANGE) => continue,223Err(e) => return Err(e),224}225}226}227228229