xref: /linux/drivers/gpu/nova-core/gsp/boot.rs (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
1 // SPDX-License-Identifier: GPL-2.0
2 // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 
4 use kernel::{
5     bits,
6     io::poll::read_poll_timeout,
7     prelude::*,
8     time::Delta,
9     types::ScopeGuard, //
10 };
11 
12 use crate::{
13     driver::Bar0,
14     falcon::{
15         gsp::Gsp,
16         Falcon, //
17     },
18     firmware::gsp::GspFirmware,
19     gsp::{
20         cmdq::Cmdq,
21         commands, //
22     },
23 };
24 
25 impl super::Gsp {
26     /// Attempt to boot the GSP.
27     ///
28     /// This is a GPU-dependent and complex procedure that involves loading firmware files from
29     /// user-space, patching them with signatures, and building firmware-specific intricate data
30     /// structures that the GSP will use at runtime.
31     ///
32     /// Upon return, the GSP is up and running, and its unload bundle (to be given as argument to
33     /// [`Self::unload`]) returned.
34     pub(crate) fn boot(
35         self: Pin<&mut Self>,
36         mut ctx: super::GspBootContext<'_, '_>,
37     ) -> Result<Option<super::UnloadBundle>> {
38         let pdev = ctx.pdev;
39         let bar = ctx.bar;
40         let chipset = ctx.chipset;
41         let gsp_falcon = ctx.gsp_falcon;
42         let dev = pdev.as_ref();
43         let hal = super::hal::gsp_hal(chipset);
44 
45         let gsp_fw = KBox::pin_init(GspFirmware::new(dev, chipset), GFP_KERNEL)?;
46 
47         // Perform the chipset-specific boot sequence, and retrieve the unload bundle.
48         let unload_bundle = hal.boot(&self, &mut ctx, &gsp_fw)?.or_else(|| {
49             dev_warn!(dev, "The GSP won't be able to unload properly on unbind.\n");
50             dev_warn!(
51                 dev,
52                 "The GPU will need to be reset before the driver can bind again.\n"
53             );
54 
55             None
56         });
57 
58         let mut unload_guard =
59             ScopeGuard::new_with_data((ctx, unload_bundle), |(ctx, unload_bundle)| {
60                 let _ = self.unload(ctx, unload_bundle);
61             });
62         let ctx = &mut unload_guard.0;
63 
64         gsp_falcon.write_os_version(gsp_fw.bootloader.app_version);
65 
66         // Poll for RISC-V to become active before continuing.
67         read_poll_timeout(
68             || Ok(gsp_falcon.is_riscv_active()),
69             |val: &bool| *val,
70             Delta::from_millis(10),
71             Delta::from_secs(5),
72         )?;
73 
74         dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(),);
75 
76         self.cmdq
77             .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?;
78         self.cmdq
79             .send_command_no_wait(bar, commands::SetRegistry::new(ctx.vgpu.state())?)?;
80 
81         hal.post_boot(&self, ctx, &gsp_fw)?;
82 
83         // Wait until GSP is fully initialized.
84         commands::wait_gsp_init_done(&self.cmdq)?;
85 
86         Ok(unload_guard.dismiss().1)
87     }
88 
89     /// Shut down the GSP and wait until it is offline.
90     fn shutdown_gsp(
91         cmdq: &Cmdq,
92         bar: Bar0<'_>,
93         gsp_falcon: &Falcon<'_, Gsp>,
94         mode: commands::PowerStateLevel,
95     ) -> Result {
96         // Command to shut the GSP down.
97         cmdq.send_command(bar, commands::UnloadingGuestDriver::new(mode))?;
98 
99         // Wait until GSP signals it is suspended.
100         const LIBOS_INTERRUPT_PROCESSOR_SUSPENDED: u32 = bits::bit_u32(31);
101         read_poll_timeout(
102             || Ok(gsp_falcon.read_mailbox0()),
103             |&mb0| mb0 & LIBOS_INTERRUPT_PROCESSOR_SUSPENDED != 0,
104             Delta::from_millis(10),
105             Delta::from_secs(5),
106         )
107         .map(|_| ())
108     }
109 
110     /// Attempts to unload the GSP firmware.
111     ///
112     /// This stops all activity on the GSP.
113     pub(crate) fn unload(
114         &self,
115         mut ctx: super::GspBootContext<'_, '_>,
116         unload_bundle: Option<super::UnloadBundle>,
117     ) -> Result {
118         let dev = ctx.dev();
119 
120         // Shut down the GSP. Keep going even in case of error.
121         let mut res = Self::shutdown_gsp(
122             &self.cmdq,
123             ctx.bar,
124             ctx.gsp_falcon,
125             commands::PowerStateLevel::Level0,
126         )
127         .inspect_err(|e| dev_err!(dev, "GSP shutdown failed: {:?}\n", e));
128 
129         // Run the unload bundle to reset the GSP so it can be booted again.
130         if let Some(unload_bundle) = unload_bundle {
131             res = res.and(
132                 unload_bundle
133                     .0
134                     .run(&mut ctx)
135                     .inspect_err(|e| dev_err!(dev, "Unload bundle failed: {:?}\n", e)),
136             );
137         } else {
138             dev_warn!(
139                 dev,
140                 "Unload bundle is missing, GSP won't be properly reset.\n"
141             );
142 
143             res = Err(EAGAIN);
144         }
145 
146         res.inspect(|()| dev_info!(dev, "GSP successfully unloaded\n"))
147     }
148 }
149