From: Joel Fernandes Date: Fri, 14 Nov 2025 19:55:47 +0000 (-0500) Subject: gpu: nova-core: sequencer: Add register opcodes X-Git-Tag: v6.19-rc1~157^2~8^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2367ce2e9e5eae3bfe72ed79a7fbd86936158569;p=thirdparty%2Fkernel%2Flinux.git 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 Signed-off-by: Alexandre Courbot [acourbot@nvidia.com: apply Lyude's suggested fixes.] Message-ID: <20251114195552.739371-9-joelagnelf@nvidia.com> --- diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index 4b569fc4c0b10..99486f194b07b 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -389,7 +389,6 @@ impl From for u32 { #[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 @@ impl RegStorePayload { } /// Returns the storage index. + #[allow(unused)] pub(crate) fn index(&self) -> u32 { self.0.index } diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs index 1f4f0a0d999bf..de5d6b4433a29 100644 --- a/drivers/gpu/nova-core/gsp/sequencer.rs +++ b/drivers/gpu/nova-core/gsp/sequencer.rs @@ -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 @@ use crate::{ }, fw, }, + num::FromSafeCast, sbuffer::SBufferIter, }; @@ -61,18 +66,50 @@ const CMD_SIZE: usize = size_of::(); /// 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::(); + 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::(); - // 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), + } } }