xref: /linux/drivers/gpu/nova-core/vgpu.rs (revision c0ce158096d4c2e88d270777588bf5ea7cee5f5c)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 use core::num::NonZero;
4 
5 use kernel::{
6     device,
7     pci,
8     prelude::*, //
9 };
10 
11 use crate::{
12     fsp::{
13         Fsp,
14         VgpuMode, //
15     },
16     gpu::Chipset, //
17 };
18 
19 mod hal;
20 
21 /// vGPU state detected during GPU construction.
22 #[derive(Debug, Clone, Copy)]
23 pub(crate) enum VgpuState {
24     /// vGPU mode is not enabled for this boot.
25     Disabled,
26     /// vGPU mode is enabled for this boot.
27     Enabled {
28         /// Total number of SR-IOV VFs supported by this device.
29         #[expect(dead_code)]
30         total_vfs: NonZero<u16>,
31     },
32 }
33 
34 /// vGPU state manager.
35 pub(crate) struct VgpuManager {
36     state: VgpuState,
37 }
38 
39 impl VgpuManager {
40     /// Creates a vGPU manager by querying SR-IOV and the FSP PRC vGPU knob.
41     pub(crate) fn new(
42         pdev: &pci::Device<device::Core<'_>>,
43         chipset: Chipset,
44         fsp: Option<&mut Fsp<'_>>,
45     ) -> Self {
46         let state = Self::detect_state(pdev, chipset, fsp).unwrap_or_else(|e| {
47             dev_warn!(
48                 pdev,
49                 "vGPU state detection failed: {:?}; disabling vGPU\n",
50                 e
51             );
52             VgpuState::Disabled
53         });
54         dev_dbg!(pdev, "vGPU state: {:?}\n", state);
55 
56         Self { state }
57     }
58 
59     /// Detects the vGPU state from the chipset, SR-IOV capability and FSP PRC knob.
60     fn detect_state(
61         pdev: &pci::Device<device::Core<'_>>,
62         chipset: Chipset,
63         fsp: Option<&mut Fsp<'_>>,
64     ) -> Result<VgpuState> {
65         if !hal::vgpu_hal(chipset).supports_vgpu() {
66             return Ok(VgpuState::Disabled);
67         }
68 
69         let Some(total_vfs) = pdev.sriov_get_totalvfs() else {
70             return Ok(VgpuState::Disabled);
71         };
72 
73         if total_vfs.get() < 2 {
74             // The current vGPU path does not support single-VF SR-IOV devices yet.
75             // Treat one total VF as vGPU-disabled for now; single-VF support can relax
76             // this gate once the manager handles that topology.
77             return Ok(VgpuState::Disabled);
78         }
79 
80         let fsp = fsp.ok_or(ENODEV)?;
81 
82         match fsp.read_vgpu_mode(pdev.as_ref())? {
83             VgpuMode::Enabled => Ok(VgpuState::Enabled { total_vfs }),
84             VgpuMode::Disabled => Ok(VgpuState::Disabled),
85         }
86     }
87 
88     /// Returns the detected vGPU state for this boot.
89     #[expect(dead_code)]
90     pub(crate) fn state(&self) -> VgpuState {
91         self.state
92     }
93 }
94