From: "Alexandre Courbot" <acourbot@nvidia.com>
To: "Zhi Wang" <zhiw@nvidia.com>
Cc: <dakr@kernel.org>, <airlied@gmail.com>, <simona@ffwll.ch>,
<ojeda@kernel.org>, <alex.gaynor@gmail.com>,
<boqun.feng@gmail.com>, <gary@garyguo.net>,
<bjorn3_gh@protonmail.com>, <lossin@kernel.org>,
<a.hindborg@kernel.org>, <aliceryhl@google.com>,
<tmgross@umich.edu>, <jhubbard@nvidia.com>,
<ecourtney@nvidia.com>, <joelagnelf@nvidia.com>,
<apopple@nvidia.com>, <cjia@nvidia.com>, <smitra@nvidia.com>,
<kjaju@nvidia.com>, <alkumar@nvidia.com>, <ankita@nvidia.com>,
<aniketa@nvidia.com>, <kwankhede@nvidia.com>,
<targupta@nvidia.com>, <nova-gpu@lists.linux.dev>,
<linux-kernel@vger.kernel.org>, <zhiwang@kernel.org>
Subject: Re: [PATCH 7/9] gpu: nova-core: add vGPU preludes
Date: Wed, 17 Jun 2026 12:08:01 +0900 [thread overview]
Message-ID: <DJAZRULU1QHZ.2NSTR1ZPOQUSN@nvidia.com> (raw)
In-Reply-To: <20260604114339.1565660-8-zhiw@nvidia.com>
On Thu Jun 4, 2026 at 8:43 PM JST, Zhi Wang wrote:
> The driver needs to detect vGPU capability before firmware loading so
> that the GSP boot flow can be adjusted accordingly.
>
> vGPU capability is determined by two sources: the PCI SR-IOV totalvfs
> count (whether the device advertises VFs) and the FSP PRC (Product
> Reconfiguration Control) knob (whether vGPU mode is actively enabled
> on this boot cycle). Both must agree for vGPU to proceed.
>
> Introduce VgpuManager to encapsulate vGPU state detection and tracking.
> On creation it queries totalvfs via sriov_get_totalvfs(); during GSP
> boot the PRC knob is read from FSP to refine the initial estimate.
> Extend GspBootContext with vgpu_requested and total_vfs fields to carry
> this state across the boot sequence. The FSP PRC read is performed
> inside the GH100 HAL boot method, where the FSP falcon is already
> available.
>
> Signed-off-by: Zhi Wang <zhiw@nvidia.com>
> ---
> drivers/gpu/nova-core/fsp.rs | 1 -
> drivers/gpu/nova-core/gpu.rs | 24 +++++++++++--
> drivers/gpu/nova-core/gsp.rs | 5 +++
> drivers/gpu/nova-core/gsp/hal/gh100.rs | 8 ++++-
> drivers/gpu/nova-core/nova_core.rs | 1 +
> drivers/gpu/nova-core/vgpu.rs | 47 ++++++++++++++++++++++++++
> 6 files changed, 82 insertions(+), 4 deletions(-)
> create mode 100644 drivers/gpu/nova-core/vgpu.rs
>
> diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
> index ce11efeba37e..c775e12c5451 100644
> --- a/drivers/gpu/nova-core/fsp.rs
> +++ b/drivers/gpu/nova-core/fsp.rs
> @@ -329,7 +329,6 @@ impl Fsp {
> /// Queries FSP's Management Partition for the active vGPU mode knob value.
> /// Returns [`VgpuMode::Enabled`] if vGPU support is active on this GPU,
> /// [`VgpuMode::Disabled`] otherwise.
> - #[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 69569e218d9b..6d8e60dd5292 100644
> --- a/drivers/gpu/nova-core/gpu.rs
> +++ b/drivers/gpu/nova-core/gpu.rs
> @@ -9,7 +9,11 @@
> io::Io,
> num::Bounded,
> pci,
> - prelude::*, //
> + prelude::*,
> + sync::{
> + new_mutex,
> + Mutex, //
> + },
> };
>
> use crate::{
> @@ -27,6 +31,7 @@
> GspBootContext, //
> },
> regs,
> + vgpu::VgpuManager,
> };
>
> mod hal;
> @@ -180,6 +185,13 @@ pub(crate) enum Architecture with TryFrom<Bounded<u32, 6>> {
> }
> }
>
> +impl Architecture {
> + /// Returns true for architectures that support vGPU (RTX PRO 6000 Blackwell Server Edition).
> + pub(crate) const fn supports_vgpu(&self) -> bool {
> + matches!(self, Self::BlackwellGB20x)
> + }
> +}
Is this needed at all? It is only used in `VgpuManager::new` to
condition the call to `sriov_get_totalvfs`. But `sriov_get_totalvfs`
should return `0` if the device does not support virtual functions,
which is the value used on devices for which this method returns
`false`. So unless we can have virtual functions without vGPU support,
it seems like we can rely solely on the result of `sriov_get_totalvfs`.
Another potential gate is `read_vgpu_mode` - if this always returns
`false` on architectures that don't support vGPU, then we can also rely
on that instead of hardcoding supported archs in the driver.
In case we need to keep this method, it should use a HAL method (see
`pci_config_mirror_range` for an example). But I'd rather just remove it
if that's possible.
> +
> #[derive(Clone, Copy)]
> pub(crate) struct Revision {
> major: Bounded<u8, 4>,
> @@ -278,9 +290,12 @@ pub(crate) struct Gpu<'gpu> {
> gsp_falcon: Falcon<GspFalcon>,
> /// SEC2 falcon instance, used for GSP boot up and cleanup.
> sec2_falcon: Falcon<Sec2Falcon>,
> - /// GSP runtime data. Temporarily an empty placeholder.
> + /// GSP runtime data.
> #[pin]
> gsp: Gsp,
> + /// vGPU state (SR-IOV / FSP PRC), behind Mutex for FFI concurrency.
> + #[pin]
> + vgpu: Mutex<VgpuManager>,
The `Mutex` should not be needed - afaict `vgpu` is not modified, and we
can get a mutable reference to it while we are contructing the GPU
anyway.
> /// GSP unload firmware bundle, if any.
> unload_bundle: Option<gsp::UnloadBundle>,
> }
> @@ -319,18 +334,23 @@ pub(crate) fn new(
>
> sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
>
> + vgpu <- new_mutex!(VgpuManager::new(pdev, spec.chipset.arch())?, "vgpu_manager"),
> +
> gsp <- Gsp::new(pdev),
>
> // This member must be initialized last, so the `UnloadBundle` can never be dropped from
> // outside of the constructed `Gpu`, ensuring that the unload sequence is properly run
> // in case of failure.
> unload_bundle: {
> + let mgr = vgpu.lock();
> let ctx = GspBootContext {
> pdev,
> bar,
> chipset: spec.chipset,
> gsp_falcon,
> sec2_falcon,
> + vgpu_requested: core::cell::Cell::new(mgr.vgpu_requested),
> + total_vfs: mgr.total_vfs,
> };
> gsp.boot(&ctx)?
> },
> diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
> index f0901bf86258..94cd4a784b79 100644
> --- a/drivers/gpu/nova-core/gsp.rs
> +++ b/drivers/gpu/nova-core/gsp.rs
> @@ -3,6 +3,8 @@
> mod boot;
> mod hal;
>
> +use core::cell::Cell;
> +
> use kernel::{
> debugfs,
> device,
> @@ -56,6 +58,9 @@ pub(crate) struct GspBootContext<'a> {
> pub(crate) chipset: Chipset,
> pub(crate) gsp_falcon: &'a Falcon<GspFalcon>,
> pub(crate) sec2_falcon: &'a Falcon<Sec2Falcon>,
> + pub(crate) vgpu_requested: Cell<bool>,
I think we can do without the `Cell`. Since we own the `GspBootContext`,
we can pass it by value to `Gsp::boot`, which can them modify it, and
pass mutable references to it to the other methods is calls. But it
would be even better if we didn't need to modify this at all.
The problem seems to come from the fact that we only build `Fsp` in the
GSP boot code. But vGPU would ideally query it outside of the boot
sequence. So a better design would probably be to make `Fsp` a member of
`Gpu` (behind an `Option`, as all GPUs don't have one) so we can call
`read_vgpu_mode` outside of the GSP boot sequence and get the definitive
enabled state of vGPU earlier in the GPU construction.
I think this is going to be needed anyway because patch 9 also wants to
pass the vGPU enabled status to build `FbLayout`, but can only do so
*before* we query the FSP about the PRC knob. So it doesn't necessarily
have the correct state.
Another benefit of having the `Fsp` moved to `Gpu` will be that you can
then pass a reference to it to the `VgpuManager::new` and have all the
vGPU stuff done in `vgpu.rs`.
Once we have that, we should also be able to add a reference to the (now
read-only) `VgpuManager` to `GspBootContext`, and get the parameters
directly from the source instead of duplicating them.
I can work on a patch to move `Fsp` if my suggestion is not clear, or
let me know if you prefer to do it yourself.
> + #[expect(dead_code)]
> + pub(crate) total_vfs: u16,
> }
>
> impl<'a> GspBootContext<'a> {
> diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs
> index c9fdc8cacedc..e133a92fb67f 100644
> --- a/drivers/gpu/nova-core/gsp/hal/gh100.rs
> +++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs
> @@ -24,7 +24,8 @@
> },
> fsp::{
> FmcBootArgs,
> - Fsp, //
> + Fsp,
> + VgpuMode, //
> },
> gsp::{
> boot::BootUnloadGuard,
> @@ -174,6 +175,11 @@ fn boot<'a>(
>
> let mut fsp = Fsp::wait_secure_boot(dev, bar, chipset, fsp_fw)?;
>
> + let vgpu_mode = fsp.read_vgpu_mode(dev, bar)?;
> + dev_dbg!(dev, "vGPU mode: {:?}\n", vgpu_mode);
> + ctx.vgpu_requested
> + .set(ctx.vgpu_requested.get() && vgpu_mode == VgpuMode::Enabled);
> +
> let args = FmcBootArgs::new(
> dev,
> chipset,
> diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
> index 9f0199f7b38c..6f55a9242027 100644
> --- a/drivers/gpu/nova-core/nova_core.rs
> +++ b/drivers/gpu/nova-core/nova_core.rs
> @@ -26,6 +26,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..c8f1b74037c7
> --- /dev/null
> +++ b/drivers/gpu/nova-core/vgpu.rs
> @@ -0,0 +1,47 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +use kernel::{
> + device,
> + pci,
> + prelude::*, //
> +};
> +
> +use crate::gpu::Architecture;
> +
> +/// vGPU manager.
> +///
> +/// On creation, performs platform detection to determine whether vGPU is
> +/// requested (PRC knob + totalvfs for Blackwell). The `vgpu_requested`
> +/// flag may be further refined during boot (e.g. FSP PRC knob read).
> +pub(crate) struct VgpuManager {
> + pub(crate) vgpu_requested: bool,
> + pub(crate) vgpu_enabled: bool,
> + pub(crate) total_vfs: u16,
> +}
> +
> +impl VgpuManager {
> + pub(crate) fn new(
> + pdev: &pci::Device<device::Bound>,
> + arch: Architecture,
> + ) -> Result<VgpuManager> {
> + let total_vfs: u16 = if arch.supports_vgpu() {
> + pdev.sriov_get_totalvfs()
> + .ok()
> + .and_then(|n| n.try_into().ok())
> + .unwrap_or(0)
> + } else {
> + 0
> + };
> +
> + Ok(VgpuManager {
> + vgpu_requested: total_vfs > 0,
> + vgpu_enabled: false,
> + total_vfs,
> + })
> + }
> +
> + #[expect(dead_code)]
> + pub(crate) fn set_vgpu_enabled(&mut self, enabled: bool) {
> + self.vgpu_enabled = enabled;
> + }
This method doesn't seem to be called anywhere in the series - let's
remove it if it is not needed.
next prev parent reply other threads:[~2026-06-17 3:08 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-04 11:43 [PATCH 0/9] gpu: nova-core: boot GSP with vGPU enabled on Zhi Wang
2026-06-04 11:43 ` [PATCH 1/9] rust: pci: expose sriov_get_totalvfs() helper Zhi Wang
2026-06-05 14:08 ` Alexandre Courbot
2026-06-04 11:43 ` [PATCH 2/9] gpu: nova-core: factor out common FSP message header Zhi Wang
2026-06-05 13:21 ` Alexandre Courbot
2026-06-04 11:43 ` [PATCH 3/9] gpu: nova-core: return FSP response buffer to caller Zhi Wang
2026-06-05 13:25 ` Alexandre Courbot
2026-06-05 16:04 ` Zhi Wang
2026-06-09 6:07 ` Alexandre Courbot
2026-06-04 11:43 ` [PATCH 4/9] gpu: nova-core: read vGPU mode from FSP via PRC protocol Zhi Wang
2026-06-16 8:35 ` Alexandre Courbot
2026-06-04 11:43 ` [PATCH 5/9] gpu: nova-core: add FSP and PRC protocol documentation Zhi Wang
2026-06-16 8:17 ` Alexandre Courbot
2026-06-04 11:43 ` [PATCH 6/9] gpu: nova-core: consolidate GSP boot parameters into GspBootContext Zhi Wang
2026-06-16 14:13 ` Alexandre Courbot
2026-06-04 11:43 ` [PATCH 7/9] gpu: nova-core: add vGPU preludes Zhi Wang
2026-06-17 3:08 ` Alexandre Courbot [this message]
2026-06-04 11:43 ` [PATCH 8/9] gpu: nova-core: set RMSetSriovMode when NVIDIA vGPU is enabled Zhi Wang
2026-06-17 3:13 ` Alexandre Courbot
2026-06-04 11:43 ` [PATCH] gpu: nova-core: reserve a larger GSP WPR2 heap when " Zhi Wang
2026-06-16 14:20 ` Alexandre Courbot
2026-06-17 3:09 ` Alexandre Courbot
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=DJAZRULU1QHZ.2NSTR1ZPOQUSN@nvidia.com \
--to=acourbot@nvidia.com \
--cc=a.hindborg@kernel.org \
--cc=airlied@gmail.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=alkumar@nvidia.com \
--cc=aniketa@nvidia.com \
--cc=ankita@nvidia.com \
--cc=apopple@nvidia.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=cjia@nvidia.com \
--cc=dakr@kernel.org \
--cc=ecourtney@nvidia.com \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=joelagnelf@nvidia.com \
--cc=kjaju@nvidia.com \
--cc=kwankhede@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=nova-gpu@lists.linux.dev \
--cc=ojeda@kernel.org \
--cc=simona@ffwll.ch \
--cc=smitra@nvidia.com \
--cc=targupta@nvidia.com \
--cc=tmgross@umich.edu \
--cc=zhiw@nvidia.com \
--cc=zhiwang@kernel.org \
/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