xref: /linux/drivers/gpu/nova-core/gsp/sequencer.rs (revision 6ddfc892a529cb314e4708c5654beb0fa37e2071)
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 }
237