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