mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
gpu: nova-core: gsp: Add SetRegistry command
Add support for sending the SetRegistry command, which is critical to GSP initialization. The RM registry is serialized into a packed format and sent via the command queue. For now only three parameters which are required to boot GSP are hardcoded. In the future a kernel module parameter will be added to enable other parameters to be added. Signed-off-by: Alistair Popple <apopple@nvidia.com> [acourbot@nvidia.com: split into its own patch.] Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Message-ID: <20251110-gsp_boot-v9-12-8ae4058e3c0e@nvidia.com>
This commit is contained in:
committed by
Alexandre Courbot
parent
edcb134264
commit
19b0a6e7c2
@@ -158,6 +158,7 @@ impl super::Gsp {
|
||||
|
||||
self.cmdq
|
||||
.send_command(bar, commands::SetSystemInfo::new(pdev))?;
|
||||
self.cmdq.send_command(bar, commands::SetRegistry::new())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use core::convert::Infallible;
|
||||
|
||||
use kernel::{
|
||||
device,
|
||||
pci,
|
||||
prelude::*, //
|
||||
prelude::*,
|
||||
transmute::AsBytes, //
|
||||
};
|
||||
|
||||
use crate::gsp::{
|
||||
cmdq::CommandToGsp,
|
||||
fw::{
|
||||
commands::GspSetSystemInfo,
|
||||
MsgFunction, //
|
||||
use crate::{
|
||||
gsp::{
|
||||
cmdq::CommandToGsp,
|
||||
fw::{
|
||||
commands::*,
|
||||
MsgFunction, //
|
||||
},
|
||||
},
|
||||
sbuffer::SBufferIter,
|
||||
};
|
||||
|
||||
/// The `GspSetSystemInfo` command.
|
||||
@@ -35,3 +41,89 @@ impl<'a> CommandToGsp for SetSystemInfo<'a> {
|
||||
GspSetSystemInfo::init(self.pdev)
|
||||
}
|
||||
}
|
||||
|
||||
struct RegistryEntry {
|
||||
key: &'static str,
|
||||
value: u32,
|
||||
}
|
||||
|
||||
/// The `SetRegistry` command.
|
||||
pub(crate) struct SetRegistry {
|
||||
entries: [RegistryEntry; Self::NUM_ENTRIES],
|
||||
}
|
||||
|
||||
impl SetRegistry {
|
||||
// For now we hard-code the registry entries. Future work will allow others to
|
||||
// be added as module parameters.
|
||||
const NUM_ENTRIES: usize = 3;
|
||||
|
||||
/// Creates a new `SetRegistry` command, using a set of hardcoded entries.
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
entries: [
|
||||
// RMSecBusResetEnable - enables PCI secondary bus reset
|
||||
RegistryEntry {
|
||||
key: "RMSecBusResetEnable",
|
||||
value: 1,
|
||||
},
|
||||
// RMForcePcieConfigSave - forces GSP-RM to preserve PCI configuration registers on
|
||||
// any PCI reset.
|
||||
RegistryEntry {
|
||||
key: "RMForcePcieConfigSave",
|
||||
value: 1,
|
||||
},
|
||||
// RMDevidCheckIgnore - allows GSP-RM to boot even if the PCI dev ID is not found
|
||||
// in the internal product name database.
|
||||
RegistryEntry {
|
||||
key: "RMDevidCheckIgnore",
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandToGsp for SetRegistry {
|
||||
const FUNCTION: MsgFunction = MsgFunction::SetRegistry;
|
||||
type Command = PackedRegistryTable;
|
||||
type InitError = Infallible;
|
||||
|
||||
fn init(&self) -> impl Init<Self::Command, Self::InitError> {
|
||||
PackedRegistryTable::init(Self::NUM_ENTRIES as u32, self.variable_payload_len() as u32)
|
||||
}
|
||||
|
||||
fn variable_payload_len(&self) -> usize {
|
||||
let mut key_size = 0;
|
||||
for i in 0..Self::NUM_ENTRIES {
|
||||
key_size += self.entries[i].key.len() + 1; // +1 for NULL terminator
|
||||
}
|
||||
Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>() + key_size
|
||||
}
|
||||
|
||||
fn init_variable_payload(
|
||||
&self,
|
||||
dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,
|
||||
) -> Result {
|
||||
let string_data_start_offset =
|
||||
size_of::<PackedRegistryTable>() + Self::NUM_ENTRIES * size_of::<PackedRegistryEntry>();
|
||||
|
||||
// Array for string data.
|
||||
let mut string_data = KVec::new();
|
||||
|
||||
for entry in self.entries.iter().take(Self::NUM_ENTRIES) {
|
||||
dst.write_all(
|
||||
PackedRegistryEntry::new(
|
||||
(string_data_start_offset + string_data.len()) as u32,
|
||||
entry.value,
|
||||
)
|
||||
.as_bytes(),
|
||||
)?;
|
||||
|
||||
let key_bytes = entry.key.as_bytes();
|
||||
string_data.extend_from_slice(key_bytes, GFP_KERNEL)?;
|
||||
string_data.push(0, GFP_KERNEL)?;
|
||||
}
|
||||
|
||||
dst.write_all(string_data.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,3 +54,53 @@ unsafe impl AsBytes for GspSetSystemInfo {}
|
||||
// SAFETY: These structs don't meet the no-padding requirements of FromBytes but
|
||||
// that is not a problem because they are not used outside the kernel.
|
||||
unsafe impl FromBytes for GspSetSystemInfo {}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct PackedRegistryEntry(bindings::PACKED_REGISTRY_ENTRY);
|
||||
|
||||
impl PackedRegistryEntry {
|
||||
pub(crate) fn new(offset: u32, value: u32) -> Self {
|
||||
Self({
|
||||
bindings::PACKED_REGISTRY_ENTRY {
|
||||
nameOffset: offset,
|
||||
|
||||
// We only support DWORD types for now. Support for other types
|
||||
// will come later if required.
|
||||
type_: bindings::REGISTRY_TABLE_ENTRY_TYPE_DWORD as u8,
|
||||
__bindgen_padding_0: Default::default(),
|
||||
data: value,
|
||||
length: 0,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: Padding is explicit and will not contain uninitialized data.
|
||||
unsafe impl AsBytes for PackedRegistryEntry {}
|
||||
|
||||
/// Payload of the `SetRegistry` command.
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct PackedRegistryTable {
|
||||
inner: bindings::PACKED_REGISTRY_TABLE,
|
||||
}
|
||||
|
||||
impl PackedRegistryTable {
|
||||
#[allow(non_snake_case)]
|
||||
pub(crate) fn init(num_entries: u32, size: u32) -> impl Init<Self> {
|
||||
type InnerPackedRegistryTable = bindings::PACKED_REGISTRY_TABLE;
|
||||
let init_inner = init!(InnerPackedRegistryTable {
|
||||
numEntries: num_entries,
|
||||
size,
|
||||
entries: Default::default()
|
||||
});
|
||||
|
||||
init!(PackedRegistryTable { inner <- init_inner })
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: Padding is explicit and will not contain uninitialized data.
|
||||
unsafe impl AsBytes for PackedRegistryTable {}
|
||||
|
||||
// SAFETY: This struct only contains integer types for which all bit patterns
|
||||
// are valid.
|
||||
unsafe impl FromBytes for PackedRegistryTable {}
|
||||
|
||||
@@ -649,6 +649,22 @@ pub struct LibosMemoryRegionInitArgument {
|
||||
pub __bindgen_padding_0: [u8; 6usize],
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct PACKED_REGISTRY_ENTRY {
|
||||
pub nameOffset: u32_,
|
||||
pub type_: u8_,
|
||||
pub __bindgen_padding_0: [u8; 3usize],
|
||||
pub data: u32_,
|
||||
pub length: u32_,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PACKED_REGISTRY_TABLE {
|
||||
pub size: u32_,
|
||||
pub numEntries: u32_,
|
||||
pub entries: __IncompleteArrayField<PACKED_REGISTRY_ENTRY>,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone, Zeroable)]
|
||||
pub struct msgqTxHeader {
|
||||
pub version: u32_,
|
||||
|
||||
@@ -199,7 +199,6 @@ where
|
||||
|
||||
/// Ideally we would implement [`Write`], but it is not available in `core`.
|
||||
/// So mimic `std::io::Write::write_all`.
|
||||
#[expect(unused)]
|
||||
pub(crate) fn write_all(&mut self, mut src: &[u8]) -> Result {
|
||||
while !src.is_empty() {
|
||||
match self.get_slice_mut(src.len()) {
|
||||
|
||||
Reference in New Issue
Block a user