[PATCH v2 1/1] gpu: nova-core: populate GSP_VF_INFO when vGPU is enabled

Zhi Wang <[email protected]>
Newsgroups dev.linux.lists.nova-gpu,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
GSP firmware requires VF BAR layout information to correctly route
interrupts and doorbell events to individual virtual functions.
Without this data the firmware cannot set up per-VF event routing.

When vGPU mode is enabled, read the VF topology from the typed PCI
SR-IOV extended capability and populate the GSP_VF_INFO embedded in
the GSP_SYSTEM_INFO command. Keep the VF information builder associated
with GspSetSystemInfo since it is only used to construct that command.

Link: https://lore.kernel.org/nova-gpu/[email protected]/
Signed-off-by: Zhi Wang <[email protected]>
---
 drivers/gpu/nova-core/gsp/boot.rs        |  6 ++--
 drivers/gpu/nova-core/gsp/commands.rs    | 15 ++++++++--
 drivers/gpu/nova-core/gsp/fw/commands.rs | 37 +++++++++++++++++++++++-
 3 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index 727b8ae4bcb7..c086026dc2d8 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -86,8 +86,10 @@ pub(crate) fn boot(
 
         dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(),);
 
-        self.cmdq
-            .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?;
+        self.cmdq.send_command_no_wait(
+            bar,
+            commands::SetSystemInfo::new(pdev, chipset, ctx.vgpu.state()),
+        )?;
         self.cmdq
             .send_command_no_wait(bar, commands::SetRegistry::new(ctx.vgpu.state())?)?;
 
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index ffc25fd8c47b..11d0c7ec371e 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -41,12 +41,21 @@
 pub(crate) struct SetSystemInfo<'a> {
     pdev: &'a pci::Device<device::Bound>,
     chipset: Chipset,
+    vgpu_state: VgpuState,
 }
 
 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,
+        vgpu_state: VgpuState,
+    ) -> Self {
+        Self {
+            pdev,
+            chipset,
+            vgpu_state,
+        }
     }
 }
 
@@ -57,7 +66,7 @@ impl<'a> CommandToGsp for SetSystemInfo<'a> {
     type InitError = Error;
 
     fn init(&self) -> impl Init<Self::Command, Self::InitError> {
-        Self::Command::init(self.pdev, self.chipset)
+        Self::Command::init(self.pdev, self.chipset, self.vgpu_state)
     }
 }
 
diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-core/gsp/fw/commands.rs
index 6dc31d1bf5ae..71feda9c1e69 100644
--- a/drivers/gpu/nova-core/gsp/fw/commands.rs
+++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
@@ -16,7 +16,8 @@
 use crate::{
     gpu::Chipset,
     gsp::GSP_PAGE_SIZE,
-    num::IntoSafeCast, //
+    num::IntoSafeCast,
+    vgpu::VgpuState, //
 };
 
 use super::bindings;
@@ -29,10 +30,43 @@ pub(crate) struct GspSetSystemInfo {
 static_assert!(size_of::<GspSetSystemInfo>() < GSP_PAGE_SIZE);
 
 impl GspSetSystemInfo {
+    /// Builds the VF topology passed to GSP-RM as part of the system information.
+    fn build_vf_info(
+        dev: &pci::Device<device::Bound>,
+        vgpu_state: VgpuState,
+    ) -> Result<bindings::GSP_VF_INFO> {
+        let VgpuState::Enabled { total_vfs } = vgpu_state else {
+            return Ok(Default::default());
+        };
+
+        let sriov = dev
+            .config_space_extended()?
+            .find_ext_capability::<pci::ExtSriovRegs>()?
+            .ok_or(ENODEV)?;
+
+        let mut vf_bars = sriov.vf_bars()?;
+        let bar0 = vf_bars.next().ok_or(EINVAL)?;
+        let bar1 = vf_bars.next().ok_or(EINVAL)?;
+        let bar2 = vf_bars.next().ok_or(EINVAL)?;
+
+        Ok(bindings::GSP_VF_INFO {
+            totalVFs: u32::from(total_vfs.get()),
+            firstVFOffset: u32::from(kernel::io_read!(sriov, .vf_offset)),
+            FirstVFBar0Address: bar0.address,
+            FirstVFBar1Address: bar1.address,
+            FirstVFBar2Address: bar2.address,
+            b64bitBar0: u8::from(bar0.is_64bit),
+            b64bitBar1: u8::from(bar1.is_64bit),
+            b64bitBar2: u8::from(bar2.is_64bit),
+            ..Zeroable::zeroed()
+        })
+    }
+
     /// Returns an in-place initializer for the `GspSetSystemInfo` command.
     pub(crate) fn init<'a>(
         dev: &'a pci::Device<device::Bound>,
         chipset: Chipset,
+        vgpu_state: VgpuState,
     ) -> impl Init<Self, Error> + 'a {
         type InnerGspSystemInfo = bindings::GspSystemInfo;
         let pci_config_mirror_range = chipset.pci_config_mirror_range();
@@ -54,6 +88,7 @@ pub(crate) fn init<'a>(
             PCIRevisionID: u32::from(dev.revision_id()),
             bIsPrimary: 0,
             bPreserveVideoMemoryAllocations: 0,
+            gspVFInfo: Self::build_vf_info(dev, vgpu_state)?,
             ..Zeroable::init_zeroed()
         });
 
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.