mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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)
> +    }
> +}
> 


  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®