gpu: nova-core: sequencer: Add register opcodes

These opcodes are used for register write, modify, poll and store (save)
sequencer operations.

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
[acourbot@nvidia.com: apply Lyude's suggested fixes.]
Message-ID: <20251114195552.739371-9-joelagnelf@nvidia.com>
This commit is contained in:
Joel Fernandes 2025-11-14 14:55:47 -05:00 committed by Alexandre Courbot
parent 6ddfc892a5
commit 2367ce2e9e
2 changed files with 107 additions and 15 deletions

View File

@ -389,7 +389,6 @@ fn from(value: SeqBufOpcode) -> Self {
#[derive(Copy, Clone)]
pub(crate) struct RegWritePayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_WRITE);
#[expect(unused)]
impl RegWritePayload {
/// Returns the register address.
pub(crate) fn addr(&self) -> u32 {
@ -413,7 +412,6 @@ unsafe impl AsBytes for RegWritePayload {}
#[derive(Copy, Clone)]
pub(crate) struct RegModifyPayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY);
#[expect(unused)]
impl RegModifyPayload {
/// Returns the register address.
pub(crate) fn addr(&self) -> u32 {
@ -442,7 +440,6 @@ unsafe impl AsBytes for RegModifyPayload {}
#[derive(Copy, Clone)]
pub(crate) struct RegPollPayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_POLL);
#[expect(unused)]
impl RegPollPayload {
/// Returns the register address.
pub(crate) fn addr(&self) -> u32 {
@ -495,7 +492,6 @@ unsafe impl AsBytes for DelayUsPayload {}
#[derive(Copy, Clone)]
pub(crate) struct RegStorePayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_STORE);
#[expect(unused)]
impl RegStorePayload {
/// Returns the register address.
pub(crate) fn addr(&self) -> u32 {
@ -503,6 +499,7 @@ pub(crate) fn addr(&self) -> u32 {
}
/// Returns the storage index.
#[allow(unused)]
pub(crate) fn index(&self) -> u32 {
self.0.index
}

View File

@ -4,11 +4,15 @@
use core::{
array,
mem::size_of, //
mem::{
size_of,
size_of_val, //
},
};
use kernel::{
device,
io::poll::read_poll_timeout,
prelude::*,
time::Delta,
transmute::FromBytes,
@ -29,6 +33,7 @@
},
fw,
},
num::FromSafeCast,
sbuffer::SBufferIter,
};
@ -61,18 +66,50 @@ fn read(
/// GSP Sequencer Command types with payload data.
/// Commands have an opcode and an opcode-dependent struct.
#[allow(dead_code)]
pub(crate) enum GspSeqCmd {}
#[allow(clippy::enum_variant_names)]
pub(crate) enum GspSeqCmd {
RegWrite(fw::RegWritePayload),
RegModify(fw::RegModifyPayload),
RegPoll(fw::RegPollPayload),
RegStore(fw::RegStorePayload),
}
impl GspSeqCmd {
/// Creates a new `GspSeqCmd` from raw data returning the command and its size in bytes.
pub(crate) fn new(data: &[u8], _dev: &device::Device) -> Result<(Self, usize)> {
let _fw_cmd = fw::SequencerBufferCmd::from_bytes(data).ok_or(EINVAL)?;
let _opcode_size = core::mem::size_of::<u32>();
pub(crate) fn new(data: &[u8], dev: &device::Device) -> Result<(Self, usize)> {
let fw_cmd = fw::SequencerBufferCmd::from_bytes(data).ok_or(EINVAL)?;
let opcode_size = core::mem::size_of::<u32>();
// NOTE: At this commit, NO opcodes exist yet, so just return error.
// Later commits will add match arms here.
Err(EINVAL)
let (cmd, size) = match fw_cmd.opcode()? {
fw::SeqBufOpcode::RegWrite => {
let payload = fw_cmd.reg_write_payload()?;
let size = opcode_size + size_of_val(&payload);
(GspSeqCmd::RegWrite(payload), size)
}
fw::SeqBufOpcode::RegModify => {
let payload = fw_cmd.reg_modify_payload()?;
let size = opcode_size + size_of_val(&payload);
(GspSeqCmd::RegModify(payload), size)
}
fw::SeqBufOpcode::RegPoll => {
let payload = fw_cmd.reg_poll_payload()?;
let size = opcode_size + size_of_val(&payload);
(GspSeqCmd::RegPoll(payload), size)
}
fw::SeqBufOpcode::RegStore => {
let payload = fw_cmd.reg_store_payload()?;
let size = opcode_size + size_of_val(&payload);
(GspSeqCmd::RegStore(payload), size)
}
_ => return Err(EINVAL),
};
if data.len() < size {
dev_err!(dev, "Data is not enough for command");
return Err(EINVAL);
}
Ok((cmd, size))
}
}
@ -100,9 +137,67 @@ pub(crate) trait GspSeqCmdRunner {
fn run(&self, sequencer: &GspSequencer<'_>) -> Result;
}
impl GspSeqCmdRunner for fw::RegWritePayload {
fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
let addr = usize::from_safe_cast(self.addr());
sequencer.bar.try_write32(self.val(), addr)
}
}
impl GspSeqCmdRunner for fw::RegModifyPayload {
fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
let addr = usize::from_safe_cast(self.addr());
sequencer.bar.try_read32(addr).and_then(|val| {
sequencer
.bar
.try_write32((val & !self.mask()) | self.val(), addr)
})
}
}
impl GspSeqCmdRunner for fw::RegPollPayload {
fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
let addr = usize::from_safe_cast(self.addr());
// Default timeout to 4 seconds.
let timeout_us = if self.timeout() == 0 {
4_000_000
} else {
i64::from(self.timeout())
};
// First read.
sequencer.bar.try_read32(addr)?;
// Poll the requested register with requested timeout.
read_poll_timeout(
|| sequencer.bar.try_read32(addr),
|current| (current & self.mask()) == self.val(),
Delta::ZERO,
Delta::from_micros(timeout_us),
)
.map(|_| ())
}
}
impl GspSeqCmdRunner for fw::RegStorePayload {
fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
let addr = usize::from_safe_cast(self.addr());
sequencer.bar.try_read32(addr).map(|_| ())
}
}
impl GspSeqCmdRunner for GspSeqCmd {
fn run(&self, _seq: &GspSequencer<'_>) -> Result {
Ok(())
fn run(&self, seq: &GspSequencer<'_>) -> Result {
match self {
GspSeqCmd::RegWrite(cmd) => cmd.run(seq),
GspSeqCmd::RegModify(cmd) => cmd.run(seq),
GspSeqCmd::RegPoll(cmd) => cmd.run(seq),
GspSeqCmd::RegStore(cmd) => cmd.run(seq),
}
}
}