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 pub(crate) fn state(&self) -> VgpuState { 90 self.state 91 } 92 } 93