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