Commit 2367ce2e authored by Joel Fernandes's avatar Joel Fernandes Committed by Alexandre Courbot
Browse files

gpu: nova-core: sequencer: Add register opcodes



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

Signed-off-by: default avatarJoel Fernandes <joelagnelf@nvidia.com>
Signed-off-by: default avatarAlexandre Courbot <acourbot@nvidia.com>
[acourbot@nvidia.com: apply Lyude's suggested fixes.]
Message-ID: <20251114195552.739371-9-joelagnelf@nvidia.com>
parent 6ddfc892
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -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
    }
+106 −11
Original line number Diff line number Diff line
@@ -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),
        }
    }
}