[PATCH v10 06/28] gpu: nova-core: move GFW boot wait into a GPU HAL

John Hubbard posted 28 patches 1 day, 11 hours ago
[PATCH v10 06/28] gpu: nova-core: move GFW boot wait into a GPU HAL
Posted by John Hubbard 1 day, 11 hours ago
Introduce a GpuHal trait and per-family dispatch so GPU boot
behavior can vary by architecture. Move wait_gfw_boot_completion()
from the standalone gfw module into gpu/hal/tu102.rs as the first
GpuHal implementation. All architectures currently dispatch to this
implementation, preserving existing behavior.

Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
 drivers/gpu/nova-core/gfw.rs           | 76 -----------------------
 drivers/gpu/nova-core/gpu.rs           |  5 +-
 drivers/gpu/nova-core/gpu/hal.rs       | 29 +++++++++
 drivers/gpu/nova-core/gpu/hal/tu102.rs | 86 ++++++++++++++++++++++++++
 drivers/gpu/nova-core/nova_core.rs     |  1 -
 5 files changed, 118 insertions(+), 79 deletions(-)
 delete mode 100644 drivers/gpu/nova-core/gfw.rs
 create mode 100644 drivers/gpu/nova-core/gpu/hal.rs
 create mode 100644 drivers/gpu/nova-core/gpu/hal/tu102.rs

diff --git a/drivers/gpu/nova-core/gfw.rs b/drivers/gpu/nova-core/gfw.rs
deleted file mode 100644
index fb75dd10a172..000000000000
--- a/drivers/gpu/nova-core/gfw.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-//! GPU Firmware (`GFW`) support, a.k.a `devinit`.
-//!
-//! Upon reset, the GPU runs some firmware code from the BIOS to setup its core parameters. Most of
-//! the GPU is considered unusable until this step is completed, so we must wait on it before
-//! performing driver initialization.
-//!
-//! A clarification about devinit terminology: devinit is a sequence of register read/writes after
-//! reset that performs tasks such as:
-//! 1. Programming VRAM memory controller timings.
-//! 2. Power sequencing.
-//! 3. Clock and PLL configuration.
-//! 4. Thermal management.
-//!
-//! devinit itself is a 'script' which is interpreted by an interpreter program typically running
-//! on the PMU microcontroller.
-//!
-//! Note that the devinit sequence also needs to run during suspend/resume.
-
-use kernel::{
-    io::{
-        poll::read_poll_timeout,
-        Io, //
-    },
-    prelude::*,
-    time::Delta, //
-};
-
-use crate::{
-    driver::Bar0,
-    regs, //
-};
-
-/// Wait for the `GFW` (GPU firmware) boot completion signal (`GFW_BOOT`), or a 4 seconds timeout.
-///
-/// Upon GPU reset, several microcontrollers (such as PMU, SEC2, GSP etc) run some firmware code to
-/// setup its core parameters. Most of the GPU is considered unusable until this step is completed,
-/// so it must be waited on very early during driver initialization.
-///
-/// The `GFW` code includes several components that need to execute before the driver loads. These
-/// components are located in the VBIOS ROM and executed in a sequence on these different
-/// microcontrollers. The devinit sequence typically runs on the PMU, and the FWSEC runs on the
-/// GSP.
-///
-/// This function waits for a signal indicating that core initialization is complete. Before this
-/// signal is received, little can be done with the GPU. This signal is set by the FWSEC running on
-/// the GSP in Heavy-secured mode.
-pub(crate) fn wait_gfw_boot_completion(bar: &Bar0) -> Result {
-    // Before accessing the completion status in `NV_PGC6_AON_SECURE_SCRATCH_GROUP_05`, we must
-    // first check `NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK`. This is because
-    // `NV_PGC6_AON_SECURE_SCRATCH_GROUP_05` becomes accessible only after the secure firmware
-    // (FWSEC) lowers the privilege level to allow CPU (LS/Light-secured) access. We can only
-    // safely read the status register from CPU (LS/Light-secured) once the mask indicates
-    // that the privilege level has been lowered.
-    //
-    // TIMEOUT: arbitrarily large value. GFW starts running immediately after the GPU is put out of
-    // reset, and should complete in less time than that.
-    read_poll_timeout(
-        || {
-            Ok(
-                // Check that FWSEC has lowered its protection level before reading the GFW_BOOT
-                // status.
-                bar.read(regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK)
-                    .read_protection_level0()
-                    && bar
-                        .read(regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT)
-                        .completed(),
-            )
-        },
-        |&gfw_booted| gfw_booted,
-        Delta::from_millis(1),
-        Delta::from_secs(4),
-    )
-    .map(|_| ())
-}
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 6db646a49519..0b3a62f6ad1b 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -24,11 +24,12 @@
         Falcon, //
     },
     fb::SysmemFlush,
-    gfw,
     gsp::Gsp,
     regs,
 };
 
