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