xref: /linux/drivers/gpu/nova-core/falcon/hal.rs (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
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