From: Alistair Popple <[email protected]> After GSP initialization is complete, retrieve the static configuration information from GSP-RM. This information includes GPU name, capabilities, memory configuration, and other properties. On some GPU variants, it is also required to do this for initialization to complete.
Signed-off-by: Alistair Popple <[email protected]> Co-developed-by: Joel Fernandes <[email protected]> Signed-off-by: Joel Fernandes <[email protected]> --- drivers/gpu/nova-core/gsp/boot.rs | 8 + drivers/gpu/nova-core/gsp/commands.rs | 63 +++++++ drivers/gpu/nova-core/gsp/fw.rs | 3 + .../gpu/nova-core/gsp/fw/r570_144/bindings.rs | 163 ++++++++++++++++++ drivers/gpu/nova-core/nova_core.rs | 1 + drivers/gpu/nova-core/util.rs | 16 ++ 6 files changed, 254 insertions(+) create mode 100644 drivers/gpu/nova-core/util.rs diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs index 0dd8099f5f8c..b8588ff8d21e 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -20,6 +20,7 @@ use crate::gpu::Chipset; use crate::gsp::commands::{ build_registry, + get_gsp_info, gsp_init_done, set_system_info, // }; @@ -31,6 +32,7 @@ GspFwWprMeta, // }; use crate::regs; +use crate::util; use crate::vbios::Vbios; impl super::Gsp { @@ -226,6 +228,12 @@ pub(crate) fn boot( GspSequencer::run(&mut self.cmdq, seq_params, Delta::from_secs(10))?; gsp_init_done(&mut self.cmdq, Delta::from_secs(10))?; + let info = get_gsp_info(&mut self.cmdq, bar)?; + dev_info!( + pdev.as_ref(), + "GPU name: {}\n", + util::str_from_null_terminated(&info.gpu_name) + ); Ok(()) } diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs index 521e252c2805..e70067a49d85 100644 --- a/drivers/gpu/nova-core/gsp/commands.rs +++ b/drivers/gpu/nova-core/gsp/commands.rs @@ -11,6 +11,7 @@ }; use super::fw::commands::*; +use super::fw::GspStaticConfigInfo_t; use super::fw::MsgFunction; use crate::driver::Bar0; use crate::gsp::cmdq::Cmdq; @@ -23,6 +24,17 @@ use crate::gsp::GSP_PAGE_SIZE; use crate::sbuffer::SBufferIter; +// SAFETY: Padding is explicit and will not contain uninitialized data. +unsafe impl AsBytes for GspStaticConfigInfo_t {} + +// SAFETY: This struct only contains integer types for which all bit patterns +// are valid. +unsafe impl FromBytes for GspStaticConfigInfo_t {} + +pub(crate) struct GspStaticConfigInfo { + pub gpu_name: [u8; 40], +} + /// Message type for GSP initialization done notification. struct GspInitDone {} @@ -49,6 +61,57 @@ pub(crate) fn gsp_init_done(cmdq: &mut Cmdq, timeout: Delta) -> Result { } } +impl MessageFromGsp for GspStaticConfigInfo_t { + const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo; +} + +impl CommandToGspBase for GspStaticConfigInfo_t { + const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo; +} + +impl CommandToGsp for GspStaticConfigInfo_t {} + +// SAFETY: This struct only contains integer types and fixed-size arrays for which +// all bit patterns are valid. +unsafe impl Zeroable for GspStaticConfigInfo_t {} + +impl GspStaticConfigInfo_t { + fn init() -> impl Init<Self> { + init!(GspStaticConfigInfo_t { + ..Zeroable::init_zeroed() + }) + } +} + +pub(crate) fn get_gsp_info(cmdq: &mut Cmdq, bar: &Bar0) -> Result<GspStaticConfigInfo> { + cmdq.send_gsp_command(bar, GspStaticConfigInfo_t::init())?; + cmdq.receive_msg_from_gsp::<GspStaticConfigInfo_t, GspStaticConfigInfo>( + Delta::from_secs(5), + |info, _| { + let gpu_name_str = info + .gpuNameString + .get( + 0..=info + .gpuNameString + .iter() + .position(|&b| b == 0) + .unwrap_or(info.gpuNameString.len() - 1), + ) + .and_then(|bytes| CStr::from_bytes_with_nul(bytes).ok()) + .and_then(|cstr| cstr.to_str().ok()) + .unwrap_or("invalid utf8"); + + let mut gpu_name = [0u8; 40]; + let bytes = gpu_name_str.as_bytes(); + let copy_len = core::cmp::min(bytes.len(), gpu_name.len()); + gpu_name[..copy_len].copy_from_slice(&bytes[..copy_len]); + gpu_name[copy_len] = b'\0'; + + Ok(GspStaticConfigInfo { gpu_name }) + }, + ) +} + // For now we hard-code the registry entries. Future work will allow others to // be added as module parameters. const GSP_REGISTRY_NUM_ENTRIES: usize = 3; diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index bb79f92432aa..62bac19fcdee 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -547,6 +547,9 @@ pub(crate) fn element_count(&self) -> u32 { // GSP sequencer run structure with information on how to run the sequencer. rpc_run_cpu_sequencer_v17_00, + // GSP static configuration information. + GspStaticConfigInfo_t, + // GSP sequencer structures. GSP_SEQUENCER_BUFFER_CMD, GSP_SEQ_BUF_OPCODE, diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs index c5c589c1e2ac..f081ac1708e6 100644 --- a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs +++ b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs @@ -320,6 +320,77 @@ fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { pub const NV_VGPU_MSG_EVENT_NUM_EVENTS: _bindgen_ty_3 = 4131; pub type _bindgen_ty_3 = ffi::c_uint; #[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS { + pub totalVFs: u32_, + pub firstVfOffset: u32_, + pub vfFeatureMask: u32_, + pub FirstVFBar0Address: u64_, + pub FirstVFBar1Address: u64_, + pub FirstVFBar2Address: u64_, + pub bar0Size: u64_, + pub bar1Size: u64_, + pub bar2Size: u64_, + pub b64bitBar0: u8_, + pub b64bitBar1: u8_, + pub b64bitBar2: u8_, + pub bSriovEnabled: u8_, + pub bSriovHeavyEnabled: u8_, + pub bEmulateVFBar0TlbInvalidationRegister: u8_, + pub bClientRmAllocatedCtxBuffer: u8_, + pub bNonPowerOf2ChannelCountSupported: u8_, + pub bVfResizableBAR1Supported: u8_, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct NV2080_CTRL_BIOS_GET_SKU_INFO_PARAMS { + pub BoardID: u32_, + pub chipSKU: [ffi::c_char; 9usize], + pub chipSKUMod: [ffi::c_char; 5usize], + pub skuConfigVersion: u32_, + pub project: [ffi::c_char; 5usize], + pub projectSKU: [ffi::c_char; 5usize], + pub CDP: [ffi::c_char; 6usize], + pub projectSKUMod: [ffi::c_char; 2usize], + pub businessCycle: u32_, +} +pub type NV2080_CTRL_CMD_FB_GET_FB_REGION_SURFACE_MEM_TYPE_FLAG = [u8_; 17usize]; +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO { + pub base: u64_, + pub limit: u64_, + pub reserved: u64_, + pub performance: u32_, + pub supportCompressed: u8_, + pub supportISO: u8_, + pub bProtected: u8_, + pub blackList: NV2080_CTRL_CMD_FB_GET_FB_REGION_SURFACE_MEM_TYPE_FLAG, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_PARAMS { + pub numFBRegions: u32_, + pub fbRegion: [NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO; 16usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NV2080_CTRL_GPU_GET_GID_INFO_PARAMS { + pub index: u32_, + pub flags: u32_, + pub length: u32_, + pub data: [u8_; 256usize], +} +impl Default for NV2080_CTRL_GPU_GET_GID_INFO_PARAMS { + fn default() -> Self { + let mut s = ::core::mem::MaybeUninit::<Self>::uninit(); + unsafe { + ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] #[derive(Debug, Default, Copy, Clone, Zeroable)] pub struct DOD_METHOD_DATA { pub status: u32_, @@ -367,6 +438,19 @@ pub struct ACPI_METHOD_DATA { pub capsMethodData: CAPS_METHOD_DATA, } #[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct VIRTUAL_DISPLAY_GET_MAX_RESOLUTION_PARAMS { + pub headIndex: u32_, + pub maxHResolution: u32_, + pub maxVResolution: u32_, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct VIRTUAL_DISPLAY_GET_NUM_HEADS_PARAMS { + pub numHeads: u32_, + pub maxNumHeads: u32_, +} +#[repr(C)] #[derive(Debug, Default, Copy, Clone, Zeroable)] pub struct BUSINFO { pub deviceID: u16_, @@ -395,6 +479,85 @@ pub struct GSP_PCIE_CONFIG_REG { pub linkCap: u32_, } #[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct EcidManufacturingInfo { + pub ecidLow: u32_, + pub ecidHigh: u32_, + pub ecidExtended: u32_, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct FW_WPR_LAYOUT_OFFSET { + pub nonWprHeapOffset: u64_, + pub frtsOffset: u64_, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct GspStaticConfigInfo_t { + pub grCapsBits: [u8_; 23usize], + pub gidInfo: NV2080_CTRL_GPU_GET_GID_INFO_PARAMS, + pub SKUInfo: NV2080_CTRL_BIOS_GET_SKU_INFO_PARAMS, + pub fbRegionInfoParams: NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_PARAMS, + pub sriovCaps: NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS, + pub sriovMaxGfid: u32_, + pub engineCaps: [u32_; 3usize], + pub poisonFuseEnabled: u8_, + pub fb_length: u64_, + pub fbio_mask: u64_, + pub fb_bus_width: u32_, + pub fb_ram_type: u32_, + pub fbp_mask: u64_, + pub l2_cache_size: u32_, + pub gpuNameString: [u8_; 64usize], + pub gpuShortNameString: [u8_; 64usize], + pub gpuNameString_Unicode: [u16_; 64usize], + pub bGpuInternalSku: u8_, + pub bIsQuadroGeneric: u8_, + pub bIsQuadroAd: u8_, + pub bIsNvidiaNvs: u8_, + pub bIsVgx: u8_, + pub bGeforceSmb: u8_, + pub bIsTitan: u8_, + pub bIsTesla: u8_, + pub bIsMobile: u8_, + pub bIsGc6Rtd3Allowed: u8_, + pub bIsGc8Rtd3Allowed: u8_, + pub bIsGcOffRtd3Allowed: u8_, + pub bIsGcoffLegacyAllowed: u8_, + pub bIsMigSupported: u8_, + pub RTD3GC6TotalBoardPower: u16_, + pub RTD3GC6PerstDelay: u16_, + pub bar1PdeBase: u64_, + pub bar2PdeBase: u64_, + pub bVbiosValid: u8_, + pub vbiosSubVendor: u32_, + pub vbiosSubDevice: u32_, + pub bPageRetirementSupported: u8_, + pub bSplitVasBetweenServerClientRm: u8_, + pub bClRootportNeedsNosnoopWAR: u8_, + pub displaylessMaxHeads: VIRTUAL_DISPLAY_GET_NUM_HEADS_PARAMS, + pub displaylessMaxResolution: VIRTUAL_DISPLAY_GET_MAX_RESOLUTION_PARAMS, + pub displaylessMaxPixels: u64_, + pub hInternalClient: u32_, + pub hInternalDevice: u32_, + pub hInternalSubdevice: u32_, + pub bSelfHostedMode: u8_, + pub bAtsSupported: u8_, + pub bIsGpuUefi: u8_, + pub bIsEfiInit: u8_, + pub ecidInfo: [EcidManufacturingInfo; 2usize], + pub fwWprLayoutOffset: FW_WPR_LAYOUT_OFFSET, +} +impl Default for GspStaticConfigInfo_t { + fn default() -> Self { + let mut s = ::core::mem::MaybeUninit::<Self>::uninit(); + unsafe { + ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] #[derive(Debug, Default, Copy, Clone, Zeroable)] pub struct GspSystemInfo { pub gpuPhysAddr: u64_, diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs index c1121e7c64c5..b98a1c03f13d 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -16,6 +16,7 @@ mod num; mod regs; mod sbuffer; +mod util; mod vbios; pub(crate) const MODULE_NAME: &kernel::str::CStr = <LocalModule as kernel::ModuleMetadata>::NAME; diff --git a/drivers/gpu/nova-core/util.rs b/drivers/gpu/nova-core/util.rs new file mode 100644 index 000000000000..f1a4dea44c10 --- /dev/null +++ b/drivers/gpu/nova-core/util.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 + +/// Converts a null-terminated byte array to a string slice. +/// +/// Returns "invalid" if the bytes are not valid UTF-8 or not null-terminated. +pub(crate) fn str_from_null_terminated(bytes: &[u8]) -> &str { + use kernel::str::CStr; + + // Find the first null byte, then create a slice that includes it. + bytes + .iter() + .position(|&b| b == 0) + .and_then(|null_pos| CStr::from_bytes_with_nul(&bytes[..=null_pos]).ok()) + .and_then(|cstr| cstr.to_str().ok()) + .unwrap_or("invalid") +} -- 2.34.1
