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

Reply via email to