// SPDX-License-Identifier: GPL-2.0 use core::num::NonZero; use kernel::{ device, pci, prelude::*, // }; use crate::{ fsp::{ Fsp, VgpuMode, // }, gpu::Chipset, // }; mod hal; /// vGPU state detected during GPU construction. #[derive(Debug, Clone, Copy)] pub(crate) enum VgpuState { /// vGPU mode is not enabled for this boot. Disabled, /// vGPU mode is enabled for this boot. Enabled { /// Total number of SR-IOV VFs supported by this device. total_vfs: NonZero, }, } /// vGPU state manager. pub(crate) struct VgpuManager { state: VgpuState, } impl VgpuManager { /// Creates a vGPU manager by querying SR-IOV and the FSP PRC vGPU knob. pub(crate) fn new( pdev: &pci::Device>, chipset: Chipset, fsp: Option<&mut Fsp<'_>>, ) -> Self { let state = Self::detect_state(pdev, chipset, fsp).unwrap_or_else(|e| { dev_warn!( pdev, "vGPU state detection failed: {:?}; disabling vGPU\n", e ); VgpuState::Disabled }); dev_dbg!(pdev, "vGPU state: {:?}\n", state); Self { state } } /// Detects the vGPU state from the chipset, SR-IOV capability and FSP PRC knob. fn detect_state( pdev: &pci::Device>, chipset: Chipset, fsp: Option<&mut Fsp<'_>>, ) -> Result { if !hal::vgpu_hal(chipset).supports_vgpu() { return Ok(VgpuState::Disabled); } let Some(total_vfs) = pdev.sriov_get_totalvfs() else { return Ok(VgpuState::Disabled); }; if total_vfs.get() < 2 { // The current vGPU path does not support single-VF SR-IOV devices yet. // Treat one total VF as vGPU-disabled for now; single-VF support can relax // this gate once the manager handles that topology. return Ok(VgpuState::Disabled); } let fsp = fsp.ok_or(ENODEV)?; match fsp.read_vgpu_mode(pdev.as_ref())? { VgpuMode::Enabled => Ok(VgpuState::Enabled { total_vfs }), VgpuMode::Disabled => Ok(VgpuState::Disabled), } } /// Returns the detected vGPU state for this boot. pub(crate) fn state(&self) -> VgpuState { self.state } }