boot.rs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // SPDX-License-Identifier: GPL-2.0
  2. use kernel::{
  3. device,
  4. dma::CoherentAllocation,
  5. dma_write,
  6. io::poll::read_poll_timeout,
  7. pci,
  8. prelude::*,
  9. time::Delta, //
  10. };
  11. use crate::{
  12. driver::Bar0,
  13. falcon::{
  14. gsp::Gsp,
  15. sec2::Sec2,
  16. Falcon, //
  17. },
  18. fb::FbLayout,
  19. firmware::{
  20. booter::{
  21. BooterFirmware,
  22. BooterKind, //
  23. },
  24. fwsec::{
  25. FwsecCommand,
  26. FwsecFirmware, //
  27. },
  28. gsp::GspFirmware,
  29. FIRMWARE_VERSION, //
  30. },
  31. gpu::Chipset,
  32. gsp::{
  33. commands,
  34. sequencer::{
  35. GspSequencer,
  36. GspSequencerParams, //
  37. },
  38. GspFwWprMeta, //
  39. },
  40. regs,
  41. vbios::Vbios,
  42. };
  43. impl super::Gsp {
  44. /// Helper function to load and run the FWSEC-FRTS firmware and confirm that it has properly
  45. /// created the WPR2 region.
  46. fn run_fwsec_frts(
  47. dev: &device::Device<device::Bound>,
  48. falcon: &Falcon<Gsp>,
  49. bar: &Bar0,
  50. bios: &Vbios,
  51. fb_layout: &FbLayout,
  52. ) -> Result<()> {
  53. // Check that the WPR2 region does not already exists - if it does, we cannot run
  54. // FWSEC-FRTS until the GPU is reset.
  55. if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != 0 {
  56. dev_err!(
  57. dev,
  58. "WPR2 region already exists - GPU needs to be reset to proceed\n"
  59. );
  60. return Err(EBUSY);
  61. }
  62. let fwsec_frts = FwsecFirmware::new(
  63. dev,
  64. falcon,
  65. bar,
  66. bios,
  67. FwsecCommand::Frts {
  68. frts_addr: fb_layout.frts.start,
  69. frts_size: fb_layout.frts.end - fb_layout.frts.start,
  70. },
  71. )?;
  72. // Run FWSEC-FRTS to create the WPR2 region.
  73. fwsec_frts.run(dev, falcon, bar)?;
  74. // SCRATCH_E contains the error code for FWSEC-FRTS.
  75. let frts_status = regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar).frts_err_code();
  76. if frts_status != 0 {
  77. dev_err!(
  78. dev,
  79. "FWSEC-FRTS returned with error code {:#x}\n",
  80. frts_status
  81. );
  82. return Err(EIO);
  83. }
  84. // Check that the WPR2 region has been created as we requested.
  85. let (wpr2_lo, wpr2_hi) = (
  86. regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(),
  87. regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(),
  88. );
  89. match (wpr2_lo, wpr2_hi) {
  90. (_, 0) => {
  91. dev_err!(dev, "WPR2 region not created after running FWSEC-FRTS\n");
  92. Err(EIO)
  93. }
  94. (wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => {
  95. dev_err!(
  96. dev,
  97. "WPR2 region created at unexpected address {:#x}; expected {:#x}\n",
  98. wpr2_lo,
  99. fb_layout.frts.start,
  100. );
  101. Err(EIO)
  102. }
  103. (wpr2_lo, wpr2_hi) => {
  104. dev_dbg!(dev, "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi);
  105. dev_dbg!(dev, "GPU instance built\n");
  106. Ok(())
  107. }
  108. }
  109. }
  110. /// Attempt to boot the GSP.
  111. ///
  112. /// This is a GPU-dependent and complex procedure that involves loading firmware files from
  113. /// user-space, patching them with signatures, and building firmware-specific intricate data
  114. /// structures that the GSP will use at runtime.
  115. ///
  116. /// Upon return, the GSP is up and running, and its runtime object given as return value.
  117. pub(crate) fn boot(
  118. mut self: Pin<&mut Self>,
  119. pdev: &pci::Device<device::Bound>,
  120. bar: &Bar0,
  121. chipset: Chipset,
  122. gsp_falcon: &Falcon<Gsp>,
  123. sec2_falcon: &Falcon<Sec2>,
  124. ) -> Result {
  125. let dev = pdev.as_ref();
  126. let bios = Vbios::new(dev, bar)?;
  127. let gsp_fw = KBox::pin_init(GspFirmware::new(dev, chipset, FIRMWARE_VERSION), GFP_KERNEL)?;
  128. let fb_layout = FbLayout::new(chipset, bar, &gsp_fw)?;
  129. dev_dbg!(dev, "{:#x?}\n", fb_layout);
  130. Self::run_fwsec_frts(dev, gsp_falcon, bar, &bios, &fb_layout)?;
  131. let booter_loader = BooterFirmware::new(
  132. dev,
  133. BooterKind::Loader,
  134. chipset,
  135. FIRMWARE_VERSION,
  136. sec2_falcon,
  137. bar,
  138. )?;
  139. let wpr_meta =
  140. CoherentAllocation::<GspFwWprMeta>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?;
  141. dma_write!(wpr_meta, [0]?, GspFwWprMeta::new(&gsp_fw, &fb_layout));
  142. self.cmdq
  143. .send_command(bar, commands::SetSystemInfo::new(pdev))?;
  144. self.cmdq.send_command(bar, commands::SetRegistry::new())?;
  145. gsp_falcon.reset(bar)?;
  146. let libos_handle = self.libos.dma_handle();
  147. let (mbox0, mbox1) = gsp_falcon.boot(
  148. bar,
  149. Some(libos_handle as u32),
  150. Some((libos_handle >> 32) as u32),
  151. )?;
  152. dev_dbg!(
  153. pdev.as_ref(),
  154. "GSP MBOX0: {:#x}, MBOX1: {:#x}\n",
  155. mbox0,
  156. mbox1
  157. );
  158. dev_dbg!(
  159. pdev.as_ref(),
  160. "Using SEC2 to load and run the booter_load firmware...\n"
  161. );
  162. sec2_falcon.reset(bar)?;
  163. sec2_falcon.load(bar, &booter_loader)?;
  164. let wpr_handle = wpr_meta.dma_handle();
  165. let (mbox0, mbox1) = sec2_falcon.boot(
  166. bar,
  167. Some(wpr_handle as u32),
  168. Some((wpr_handle >> 32) as u32),
  169. )?;
  170. dev_dbg!(
  171. pdev.as_ref(),
  172. "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n",
  173. mbox0,
  174. mbox1
  175. );
  176. if mbox0 != 0 {
  177. dev_err!(
  178. pdev.as_ref(),
  179. "Booter-load failed with error {:#x}\n",
  180. mbox0
  181. );
  182. return Err(ENODEV);
  183. }
  184. gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version);
  185. // Poll for RISC-V to become active before running sequencer
  186. read_poll_timeout(
  187. || Ok(gsp_falcon.is_riscv_active(bar)),
  188. |val: &bool| *val,
  189. Delta::from_millis(10),
  190. Delta::from_secs(5),
  191. )?;
  192. dev_dbg!(
  193. pdev.as_ref(),
  194. "RISC-V active? {}\n",
  195. gsp_falcon.is_riscv_active(bar),
  196. );
  197. // Create and run the GSP sequencer.
  198. let seq_params = GspSequencerParams {
  199. bootloader_app_version: gsp_fw.bootloader.app_version,
  200. libos_dma_handle: libos_handle,
  201. gsp_falcon,
  202. sec2_falcon,
  203. dev: pdev.as_ref().into(),
  204. bar,
  205. };
  206. GspSequencer::run(&mut self.cmdq, seq_params)?;
  207. // Wait until GSP is fully initialized.
  208. commands::wait_gsp_init_done(&mut self.cmdq)?;
  209. // Obtain and display basic GPU information.
  210. let info = commands::get_gsp_info(&mut self.cmdq, bar)?;
  211. match info.gpu_name() {
  212. Ok(name) => dev_info!(pdev.as_ref(), "GPU name: {}\n", name),
  213. Err(e) => dev_warn!(pdev.as_ref(), "GPU name unavailable: {:?}\n", e),
  214. }
  215. Ok(())
  216. }
  217. }