* [PATCH v6 0/2] nova-core: add initial support for gpu timer (v6)
@ 2026-11-09 1:55 Dave Airlie via B4 Relay
2026-11-09 1:55 ` [PATCH v6 1/2] rust: time: expose as_nanos for clock sources Dave Airlie via B4 Relay
2026-11-09 1:55 ` [PATCH v6 2/2] gpu: nova-core: add support for GPU timer block. (v6) Dave Airlie via B4 Relay
0 siblings, 2 replies; 9+ messages in thread
From: Dave Airlie via B4 Relay @ 2026-11-09 1:55 UTC (permalink / raw)
To: Andreas Hindborg, FUJITA Tomonori, Gary Guo, Alice Ryhl,
Danilo Krummrich, Daniel Almeida, Alexandre Courbot
Cc: nova-gpu, dri-devel, Dave Airlie
The GPU has a timer, one of the pieces of information
we need to pass into GSP init later is the timer offset.
This series just adds support for setting up the timer
on Turing+, with hals for Turing and Hopper.
Right now it calculates the value to send to GSP but
the code to send it will be added later.
For some hardware variants sending a proper value
is required for GSP init to succeed.
Signed-off-by: Dave Airlie <airlied@redhat.com>
---
Changes in v6:
- Alexandre's review comment handled
- fsp hal stores in fsp
- register cleanups
- Link to v5: https://lore.kernel.org/r/20261106-nova-timer-v5-0-a0cd25f3ee18@redhat.com
Changes in v5:
- Alexandre's review comments handled
- reworked registers/workaround logic into fsp
- fixed all the timer register handling to be non-falling.
- Link to v4: https://lore.kernel.org/r/20261105-nova-timer-v4-0-45a7c121d4de@redhat.com
Changes in v4:
- reworked register handling
- used a timerstate.
- Link to v3: https://lore.kernel.org/r/20261103-nova-timer-v3-0-0cf9bbae8fd9@redhat.com
---
Dave Airlie (2):
rust: time: expose as_nanos for clock sources.
gpu: nova-core: add support for GPU timer block. (v6)
drivers/gpu/nova-core/fsp.rs | 16 +++++-
drivers/gpu/nova-core/fsp/hal.rs | 7 ++-
drivers/gpu/nova-core/fsp/hal/gh100.rs | 5 ++
drivers/gpu/nova-core/fsp/regs.rs | 31 ++++++++++
drivers/gpu/nova-core/gpu.rs | 8 +++
drivers/gpu/nova-core/nova_core.rs | 1 +
drivers/gpu/nova-core/timer.rs | 38 +++++++++++++
drivers/gpu/nova-core/timer/hal.rs | 31 ++++++++++
drivers/gpu/nova-core/timer/hal/gh100.rs | 63 ++++++++++++++++++++
drivers/gpu/nova-core/timer/hal/tu102.rs | 41 +++++++++++++
drivers/gpu/nova-core/timer/regs.rs | 98 ++++++++++++++++++++++++++++++++
rust/kernel/time.rs | 3 +-
12 files changed, 337 insertions(+), 5 deletions(-)
---
base-commit: 7a6bc132f1b51437063c9203e7221067b40a791e
change-id: 20261102-nova-timer-f4b9de3274a1
Best regards,
--
Dave Airlie <airlied@redhat.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v6 1/2] rust: time: expose as_nanos for clock sources.
2026-11-09 1:55 [PATCH v6 0/2] nova-core: add initial support for gpu timer (v6) Dave Airlie via B4 Relay
@ 2026-11-09 1:55 ` Dave Airlie via B4 Relay
2026-11-10 13:56 ` Alexandre Courbot
2026-11-11 14:50 ` Gary Guo
2026-11-09 1:55 ` [PATCH v6 2/2] gpu: nova-core: add support for GPU timer block. (v6) Dave Airlie via B4 Relay
1 sibling, 2 replies; 9+ messages in thread
From: Dave Airlie via B4 Relay @ 2026-11-09 1:55 UTC (permalink / raw)
To: Andreas Hindborg, FUJITA Tomonori, Gary Guo, Alice Ryhl,
Danilo Krummrich, Daniel Almeida, Alexandre Courbot
Cc: nova-gpu, dri-devel, Dave Airlie
From: Dave Airlie <airlied@redhat.com>
The nouveau C driver does ktime_to_ns(ktime_get()) to program
the cpu ns into some hw/fw, so allow this method for rust drivers.
This is needed for following nova patch.
Reviewed-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
---
rust/kernel/time.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index b6a2aab12a50..4409291f3ffa 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -215,8 +215,9 @@ pub fn elapsed(&self) -> Delta {
Self::now() - *self
}
+ /// Return the raw nanoseconds values since the epoch of clock `C`.
#[inline]
- pub(crate) fn as_nanos(&self) -> i64 {
+ pub fn as_nanos(&self) -> i64 {
self.inner
}
--
2.56.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v6 2/2] gpu: nova-core: add support for GPU timer block. (v6)
2026-11-09 1:55 [PATCH v6 0/2] nova-core: add initial support for gpu timer (v6) Dave Airlie via B4 Relay
2026-11-09 1:55 ` [PATCH v6 1/2] rust: time: expose as_nanos for clock sources Dave Airlie via B4 Relay
@ 2026-11-09 1:55 ` Dave Airlie via B4 Relay
2026-11-09 2:09 ` sashiko-bot
2026-11-10 13:56 ` Alexandre Courbot
1 sibling, 2 replies; 9+ messages in thread
From: Dave Airlie via B4 Relay @ 2026-11-09 1:55 UTC (permalink / raw)
To: Andreas Hindborg, FUJITA Tomonori, Gary Guo, Alice Ryhl,
Danilo Krummrich, Daniel Almeida, Alexandre Courbot
Cc: nova-gpu, dri-devel, Dave Airlie
From: Dave Airlie <airlied@redhat.com>
This is needed to calculate the system timer offset that is passed
to GSP init.
2 HALs exist:
a) tu102 is the gv100 path from open-gpu, the priv level is checked
and the cpu time is written to the gpu timer. no offset is used.
b) gh100 is for hopper+
This is the gh100 path from open-gpu, where the secure system
timer is read, the offset is calculated.
The offset is written to hw offset registers, except on the
original gh100 where a workaround is needed for older FSP versions.
Signed-off-by: Dave Airlie <airlied@redhat.com>
---
drivers/gpu/nova-core/fsp.rs | 16 +++++-
drivers/gpu/nova-core/fsp/hal.rs | 7 ++-
drivers/gpu/nova-core/fsp/hal/gh100.rs | 5 ++
drivers/gpu/nova-core/fsp/regs.rs | 31 ++++++++++
drivers/gpu/nova-core/gpu.rs | 8 +++
drivers/gpu/nova-core/nova_core.rs | 1 +
drivers/gpu/nova-core/timer.rs | 38 +++++++++++++
drivers/gpu/nova-core/timer/hal.rs | 31 ++++++++++
drivers/gpu/nova-core/timer/hal/gh100.rs | 63 ++++++++++++++++++++
drivers/gpu/nova-core/timer/hal/tu102.rs | 41 +++++++++++++
drivers/gpu/nova-core/timer/regs.rs | 98 ++++++++++++++++++++++++++++++++
11 files changed, 335 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index 3a4a10487f33..74cbbe3996c6 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -50,10 +50,11 @@
NvdmHeader,
NvdmType, //
},
- regs, //
+ regs as bootregs, //
};
mod hal;
+mod regs;
/// PRC message sub-command.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -389,6 +390,7 @@ pub(crate) fn boot_params(&self) -> &Coherent<'_, GspFmcBootParams> {
pub(crate) struct Fsp<'a> {
falcon: Falcon<'a, FspEngine>,
fmc_fw: GspFmcFirmware<'a>,
+ hal: &'static dyn hal::FspHal,
}
impl<'a> Fsp<'a> {
@@ -428,7 +430,7 @@ fn wait_secure_boot(
read_poll_timeout(
|| Ok(hal.fsp_boot_status(bar)),
- |&status| status == regs::NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE_STATUS_SUCCESS,
+ |&status| status == bootregs::NV_THERM_I2CS_SCRATCH_FSP_BOOT_COMPLETE_STATUS_SUCCESS,
Delta::from_millis(10),
Delta::from_millis(FSP_SECURE_BOOT_TIMEOUT_MS),
)
@@ -436,7 +438,11 @@ fn wait_secure_boot(
dev_err!(dev, "FSP secure boot completion error: {:?}\n", e);
})?;
- Ok(Fsp { falcon, fmc_fw })
+ Ok(Fsp {
+ falcon,
+ fmc_fw,
+ hal,
+ })
}
/// Sends a message to FSP and waits for the response.
@@ -549,4 +555,8 @@ pub(crate) fn boot_fmc(
dev_dbg!(dev, "FSP Chain of Trust completed successfully\n");
Ok(())
}
+
+ pub(crate) fn is_bug_3957833_affected(&self, bar: Bar0<'_>) -> bool {
+ self.hal.is_bug_3957833_affected(bar)
+ }
}
diff --git a/drivers/gpu/nova-core/fsp/hal.rs b/drivers/gpu/nova-core/fsp/hal.rs
index eaf5837ac5a8..f2de7cc296ce 100644
--- a/drivers/gpu/nova-core/fsp/hal.rs
+++ b/drivers/gpu/nova-core/fsp/hal.rs
@@ -13,7 +13,7 @@
mod gb202;
mod gh100;
-pub(super) trait FspHal {
+pub(super) trait FspHal: Sync {
/// Returns the secure boot status from the architecture-specific `NV_THERM_I2CS_SCRATCH` register.
fn fsp_boot_status(&self, bar: Bar0<'_>) -> u32;
@@ -23,6 +23,11 @@ pub(super) trait FspHal {
// TODO: consider moving this into the TLV firmware metadata when ready
/// Returns the size reserved at the end of the framebuffer, in bytes.
fn fb_end_reserved_size(&self) -> u64;
+
+ /// Return if the bug 3957833 is affected
+ fn is_bug_3957833_affected(&self, _bar: Bar0<'_>) -> bool {
+ false
+ }
}
/// Returns the FSP HAL, or `None` if the architecture doesn't support FSP.
diff --git a/drivers/gpu/nova-core/fsp/hal/gh100.rs b/drivers/gpu/nova-core/fsp/hal/gh100.rs
index 9a8563799da8..7f6c8e404f30 100644
--- a/drivers/gpu/nova-core/fsp/hal/gh100.rs
+++ b/drivers/gpu/nova-core/fsp/hal/gh100.rs
@@ -9,6 +9,7 @@
use crate::{
driver::Bar0,
fsp::hal::FspHal,
+ fsp::regs::*,
regs, //
};
@@ -33,6 +34,10 @@ fn cot_version(&self) -> u16 {
fn fb_end_reserved_size(&self) -> u64 {
u64::SZ_2M
}
+
+ fn is_bug_3957833_affected(&self, bar: Bar0<'_>) -> bool {
+ bar.read(NV_GFW_FSP_UCODE_VERSION).is_bug_3957833_affected()
+ }
}
const GH100: Gh100 = Gh100;
diff --git a/drivers/gpu/nova-core/fsp/regs.rs b/drivers/gpu/nova-core/fsp/regs.rs
new file mode 100644
index 000000000000..d04c48ac8e5f
--- /dev/null
+++ b/drivers/gpu/nova-core/fsp/regs.rs
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use kernel::io::register;
+
+use crate::driver::NovaRegisters;
+
+register! {
+ base: NovaRegisters;
+
+ pub(super) NV_PFSP_FALCON_COMMON_SCRATCH_GROUP_3(u32)[4] @ 0x008f0330 {
+ 31:0 val;
+ }
+
+ /// FSP ucode version
+ pub(super) NV_GFW_FSP_UCODE_VERSION(u32) => NV_PFSP_FALCON_COMMON_SCRATCH_GROUP_3[1] {
+ 11:0 full;
+ }
+}
+
+impl NV_GFW_FSP_UCODE_VERSION {
+ /// OpenRM kfspRequiresBug3957833WAR_HAL:
+ /// returns `true` if the FSP ucode predates the fix for
+ /// bug 3957833 and hence the sys timer offset must not be programmed.
+ /// Can only be true on GH100 with older FSP.
+ pub(super) fn is_bug_3957833_affected(self) -> bool {
+ /// FSP ucode version from which on the fix for bug 3957833 is included.
+ const FSP_BUG_3957833_FIX_VERSION: u32 = 0x44c;
+
+ self.full() < FSP_BUG_3957833_FIX_VERSION
+ }
+}
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index ac5305d7ff5e..cd281460c509 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -53,6 +53,10 @@
GpuMm,
VramAddress, //
},
+ timer::{
+ Timer,
+ TimerState, //
+ },
vgpu::VgpuManager, //
};
@@ -331,6 +335,8 @@ struct GspResources<'gpu> {
// TODO: use different resource types for each boot method, and make the relevant Gsp methods
// generic against them.
fsp: Option<Fsp<'gpu>>,
+ /// Timer state - contains system timer offset
+ timer: TimerState,
/// vGPU state detected before GSP boot.
vgpu: VgpuManager,
/// GSP runtime data.
@@ -497,6 +503,8 @@ pub(crate) fn new<'a>(
fsp: Fsp::try_new(dev, bar, spec.chipset)?,
+ timer: Timer::setup(bar, spec.chipset, fsp.as_ref())?,
+
vgpu: VgpuManager::new(pdev, spec.chipset, fsp.as_mut()),
gsp <- Gsp::new(pdev, bar),
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index a8f6dc22057b..ee59d81e5105 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -27,6 +27,7 @@
mod sbuffer;
#[cfg(CONFIG_NOVA_CORE_SELFTESTS)]
mod selftest;
+mod timer;
mod vbios;
mod vgpu;
diff --git a/drivers/gpu/nova-core/timer.rs b/drivers/gpu/nova-core/timer.rs
new file mode 100644
index 000000000000..4c329221c674
--- /dev/null
+++ b/drivers/gpu/nova-core/timer.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+mod hal;
+mod regs;
+
+use kernel::{
+ prelude::*, //
+};
+
+use crate::{
+ driver::Bar0,
+ fsp::Fsp,
+ gpu::Chipset, //
+};
+
+pub(crate) struct Timer;
+
+/// Struct that holds the sys timer offset value
+/// after initialising the GPU timer block.
+pub(crate) struct TimerState {
+ /// This value is to be passed to GspInit SYS_TIMER_OFFSET_NS
+ /// It is considered an opaque value, passed from timer hal to GSP.
+ #[expect(dead_code)]
+ pub(crate) sys_timer_offset_ns: u64,
+}
+
+impl Timer {
+ /// Setup the GPU timer hardware
+ pub(crate) fn setup(
+ bar: Bar0<'_>,
+ chipset: Chipset,
+ fsp: Option<&Fsp<'_>>,
+ ) -> Result<TimerState> {
+ Ok(TimerState {
+ sys_timer_offset_ns: hal::timer_hal(chipset).setup(bar, fsp)?,
+ })
+ }
+}
diff --git a/drivers/gpu/nova-core/timer/hal.rs b/drivers/gpu/nova-core/timer/hal.rs
new file mode 100644
index 000000000000..c2f2bbcad890
--- /dev/null
+++ b/drivers/gpu/nova-core/timer/hal.rs
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use kernel::prelude::*;
+
+use crate::{
+ driver::Bar0,
+ fsp::Fsp,
+ gpu::{
+ Architecture,
+ Chipset, //
+ },
+};
+
+mod gh100;
+mod tu102;
+
+pub(super) trait TimerHal {
+ /// Setup the GPU's system timer.
+ ///
+ /// Returns the value to program into GspInitRequest.
+ fn setup(&self, bar: Bar0<'_>, fsp: Option<&Fsp<'_>>) -> Result<u64>;
+}
+
+pub(super) fn timer_hal(chipset: Chipset) -> &'static dyn TimerHal {
+ match chipset.arch() {
+ Architecture::Turing | Architecture::Ampere | Architecture::Ada => tu102::TU102_HAL,
+ Architecture::Hopper | Architecture::BlackwellGB10x | Architecture::BlackwellGB20x => {
+ gh100::GH100_HAL
+ }
+ }
+}
diff --git a/drivers/gpu/nova-core/timer/hal/gh100.rs b/drivers/gpu/nova-core/timer/hal/gh100.rs
new file mode 100644
index 000000000000..154c7a301a0c
--- /dev/null
+++ b/drivers/gpu/nova-core/timer/hal/gh100.rs
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use super::TimerHal;
+
+use kernel::{
+ io::Io,
+ prelude::*,
+ time::*, //
+};
+
+use crate::{
+ driver::Bar0,
+ fsp::Fsp,
+ timer::regs::gh100::*, //
+};
+
+/// Timer HAL for Hopper and Blackwell.
+struct Gh100;
+
+fn sec_timer_read(bar: Bar0<'_>) -> u64 {
+ let mut hi2 = bar.read(NV_PGC6_SCI_SEC_TIMER_TIME_1);
+ loop {
+ let lo = bar.read(NV_PGC6_SCI_SEC_TIMER_TIME_0);
+ let hi = bar.read(NV_PGC6_SCI_SEC_TIMER_TIME_1);
+ if hi == hi2 {
+ return u64::from(u32::from(hi)) << 32 | u64::from(u32::from(lo));
+ }
+ hi2 = bar.read(NV_PGC6_SCI_SEC_TIMER_TIME_1);
+ }
+}
+
+fn set_sys_timer_offset(bar: Bar0<'_>, fsp: &Fsp<'_>, time_ns: u64) -> Result<u64> {
+ let sec_timer_ns = sec_timer_read(bar);
+
+ let sys_timer_offset_ns = time_ns.wrapping_sub(sec_timer_ns);
+
+ // Don't set the timer offset registers on buggy firmware
+ if !fsp.is_bug_3957833_affected(bar) {
+ bar.write_reg(NV_PGC6_SCI_SYS_TIMER_OFFSET_1::from_nsec(
+ sys_timer_offset_ns,
+ ));
+ bar.write_reg(
+ NV_PGC6_SCI_SYS_TIMER_OFFSET_0::from_nsec(sys_timer_offset_ns).with_update(true),
+ );
+ }
+ Ok(sys_timer_offset_ns)
+}
+
+impl TimerHal for Gh100 {
+ fn setup(&self, bar: Bar0<'_>, fsp: Option<&Fsp<'_>>) -> Result<u64> {
+ // The OpenRM driver uses wall clock time here not monotonic
+ let sys_time_ns = Instant::<RealTime>::now().as_nanos();
+
+ // fsp is required on gh100 - return error if not available.
+ let fsp = fsp.ok_or(EINVAL)?;
+
+ // CAST: realtime system time can't be negative.
+ set_sys_timer_offset(bar, fsp, sys_time_ns as u64)
+ }
+}
+
+const GH100: Gh100 = Gh100;
+pub(super) const GH100_HAL: &dyn TimerHal = &GH100;
diff --git a/drivers/gpu/nova-core/timer/hal/tu102.rs b/drivers/gpu/nova-core/timer/hal/tu102.rs
new file mode 100644
index 000000000000..064f9b92666e
--- /dev/null
+++ b/drivers/gpu/nova-core/timer/hal/tu102.rs
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use super::TimerHal;
+
+use kernel::{
+ io::Io,
+ prelude::*,
+ time::*, //
+};
+
+use crate::{
+ driver::Bar0,
+ fsp::Fsp,
+ timer::regs::*, //
+};
+
+/// Timer HAL for Turing, Ampere, Ada
+struct Tu102;
+
+fn set_time(bar: Bar0<'_>, time_ns: u64) -> Result {
+ if !bar.read(NV_PTIMER_TIME_PRIV_LEVEL_MASK).level0() {
+ return Err(EINVAL);
+ }
+ bar.write_reg(NV_PTIMER_TIME_1::from_nsec(time_ns));
+ bar.write_reg(NV_PTIMER_TIME_0::from_nsec(time_ns));
+ Ok(())
+}
+
+impl TimerHal for Tu102 {
+ fn setup(&self, bar: Bar0<'_>, _fsp: Option<&Fsp<'_>>) -> Result<u64> {
+ // The OpenRM driver uses wall clock time here not monotonic
+ let sys_time_ns = Instant::<RealTime>::now().as_nanos();
+
+ // CAST: realtime system time can't be negative.
+ set_time(bar, sys_time_ns as u64)?;
+ Ok(0_u64)
+ }
+}
+
+const TU102: Tu102 = Tu102;
+pub(super) const TU102_HAL: &dyn TimerHal = &TU102;
diff --git a/drivers/gpu/nova-core/timer/regs.rs b/drivers/gpu/nova-core/timer/regs.rs
new file mode 100644
index 000000000000..229babc2c296
--- /dev/null
+++ b/drivers/gpu/nova-core/timer/regs.rs
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use kernel::io::register;
+use kernel::num::Bounded;
+
+use crate::driver::NovaRegisters;
+use pin_init::Zeroable;
+
+/// Field value for the NSEC field (31:5) of the `_0` registers: `nsec[31:5]`.
+///
+/// The GPU timer counts nanoseconds with 32 ns granularity, so `nsec[4:0]` is dropped.
+fn nsec_lo(nsec: u64) -> Bounded<u32, 27> {
+ Bounded::<u32, 32>::from(nsec as u32).shr::<5, _>()
+}
+
+/// Field value for the NSEC field (28:0) of the `_1` registers: `nsec[60:32]`.
+///
+/// The GPU timer is 61 bits wide, so `nsec[63:61]` is not representable and is
+/// truncated - the same bits the hardware discards on a raw register write.
+fn nsec_hi(nsec: u64) -> Bounded<u32, 29> {
+ Bounded::<u32, 29>::from_expr((nsec >> 32) as u32 & 0x1fff_ffff)
+}
+
+// PTIMER
+
+register! {
+ base: NovaRegisters;
+
+ pub(super) NV_PTIMER_TIME_PRIV_LEVEL_MASK(u32) @ 0x00009430 {
+ 4:4 level0 => bool;
+ }
+
+ pub(super) NV_PTIMER_TIME_0(u32) @ 0x00009400 {
+ 31:5 nsec;
+ }
+
+ pub(super) NV_PTIMER_TIME_1(u32) @ 0x00009410 {
+ 28:0 nsec;
+ }
+}
+
+impl NV_PTIMER_TIME_0 {
+ pub(super) fn from_nsec(nsec: u64) -> Self {
+ Self::zeroed().with_nsec(nsec_lo(nsec))
+ }
+}
+
+impl NV_PTIMER_TIME_1 {
+ pub(super) fn from_nsec(nsec: u64) -> Self {
+ Self::zeroed().with_nsec(nsec_hi(nsec))
+ }
+}
+
+pub(super) mod gh100 {
+ use kernel::io::register;
+
+ use super::{
+ nsec_hi, //
+ nsec_lo,
+ };
+ use crate::driver::NovaRegisters;
+ use pin_init::Zeroable;
+
+ // PGC6/TIMER
+ register! {
+ base: NovaRegisters;
+
+ pub(in crate::timer) NV_PGC6_SCI_SEC_TIMER_TIME_0(u32) @ 0x00118f54 {
+ 31:5 nsec;
+ }
+
+ pub(in crate::timer) NV_PGC6_SCI_SEC_TIMER_TIME_1(u32) @ 0x00118f58 {
+ 28:0 nsec;
+ }
+
+ pub(in crate::timer) NV_PGC6_SCI_SYS_TIMER_OFFSET_0(u32) @ 0x00118df4 {
+ 0:0 update;
+ 31:5 nsec;
+ }
+
+ pub(in crate::timer) NV_PGC6_SCI_SYS_TIMER_OFFSET_1(u32) @ 0x00118df8 {
+ 28:0 nsec;
+ }
+
+ }
+
+ impl NV_PGC6_SCI_SYS_TIMER_OFFSET_0 {
+ pub(in crate::timer) fn from_nsec(nsec: u64) -> Self {
+ Self::zeroed().with_nsec(nsec_lo(nsec))
+ }
+ }
+
+ impl NV_PGC6_SCI_SYS_TIMER_OFFSET_1 {
+ pub(in crate::timer) fn from_nsec(nsec: u64) -> Self {
+ Self::zeroed().with_nsec(nsec_hi(nsec))
+ }
+ }
+}
--
2.56.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v6 2/2] gpu: nova-core: add support for GPU timer block. (v6)
2026-11-09 1:55 ` [PATCH v6 2/2] gpu: nova-core: add support for GPU timer block. (v6) Dave Airlie via B4 Relay
@ 2026-11-09 2:09 ` sashiko-bot
2026-11-10 13:56 ` Alexandre Courbot
1 sibling, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-11-09 2:09 UTC (permalink / raw)
To: Dave Airlie, Andreas Hindborg, FUJITA Tomonori, Gary Guo,
Alice Ryhl, Danilo Krummrich, Daniel Almeida, Alexandre Courbot
Cc: nova-gpu, dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] gpu: nova-core: wrapped timer offset programmed in
set_sys_timer_offset()
--
commit 7d2284f17f67e098294d4252bcce87d29a2a59b1
Author: Dave Airlie <airlied@redhat.com>
gpu: nova-core: add support for GPU timer block. (v6)
This commit adds GPU timer block initialization for Turing through
Blackwell GPUs to compute the system timer offset for GSP initialization,
including a GH100 FSP ucode version check for bug 3957833.
> diff --git a/drivers/gpu/nova-core/timer/hal/gh100.rs b/drivers/gpu/nova-core/timer/hal/gh100.rs
> new file mode 100644
> index 0000000000000..154c7a301a0c1
> --- /dev/null
> +++ b/drivers/gpu/nova-core/timer/hal/gh100.rs
[ ... ]
> +fn set_sys_timer_offset(bar: Bar0<'_>, fsp: &Fsp<'_>, time_ns: u64) -> Result<u64> {
> + let sec_timer_ns = sec_timer_read(bar);
> +
> + let sys_timer_offset_ns = time_ns.wrapping_sub(sec_timer_ns);
> +
> + // Don't set the timer offset registers on buggy firmware
> + if !fsp.is_bug_3957833_affected(bar) {
> + bar.write_reg(NV_PGC6_SCI_SYS_TIMER_OFFSET_1::from_nsec(
> + sys_timer_offset_ns,
> + ));
> + bar.write_reg(
> + NV_PGC6_SCI_SYS_TIMER_OFFSET_0::from_nsec(sys_timer_offset_ns).with_update(true),
> + );
> + }
> + Ok(sys_timer_offset_ns)
> +}
[Severity: Medium]
As reported by Alexandre Courbot on v4 [1], can set_sys_timer_offset()
program a wrapped value into NV_PGC6_SCI_SYS_TIMER_OFFSET_1 and
NV_PGC6_SCI_SYS_TIMER_OFFSET_0 when sec_timer_ns exceeds time_ns?
If the host wall-clock time is behind the GPU secure timer, wrapping_sub()
produces a large wrapped u64 that nsec_hi() truncates to 61 bits when
writing the hardware offset registers while returning the unmasked 64-bit
value for GSP initialization. In OpenRM, tmrSetCurrentTime_GH100 verifies
secTimerNs < osTimeNs and returns early without programming the offset
registers if the delta is not positive, with the caller logging and
ignoring the error.
[1] https://lore.kernel.org/r/DMO7FUYY05LK.123ZPLIW24C2S@nvidia.com
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261109-nova-timer-v6-0-5544a3bd8b28@redhat.com?part=2
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 1/2] rust: time: expose as_nanos for clock sources.
2026-11-09 1:55 ` [PATCH v6 1/2] rust: time: expose as_nanos for clock sources Dave Airlie via B4 Relay
@ 2026-11-10 13:56 ` Alexandre Courbot
2026-11-11 19:48 ` Andreas Hindborg
2026-11-11 14:50 ` Gary Guo
1 sibling, 1 reply; 9+ messages in thread
From: Alexandre Courbot @ 2026-11-10 13:56 UTC (permalink / raw)
To: Dave Airlie via B4 Relay
Cc: airlied, Andreas Hindborg, FUJITA Tomonori, Gary Guo, Alice Ryhl,
Danilo Krummrich, Daniel Almeida, nova-gpu, dri-devel
On Mon Nov 9, 2026 at 10:55 AM JST, Dave Airlie via B4 Relay wrote:
> From: Dave Airlie <airlied@redhat.com>
>
> The nouveau C driver does ktime_to_ns(ktime_get()) to program
> the cpu ns into some hw/fw, so allow this method for rust drivers.
>
> This is needed for following nova patch.
>
> Reviewed-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
> Signed-off-by: Dave Airlie <airlied@redhat.com>
This patch has also received a maintainer acked-by:
https://lore.kernel.org/all/875wyoydqk.fsf@t14s.mail-host-address-is-not-set/
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 2/2] gpu: nova-core: add support for GPU timer block. (v6)
2026-11-09 1:55 ` [PATCH v6 2/2] gpu: nova-core: add support for GPU timer block. (v6) Dave Airlie via B4 Relay
2026-11-09 2:09 ` sashiko-bot
@ 2026-11-10 13:56 ` Alexandre Courbot
1 sibling, 0 replies; 9+ messages in thread
From: Alexandre Courbot @ 2026-11-10 13:56 UTC (permalink / raw)
To: Dave Airlie via B4 Relay
Cc: airlied, Andreas Hindborg, FUJITA Tomonori, Gary Guo, Alice Ryhl,
Danilo Krummrich, Daniel Almeida, nova-gpu, dri-devel
On Mon Nov 9, 2026 at 10:55 AM JST, Dave Airlie via B4 Relay wrote:
<...>
> diff --git a/drivers/gpu/nova-core/timer/hal/gh100.rs b/drivers/gpu/nova-core/timer/hal/gh100.rs
> new file mode 100644
> index 000000000000..154c7a301a0c
> --- /dev/null
> +++ b/drivers/gpu/nova-core/timer/hal/gh100.rs
> @@ -0,0 +1,63 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +use super::TimerHal;
> +
> +use kernel::{
> + io::Io,
> + prelude::*,
> + time::*, //
> +};
> +
> +use crate::{
> + driver::Bar0,
> + fsp::Fsp,
> + timer::regs::gh100::*, //
> +};
> +
> +/// Timer HAL for Hopper and Blackwell.
> +struct Gh100;
> +
> +fn sec_timer_read(bar: Bar0<'_>) -> u64 {
> + let mut hi2 = bar.read(NV_PGC6_SCI_SEC_TIMER_TIME_1);
> + loop {
> + let lo = bar.read(NV_PGC6_SCI_SEC_TIMER_TIME_0);
> + let hi = bar.read(NV_PGC6_SCI_SEC_TIMER_TIME_1);
> + if hi == hi2 {
> + return u64::from(u32::from(hi)) << 32 | u64::from(u32::from(lo));
> + }
> + hi2 = bar.read(NV_PGC6_SCI_SEC_TIMER_TIME_1);
> + }
> +}
> +
> +fn set_sys_timer_offset(bar: Bar0<'_>, fsp: &Fsp<'_>, time_ns: u64) -> Result<u64> {
This method cannot fail, so it should return just `u64`.
> + let sec_timer_ns = sec_timer_read(bar);
> +
> + let sys_timer_offset_ns = time_ns.wrapping_sub(sec_timer_ns);
As discussed in my other response, wrapping here is defensible, but I'd
like to have a comment explaining why this is so, i.e. that even if we
wrap after an underflow the SEC_TIMER + OFFSET value module 61 bits will
match the system clock.
> +
> + // Don't set the timer offset registers on buggy firmware
> + if !fsp.is_bug_3957833_affected(bar) {
> + bar.write_reg(NV_PGC6_SCI_SYS_TIMER_OFFSET_1::from_nsec(
> + sys_timer_offset_ns,
> + ));
> + bar.write_reg(
> + NV_PGC6_SCI_SYS_TIMER_OFFSET_0::from_nsec(sys_timer_offset_ns).with_update(true),
> + );
> + }
> + Ok(sys_timer_offset_ns)
> +}
> +
> +impl TimerHal for Gh100 {
> + fn setup(&self, bar: Bar0<'_>, fsp: Option<&Fsp<'_>>) -> Result<u64> {
> + // The OpenRM driver uses wall clock time here not monotonic
> + let sys_time_ns = Instant::<RealTime>::now().as_nanos();
> +
> + // fsp is required on gh100 - return error if not available.
> + let fsp = fsp.ok_or(EINVAL)?;
> +
> + // CAST: realtime system time can't be negative.
> + set_sys_timer_offset(bar, fsp, sys_time_ns as u64)
> + }
> +}
> +
> +const GH100: Gh100 = Gh100;
> +pub(super) const GH100_HAL: &dyn TimerHal = &GH100;
> diff --git a/drivers/gpu/nova-core/timer/hal/tu102.rs b/drivers/gpu/nova-core/timer/hal/tu102.rs
> new file mode 100644
> index 000000000000..064f9b92666e
> --- /dev/null
> +++ b/drivers/gpu/nova-core/timer/hal/tu102.rs
> @@ -0,0 +1,41 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +use super::TimerHal;
> +
> +use kernel::{
> + io::Io,
> + prelude::*,
> + time::*, //
> +};
> +
> +use crate::{
> + driver::Bar0,
> + fsp::Fsp,
> + timer::regs::*, //
> +};
> +
> +/// Timer HAL for Turing, Ampere, Ada
> +struct Tu102;
> +
> +fn set_time(bar: Bar0<'_>, time_ns: u64) -> Result {
> + if !bar.read(NV_PTIMER_TIME_PRIV_LEVEL_MASK).level0() {
> + return Err(EINVAL);
> + }
I don't think we want to make probe fail on this since the GPU should
still be usable (I don't know of a pre-GH100 platform that requires the
timer registers to be set in order to work). Let's log in the caller
(which should take a device::Device as argument for that) if this method
returns and error, and continue.
> + bar.write_reg(NV_PTIMER_TIME_1::from_nsec(time_ns));
> + bar.write_reg(NV_PTIMER_TIME_0::from_nsec(time_ns));
> + Ok(())
> +}
> +
> +impl TimerHal for Tu102 {
> + fn setup(&self, bar: Bar0<'_>, _fsp: Option<&Fsp<'_>>) -> Result<u64> {
> + // The OpenRM driver uses wall clock time here not monotonic
> + let sys_time_ns = Instant::<RealTime>::now().as_nanos();
> +
> + // CAST: realtime system time can't be negative.
> + set_time(bar, sys_time_ns as u64)?;
> + Ok(0_u64)
> + }
> +}
> +
> +const TU102: Tu102 = Tu102;
> +pub(super) const TU102_HAL: &dyn TimerHal = &TU102;
> diff --git a/drivers/gpu/nova-core/timer/regs.rs b/drivers/gpu/nova-core/timer/regs.rs
> new file mode 100644
> index 000000000000..229babc2c296
> --- /dev/null
> +++ b/drivers/gpu/nova-core/timer/regs.rs
> @@ -0,0 +1,98 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +use kernel::io::register;
> +use kernel::num::Bounded;
nit: `kernel` imports should be grouped.
> +
> +use crate::driver::NovaRegisters;
> +use pin_init::Zeroable;
> +
> +/// Field value for the NSEC field (31:5) of the `_0` registers: `nsec[31:5]`.
> +///
> +/// The GPU timer counts nanoseconds with 32 ns granularity, so `nsec[4:0]` is dropped.
> +fn nsec_lo(nsec: u64) -> Bounded<u32, 27> {
> + Bounded::<u32, 32>::from(nsec as u32).shr::<5, _>()
Since this uses `as`, this needs a `CAST:` comment. Something like:
// CAST: we want to take the lowest 32 bits of `nsec`.
(we may turn a linter on in the future that warns if such comments are
missing, so I'd like to make sure we set them ahead-of-time even if they
are trivial)
> +}
> +
> +/// Field value for the NSEC field (28:0) of the `_1` registers: `nsec[60:32]`.
> +///
> +/// The GPU timer is 61 bits wide, so `nsec[63:61]` is not representable and is
> +/// truncated - the same bits the hardware discards on a raw register write.
> +fn nsec_hi(nsec: u64) -> Bounded<u32, 29> {
> + Bounded::<u32, 29>::from_expr((nsec >> 32) as u32 & 0x1fff_ffff)
And for this one it can be:
// CAST: we are shifting a 64-bit number by 32 bits, leaving 32 bits of value.
Also, instead of the `0x1fff_ffff` mask, can you use
`bits::genmask_u32(0..=28)` (after importing `kernel::bits`)? It makes
it easier to understand what we are masking.
> +}
> +
> +// PTIMER
> +
> +register! {
> + base: NovaRegisters;
> +
> + pub(super) NV_PTIMER_TIME_PRIV_LEVEL_MASK(u32) @ 0x00009430 {
> + 4:4 level0 => bool;
> + }
> +
> + pub(super) NV_PTIMER_TIME_0(u32) @ 0x00009400 {
> + 31:5 nsec;
> + }
> +
> + pub(super) NV_PTIMER_TIME_1(u32) @ 0x00009410 {
> + 28:0 nsec;
> + }
> +}
> +
> +impl NV_PTIMER_TIME_0 {
> + pub(super) fn from_nsec(nsec: u64) -> Self {
> + Self::zeroed().with_nsec(nsec_lo(nsec))
> + }
> +}
> +
> +impl NV_PTIMER_TIME_1 {
> + pub(super) fn from_nsec(nsec: u64) -> Self {
> + Self::zeroed().with_nsec(nsec_hi(nsec))
> + }
> +}
> +
> +pub(super) mod gh100 {
> + use kernel::io::register;
> +
> + use super::{
> + nsec_hi, //
> + nsec_lo,
nit: `//` should be on the last import.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 1/2] rust: time: expose as_nanos for clock sources.
2026-11-09 1:55 ` [PATCH v6 1/2] rust: time: expose as_nanos for clock sources Dave Airlie via B4 Relay
2026-11-10 13:56 ` Alexandre Courbot
@ 2026-11-11 14:50 ` Gary Guo
1 sibling, 0 replies; 9+ messages in thread
From: Gary Guo @ 2026-11-11 14:50 UTC (permalink / raw)
To: airlied, Andreas Hindborg, FUJITA Tomonori, Gary Guo, Alice Ryhl,
Danilo Krummrich, Daniel Almeida, Alexandre Courbot
Cc: nova-gpu, dri-devel
On Mon Nov 9, 2026 at 1:55 AM GMT, Dave Airlie via B4 Relay wrote:
> From: Dave Airlie <airlied@redhat.com>
>
> The nouveau C driver does ktime_to_ns(ktime_get()) to program
> the cpu ns into some hw/fw, so allow this method for rust drivers.
>
> This is needed for following nova patch.
>
> Reviewed-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
> Signed-off-by: Dave Airlie <airlied@redhat.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
> ---
> rust/kernel/time.rs | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 1/2] rust: time: expose as_nanos for clock sources.
2026-11-10 13:56 ` Alexandre Courbot
@ 2026-11-11 19:48 ` Andreas Hindborg
2026-11-11 19:50 ` David Airlie
0 siblings, 1 reply; 9+ messages in thread
From: Andreas Hindborg @ 2026-11-11 19:48 UTC (permalink / raw)
To: Alexandre Courbot, Dave Airlie via B4 Relay
Cc: airlied, FUJITA Tomonori, Gary Guo, Alice Ryhl, Danilo Krummrich,
Daniel Almeida, nova-gpu, dri-devel
"Alexandre Courbot" <acourbot@nvidia.com> writes:
> On Mon Nov 9, 2026 at 10:55 AM JST, Dave Airlie via B4 Relay wrote:
>> From: Dave Airlie <airlied@redhat.com>
>>
>> The nouveau C driver does ktime_to_ns(ktime_get()) to program
>> the cpu ns into some hw/fw, so allow this method for rust drivers.
>>
>> This is needed for following nova patch.
>>
>> Reviewed-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
>> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
>> Signed-off-by: Dave Airlie <airlied@redhat.com>
>
> This patch has also received a maintainer acked-by:
>
> https://lore.kernel.org/all/875wyoydqk.fsf@t14s.mail-host-address-is-not-set/
You guys want to take this through your tree? Otherwise I will apply it
to rust-timekeeping this week.
Best regards,
Andreas Hindborg
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 1/2] rust: time: expose as_nanos for clock sources.
2026-11-11 19:48 ` Andreas Hindborg
@ 2026-11-11 19:50 ` David Airlie
0 siblings, 0 replies; 9+ messages in thread
From: David Airlie @ 2026-11-11 19:50 UTC (permalink / raw)
To: Andreas Hindborg
Cc: Alexandre Courbot, Dave Airlie via B4 Relay, FUJITA Tomonori,
Gary Guo, Alice Ryhl, Danilo Krummrich, Daniel Almeida, nova-gpu,
dri-devel
> "Alexandre Courbot" <acourbot@nvidia.com> writes:
>
> > On Mon Nov 9, 2026 at 10:55 AM JST, Dave Airlie via B4 Relay wrote:
> >> From: Dave Airlie <airlied@redhat.com>
> >>
> >> The nouveau C driver does ktime_to_ns(ktime_get()) to program
> >> the cpu ns into some hw/fw, so allow this method for rust drivers.
> >>
> >> This is needed for following nova patch.
> >>
> >> Reviewed-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> >> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
> >> Signed-off-by: Dave Airlie <airlied@redhat.com>
> >
> > This patch has also received a maintainer acked-by:
> >
> > https://lore.kernel.org/all/875wyoydqk.fsf@t14s.mail-host-address-is-not-set/
>
> You guys want to take this through your tree? Otherwise I will apply it
> to rust-timekeeping this week.
I think we want this to land through d-r-n whenever the timer patch
lands, I suppose we could merge it to d-r-n now actually.
Dave.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-11-11 19:51 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-09 1:55 [PATCH v6 0/2] nova-core: add initial support for gpu timer (v6) Dave Airlie via B4 Relay
2026-11-09 1:55 ` [PATCH v6 1/2] rust: time: expose as_nanos for clock sources Dave Airlie via B4 Relay
2026-11-10 13:56 ` Alexandre Courbot
2026-11-11 19:48 ` Andreas Hindborg
2026-11-11 19:50 ` David Airlie
2026-11-11 14:50 ` Gary Guo
2026-11-09 1:55 ` [PATCH v6 2/2] gpu: nova-core: add support for GPU timer block. (v6) Dave Airlie via B4 Relay
2026-11-09 2:09 ` sashiko-bot
2026-11-10 13:56 ` Alexandre Courbot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox