Commit 76544ef6 authored by Alexandre Courbot's avatar Alexandre Courbot
Browse files

gpu: nova-core: replace wait_on with kernel equivalents



wait_on was a temporary helper function waiting for a kernel crate
equivalent.

Now that read_poll_timeout and fsleep are available, use them and remove
wait_on.

Acked-by: default avatarDanilo Krummrich <dakr@kernel.org>
Signed-off-by: default avatarAlexandre Courbot <acourbot@nvidia.com>
Message-ID: <20251020-nova_wait_on-v1-1-2eb87fb38d14@nvidia.com>
parent c58f00b4
Loading
Loading
Loading
Loading
+0 −11
Original line number Diff line number Diff line
@@ -153,17 +153,6 @@ A `num` core kernel module is being designed to provide these operations.
| Complexity: Intermediate
| Contact: Alexandre Courbot

Delay / Sleep abstractions [DLAY]
---------------------------------

Rust abstractions for the kernel's delay() and sleep() functions.

FUJITA Tomonori plans to work on abstractions for read_poll_timeout_atomic()
(and friends) [1].

| Complexity: Beginner
| Link: https://lore.kernel.org/netdev/20250228.080550.354359820929821928.fujita.tomonori@gmail.com/ [1]

IRQ abstractions
----------------

+28 −34
Original line number Diff line number Diff line
@@ -6,8 +6,10 @@
use hal::FalconHal;
use kernel::device;
use kernel::dma::DmaAddress;
use kernel::io::poll::read_poll_timeout;
use kernel::prelude::*;
use kernel::sync::aref::ARef;
use kernel::time::delay::fsleep;
use kernel::time::Delta;

use crate::dma::DmaObject;
@@ -15,7 +17,6 @@
use crate::gpu::Chipset;
use crate::regs;
use crate::regs::macros::RegisterBase;
use crate::util;

pub(crate) mod gsp;
mod hal;
@@ -372,13 +373,13 @@ pub(crate) fn new(dev: &device::Device, chipset: Chipset) -> Result<Self> {
    /// Wait for memory scrubbing to complete.
    fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result {
        // TIMEOUT: memory scrubbing should complete in less than 20ms.
        util::wait_on(Delta::from_millis(20), || {
            if regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID).mem_scrubbing_done() {
                Some(())
            } else {
                None
            }
        })
        read_poll_timeout(
            || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)),
            |r| r.mem_scrubbing_done(),
            Delta::ZERO,
            Delta::from_millis(20),
        )
        .map(|_| ())
    }

    /// Reset the falcon engine.
@@ -387,20 +388,17 @@ fn reset_eng(&self, bar: &Bar0) -> Result {

        // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set
        // RESET_READY so a non-failing timeout is used.
        let _ = util::wait_on(Delta::from_micros(150), || {
            let r = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID);
            if r.reset_ready() {
                Some(())
            } else {
                None
            }
        });
        let _ = read_poll_timeout(
            || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)),
            |r| r.reset_ready(),
            Delta::ZERO,
            Delta::from_micros(150),
        );

        regs::NV_PFALCON_FALCON_ENGINE::update(bar, &E::ID, |v| v.set_reset(true));

        // TODO[DLAY]: replace with udelay() or equivalent once available.
        // TIMEOUT: falcon engine should not take more than 10us to reset.
        let _: Result = util::wait_on(Delta::from_micros(10), || None);
        fsleep(Delta::from_micros(10));

        regs::NV_PFALCON_FALCON_ENGINE::update(bar, &E::ID, |v| v.set_reset(false));

@@ -504,14 +502,12 @@ fn dma_wr<F: FalconFirmware<Target = E>>(
            // Wait for the transfer to complete.
            // TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories
            // should ever take that long.
            util::wait_on(Delta::from_secs(2), || {
                let r = regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, &E::ID);
                if r.idle() {
                    Some(())
                } else {
                    None
                }
            })?;
            read_poll_timeout(
                || Ok(regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, &E::ID)),
                |r| r.idle(),
                Delta::ZERO,
                Delta::from_secs(2),
            )?;
        }

        Ok(())
@@ -574,14 +570,12 @@ pub(crate) fn boot(
        }

        // TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds.
        util::wait_on(Delta::from_secs(2), || {
            let r = regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID);
            if r.halted() {
                Some(())
            } else {
                None
            }
        })?;
        read_poll_timeout(
            || Ok(regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID)),
            |r| r.halted(),
            Delta::ZERO,
            Delta::from_secs(2),
        )?;

        let (mbox0, mbox1) = (
            regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, &E::ID).value(),
+7 −9
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
use core::marker::PhantomData;

use kernel::device;
use kernel::io::poll::read_poll_timeout;
use kernel::prelude::*;
use kernel::time::Delta;

@@ -11,7 +12,6 @@
    Falcon, FalconBromParams, FalconEngine, FalconModSelAlgo, PeregrineCoreSelect,
};
use crate::regs;
use crate::util;

use super::FalconHal;

@@ -23,14 +23,12 @@ fn select_core_ga102<E: FalconEngine>(bar: &Bar0) -> Result {
            .write(bar, &E::ID);

        // TIMEOUT: falcon core should take less than 10ms to report being enabled.
        util::wait_on(Delta::from_millis(10), || {
            let r = regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID);
            if r.valid() {
                Some(())
            } else {
                None
            }
        })?;
        read_poll_timeout(
            || Ok(regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID)),
            |r| r.valid(),
            Delta::ZERO,
            Delta::from_millis(10),
        )?;
    }

    Ok(())
+16 −20
Original line number Diff line number Diff line
@@ -18,13 +18,12 @@
//!
//! Note that the devinit sequence also needs to run during suspend/resume.

use kernel::bindings;
use kernel::io::poll::read_poll_timeout;
use kernel::prelude::*;
use kernel::time::Delta;

use crate::driver::Bar0;
use crate::regs;
use crate::util;

/// Wait for the `GFW` (GPU firmware) boot completion signal (`GFW_BOOT`), or a 4 seconds timeout.
///
@@ -50,22 +49,19 @@ pub(crate) fn wait_gfw_boot_completion(bar: &Bar0) -> Result {
    //
    // TIMEOUT: arbitrarily large value. GFW starts running immediately after the GPU is put out of
    // reset, and should complete in less time than that.
    util::wait_on(Delta::from_secs(4), || {
        // Check that FWSEC has lowered its protection level before reading the GFW_BOOT status.
        let gfw_booted = regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK::read(bar)
    read_poll_timeout(
        || {
            Ok(
                // Check that FWSEC has lowered its protection level before reading the GFW_BOOT
                // status.
                regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK::read(bar)
                    .read_protection_level0()
            && regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT::read(bar).completed();

        if gfw_booted {
            Some(())
        } else {
            // TODO[DLAY]: replace with [1] once it merges.
            // [1] https://lore.kernel.org/rust-for-linux/20250423192857.199712-6-fujita.tomonori@gmail.com/
            //
            // SAFETY: `msleep()` is safe to call with any parameter.
            unsafe { bindings::msleep(1) };

            None
        }
    })
                    && regs::NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT::read(bar).completed(),
            )
        },
        |&gfw_booted| gfw_booted,
        Delta::from_millis(1),
        Delta::from_secs(4),
    )
    .map(|_| ())
}
+0 −1
Original line number Diff line number Diff line
@@ -14,7 +14,6 @@
mod gpu;
mod gsp;
mod regs;
mod util;
mod vbios;

pub(crate) const MODULE_NAME: &kernel::str::CStr = <LocalModule as kernel::ModuleMetadata>::NAME;
Loading