GSP firmware needs to know the VF BAR offsets to correctly calculate the VF events.
The VF BAR information is stored in GSP_VF_INFO, which needs to be initialized and uploaded together with the GSP_SYSTEM_INFO. Populate GSP_VF_INFO when nova-core uploads the GSP_SYSTEM_INFO if NVIDIA vGPU is enabled. Cc: Joel Fernandes <[email protected]> Cc: John Hubbard <[email protected]> Cc: Alexandre Courbot <[email protected]> Signed-off-by: Zhi Wang <[email protected]> --- drivers/gpu/nova-core/gsp/boot.rs | 15 ++++++++-- drivers/gpu/nova-core/gsp/commands.rs | 16 ++++++++-- drivers/gpu/nova-core/gsp/fw.rs | 38 ++++++++++++++++++++++++ drivers/gpu/nova-core/gsp/fw/commands.rs | 12 +++++++- 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs index 4238df5c8104..921d5e892f8a 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -41,7 +41,10 @@ gpu::Chipset, gsp::{ commands, - fw::LibosMemoryRegionInitArgument, + fw::{ + GspVfInfo, + LibosMemoryRegionInitArgument, // + }, sequencer::{ GspSequencer, GspSequencerParams, // @@ -349,11 +352,17 @@ pub(crate) fn boot( let wpr_meta = Coherent::<GspFwWprMeta>::zeroed(dev, GFP_KERNEL)?; io_write!(wpr_meta, , GspFwWprMeta::new(&gsp_fw, &fb_layout)); + let vf_info = if ctx.vgpu_requested { + Some(GspVfInfo::new(ctx.pdev)?) + } else { + None + }; + // Architecture-specific boot path if arch.uses_sec2_boot() { // SEC2 path: send commands before GSP reset/boot (original order). self.cmdq - .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?; + .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset, vf_info))?; self.cmdq .send_command_no_wait(bar, commands::SetRegistry::new())?; @@ -395,7 +404,7 @@ pub(crate) fn boot( // For FSP path, send commands after GSP becomes active. if !arch.uses_sec2_boot() { self.cmdq - .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?; + .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset, vf_info))?; self.cmdq .send_command_no_wait(bar, commands::SetRegistry::new())?; } diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs index d31ee782ff8b..0445d05990e7 100644 --- a/drivers/gpu/nova-core/gsp/commands.rs +++ b/drivers/gpu/nova-core/gsp/commands.rs @@ -29,6 +29,7 @@ }, fw::{ commands::*, + GspVfInfo, MsgFunction, // }, }, @@ -39,12 +40,21 @@ pub(crate) struct SetSystemInfo<'a> { pdev: &'a pci::Device<device::Bound>, chipset: Chipset, + vf_info: Option<GspVfInfo>, } impl<'a> SetSystemInfo<'a> { /// Creates a new `GspSetSystemInfo` command using the parameters of `pdev`. - pub(crate) fn new(pdev: &'a pci::Device<device::Bound>, chipset: Chipset) -> Self { - Self { pdev, chipset } + pub(crate) fn new( + pdev: &'a pci::Device<device::Bound>, + chipset: Chipset, + vf_info: Option<GspVfInfo>, + ) -> Self { + Self { + pdev, + chipset, + vf_info, + } } } @@ -55,7 +65,7 @@ impl<'a> CommandToGsp for SetSystemInfo<'a> { type InitError = Error; fn init(&self) -> impl Init<Self::Command, Self::InitError> { - GspSetSystemInfo::init(self.pdev, self.chipset) + GspSetSystemInfo::init(self.pdev, self.chipset, self.vf_info) } } diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index e5f8db74a677..6d56b9b920fb 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -10,7 +10,9 @@ use core::ops::Range; use kernel::{ + device, dma::Coherent, + pci, prelude::*, ptr::{ Alignable, @@ -1309,3 +1311,39 @@ fn new(cmdq: &Cmdq) -> Self { }) } } + +/// VF information — `gspVFInfo` in `GspSetSystemInfo`. +/// +/// Populated from the PCI SR-IOV extended capability when vGPU support +/// is enabled. +#[derive(Clone, Copy, Zeroable)] +#[repr(transparent)] +pub(crate) struct GspVfInfo(pub(crate) bindings::GSP_VF_INFO); + +impl GspVfInfo { + /// Reads SR-IOV capability data from the PCI extended configuration + /// space and builds the VF information required by GSP firmware. + pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> Result<GspVfInfo> { + let total_vfs = pdev.sriov_get_totalvfs()?; + + let cfg = pdev.config_space_extended()?; + let sriov = pci::ExtSriovCapability::find(&cfg)?; + + Ok(GspVfInfo(bindings::GSP_VF_INFO { + totalVFs: u32::from(total_vfs), + firstVFOffset: u32::from(kernel::io_read!(sriov, .vf_offset)), + FirstVFBar0Address: u64::from(kernel::io_read!(sriov, .vf_bar[0]?)), + b64bitBar1: u8::from(sriov.vf_bar_is_64bit(1)?), + FirstVFBar1Address: sriov.read_vf_bar64_addr(1)?, + b64bitBar2: u8::from(sriov.vf_bar_is_64bit(3)?), + FirstVFBar2Address: sriov.read_vf_bar64_addr(3)?, + ..Zeroable::zeroed() + })) + } +} + +// SAFETY: Padding is explicit and does not contain uninitialized data. +unsafe impl AsBytes for GspVfInfo {} + +// SAFETY: This struct only contains integer types for which all bit patterns are valid. +unsafe impl FromBytes for GspVfInfo {} diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs index c9822fcbc499..3edd451e531b 100644 --- a/drivers/gpu/nova-core/gsp/fw/commands.rs +++ b/drivers/gpu/nova-core/gsp/fw/commands.rs @@ -15,7 +15,10 @@ Architecture, Chipset, // }, - gsp::GSP_PAGE_SIZE, // + gsp::{ + fw::GspVfInfo, + GSP_PAGE_SIZE, // + }, }; use super::bindings; @@ -33,6 +36,7 @@ impl GspSetSystemInfo { pub(crate) fn init<'a>( dev: &'a pci::Device<device::Bound>, chipset: Chipset, + vf_info: Option<GspVfInfo>, ) -> impl Init<Self, Error> + 'a { type InnerGspSystemInfo = bindings::GspSystemInfo; let init_inner = try_init!(InnerGspSystemInfo { @@ -57,6 +61,12 @@ pub(crate) fn init<'a>( bIsPrimary: 0, bPreserveVideoMemoryAllocations: 0, ..Zeroable::init_zeroed() + }) + .chain(move |si| { + if let Some(vf) = vf_info { + si.gspVFInfo = vf.0; + } + Ok(()) }); try_init!(GspSetSystemInfo { -- 2.51.0
