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