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