xref: /linux/drivers/gpu/nova-core/vgpu.rs (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
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         total_vfs: NonZero<u16>,
30     },
31 }
32 
33 /// vGPU state manager.
34 pub(crate) struct VgpuManager {
35     state: VgpuState,
36 }
37 
38 impl VgpuManager {
39     /// Creates a vGPU manager by querying SR-IOV and the FSP PRC vGPU knob.
40     pub(crate) fn new(
41         pdev: &pci::Device<device::Core<'_>>,
42         chipset: Chipset,
43         fsp: Option<&mut Fsp<'_>>,
44     ) -> Self {
45         let state = Self::detect_state(pdev, chipset, fsp).unwrap_or_else(|e| {
46             dev_warn!(
47                 pdev,
48                 "vGPU state detection failed: {:?}; disabling vGPU\n",
49                 e
50             );
51             VgpuState::Disabled
52         });
53         dev_dbg!(pdev, "vGPU state: {:?}\n", state);
54 
55         Self { state }
56     }
57 
58     /// Detects the vGPU state from the chipset, SR-IOV capability and FSP PRC knob.
59     fn detect_state(
60         pdev: &pci::Device<device::Core<'_>>,
61         chipset: Chipset,
62         fsp: Option<&mut Fsp<'_>>,
63     ) -> Result<VgpuState> {
64         if !hal::vgpu_hal(chipset).supports_vgpu() {
65             return Ok(VgpuState::Disabled);
66         }
67 
68         let Some(total_vfs) = pdev.sriov_get_totalvfs() else {
69             return Ok(VgpuState::Disabled);
70         };
71 
72         if total_vfs.get() < 2 {
73             // The current vGPU path does not support single-VF SR-IOV devices yet.
74             // Treat one total VF as vGPU-disabled for now; single-VF support can relax
75             // this gate once the manager handles that topology.
76             return Ok(VgpuState::Disabled);
77         }
78 
79         let fsp = fsp.ok_or(ENODEV)?;
80 
81         match fsp.read_vgpu_mode(pdev.as_ref())? {
82             VgpuMode::Enabled => Ok(VgpuState::Enabled { total_vfs }),
83             VgpuMode::Disabled => Ok(VgpuState::Disabled),
84         }
85     }
86 
87     /// Returns the detected vGPU state for this boot.
88     pub(crate) fn state(&self) -> VgpuState {
89         self.state
90     }
91 }
92