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 | 7 + drivers/gpu/nova-core/gsp/commands.rs | 65 +++++++ drivers/gpu/nova-core/gsp/fw.rs | 5 + .../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, 257 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 c0afafbf35f6..42a3abb9243d 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -40,6 +40,7 @@ GspFwWprMeta, // }, regs, + util, // vbios::Vbios, }; @@ -237,6 +238,12 @@ pub(crate) fn boot( GspSequencer::run(&mut self.cmdq, seq_params, Delta::from_secs(10))?; commands::gsp_init_done(&mut self.cmdq, Delta::from_secs(10))?; + let info = commands::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 07abfb54f9d7..6cb32e7d3436 100644 --- a/drivers/gpu/nova-core/gsp/commands.rs +++ b/drivers/gpu/nova-core/gsp/commands.rs @@ -17,6 +17,7 @@ }; use crate::{ + driver::Bar0, gsp::{ cmdq::{ Cmdq, @@ -25,12 +26,25 @@ }, fw::{ commands::*, + GspStaticConfigInfo_t, MsgFunction, // }, }, sbuffer::SBufferIter, + util, }; +// 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 {} @@ -62,6 +76,57 @@ pub(crate) fn gsp_init_done(cmdq: &mut Cmdq, timeout: Delta) -> Result { } } +impl MessageFromGsp for GspStaticConfigInfo { + const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo; + type InitError = Infallible; + type Message = GspStaticConfigInfo_t; + + fn read( + msg: &Self::Message, + _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>, + ) -> Result<Self, Self::InitError> { + let gpu_name_str = util::str_from_null_terminated(&msg.gpuNameString); + + 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 }) + } +} + +// SAFETY: This struct only contains integer types and fixed-size arrays for which +// all bit patterns are valid. +unsafe impl Zeroable for GspStaticConfigInfo_t {} + +struct GetGspInfo; + +impl CommandToGsp for GetGspInfo { + const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo; + type Command = GspStaticConfigInfo_t; + type InitError = Infallible; + + fn init(&self) -> impl Init<Self::Command, Self::InitError> { + init!(GspStaticConfigInfo_t { + ..Zeroable::init_zeroed() + }) + } +} + +pub(crate) fn get_gsp_info(cmdq: &mut Cmdq, bar: &Bar0) -> Result<GspStaticConfigInfo> { + cmdq.send_command(bar, GetGspInfo)?; + + loop { + match cmdq.receive_msg::<GspStaticConfigInfo>(Delta::from_secs(5)) { + Ok(info) => return Ok(info), + Err(ERANGE) => continue, + Err(e) => return Err(e), + } + } +} + /// The `GspSetSystemInfo` command. pub(crate) struct SetSystemInfo<'a> { pdev: &'a pci::Device<device::Bound>, diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index 0cce54310c35..5b6a906ff5dc 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -882,6 +882,11 @@ pub(crate) fn element_count(&self) -> u32 { } } +pub(crate) use r570_144::{ + // GSP static configuration information. + GspStaticConfigInfo_t, // +}; + // SAFETY: Padding is explicit and will not contain uninitialized data. unsafe impl AsBytes for GspMsgElement {} 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
