projects/linux·blob master · refs

148 lines · 4.6 KiB

1// SPDX-License-Identifier: GPL-2.0
2// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
4use kernel::{
5 bits,
6 io::poll::read_poll_timeout,
7 prelude::*,
8 time::Delta,
9 types::ScopeGuard, //
10};
11
12use 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
25impl 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}