xref: /linux/drivers/gpu/nova-core/gsp/fw/commands.rs (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
1 // SPDX-License-Identifier: GPL-2.0
2 // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 
4 use kernel::{
5     device,
6     pci,
7     prelude::*,
8     transmute::{
9         AsBytes,
10         FromBytes, //
11     }, //
12 };
13 
14 use crate::{
15     gpu::Chipset,
16     gsp::GSP_PAGE_SIZE, //
17 };
18 
19 use super::bindings;
20 
21 /// Payload of the `GspSetSystemInfo` command.
22 #[repr(transparent)]
23 pub(crate) struct GspSetSystemInfo {
24     inner: bindings::GspSystemInfo,
25 }
26 static_assert!(size_of::<GspSetSystemInfo>() < GSP_PAGE_SIZE);
27 
28 impl GspSetSystemInfo {
29     /// Returns an in-place initializer for the `GspSetSystemInfo` command.
30     #[allow(non_snake_case)]
31     pub(crate) fn init<'a>(
32         dev: &'a pci::Device<device::Bound>,
33         chipset: Chipset,
34     ) -> impl Init<Self, Error> + 'a {
35         type InnerGspSystemInfo = bindings::GspSystemInfo;
36         let pci_config_mirror_range = chipset.pci_config_mirror_range();
37         let init_inner = try_init!(InnerGspSystemInfo {
38             gpuPhysAddr: dev.resource_start(0)?,
39             gpuPhysFbAddr: dev.resource_start(1)?,
40             gpuPhysInstAddr: dev.resource_start(3)?,
41             nvDomainBusDeviceFunc: u64::from(dev.dev_id()),
42 
43             // Using TASK_SIZE in r535_gsp_rpc_set_system_info() seems wrong because
44             // TASK_SIZE is per-task. That's probably a design issue in GSP-RM though.
45             maxUserVa: (1 << 47) - 4096,
46             pciConfigMirrorBase: pci_config_mirror_range.start,
47             pciConfigMirrorSize: pci_config_mirror_range.end - pci_config_mirror_range.start,
48 
49             PCIDeviceID: (u32::from(dev.device_id()) << 16) | u32::from(dev.vendor_id().as_raw()),
50             PCISubDeviceID: (u32::from(dev.subsystem_device_id()) << 16)
51                 | u32::from(dev.subsystem_vendor_id()),
52             PCIRevisionID: u32::from(dev.revision_id()),
53             bIsPrimary: 0,
54             bPreserveVideoMemoryAllocations: 0,
55             ..Zeroable::init_zeroed()
56         });
57 
58         try_init!(GspSetSystemInfo {
59             inner <- init_inner,
60         })
61     }
62 }
63 
64 // SAFETY: These structs don't meet the no-padding requirements of AsBytes but
65 //         that is not a problem because they are not used outside the kernel.
66 unsafe impl AsBytes for GspSetSystemInfo {}
67 
68 // SAFETY: These structs don't meet the no-padding requirements of FromBytes but
69 //         that is not a problem because they are not used outside the kernel.
70 unsafe impl FromBytes for GspSetSystemInfo {}
71 
72 #[repr(transparent)]
73 pub(crate) struct PackedRegistryEntry(bindings::PACKED_REGISTRY_ENTRY);
74 
75 impl PackedRegistryEntry {
76     pub(crate) fn new(offset: u32, value: u32) -> Self {
77         Self({
78             bindings::PACKED_REGISTRY_ENTRY {
79                 nameOffset: offset,
80 
81                 // We only support DWORD types for now. Support for other types
82                 // will come later if required.
83                 type_: bindings::REGISTRY_TABLE_ENTRY_TYPE_DWORD as u8,
84                 __bindgen_padding_0: Default::default(),
85                 data: value,
86                 length: 0,
87             }
88         })
89     }
90 }
91 
92 // SAFETY: Padding is explicit and will not contain uninitialized data.
93 unsafe impl AsBytes for PackedRegistryEntry {}
94 
95 /// Payload of the `SetRegistry` command.
96 #[repr(transparent)]
97 pub(crate) struct PackedRegistryTable {
98     inner: bindings::PACKED_REGISTRY_TABLE,
99 }
100 
101 impl PackedRegistryTable {
102     #[allow(non_snake_case)]
103     pub(crate) fn init(num_entries: u32, size: u32) -> impl Init<Self> {
104         type InnerPackedRegistryTable = bindings::PACKED_REGISTRY_TABLE;
105         let init_inner = init!(InnerPackedRegistryTable {
106             numEntries: num_entries,
107             size,
108             entries: Default::default()
109         });
110 
111         init!(PackedRegistryTable { inner <- init_inner })
112     }
113 }
114 
115 // SAFETY: Padding is explicit and will not contain uninitialized data.
116 unsafe impl AsBytes for PackedRegistryTable {}
117 
118 // SAFETY: This struct only contains integer types for which all bit patterns
119 // are valid.
120 unsafe impl FromBytes for PackedRegistryTable {}
121 
122 /// Payload of the `GetGspStaticInfo` command and message.
123 #[repr(transparent)]
124 #[derive(Zeroable)]
125 pub(crate) struct GspStaticConfigInfo(bindings::GspStaticConfigInfo_t);
126 
127 impl GspStaticConfigInfo {
128     /// Returns a bytes array containing the (hopefully) zero-terminated name of this GPU.
129     pub(crate) fn gpu_name_str(&self) -> [u8; 64] {
130         self.0.gpuNameString
131     }
132 }
133 
134 // SAFETY: Padding is explicit and will not contain uninitialized data.
135 unsafe impl AsBytes for GspStaticConfigInfo {}
136 
137 // SAFETY: This struct only contains integer types for which all bit patterns
138 // are valid.
139 unsafe impl FromBytes for GspStaticConfigInfo {}
140 
141 /// Power level requested to the [`UnloadingGuestDriver`] command.
142 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
143 #[repr(u32)]
144 #[expect(unused)]
145 pub(crate) enum PowerStateLevel {
146     /// Full unload.
147     Level0 = bindings::NV2080_CTRL_GPU_SET_POWER_STATE_GPU_LEVEL_0,
148     /// S3 (suspend to RAM).
149     Level3 = bindings::NV2080_CTRL_GPU_SET_POWER_STATE_GPU_LEVEL_3,
150     /// Hibernate (suspend to disk).
151     Level7 = bindings::NV2080_CTRL_GPU_SET_POWER_STATE_GPU_LEVEL_7,
152 }
153 
154 impl PowerStateLevel {
155     /// Returns `true` if this state represents a power management transition, i.e. some GPU state
156     /// must survive it (as opposed to a full unload).
157     pub(crate) fn is_power_transition(self) -> bool {
158         self != PowerStateLevel::Level0
159     }
160 }
161 
162 /// Payload of the `UnloadingGuestDriver` command and message.
163 #[repr(transparent)]
164 #[derive(Clone, Copy, Debug, Zeroable)]
165 pub(crate) struct UnloadingGuestDriver(bindings::rpc_unloading_guest_driver_v1F_07);
166 
167 impl UnloadingGuestDriver {
168     pub(crate) fn new(level: PowerStateLevel) -> Self {
169         Self(bindings::rpc_unloading_guest_driver_v1F_07 {
170             bInPMTransition: u8::from(level.is_power_transition()),
171             bGc6Entering: 0,
172             newLevel: level as u32,
173             ..Zeroable::zeroed()
174         })
175     }
176 }
177 
178 // SAFETY: Padding is explicit and will not contain uninitialized data.
179 unsafe impl AsBytes for UnloadingGuestDriver {}
180 
181 // SAFETY: This struct only contains integer types for which all bit patterns
182 // are valid.
183 unsafe impl FromBytes for UnloadingGuestDriver {}
184