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