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