1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
// SPDX-License-Identifier: GPL-2.0
use kernel::{
io::{
io_project,
poll::read_poll_timeout,
register,
Io,
Mmio, //
},
prelude::*,
time::Delta, //
};
use crate::{
driver::{
Bar0,
NovaRegisters, //
},
falcon::{
Falcon,
FalconEngine, //
},
regs,
};
/// Type specifying the `Gsp` falcon engine. Cannot be instantiated.
pub(crate) struct Gsp(());
register! {
base: NovaRegisters;
PFALCON: super::PFalconRegisters @ 0x00110000;
PFALCON2: super::PFalcon2Registers @ 0x00111000;
}
impl FalconEngine for Gsp {
#[inline]
fn pfalcon(io: Bar0<'_>) -> Mmio<'_, super::PFalconRegisters> {
io_project!(io, build: PFALCON)
}
#[inline]
fn pfalcon2(io: Bar0<'_>) -> Mmio<'_, super::PFalcon2Registers> {
io_project!(io, build: PFALCON2)
}
}
impl<'a> Falcon<'a, Gsp> {
/// Clears the SWGEN0 latch in the GSP falcon.
///
/// While the latch is set, no later message signals the tree, so a caller that consumed a
/// notification by polling must clear it.
pub(crate) fn clear_swgen0_intr(&self) {
self.pfalcon
.write_reg(regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true));
}
/// Reads the GSP falcon causes that are routed to the host, without clearing any latch.
///
/// Every one of them other than SWGEN0 reports a GSP fault.
pub(crate) fn read_host_intr(&self) -> regs::NV_PFALCON_FALCON_IRQSTAT {
let latched = self.pfalcon.read(regs::NV_PFALCON_FALCON_IRQSTAT);
self.hal.host_routed_causes(self, latched)
}
/// Reads the host-routed causes and clears the SWGEN0 latch if it was set.
///
/// Returns the causes as read, before the clear. No other latch changes.
pub(crate) fn take_host_intr(&self) -> regs::NV_PFALCON_FALCON_IRQSTAT {
let status = self.read_host_intr();
if status.swgen0() {
self.clear_swgen0_intr();
}
status
}
/// Clears the latch of every interrupt cause set in `status`.
///
/// A cause driven from outside the falcon is still set on return, and
/// [`Self::read_host_intr`] reports the causes that remain.
pub(crate) fn clear_intr(&self, status: regs::NV_PFALCON_FALCON_IRQSTAT) {
self.pfalcon
.write_reg(regs::NV_PFALCON_FALCON_IRQSCLR::from(status.into_raw()));
}
/// Retriggers the GSP falcon, which then re-emits its host-routed causes into the tree.
///
/// Call this only once every host cause is clear. A cause still set is re-emitted at once, and
/// its vector arrives again as soon as delivery is rearmed.
///
/// Does nothing on Turing, whose falcons have no retrigger register.
pub(crate) fn retrigger_intr(&self) {
self.hal.retrigger(self);
}
/// Checks if GSP reload/resume has completed during the boot process.
pub(crate) fn check_reload_completed(&self, timeout: Delta) -> Result<bool> {
read_poll_timeout(
|| Ok(self.bar.read(regs::NV_PGC6_BSI_SECURE_SCRATCH_14)),
|val| val.boot_stage_3_handoff(),
Delta::ZERO,
timeout,
)
.map(|_| true)
}
/// Returns whether the RISC-V branch privilege lockdown bit is set.
pub(crate) fn riscv_branch_privilege_lockdown(&self) -> bool {
self.pfalcon
.read(regs::NV_PFALCON_FALCON_HWCFG2)
.riscv_br_priv_lockdown()
}
/// Returns whether GSP registers can be read by the CPU.
pub(crate) fn priv_target_mask_released(&self) -> bool {
/// Pattern returned by GSP register reads while the PRIV target mask still blocks CPU
/// access. The low byte varies; the upper 24 bits are fixed.
const LOCKED_PATTERN: u32 = 0xbadf_4100;
const LOCKED_MASK: u32 = 0xffff_ff00;
let hwcfg2 = self.pfalcon.read(regs::NV_PFALCON_FALCON_HWCFG2).into_raw();
hwcfg2 != 0 && (hwcfg2 & LOCKED_MASK) != LOCKED_PATTERN
}
}
|