1 // SPDX-License-Identifier: GPL-2.0 2 3 use kernel::prelude::*; 4 5 use crate::{ 6 falcon::{ 7 Falcon, 8 FalconBromParams, 9 FalconEngine, // 10 }, 11 gpu::{ 12 Architecture, 13 Chipset, // 14 }, 15 }; 16 17 mod ga102; 18 mod tu102; 19 20 /// Method used to load data into falcon memory. Some GPU architectures need 21 /// PIO and others can use DMA. 22 pub(crate) enum LoadMethod { 23 /// Programmed I/O 24 Pio, 25 /// Direct Memory Access 26 Dma, 27 } 28 29 /// Hardware Abstraction Layer for Falcon cores. 30 /// 31 /// Implements chipset-specific low-level operations. The trait is generic against [`FalconEngine`] 32 /// so its `BASE` parameter can be used in order to avoid runtime bound checks when accessing 33 /// registers. 34 pub(crate) trait FalconHal<E: FalconEngine>: Send + Sync { 35 /// Activates the Falcon core if the engine is a risvc/falcon dual engine. 36 fn select_core(&self, _falcon: &Falcon<'_, E>) -> Result { 37 Ok(()) 38 } 39 40 /// Returns the fused version of the signature to use in order to run a HS firmware on this 41 /// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header. 42 fn signature_reg_fuse_version( 43 &self, 44 falcon: &Falcon<'_, E>, 45 engine_id_mask: u16, 46 ucode_id: u8, 47 ) -> Result<u32>; 48 49 /// Program the boot ROM registers prior to starting a secure firmware. 50 fn program_brom(&self, falcon: &Falcon<'_, E>, params: &FalconBromParams); 51 52 /// Check if the RISC-V core is active. 53 /// Returns `true` if the RISC-V core is active, `false` otherwise. 54 fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool; 55 56 /// Checks whether the RISC-V core is halted. 57 /// 58 /// Returns [`ENOTSUPP`] if the chipset does not expose RISC-V halt status. 59 fn is_riscv_halted(&self, falcon: &Falcon<'_, E>) -> Result<bool>; 60 61 /// Wait for memory scrubbing to complete. 62 fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result; 63 64 /// Reset the falcon engine. 65 fn reset_eng(&self, falcon: &Falcon<'_, E>) -> Result; 66 67 /// Returns the method used to load data into the falcon's memory. 68 /// 69 /// The only chipsets supporting PIO are those < GA102, and PIO is the preferred method for 70 /// these. For anything above, the PIO registers appear to be masked to the CPU, so DMA is the 71 /// only usable method. 72 fn load_method(&self) -> LoadMethod; 73 } 74 75 /// Returns a boxed falcon HAL adequate for `chipset`. 76 /// 77 /// We use a heap-allocated trait object instead of a statically defined one because the 78 /// generic `FalconEngine` argument makes it difficult to define all the combinations 79 /// statically. 80 pub(super) fn falcon_hal<E: FalconEngine + 'static>( 81 chipset: Chipset, 82 ) -> Result<KBox<dyn FalconHal<E>>> { 83 let hal = match chipset.arch() { 84 Architecture::Turing => { 85 KBox::new(tu102::Tu102::<E>::new(), GFP_KERNEL)? as KBox<dyn FalconHal<E>> 86 } 87 // GA100 boots like Turing so use Turing HAL 88 Architecture::Ampere if chipset == Chipset::GA100 => { 89 KBox::new(tu102::Tu102::<E>::new(), GFP_KERNEL)? as KBox<dyn FalconHal<E>> 90 } 91 Architecture::Ampere 92 | Architecture::Ada 93 | Architecture::Hopper 94 | Architecture::BlackwellGB10x 95 | Architecture::BlackwellGB20x => { 96 KBox::new(ga102::Ga102::<E>::new(), GFP_KERNEL)? as KBox<dyn FalconHal<E>> 97 } 98 }; 99 100 Ok(hal) 101 } 102