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
|
// SPDX-License-Identifier: GPL-2.0
use kernel::{
device,
dma::{
Coherent,
DmaAddress, //
},
firmware,
prelude::*,
str::CString,
};
use crate::{
firmware::{
radix3::Radix3,
riscv::RiscvFirmware, //
tlv::{
request_tlv, //
Tlv,
},
},
gpu::Chipset,
num::FromSafeCast,
};
/// The GSP firmware image, its signatures, and the GSP bootloader.
#[pin_data]
pub(crate) struct GspFirmware<'a> {
/// The firmware image and the radix3 table that maps it.
#[pin]
radix3: Radix3<'a>,
/// Device-mapped GSP signatures matching the GPU's [`Chipset`].
pub(crate) signatures: Coherent<'a, [u8]>,
/// GSP bootloader, verifies the GSP firmware before loading and running it.
pub(crate) bootloader: RiscvFirmware<'a>,
}
impl<'a> GspFirmware<'a> {
/// Loads the GSP firmware binaries, map them into `dev`'s address-space, and creates the page
/// tables expected by the GSP bootloader to load it.
pub(crate) fn new(
dev: &'a device::Device<device::Bound>,
chipset: Chipset,
) -> impl PinInit<Self, Error> + 'a {
pin_init::pin_init_scope(move || {
let firmware = request_tlv(dev, chipset, "gsp")?;
let tlv = Tlv::new(firmware.data())?;
dev_dbg!(dev, "loaded gsp firmware v{}\n", tlv.get_string(b"VERS")?);
let size = usize::from_safe_cast(tlv.get_u32(b"SIZE")?);
let mut fw_vvec = VVec::zeroed(size, GFP_KERNEL).map_err(|_| ENOMEM)?;
let chip_name = chipset.name();
let file = tlv.get_string(b"FILE")?;
let filename = CString::try_from_fmt(fmt!("nvidia/{chip_name}/gsp/{file}"))?;
firmware::request_into_buf(&filename, dev, fw_vvec.as_mut_slice())?;
let signatures = Coherent::from_slice(dev, tlv.get_bytes(b"SIGN")?, GFP_KERNEL)?;
Ok(try_pin_init!(Self {
radix3 <- Radix3::new(dev, fw_vvec),
signatures,
bootloader: {
let bl = request_tlv(dev, chipset, "gsp_bootloader")?;
RiscvFirmware::new(dev, &bl)?
},
}))
})
}
/// Returns the size of the firmware image, in bytes.
pub(crate) fn size(&self) -> usize {
self.radix3.size()
}
/// Returns the DMA address of the radix3 table that maps the firmware image.
pub(crate) fn radix3_dma_address(&self) -> DmaAddress {
self.radix3.dma_address()
}
}
|