Re: [PATCH v4 4/6] gpu: nova-core: add vGPU preludes

From: Alexandre Courbot

Date: Fri Jul 17 2026 - 14:40:50 EST


The patch title is a bit vague; maybe switch it to something more
informative like "detect and store vGPU state"?

On Thu Jul 9, 2026 at 8:02 AM PDT, Zhi Wang wrote:
> GSP boot needs a stable view of vGPU state before it starts building the
> boot-time data structures that depend on SR-IOV and firmware policy. That
> state must be derived once from the PCI VF count and the FSP PRC vGPU mode
> knob before booting GSP.
>
> Add VgpuManager to detect and retain the vGPU state during GPU
> construction. Keep the manager separate from the detected state because
> later vGPU milestones will add vGPU resources and lifecycle state to it.
>
> Keep the vGPU capability gate local to the vGPU module with per-chip HAL
> modules. Treat failures to detect the optional vGPU state as disabled so
> they do not prevent a bare-metal probe, and log both the failure and the
> detected state where the manager is constructed.
>
> Cc: Alexandre Courbot <acourbot@xxxxxxxxxx>
> Signed-off-by: Zhi Wang <zhiw@xxxxxxxxxx>
> ---
> drivers/gpu/nova-core/fsp.rs | 1 -
> drivers/gpu/nova-core/gpu.rs | 7 ++
> drivers/gpu/nova-core/gsp.rs | 2 +
> drivers/gpu/nova-core/nova_core.rs | 1 +
> drivers/gpu/nova-core/vgpu.rs | 90 +++++++++++++++++++++++++
> drivers/gpu/nova-core/vgpu/hal.rs | 25 +++++++
> drivers/gpu/nova-core/vgpu/hal/gb202.rs | 15 +++++
> drivers/gpu/nova-core/vgpu/hal/tu102.rs | 15 +++++
> 8 files changed, 155 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/nova-core/vgpu.rs
> create mode 100644 drivers/gpu/nova-core/vgpu/hal.rs
> create mode 100644 drivers/gpu/nova-core/vgpu/hal/gb202.rs
> create mode 100644 drivers/gpu/nova-core/vgpu/hal/tu102.rs
>
> diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
> index 3a6b02f0dc11..abc161c4ba96 100644
> --- a/drivers/gpu/nova-core/fsp.rs
> +++ b/drivers/gpu/nova-core/fsp.rs
> @@ -487,7 +487,6 @@ fn send_sync_fsp<M>(&mut self, dev: &device::Device, msg: &M) -> Result<KVec<u8>
> /// Reads the active vGPU mode from FSP using the PRC protocol.
> ///
> /// Queries FSP's Management Partition for the active vGPU mode knob value.
> - #[expect(dead_code)]
> pub(crate) fn read_vgpu_mode(
> &mut self,
> dev: &device::Device<device::Bound>,
> diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
> index 442c0979f9c6..42a4cd7971fa 100644
> --- a/drivers/gpu/nova-core/gpu.rs
> +++ b/drivers/gpu/nova-core/gpu.rs
> @@ -30,6 +30,7 @@
> GspBootContext, //
> },
> regs,
> + vgpu::VgpuManager, //
> };
>
> mod hal;
> @@ -267,6 +268,8 @@ struct GspResources<'gpu> {
> // TODO: use different resource types for each boot method, and make the relevant Gsp methods
> // generic against them.
> fsp: Option<Fsp<'gpu>>,
> + /// vGPU state detected before GSP boot.
> + vgpu: VgpuManager,
> /// GSP runtime data.
> #[pin]
> gsp: Gsp,
> @@ -311,6 +314,7 @@ fn drop(self: Pin<&mut Self>) {
> gsp_falcon: &*this.gsp_falcon,
> sec2_falcon: &*this.sec2_falcon,
> fsp: this.fsp.as_mut(),
> + vgpu: &*this.vgpu,
> },
> bundle,
> )
> @@ -364,6 +368,8 @@ pub(crate) fn new(
>
> fsp: Fsp::try_new(dev, bar, spec.chipset)?,
>
> + vgpu: VgpuManager::new(pdev, spec.chipset, fsp.as_mut()),
> +
> gsp <- Gsp::new(pdev),
>
> // This member must be initialized last, so the `UnloadBundle` can never be dropped
> @@ -376,6 +382,7 @@ pub(crate) fn new(
> gsp_falcon,
> sec2_falcon,
> fsp: fsp.as_mut(),
> + vgpu,
> })?,
> }),
>
> diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
> index d89cc3ba7c72..164bae8b8524 100644
> --- a/drivers/gpu/nova-core/gsp.rs
> +++ b/drivers/gpu/nova-core/gsp.rs
> @@ -49,6 +49,7 @@
> },
> },
> num,
> + vgpu::VgpuManager, //
> };
>
> pub(crate) const GSP_PAGE_SHIFT: usize = 12;
> @@ -67,6 +68,7 @@ pub(crate) struct GspBootContext<'ctx, 'gpu> {
> pub(crate) gsp_falcon: &'ctx Falcon<'gpu, GspFalcon>,
> pub(crate) sec2_falcon: &'ctx Falcon<'gpu, Sec2Falcon>,
> pub(crate) fsp: Option<&'ctx mut Fsp<'gpu>>,
> + pub(crate) vgpu: &'ctx VgpuManager,
> }
>
> impl<'ctx, 'gpu> GspBootContext<'ctx, 'gpu> {
> diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
> index a61406ba5c0b..35a8b1214b0e 100644
> --- a/drivers/gpu/nova-core/nova_core.rs
> +++ b/drivers/gpu/nova-core/nova_core.rs
> @@ -23,6 +23,7 @@
> mod regs;
> mod sbuffer;
> mod vbios;
> +mod vgpu;
>
> pub(crate) const MODULE_NAME: &core::ffi::CStr = <LocalModule as kernel::ModuleMetadata>::NAME;
>
> diff --git a/drivers/gpu/nova-core/vgpu.rs b/drivers/gpu/nova-core/vgpu.rs
> new file mode 100644
> index 000000000000..fcc15bddd53e
> --- /dev/null
> +++ b/drivers/gpu/nova-core/vgpu.rs
> @@ -0,0 +1,90 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +use kernel::{
> + device,
> + pci,
> + prelude::*, //
> +};
> +
> +use crate::{
> + fsp::{
> + Fsp,
> + VgpuMode, //
> + },
> + gpu::Chipset, //
> +};
> +
> +mod hal;
> +
> +/// vGPU state detected during GPU construction.
> +#[derive(Debug, Clone, Copy)]
> +pub(crate) enum VgpuState {
> + /// vGPU mode is not enabled for this boot.
> + Disabled,
> + /// vGPU mode is enabled for this boot.
> + Enabled {
> + /// Total number of SR-IOV VFs supported by this device.
> + total_vfs: u16,

Patch 2 returns a `NonNull<u16>`, which is the correct type - can we use
that type here as well? Since a value of `0` would mean `Disabled`
anwyay.

> + },
> +}
> +
> +/// vGPU state manager.
> +pub(crate) struct VgpuManager {
> + state: VgpuState,
> +}
> +
> +impl VgpuManager {
> + /// Creates a vGPU manager by querying SR-IOV and the FSP PRC vGPU knob.
> + pub(crate) fn new(
> + pdev: &pci::Device<device::Bound>,
> + chipset: Chipset,
> + fsp: Option<&mut Fsp<'_>>,
> + ) -> Self {
> + let state = Self::detect_state(pdev, chipset, fsp).unwrap_or_else(|e| {
> + dev_warn!(
> + pdev.as_ref(),
> + "vGPU state detection failed: {:?}; disabling vGPU\n",
> + e
> + );
> + VgpuState::Disabled
> + });
> + dev_dbg!(pdev.as_ref(), "vGPU state: {:?}\n", state);

Note that you can just use `dev_dbg!(pdev, ...)` here (also applies to a
few other sites).

I believe these will be my last nits for this series. :) Thanks for your
patience.