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