Skip to content

Commit 6ddfc89

Browse files
Joel FernandesGnurou
authored andcommitted
gpu: nova-core: Implement the GSP sequencer
Implement the GSP sequencer which culminates in INIT_DONE message being received from the GSP indicating that the GSP has successfully booted. This is just initial sequencer support, the actual commands will be added in the next patches. Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> [acourbot@nvidia.com: move GspSequencerInfo definition before its impl blocks and rename it to GspSequence, adapt imports in sequencer.rs to new formatting rules, remove `timeout` argument to harmonize with other commands.] Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Message-ID: <20251114195552.739371-8-joelagnelf@nvidia.com>
1 parent eaf0989 commit 6ddfc89

6 files changed

Lines changed: 252 additions & 3 deletions

File tree

drivers/gpu/nova-core/gsp.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use kernel::{
1717
pub(crate) mod cmdq;
1818
pub(crate) mod commands;
1919
mod fw;
20+
mod sequencer;
2021

2122
pub(crate) use fw::{
2223
GspFwWprMeta,

drivers/gpu/nova-core/gsp/boot.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ use crate::{
3333
gpu::Chipset,
3434
gsp::{
3535
commands,
36+
sequencer::{
37+
GspSequencer,
38+
GspSequencerParams, //
39+
},
3640
GspFwWprMeta, //
3741
},
3842
regs,
@@ -221,6 +225,17 @@ impl super::Gsp {
221225
gsp_falcon.is_riscv_active(bar),
222226
);
223227

228+
// Create and run the GSP sequencer.
229+
let seq_params = GspSequencerParams {
230+
bootloader_app_version: gsp_fw.bootloader.app_version,
231+
libos_dma_handle: libos_handle,
232+
gsp_falcon,
233+
sec2_falcon,
234+
dev: pdev.as_ref().into(),
235+
bar,
236+
};
237+
GspSequencer::run(&mut self.cmdq, seq_params)?;
238+
224239
Ok(())
225240
}
226241
}

drivers/gpu/nova-core/gsp/cmdq.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,6 @@ impl Cmdq {
645645
/// - `EIO` if there was some inconsistency (e.g. message shorter than advertised) on the
646646
/// message queue.
647647
/// - `EINVAL` if the function of the message was unrecognized.
648-
#[expect(unused)]
649648
pub(crate) fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M>
650649
where
651650
// This allows all error types, including `Infallible`, to be used for `M::InitError`.

drivers/gpu/nova-core/gsp/fw.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,6 @@ unsafe impl AsBytes for SequencerBufferCmd {}
621621
#[repr(transparent)]
622622
pub(crate) struct RunCpuSequencer(r570_144::rpc_run_cpu_sequencer_v17_00);
623623

624-
#[expect(unused)]
625624
impl RunCpuSequencer {
626625
/// Returns the command index.
627626
pub(crate) fn cmd_index(&self) -> u32 {
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! GSP Sequencer implementation for Pre-hopper GSP boot sequence.
4+
5+
use core::{
6+
array,
7+
mem::size_of, //
8+
};
9+
10+
use kernel::{
11+
device,
12+
prelude::*,
13+
time::Delta,
14+
transmute::FromBytes,
15+
types::ARef, //
16+
};
17+
18+
use crate::{
19+
driver::Bar0,
20+
falcon::{
21+
gsp::Gsp,
22+
sec2::Sec2,
23+
Falcon, //
24+
},
25+
gsp::{
26+
cmdq::{
27+
Cmdq,
28+
MessageFromGsp, //
29+
},
30+
fw,
31+
},
32+
sbuffer::SBufferIter,
33+
};
34+
35+
/// GSP Sequencer information containing the command sequence and data.
36+
struct GspSequence {
37+
/// Current command index for error reporting.
38+
cmd_index: u32,
39+
/// Command data buffer containing the sequence of commands.
40+
cmd_data: KVec<u8>,
41+
}
42+
43+
impl MessageFromGsp for GspSequence {
44+
const FUNCTION: fw::MsgFunction = fw::MsgFunction::GspRunCpuSequencer;
45+
type InitError = Error;
46+
type Message = fw::RunCpuSequencer;
47+
48+
fn read(
49+
msg: &Self::Message,
50+
sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
51+
) -> Result<Self, Self::InitError> {
52+
let cmd_data = sbuffer.flush_into_kvec(GFP_KERNEL)?;
53+
Ok(GspSequence {
54+
cmd_index: msg.cmd_index(),
55+
cmd_data,
56+
})
57+
}
58+
}
59+
60+
const CMD_SIZE: usize = size_of::<fw::SequencerBufferCmd>();
61+
62+
/// GSP Sequencer Command types with payload data.
63+
/// Commands have an opcode and an opcode-dependent struct.
64+
#[allow(dead_code)]
65+
pub(crate) enum GspSeqCmd {}
66+
67+
impl GspSeqCmd {
68+
/// Creates a new `GspSeqCmd` from raw data returning the command and its size in bytes.
69+
pub(crate) fn new(data: &[u8], _dev: &device::Device) -> Result<(Self, usize)> {
70+
let _fw_cmd = fw::SequencerBufferCmd::from_bytes(data).ok_or(EINVAL)?;
71+
let _opcode_size = core::mem::size_of::<u32>();
72+
73+
// NOTE: At this commit, NO opcodes exist yet, so just return error.
74+
// Later commits will add match arms here.
75+
Err(EINVAL)
76+
}
77+
}
78+
79+
/// GSP Sequencer for executing firmware commands during boot.
80+
#[expect(dead_code)]
81+
pub(crate) struct GspSequencer<'a> {
82+
/// Sequencer information with command data.
83+
seq_info: GspSequence,
84+
/// `Bar0` for register access.
85+
bar: &'a Bar0,
86+
/// SEC2 falcon for core operations.
87+
sec2_falcon: &'a Falcon<Sec2>,
88+
/// GSP falcon for core operations.
89+
gsp_falcon: &'a Falcon<Gsp>,
90+
/// LibOS DMA handle address.
91+
libos_dma_handle: u64,
92+
/// Bootloader application version.
93+
bootloader_app_version: u32,
94+
/// Device for logging.
95+
dev: ARef<device::Device>,
96+
}
97+
98+
/// Trait for running sequencer commands.
99+
pub(crate) trait GspSeqCmdRunner {
100+
fn run(&self, sequencer: &GspSequencer<'_>) -> Result;
101+
}
102+
103+
impl GspSeqCmdRunner for GspSeqCmd {
104+
fn run(&self, _seq: &GspSequencer<'_>) -> Result {
105+
Ok(())
106+
}
107+
}
108+
109+
/// Iterator over GSP sequencer commands.
110+
pub(crate) struct GspSeqIter<'a> {
111+
/// Command data buffer.
112+
cmd_data: &'a [u8],
113+
/// Current position in the buffer.
114+
current_offset: usize,
115+
/// Total number of commands to process.
116+
total_cmds: u32,
117+
/// Number of commands processed so far.
118+
cmds_processed: u32,
119+
/// Device for logging.
120+
dev: ARef<device::Device>,
121+
}
122+
123+
impl<'a> Iterator for GspSeqIter<'a> {
124+
type Item = Result<GspSeqCmd>;
125+
126+
fn next(&mut self) -> Option<Self::Item> {
127+
// Stop if we've processed all commands or reached the end of data.
128+
if self.cmds_processed >= self.total_cmds || self.current_offset >= self.cmd_data.len() {
129+
return None;
130+
}
131+
132+
// Check if we have enough data for opcode.
133+
if self.current_offset + core::mem::size_of::<u32>() > self.cmd_data.len() {
134+
return Some(Err(EIO));
135+
}
136+
137+
let offset = self.current_offset;
138+
139+
// Handle command creation based on available data,
140+
// zero-pad if necessary (since last command may not be full size).
141+
let mut buffer = [0u8; CMD_SIZE];
142+
let copy_len = if offset + CMD_SIZE <= self.cmd_data.len() {
143+
CMD_SIZE
144+
} else {
145+
self.cmd_data.len() - offset
146+
};
147+
buffer[..copy_len].copy_from_slice(&self.cmd_data[offset..offset + copy_len]);
148+
let cmd_result = GspSeqCmd::new(&buffer, &self.dev);
149+
150+
cmd_result.map_or_else(
151+
|_err| {
152+
dev_err!(self.dev, "Error parsing command at offset {}", offset);
153+
None
154+
},
155+
|(cmd, size)| {
156+
self.current_offset += size;
157+
self.cmds_processed += 1;
158+
Some(Ok(cmd))
159+
},
160+
)
161+
}
162+
}
163+
164+
impl<'a> GspSequencer<'a> {
165+
fn iter(&self) -> GspSeqIter<'_> {
166+
let cmd_data = &self.seq_info.cmd_data[..];
167+
168+
GspSeqIter {
169+
cmd_data,
170+
current_offset: 0,
171+
total_cmds: self.seq_info.cmd_index,
172+
cmds_processed: 0,
173+
dev: self.dev.clone(),
174+
}
175+
}
176+
}
177+
178+
/// Parameters for running the GSP sequencer.
179+
pub(crate) struct GspSequencerParams<'a> {
180+
/// Bootloader application version.
181+
pub(crate) bootloader_app_version: u32,
182+
/// LibOS DMA handle address.
183+
pub(crate) libos_dma_handle: u64,
184+
/// GSP falcon for core operations.
185+
pub(crate) gsp_falcon: &'a Falcon<Gsp>,
186+
/// SEC2 falcon for core operations.
187+
pub(crate) sec2_falcon: &'a Falcon<Sec2>,
188+
/// Device for logging.
189+
pub(crate) dev: ARef<device::Device>,
190+
/// BAR0 for register access.
191+
pub(crate) bar: &'a Bar0,
192+
}
193+
194+
impl<'a> GspSequencer<'a> {
195+
pub(crate) fn run(cmdq: &mut Cmdq, params: GspSequencerParams<'a>) -> Result {
196+
let seq_info = loop {
197+
match cmdq.receive_msg::<GspSequence>(Delta::from_secs(10)) {
198+
Ok(seq_info) => break seq_info,
199+
Err(ERANGE) => continue,
200+
Err(e) => return Err(e),
201+
}
202+
};
203+
204+
let sequencer = GspSequencer {
205+
seq_info,
206+
bar: params.bar,
207+
sec2_falcon: params.sec2_falcon,
208+
gsp_falcon: params.gsp_falcon,
209+
libos_dma_handle: params.libos_dma_handle,
210+
bootloader_app_version: params.bootloader_app_version,
211+
dev: params.dev,
212+
};
213+
214+
dev_dbg!(sequencer.dev, "Running CPU Sequencer commands");
215+
216+
for cmd_result in sequencer.iter() {
217+
match cmd_result {
218+
Ok(cmd) => cmd.run(&sequencer)?,
219+
Err(e) => {
220+
dev_err!(
221+
sequencer.dev,
222+
"Error running command at index {}",
223+
sequencer.seq_info.cmd_index
224+
);
225+
return Err(e);
226+
}
227+
}
228+
}
229+
230+
dev_dbg!(
231+
sequencer.dev,
232+
"CPU Sequencer commands completed successfully"
233+
);
234+
Ok(())
235+
}
236+
}

drivers/gpu/nova-core/sbuffer.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ where
168168
/// Read all the remaining data into a [`KVec`].
169169
///
170170
/// `self` will be empty after this operation.
171-
#[expect(unused)]
172171
pub(crate) fn flush_into_kvec(&mut self, flags: kernel::alloc::Flags) -> Result<KVec<u8>> {
173172
let mut buf = KVec::<u8>::new();
174173

0 commit comments

Comments
 (0)