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