+mod hal;
+
 macro_rules! define_chipset {
     ({ $($variant:ident = $value:expr),* $(,)* }) =>
     {
@@ -291,7 +292,7 @@ pub(crate) fn new<'a>(
                 // still constructing it, so no concurrent DMA allocations can exist.
                 unsafe { pdev.dma_set_mask_and_coherent(spec.chipset.arch().dma_mask())? };
 
-                gfw::wait_gfw_boot_completion(bar)
+                hal::gpu_hal(spec.chipset).wait_gfw_boot_completion(bar)
                     .inspect_err(|_| dev_err!(pdev, "GFW boot did not complete\n"))?;
             },
 
diff --git a/drivers/gpu/nova-core/gpu/hal.rs b/drivers/gpu/nova-core/gpu/hal.rs
new file mode 100644
index 000000000000..a261c6af92be
--- /dev/null
+++ b/drivers/gpu/nova-core/gpu/hal.rs
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use kernel::prelude::*;
+
+use crate::{
+    driver::Bar0,
+    gpu::{
+        Architecture,
+        Chipset, //
+    },
+};
+
+mod tu102;
+
+pub(crate) trait GpuHal {
+    /// Waits for GFW_BOOT completion if required by this hardware family.
+    fn wait_gfw_boot_completion(&self, bar: &Bar0) -> Result;
+}
+
+pub(super) fn gpu_hal(chipset: Chipset) -> &'static dyn GpuHal {
+    match chipset.arch() {
+        Architecture::Turing
+        | Architecture::Ampere
+        | Architecture::Ada
+        | Architecture::Hopper
+        | Architecture::BlackwellGB10x
+        | Architecture::BlackwellGB20x => tu102::TU102_HAL,
+    }
+}
diff --git a/drivers/gpu/nova-core/gpu/hal/tu102.rs b/drivers/gpu/nova-core/gpu/hal/tu102.rs
new file mode 100644
index 000000000000..08dd4434bd72
--- /dev/null
+++ b/drivers/gpu/nova-core/gpu/hal/tu102.rs
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! GPU Firmware (`GFW`) support, a.k.a `devinit`.
+//!
+//! Upon reset, the GPU runs some firmware code from the BIOS to setup its core parameters. Most of
+//! the GPU is considered unusable until this step is completed, so we must wait on it before
+//! performing driver initialization.
+//!
+//! A clarification about devinit terminology: devinit is a sequence of register read/writes after
+//! reset that performs tasks such as:
+//! 1. Programming VRAM memory controller timings.
+//! 2. Power sequencing.
+//! 3. Clock and PLL configuration.
+//! 4. Thermal management.
+//!
+//! devinit itself is a 'script' which is interpreted by an interpreter program typically running
+//! on the PMU microcontroller.
+//!
+//! Note that the devinit sequence also needs to run during suspend/resume.
+
+use kernel::{
+    io::{
+        poll::read_poll_timeout,
+        Io, //
+    },
+    prelude::*,
+    time::Delta, //
+};
+
+use crate::{
+    driver::Bar0,
+    regs, //
+};
+
+use super::GpuHal;
+
+struct Tu102;
+
+impl GpuHal for Tu102 {
+    /// Wait for the `GFW` (GPU firmware) boot completion signal (`GFW_BOOT`), or a 4 seconds
+    /// timeout.
+    ///
+    /// Upon GPU reset, several microcontrollers (such as PMU, SEC2, GSP etc) run some firmware
+    /// code to setup its core parameters. Most of the GPU is considered unusable until this step
+    /// is completed, so it must be waited on very early during driver initialization.
+    ///
+    /// The `GFW` code includes several components that need to execute before the driver loads.
+    /// These components are located in the VBIOS ROM and executed in a sequence on these different
+    /// microcontrollers. The devinit sequence typically runs on the PMU, and the FWSEC runs on the
+    /// GSP.
+    ///
+    /// This function waits for a signal indicating that core initialization is complete. Before
+    /// this signal is received, little can be done with the GPU. This signal is set by the FWSEC
+    /// running on the GSP in Heavy-secured mode.
+    fn wait_gfw_boot_completion(&self, bar: &Bar0) -> Result {
+        // Before accessing the completion status in `NV_PGC6_AON_SECURE_SCRATCH_GROUP_05`, we must
+        // first check `NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK`. This is because
+        // `NV_PGC6_AON_SECURE_SCRATCH_GROUP_05` becomes accessible only after the secure firmware
+        // (FWSEC) lowers the privilege level to allow CPU (LS/Light-secured) access. We can only
+        // safely read the status register from CPU (LS/Light-secured) once the mask indicates
+        // that the privilege level has been lowered.
+        //
+        // TIMEOUT: arbitrarily large value. GFW starts running immediately after the GPU is put
+        // out of reset, and should complete in less time than that.
+        read_poll_timeout(
+            || {
+                Ok(
+                    // Check that FWSEC has lowered its protection level before reading the
+                    // GFW_BOOT status.
+                    bar.read(regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK)
+                        .read_protection_level0()
+                        && bar
+                            .read(regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT)
+                            .completed(),
+                )
+            },
+            |&gfw_booted| gfw_booted,
+            Delta::from_millis(1),
+            Delta::from_secs(4),
+        )
+        .map(|_| ())
+    }
+}
+
+const TU102: Tu102 = Tu102;
+pub(super) const TU102_HAL: &dyn GpuHal = &TU102;
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index 04a1fa6b25f8..3a609f6937e4 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -17,7 +17,6 @@
 mod falcon;
 mod fb;
 mod firmware;
-mod gfw;
 mod gpu;
 mod gsp;
 #[macro_use]
-- 
2.53.0