xref: /linux/drivers/gpu/nova-core/gsp/boot.rs (revision adb99ce3cc78d277a719f15a8131eafc60162f22)
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     pci,
10     prelude::*,
11     time::Delta, //
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     gpu::Chipset,
27     gsp::{
28         cmdq::Cmdq,
29         commands,
30         GspFwWprMeta, //
31     },
32 };
33 
34 impl super::Gsp {
35     /// Attempt to boot the GSP.
36     ///
37     /// This is a GPU-dependent and complex procedure that involves loading firmware files from
38     /// user-space, patching them with signatures, and building firmware-specific intricate data
39     /// structures that the GSP will use at runtime.
40     ///
41     /// Upon return, the GSP is up and running, and its unload bundle (to be given as argument to
42     /// [`Self::unload`]) returned.
43     pub(crate) fn boot(
44         self: Pin<&mut Self>,
45         pdev: &pci::Device<device::Bound>,
46         bar: &Bar0,
47         chipset: Chipset,
48         gsp_falcon: &Falcon<Gsp>,
49         sec2_falcon: &Falcon<Sec2>,
50     ) -> Result<Option<super::UnloadBundle>> {
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(
63             &self,
64             dev,
65             bar,
66             chipset,
67             &fb_layout,
68             &wpr_meta,
69             gsp_falcon,
70             sec2_falcon,
71         )?;
72 
73         gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version);
74 
75         // Poll for RISC-V to become active before continuing.
76         read_poll_timeout(
77             || Ok(gsp_falcon.is_riscv_active(bar)),
78             |val: &bool| *val,
79             Delta::from_millis(10),
80             Delta::from_secs(5),
81         )?;
82 
83         dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar),);
84 
85         self.cmdq
86             .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev))?;
87         self.cmdq
88             .send_command_no_wait(bar, commands::SetRegistry::new())?;
89 
90         hal.post_boot(&self, dev, bar, &gsp_fw, gsp_falcon, sec2_falcon)?;
91 
92         // Wait until GSP is fully initialized.
93         commands::wait_gsp_init_done(&self.cmdq)?;
94 
95         // Obtain and display basic GPU information.
96         let info = self.cmdq.send_command(bar, commands::GetGspStaticInfo)?;
97         match info.gpu_name() {
98             Ok(name) => dev_info!(pdev, "GPU name: {}\n", name),
99             Err(e) => dev_warn!(pdev, "GPU name unavailable: {:?}\n", e),
100         }
101 
102         Ok(unload_bundle)
103     }
104 
105     /// Shut down the GSP and wait until it is offline.
106     fn shutdown_gsp(
107         cmdq: &Cmdq,
108         bar: &Bar0,
109         gsp_falcon: &Falcon<Gsp>,
110         mode: commands::PowerStateLevel,
111     ) -> Result {
112         // Command to shut the GSP down.
113         cmdq.send_command(bar, commands::UnloadingGuestDriver::new(mode))?;
114 
115         // Wait until GSP signals it is suspended.
116         const LIBOS_INTERRUPT_PROCESSOR_SUSPENDED: u32 = bits::bit_u32(31);
117         read_poll_timeout(
118             || Ok(gsp_falcon.read_mailbox0(bar)),
119             |&mb0| mb0 & LIBOS_INTERRUPT_PROCESSOR_SUSPENDED != 0,
120             Delta::from_millis(10),
121             Delta::from_secs(5),
122         )
123         .map(|_| ())
124     }
125 
126     /// Attempts to unload the GSP firmware.
127     ///
128     /// This stops all activity on the GSP.
129     pub(crate) fn unload(
130         &self,
131         dev: &device::Device<device::Bound>,
132         bar: &Bar0,
133         gsp_falcon: &Falcon<Gsp>,
134         sec2_falcon: &Falcon<Sec2>,
135         unload_bundle: Option<super::UnloadBundle>,
136     ) -> Result {
137         // Shut down the GSP. Keep going even in case of error.
138         let mut res = Self::shutdown_gsp(
139             &self.cmdq,
140             bar,
141             gsp_falcon,
142             commands::PowerStateLevel::Level0,
143         )
144         .inspect_err(|e| dev_err!(dev, "GSP shutdown failed: {:?}\n", e));
145 
146         // Run the unload bundle to reset the GSP so it can be booted again.
147         if let Some(unload_bundle) = unload_bundle {
148             res = res.and(
149                 unload_bundle
150                     .0
151                     .run(dev, bar, gsp_falcon, sec2_falcon)
152                     .inspect_err(|e| dev_err!(dev, "Unload bundle failed: {:?}\n", e)),
153             );
154         } else {
155             dev_warn!(
156                 dev,
157                 "Unload bundle is missing, GSP won't be properly reset.\n"
158             );
159 
160             res = Err(EAGAIN);
161         }
162 
163         res.inspect(|()| dev_info!(dev, "GSP successfully unloaded\n"))
164     }
165 }
166