| // 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<u16>, |
| }, |
| } |
| |
| /// 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<device::Core<'_>>, |
| 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<device::Core<'_>>, |
| chipset: Chipset, |
| fsp: Option<&mut Fsp<'_>>, |
| ) -> Result<VgpuState> { |
| 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 |
| } |
| } |