From: Zhi Wang <zhiw@nvidia.com>
To: Alexandre Courbot <acourbot@nvidia.com>
Cc: John Hubbard <jhubbard@nvidia.com>,
Danilo Krummrich <dakr@kernel.org>,
Alice Ryhl <aliceryhl@google.com>,
David Airlie <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
Benno Lossin <lossin@kernel.org>, Gary Guo <gary@garyguo.net>,
Alistair Popple <apopple@nvidia.com>,
Timur Tabi <ttabi@nvidia.com>,
Eliot Courtney <ecourtney@nvidia.com>, <nova-gpu@lists.linux.dev>,
<dri-devel@lists.freedesktop.org>, <linux-kernel@vger.kernel.org>,
<rust-for-linux@vger.kernel.org>
Subject: Re: [PATCH v2 8/9] gpu: nova-core: gsp: move the RPC commands into a sub-module
Date: Mon, 28 Sep 2026 12:20:15 +0300 [thread overview]
Message-ID: <20260928122015.3df66b3e@inno-dell> (raw)
In-Reply-To: <20260927-cmdq-rpc-v2-8-c3f66ae73be4@nvidia.com>
On Sun, 27 Sep 2026 22:46:25 +0900
Alexandre Courbot <acourbot@nvidia.com> wrote:
> Move the types and code related to RPC commands into the
> `rpc` sub-module, and update their users to reference them from their
> new location.
>
> This is a pure move commit, with no functional change intended.
>
Hi Alex:
What would be the plan for commands.rs in the future after the movement?
I was adopting the similar code structures (fw.rs/command.rs) for vGPU
manager's RPCs and GSP plugin RPCs, e.g. having RPC typed code and
function handler(wrapper)s, it would be nice that I can align with the
idea accordingly.
Z.
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
> drivers/gpu/nova-core/api.rs | 2 +-
> drivers/gpu/nova-core/gpu.rs | 2 +-
> drivers/gpu/nova-core/gsp.rs | 4 +-
> drivers/gpu/nova-core/gsp/boot.rs | 12 +-
> drivers/gpu/nova-core/gsp/commands.rs | 337
> +----------------------------
> drivers/gpu/nova-core/gsp/commands/rpc.rs | 339
> ++++++++++++++++++++++++++++++ 6 files changed, 350 insertions(+),
> 346 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/api.rs
> b/drivers/gpu/nova-core/api.rs index f02c6c7c7e51..84a15265e849 100644
> --- a/drivers/gpu/nova-core/api.rs
> +++ b/drivers/gpu/nova-core/api.rs
> @@ -16,7 +16,7 @@
> pub use crate::gpu::Spec;
>
> use crate::gpu::Gpu;
> -use crate::gsp::commands::GetGspStaticInfoReply;
> +use crate::gsp::commands::rpc::GetGspStaticInfoReply;
>
> /// API handle for the auxiliary bus child drivers to interact with
> nova-core. pub struct NovaCoreApi<'bound> {
> diff --git a/drivers/gpu/nova-core/gpu.rs
> b/drivers/gpu/nova-core/gpu.rs index fb6f8a86a503..2a3bd619acf6 100644
> --- a/drivers/gpu/nova-core/gpu.rs
> +++ b/drivers/gpu/nova-core/gpu.rs
> @@ -34,7 +34,7 @@
> fsp::Fsp,
> gsp::{
> self,
> - commands::GetGspStaticInfoReply,
> + commands::rpc::GetGspStaticInfoReply,
> Gsp,
> GspBootContext, //
> },
> diff --git a/drivers/gpu/nova-core/gsp.rs
> b/drivers/gpu/nova-core/gsp.rs index dda58095f40b..75a3ba7d50f4 100644
> --- a/drivers/gpu/nova-core/gsp.rs
> +++ b/drivers/gpu/nova-core/gsp.rs
> @@ -220,8 +220,8 @@ pub(crate) fn new(
> }
>
> /// Query the GSP for the static GPU information.
> - pub(crate) fn get_static_info(&self) ->
> Result<commands::GetGspStaticInfoReply> {
> - self.cmdq.send_command(commands::GetGspStaticInfo)
> + pub(crate) fn get_static_info(&self) ->
> Result<commands::rpc::GetGspStaticInfoReply> {
> + self.cmdq.send_command(commands::rpc::GetGspStaticInfo)
> }
> }
>
> diff --git a/drivers/gpu/nova-core/gsp/boot.rs
> b/drivers/gpu/nova-core/gsp/boot.rs index 4fb1b69ac9d5..8e446ad1eac2
> 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs
> +++ b/drivers/gpu/nova-core/gsp/boot.rs
> @@ -43,9 +43,9 @@ pub(crate) fn boot(
> let gsp_fw = KBox::pin_init(GspFirmware::new(dev, chipset),
> GFP_KERNEL)?;
> self.cmdq
> - .send_command_no_wait(commands::SetSystemInfo::new(pdev,
> chipset))?;
> +
> .send_command_no_wait(commands::rpc::SetSystemInfo::new(pdev,
> chipset))?; self.cmdq
> -
> .send_command_no_wait(commands::SetRegistry::new(ctx.vgpu.state())?)?;
> +
> .send_command_no_wait(commands::rpc::SetRegistry::new(ctx.vgpu.state())?)?;
> // Perform the chipset-specific boot sequence, and retrieve
> the unload bundle. let unload_bundle = hal.boot(&self, &mut ctx,
> &gsp_fw)?.or_else(|| { @@ -79,7 +79,7 @@ pub(crate) fn boot(
> hal.post_boot(&self, ctx, &gsp_fw)?;
>
> // Wait until GSP is fully initialized.
> - commands::wait_gsp_init_done(&self.cmdq)?;
> + commands::rpc::wait_gsp_init_done(&self.cmdq)?;
>
> Ok(unload_guard.dismiss().1)
> }
> @@ -88,10 +88,10 @@ pub(crate) fn boot(
> fn shutdown_gsp(
> cmdq: &Cmdq<'_>,
> gsp_falcon: &Falcon<'_, Gsp>,
> - mode: commands::PowerStateLevel,
> + mode: commands::rpc::PowerStateLevel,
> ) -> Result {
> // Command to shut the GSP down.
> -
> cmdq.send_command(commands::UnloadingGuestDriver::new(mode))?;
> +
> cmdq.send_command(commands::rpc::UnloadingGuestDriver::new(mode))?;
> // Wait until GSP signals it is suspended.
> const LIBOS_INTERRUPT_PROCESSOR_SUSPENDED: u32 =
> bits::bit_u32(31); @@ -118,7 +118,7 @@ pub(crate) fn unload(
> let mut res = Self::shutdown_gsp(
> &self.cmdq,
> ctx.gsp_falcon,
> - commands::PowerStateLevel::Level0,
> + commands::rpc::PowerStateLevel::Level0,
> )
> .inspect_err(|e| dev_err!(dev, "GSP shutdown failed:
> {:?}\n", e));
> diff --git a/drivers/gpu/nova-core/gsp/commands.rs
> b/drivers/gpu/nova-core/gsp/commands.rs index
> 25a5a8d33d64..5f1c944678be 100644 ---
> a/drivers/gpu/nova-core/gsp/commands.rs +++
> b/drivers/gpu/nova-core/gsp/commands.rs @@ -1,339 +1,4 @@
> // SPDX-License-Identifier: GPL-2.0
> // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA
> CORPORATION & AFFILIATES. All rights reserved.
> -use core::{
> - array,
> - convert::Infallible,
> - ffi::FromBytesUntilNulError,
> - ops::Range,
> - str::Utf8Error, //
> -};
> -
> -use kernel::{
> - device,
> - pci,
> - prelude::*,
> - transmute::{
> - AsBytes,
> - FromBytes, //
> - }, //
> -};
> -
> -use crate::{
> - gpu::Chipset,
> - gsp::{
> - cmdq::{
> - rpc::{
> - CommandToGsp,
> - MessageFromGsp, //
> - },
> - Cmdq,
> - NoReply, //
> - },
> - fw::{
> - self,
> - MsgFunction, //
> - },
> - },
> - sbuffer::SBufferIter,
> - vgpu::VgpuState, //
> -};
> -
> -/// The `GspSetSystemInfo` command.
> -pub(crate) struct SetSystemInfo<'a> {
> - pdev: &'a pci::Device<device::Bound>,
> - chipset: Chipset,
> -}
> -
> -impl<'a> SetSystemInfo<'a> {
> - /// Creates a new `GspSetSystemInfo` command using the
> parameters of `pdev`.
> - pub(crate) fn new(pdev: &'a pci::Device<device::Bound>, chipset:
> Chipset) -> Self {
> - Self { pdev, chipset }
> - }
> -}
> -
> -impl<'a> CommandToGsp for SetSystemInfo<'a> {
> - const FUNCTION: MsgFunction = MsgFunction::GspSetSystemInfo;
> - type Command = fw::commands::GspSetSystemInfo;
> - type Reply = NoReply;
> - type InitError = Error;
> -
> - fn init(&self) -> impl Init<Self::Command, Self::InitError> {
> - Self::Command::init(self.pdev, self.chipset)
> - }
> -}
> -
> -struct RegistryEntry {
> - key: &'static str,
> - value: u32,
> -}
> -
> -/// The `SetRegistry` command.
> -pub(crate) struct SetRegistry {
> - entries: KVec<RegistryEntry>,
> -}
> -
> -impl SetRegistry {
> - /// Creates a new `SetRegistry` command, using a set of
> hardcoded entries.
> - pub(crate) fn new(vgpu_state: VgpuState) -> Result<Self> {
> - let mut entries = KVec::new();
> -
> - // RMSecBusResetEnable - enables PCI secondary bus reset
> - entries.push(
> - RegistryEntry {
> - key: "RMSecBusResetEnable",
> - value: 1,
> - },
> - GFP_KERNEL,
> - )?;
> -
> - // RMForcePcieConfigSave - forces GSP-RM to preserve PCI
> configuration registers on
> - // any PCI reset.
> - entries.push(
> - RegistryEntry {
> - key: "RMForcePcieConfigSave",
> - value: 1,
> - },
> - GFP_KERNEL,
> - )?;
> -
> - // RMDevidCheckIgnore - allows GSP-RM to boot even if the
> PCI dev ID is not found
> - // in the internal product name database.
> - entries.push(
> - RegistryEntry {
> - key: "RMDevidCheckIgnore",
> - value: 1,
> - },
> - GFP_KERNEL,
> - )?;
> -
> - if matches!(vgpu_state, VgpuState::Enabled { .. }) {
> - // RMSetSriovMode - required when vGPU is enabled.
> - entries.push(
> - RegistryEntry {
> - key: "RMSetSriovMode",
> - value: 1,
> - },
> - GFP_KERNEL,
> - )?;
> - }
> -
> - Ok(Self { entries })
> - }
> -}
> -
> -impl CommandToGsp for SetRegistry {
> - const FUNCTION: MsgFunction = MsgFunction::SetRegistry;
> - type Command = fw::commands::PackedRegistryTable;
> - type Reply = NoReply;
> - type InitError = Infallible;
> -
> - fn init(&self) -> impl Init<Self::Command, Self::InitError> {
> - Self::Command::init(self.entries.len() as u32, self.size()
> as u32)
> - }
> -
> - fn variable_payload_len(&self) -> usize {
> - let mut key_size = 0;
> - for entry in self.entries.iter() {
> - key_size += entry.key.len() + 1; // +1 for NULL
> terminator
> - }
> - self.entries.len() *
> size_of::<fw::commands::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::<Self::Command>()
> - + self.entries.len() *
> size_of::<fw::commands::PackedRegistryEntry>(); -
> - // Array for string data.
> - let mut string_data = KVec::new();
> -
> - for entry in self.entries.iter() {
> - dst.write_all(
> - fw::commands::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())
> - }
> -}
> -
> -/// Message type for GSP initialization done notification.
> -struct GspInitDone;
> -
> -// SAFETY: `GspInitDone` is a zero-sized type with no bytes,
> therefore it -// trivially has no uninitialized bytes.
> -unsafe impl FromBytes for GspInitDone {}
> -
> -impl MessageFromGsp for GspInitDone {
> - const FUNCTION: MsgFunction = MsgFunction::GspInitDone;
> - type InitError = Infallible;
> - type Message = ();
> -
> - fn read(
> - _msg: &Self::Message,
> - _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
> - ) -> Result<Self, Self::InitError> {
> - Ok(GspInitDone)
> - }
> -}
> -
> -/// Waits for GSP initialization to complete.
> -pub(crate) fn wait_gsp_init_done(cmdq: &Cmdq<'_>) -> Result {
> - loop {
> - match cmdq.receive_msg::<GspInitDone>(Cmdq::RECEIVE_TIMEOUT)
> {
> - Ok(_) => break Ok(()),
> - Err(ERANGE) => continue,
> - Err(e) => break Err(e),
> - }
> - }
> -}
> -
> -/// The `GetGspStaticInfo` command.
> -pub(crate) struct GetGspStaticInfo;
> -
> -impl CommandToGsp for GetGspStaticInfo {
> - const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
> - type Command = fw::commands::GspStaticConfigInfo;
> - type Reply = GetGspStaticInfoReply;
> - type InitError = Infallible;
> -
> - fn init(&self) -> impl Init<Self::Command, Self::InitError> {
> - Self::Command::init_zeroed()
> - }
> -}
> -
> -/// The reply from the GSP to the [`GetGspStaticInfo`] command.
> -pub struct GetGspStaticInfoReply {
> - gpu_name: [u8; 64],
> - gpu_short_name: [u8; 64],
> - /// The 16-byte SHA-1 based GPU identifier (GID) reported by
> GSP-RM.
> - pub gpu_gid: [u8; 16],
> - /// BAR1 Page Directory Entry base address.
> - pub(crate) bar1_pde_base: u64,
> - /// Usable FB (VRAM) regions for driver memory allocation.
> - pub(crate) usable_fb_regions: KVec<Range<u64>>,
> - /// Exclusive end of the FB physical address space.
> - pub(crate) total_fb_end: u64,
> -}
> -
> -impl MessageFromGsp for GetGspStaticInfoReply {
> - const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
> - type Message = fw::commands::GspStaticConfigInfo;
> - type InitError = Error;
> -
> - fn read(
> - msg: &Self::Message,
> - _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
> - ) -> Result<Self, Self::InitError> {
> - let mut usable_fb_regions = KVec::new();
> - for region in msg.usable_fb_regions() {
> - usable_fb_regions.push(region, GFP_KERNEL)?;
> - }
> - let total_fb_end = msg.total_fb_end().ok_or(EINVAL)?;
> -
> - Ok(GetGspStaticInfoReply {
> - gpu_name: msg.gpu_name_str(),
> - gpu_short_name: msg.gpu_short_name_str(),
> - gpu_gid: msg.gpu_gid(),
> - bar1_pde_base: msg.bar1_pde_base(),
> - usable_fb_regions,
> - total_fb_end,
> - })
> - }
> -}
> -
> -/// Error type for [`GetGspStaticInfoReply::gpu_name`].
> -#[derive(Debug)]
> -pub enum GpuNameError {
> - /// The GPU name string does not contain a null terminator.
> - NoNullTerminator(FromBytesUntilNulError),
> -
> - /// The GPU name string contains invalid UTF-8.
> - InvalidUtf8(Utf8Error),
> -}
> -
> -impl GetGspStaticInfoReply {
> - /// Returns the name of the GPU as a string.
> - ///
> - /// Returns an error if the string given by the GSP does not
> contain a null terminator or
> - /// contains invalid UTF-8.
> - pub fn gpu_name(&self) -> Result<&str, GpuNameError> {
> - CStr::from_bytes_until_nul(&self.gpu_name)
> - .map_err(GpuNameError::NoNullTerminator)?
> - .to_str()
> - .map_err(GpuNameError::InvalidUtf8)
> - }
> -
> - /// Returns the short name of the GPU as a string.
> - ///
> - /// Returns an error if the string given by the GSP does not
> contain a null terminator or
> - /// contains invalid UTF-8.
> - pub fn gpu_short_name(&self) -> core::result::Result<&str,
> GpuNameError> {
> - CStr::from_bytes_until_nul(&self.gpu_short_name)
> - .map_err(GpuNameError::NoNullTerminator)?
> - .to_str()
> - .map_err(GpuNameError::InvalidUtf8)
> - }
> -
> - /// Returns the total usable VRAM size in bytes, i.e. the summed
> lengths of all usable FB
> - /// regions.
> - pub fn vram_size(&self) -> u64 {
> - self.usable_fb_regions.iter().fold(0, |size, region| {
> - size.saturating_add(region.end - region.start)
> - })
> - }
> -}
> -
> -pub(crate) use fw::commands::PowerStateLevel;
> -
> -/// The `UnloadingGuestDriver` command, used to shut down the GSP.
> -///
> -/// Only used within the `gsp` module.
> -pub(super) struct UnloadingGuestDriver {
> - level: PowerStateLevel,
> -}
> -
> -impl UnloadingGuestDriver {
> - /// Creates a new `UnloadingGuestDriver` command for the given
> [`PowerStateLevel`].
> - pub(super) fn new(level: PowerStateLevel) -> Self {
> - Self { level }
> - }
> -}
> -
> -impl CommandToGsp for UnloadingGuestDriver {
> - const FUNCTION: MsgFunction = MsgFunction::UnloadingGuestDriver;
> - type Command = fw::commands::UnloadingGuestDriver;
> - type Reply = UnloadingGuestDriverReply;
> - type InitError = Infallible;
> -
> - fn init(&self) -> impl Init<Self::Command, Self::InitError> {
> - fw::commands::UnloadingGuestDriver::new(self.level)
> - }
> -}
> -
> -/// The reply from the GSP to the [`UnloadingGuestDriver`] command.
> -pub(super) struct UnloadingGuestDriverReply;
> -
> -impl MessageFromGsp for UnloadingGuestDriverReply {
> - const FUNCTION: MsgFunction = MsgFunction::UnloadingGuestDriver;
> - type InitError = Infallible;
> - type Message = ();
> -
> - fn read(
> - _msg: &Self::Message,
> - _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
> - ) -> Result<Self, Self::InitError> {
> - Ok(UnloadingGuestDriverReply)
> - }
> -}
> +pub(crate) mod rpc;
> diff --git a/drivers/gpu/nova-core/gsp/commands/rpc.rs
> b/drivers/gpu/nova-core/gsp/commands/rpc.rs new file mode 100644
> index 000000000000..0176ac79fb09
> --- /dev/null
> +++ b/drivers/gpu/nova-core/gsp/commands/rpc.rs
> @@ -0,0 +1,339 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA
> CORPORATION & AFFILIATES. All rights reserved. +
> +use core::{
> + array,
> + convert::Infallible,
> + ffi::FromBytesUntilNulError,
> + ops::Range,
> + str::Utf8Error, //
> +};
> +
> +use kernel::{
> + device,
> + pci,
> + prelude::*,
> + transmute::{
> + AsBytes,
> + FromBytes, //
> + }, //
> +};
> +
> +use crate::{
> + gpu::Chipset,
> + gsp::{
> + cmdq::{
> + rpc::{
> + CommandToGsp,
> + MessageFromGsp, //
> + },
> + Cmdq,
> + NoReply, //
> + },
> + fw::{
> + self,
> + MsgFunction, //
> + },
> + },
> + sbuffer::SBufferIter,
> + vgpu::VgpuState, //
> +};
> +
> +/// The `GspSetSystemInfo` command.
> +pub(crate) struct SetSystemInfo<'a> {
> + pdev: &'a pci::Device<device::Bound>,
> + chipset: Chipset,
> +}
> +
> +impl<'a> SetSystemInfo<'a> {
> + /// Creates a new `GspSetSystemInfo` command using the
> parameters of `pdev`.
> + pub(crate) fn new(pdev: &'a pci::Device<device::Bound>, chipset:
> Chipset) -> Self {
> + Self { pdev, chipset }
> + }
> +}
> +
> +impl<'a> CommandToGsp for SetSystemInfo<'a> {
> + const FUNCTION: MsgFunction = MsgFunction::GspSetSystemInfo;
> + type Command = fw::commands::GspSetSystemInfo;
> + type Reply = NoReply;
> + type InitError = Error;
> +
> + fn init(&self) -> impl Init<Self::Command, Self::InitError> {
> + Self::Command::init(self.pdev, self.chipset)
> + }
> +}
> +
> +struct RegistryEntry {
> + key: &'static str,
> + value: u32,
> +}
> +
> +/// The `SetRegistry` command.
> +pub(crate) struct SetRegistry {
> + entries: KVec<RegistryEntry>,
> +}
> +
> +impl SetRegistry {
> + /// Creates a new `SetRegistry` command, using a set of
> hardcoded entries.
> + pub(crate) fn new(vgpu_state: VgpuState) -> Result<Self> {
> + let mut entries = KVec::new();
> +
> + // RMSecBusResetEnable - enables PCI secondary bus reset
> + entries.push(
> + RegistryEntry {
> + key: "RMSecBusResetEnable",
> + value: 1,
> + },
> + GFP_KERNEL,
> + )?;
> +
> + // RMForcePcieConfigSave - forces GSP-RM to preserve PCI
> configuration registers on
> + // any PCI reset.
> + entries.push(
> + RegistryEntry {
> + key: "RMForcePcieConfigSave",
> + value: 1,
> + },
> + GFP_KERNEL,
> + )?;
> +
> + // RMDevidCheckIgnore - allows GSP-RM to boot even if the
> PCI dev ID is not found
> + // in the internal product name database.
> + entries.push(
> + RegistryEntry {
> + key: "RMDevidCheckIgnore",
> + value: 1,
> + },
> + GFP_KERNEL,
> + )?;
> +
> + if matches!(vgpu_state, VgpuState::Enabled { .. }) {
> + // RMSetSriovMode - required when vGPU is enabled.
> + entries.push(
> + RegistryEntry {
> + key: "RMSetSriovMode",
> + value: 1,
> + },
> + GFP_KERNEL,
> + )?;
> + }
> +
> + Ok(Self { entries })
> + }
> +}
> +
> +impl CommandToGsp for SetRegistry {
> + const FUNCTION: MsgFunction = MsgFunction::SetRegistry;
> + type Command = fw::commands::PackedRegistryTable;
> + type Reply = NoReply;
> + type InitError = Infallible;
> +
> + fn init(&self) -> impl Init<Self::Command, Self::InitError> {
> + Self::Command::init(self.entries.len() as u32, self.size()
> as u32)
> + }
> +
> + fn variable_payload_len(&self) -> usize {
> + let mut key_size = 0;
> + for entry in self.entries.iter() {
> + key_size += entry.key.len() + 1; // +1 for NULL
> terminator
> + }
> + self.entries.len() *
> size_of::<fw::commands::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::<Self::Command>()
> + + self.entries.len() *
> size_of::<fw::commands::PackedRegistryEntry>(); +
> + // Array for string data.
> + let mut string_data = KVec::new();
> +
> + for entry in self.entries.iter() {
> + dst.write_all(
> + fw::commands::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())
> + }
> +}
> +
> +/// Message type for GSP initialization done notification.
> +struct GspInitDone;
> +
> +// SAFETY: `GspInitDone` is a zero-sized type with no bytes,
> therefore it +// trivially has no uninitialized bytes.
> +unsafe impl FromBytes for GspInitDone {}
> +
> +impl MessageFromGsp for GspInitDone {
> + const FUNCTION: MsgFunction = MsgFunction::GspInitDone;
> + type InitError = Infallible;
> + type Message = ();
> +
> + fn read(
> + _msg: &Self::Message,
> + _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
> + ) -> Result<Self, Self::InitError> {
> + Ok(GspInitDone)
> + }
> +}
> +
> +/// Waits for GSP initialization to complete.
> +pub(crate) fn wait_gsp_init_done(cmdq: &Cmdq<'_>) -> Result {
> + loop {
> + match cmdq.receive_msg::<GspInitDone>(Cmdq::RECEIVE_TIMEOUT)
> {
> + Ok(_) => break Ok(()),
> + Err(ERANGE) => continue,
> + Err(e) => break Err(e),
> + }
> + }
> +}
> +
> +/// The `GetGspStaticInfo` command.
> +pub(crate) struct GetGspStaticInfo;
> +
> +impl CommandToGsp for GetGspStaticInfo {
> + const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
> + type Command = fw::commands::GspStaticConfigInfo;
> + type Reply = GetGspStaticInfoReply;
> + type InitError = Infallible;
> +
> + fn init(&self) -> impl Init<Self::Command, Self::InitError> {
> + Self::Command::init_zeroed()
> + }
> +}
> +
> +/// The reply from the GSP to the [`GetGspStaticInfo`] command.
> +pub struct GetGspStaticInfoReply {
> + gpu_name: [u8; 64],
> + gpu_short_name: [u8; 64],
> + /// The 16-byte SHA-1 based GPU identifier (GID) reported by
> GSP-RM.
> + pub gpu_gid: [u8; 16],
> + /// BAR1 Page Directory Entry base address.
> + pub(crate) bar1_pde_base: u64,
> + /// Usable FB (VRAM) regions for driver memory allocation.
> + pub(crate) usable_fb_regions: KVec<Range<u64>>,
> + /// Exclusive end of the FB physical address space.
> + pub(crate) total_fb_end: u64,
> +}
> +
> +impl MessageFromGsp for GetGspStaticInfoReply {
> + const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
> + type Message = fw::commands::GspStaticConfigInfo;
> + type InitError = Error;
> +
> + fn read(
> + msg: &Self::Message,
> + _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
> + ) -> Result<Self, Self::InitError> {
> + let mut usable_fb_regions = KVec::new();
> + for region in msg.usable_fb_regions() {
> + usable_fb_regions.push(region, GFP_KERNEL)?;
> + }
> + let total_fb_end = msg.total_fb_end().ok_or(EINVAL)?;
> +
> + Ok(GetGspStaticInfoReply {
> + gpu_name: msg.gpu_name_str(),
> + gpu_short_name: msg.gpu_short_name_str(),
> + gpu_gid: msg.gpu_gid(),
> + bar1_pde_base: msg.bar1_pde_base(),
> + usable_fb_regions,
> + total_fb_end,
> + })
> + }
> +}
> +
> +/// Error type for [`GetGspStaticInfoReply::gpu_name`].
> +#[derive(Debug)]
> +pub enum GpuNameError {
> + /// The GPU name string does not contain a null terminator.
> + NoNullTerminator(FromBytesUntilNulError),
> +
> + /// The GPU name string contains invalid UTF-8.
> + InvalidUtf8(Utf8Error),
> +}
> +
> +impl GetGspStaticInfoReply {
> + /// Returns the name of the GPU as a string.
> + ///
> + /// Returns an error if the string given by the GSP does not
> contain a null terminator or
> + /// contains invalid UTF-8.
> + pub fn gpu_name(&self) -> Result<&str, GpuNameError> {
> + CStr::from_bytes_until_nul(&self.gpu_name)
> + .map_err(GpuNameError::NoNullTerminator)?
> + .to_str()
> + .map_err(GpuNameError::InvalidUtf8)
> + }
> +
> + /// Returns the short name of the GPU as a string.
> + ///
> + /// Returns an error if the string given by the GSP does not
> contain a null terminator or
> + /// contains invalid UTF-8.
> + pub fn gpu_short_name(&self) -> core::result::Result<&str,
> GpuNameError> {
> + CStr::from_bytes_until_nul(&self.gpu_short_name)
> + .map_err(GpuNameError::NoNullTerminator)?
> + .to_str()
> + .map_err(GpuNameError::InvalidUtf8)
> + }
> +
> + /// Returns the total usable VRAM size in bytes, i.e. the summed
> lengths of all usable FB
> + /// regions.
> + pub fn vram_size(&self) -> u64 {
> + self.usable_fb_regions.iter().fold(0, |size, region| {
> + size.saturating_add(region.end - region.start)
> + })
> + }
> +}
> +
> +pub(crate) use fw::commands::PowerStateLevel;
> +
> +/// The `UnloadingGuestDriver` command, used to shut down the GSP.
> +///
> +/// Only used within the `gsp` module.
> +pub(crate) struct UnloadingGuestDriver {
> + level: PowerStateLevel,
> +}
> +
> +impl UnloadingGuestDriver {
> + /// Creates a new `UnloadingGuestDriver` command for the given
> [`PowerStateLevel`].
> + pub(crate) fn new(level: PowerStateLevel) -> Self {
> + Self { level }
> + }
> +}
> +
> +impl CommandToGsp for UnloadingGuestDriver {
> + const FUNCTION: MsgFunction = MsgFunction::UnloadingGuestDriver;
> + type Command = fw::commands::UnloadingGuestDriver;
> + type Reply = UnloadingGuestDriverReply;
> + type InitError = Infallible;
> +
> + fn init(&self) -> impl Init<Self::Command, Self::InitError> {
> + fw::commands::UnloadingGuestDriver::new(self.level)
> + }
> +}
> +
> +/// The reply from the GSP to the [`UnloadingGuestDriver`] command.
> +pub(crate) struct UnloadingGuestDriverReply;
> +
> +impl MessageFromGsp for UnloadingGuestDriverReply {
> + const FUNCTION: MsgFunction = MsgFunction::UnloadingGuestDriver;
> + type InitError = Infallible;
> + type Message = ();
> +
> + fn read(
> + _msg: &Self::Message,
> + _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
> + ) -> Result<Self, Self::InitError> {
> + Ok(UnloadingGuestDriverReply)
> + }
> +}
>
next prev parent reply other threads:[~2026-09-28 9:20 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-27 13:46 [PATCH v2 0/9] gpu: nova-core: gsp: prepare the command queue for r000 dual-message types Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 1/9] gpu: nova-core: gsp: cmdq: validate checksum earlier on receive Alexandre Courbot
2026-09-28 4:25 ` Eliot Courtney
2026-09-28 6:24 ` Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 2/9] gpu: nova-core: gsp: introduce and use proper RpcMessageHeader type Alexandre Courbot
2026-09-28 4:43 ` Eliot Courtney
2026-09-28 6:22 ` Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 3/9] gpu: nova-core: gsp: cmdq: group the RPC-specific part of send_single_command Alexandre Courbot
2026-09-28 4:52 ` Eliot Courtney
2026-09-27 13:46 ` [PATCH v2 4/9] gpu: nova-core: gsp: cmdq: split the transport part of the send path Alexandre Courbot
2026-09-28 5:16 ` Eliot Courtney
2026-09-28 6:19 ` Alexandre Courbot
2026-09-28 6:40 ` Eliot Courtney
2026-09-28 11:35 ` Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 5/9] gpu: nova-core: gsp: cmdq: move the RPC send code into a sub-module Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 6/9] gpu: nova-core: gsp: cmdq: split the transport part of the receive path Alexandre Courbot
2026-09-28 3:19 ` Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 7/9] gpu: nova-core: gsp: cmdq: move the RPC receive code into a sub-module Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 8/9] gpu: nova-core: gsp: move the RPC commands " Alexandre Courbot
2026-09-28 5:25 ` Eliot Courtney
2026-09-28 9:20 ` Zhi Wang [this message]
2026-09-28 11:40 ` Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 9/9] gpu: nova-core: gsp: add `rpc` to RPC message send/receive methods Alexandre Courbot
2026-09-28 5:32 ` Eliot Courtney
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260928122015.3df66b3e@inno-dell \
--to=zhiw@nvidia.com \
--cc=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=apopple@nvidia.com \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=ecourtney@nvidia.com \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=nova-gpu@lists.linux.dev \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=ttabi@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®