From 4e44c0520b0766ca832b91284849075efeb83906 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sat, 13 Jun 2026 15:20:40 +0800 Subject: [PATCH] GPU: detects max PCI gen & link width --- src/common/debug.h | 1 + src/common/impl/debug_windows.c | 5 + src/detection/gpu/adl.h | 3 + src/detection/gpu/d3dkmthk.h | 13 +++ src/detection/gpu/gpu.h | 3 + src/detection/gpu/gpu_amd.c | 22 +++++ src/detection/gpu/gpu_apple.c | 1 + src/detection/gpu/gpu_bsddrm.c | 1 + src/detection/gpu/gpu_driver_specific.h | 2 + src/detection/gpu/gpu_drm.c | 4 + src/detection/gpu/gpu_gnu.c | 1 + src/detection/gpu/gpu_haiku.c | 1 + src/detection/gpu/gpu_intel.c | 14 +++ src/detection/gpu/gpu_linux.c | 31 +++++++ src/detection/gpu/gpu_nbsd.c | 1 + src/detection/gpu/gpu_nvidia.c | 18 ++++ src/detection/gpu/gpu_obsd.c | 1 + src/detection/gpu/gpu_sunos.c | 1 + src/detection/gpu/gpu_windows.c | 116 ++++++++++++++---------- src/detection/gpu/igcl.h | 36 +++++++- src/detection/gpu/nvml.h | 4 + src/modules/gpu/gpu.c | 23 +++++ 22 files changed, 252 insertions(+), 50 deletions(-) diff --git a/src/common/debug.h b/src/common/debug.h index a378fc841..d79c48880 100644 --- a/src/common/debug.h +++ b/src/common/debug.h @@ -33,5 +33,6 @@ static inline const char* ffFindFileName(const char* file) { #if _WIN32 const char* ffDebugWin32Error(DWORD errorCode); const char* ffDebugNtStatus(NTSTATUS status); +const char* ffDebugConfigRet(unsigned long /*CONFIGRET*/ ret); const char* ffDebugHResult(HRESULT hr); #endif diff --git a/src/common/impl/debug_windows.c b/src/common/impl/debug_windows.c index fb76a659e..a3fb7f3dc 100644 --- a/src/common/impl/debug_windows.c +++ b/src/common/impl/debug_windows.c @@ -2,6 +2,7 @@ #include "common/windows/nt.h" #include +#include const char* ffDebugWin32Error(DWORD errorCode) { static char buffer[512]; @@ -34,6 +35,10 @@ const char* ffDebugWin32Error(DWORD errorCode) { return buffer; } +const char* ffDebugConfigRet(CONFIGRET ret) { + return ffDebugWin32Error(CM_MapCrToWin32Err(ret, ERROR_INTERNAL_ERROR)); +} + const char* ffDebugNtStatus(NTSTATUS status) { return ffDebugWin32Error(RtlNtStatusToDosError(status)); } diff --git a/src/detection/gpu/adl.h b/src/detection/gpu/adl.h index 346eece87..18510c953 100644 --- a/src/detection/gpu/adl.h +++ b/src/detection/gpu/adl.h @@ -26,6 +26,9 @@ extern int ADL2_Adapter_DedicatedVRAMUsage_Get(ADL_CONTEXT_HANDLE context, int i // Function to get the ASICFamilyType from the adapter. extern int ADL2_Adapter_ASICFamilyType_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* lpAsicTypes, int* lpValids); +// This function retrieves the chipset information for a specified adapter. +extern int ADL2_Adapter_ChipSetInfo_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLChipSetInfo* lpChipSetInfo); + // Function to retrieve current power management capabilities. extern int ADL2_Overdrive_Caps(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iSupported, int* iEnabled, int* iVersion); diff --git a/src/detection/gpu/d3dkmthk.h b/src/detection/gpu/d3dkmthk.h index da0087bae..e32241164 100644 --- a/src/detection/gpu/d3dkmthk.h +++ b/src/detection/gpu/d3dkmthk.h @@ -152,6 +152,18 @@ typedef struct _D3DKMT_QUERY_DEVICE_IDS { D3DKMT_DEVICE_IDS DeviceIds; // out: } D3DKMT_QUERY_DEVICE_IDS; +typedef enum _D3DKMT_PNP_KEY_TYPE { + D3DKMT_PNP_KEY_HARDWARE, + D3DKMT_PNP_KEY_SOFTWARE +} D3DKMT_PNP_KEY_TYPE; + +typedef struct _D3DKMT_QUERY_PHYSICAL_ADAPTER_PNP_KEY { + UINT PhysicalAdapterIndex; + D3DKMT_PNP_KEY_TYPE PnPKeyType; + WCHAR* pDest; + UINT* pCchDest; +} D3DKMT_QUERY_PHYSICAL_ADAPTER_PNP_KEY; + typedef enum _QAI_DRIVERVERSION { KMT_DRIVERVERSION_WDDM_1_0 = 1000, // Windows Vista KMT_DRIVERVERSION_WDDM_1_1_PRERELEASE = 1102, // Windows Vista with prereleased Win7 features @@ -187,6 +199,7 @@ typedef enum _KMTQUERYADAPTERINFOTYPE { KMTQAITYPE_UMD_DRIVER_VERSION = 18, KMTQAITYPE_NODEMETADATA = 25, // WDDM 2.0, Windows 10 KMTQAITYPE_PHYSICALADAPTERDEVICEIDS = 31, + KMTQAITYPE_PHYSICALADAPTERPNPKEY = 41, // WDDM 2.2, Windows 10 (1703) KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID = 60, // WDDM 2.4, Windows 10 (1803) KMTQAITYPE_NODEPERFDATA = 61, KMTQAITYPE_ADAPTERPERFDATA = 62, diff --git a/src/detection/gpu/gpu.h b/src/detection/gpu/gpu.h index ff2c24d6d..38de5a0ba 100644 --- a/src/detection/gpu/gpu.h +++ b/src/detection/gpu/gpu.h @@ -7,6 +7,7 @@ #define FF_GPU_CORE_COUNT_UNSET -1 #define FF_GPU_VMEM_SIZE_UNSET ((uint64_t) -1) #define FF_GPU_FREQUENCY_UNSET 0 +#define FF_GPU_PCI_INFO_UNSET 0 #define FF_GPU_CORE_USAGE_UNSET (-DBL_MAX) #define FF_GPU_INDEX_UNSET ((uint32_t) -1) @@ -46,6 +47,8 @@ typedef struct FFGPUResult { double coreUsage; int32_t coreCount; uint32_t frequency; // Maximum time clock frequency in MHz + uint16_t pcieGen; + uint16_t pcieLanes; FFGPUMemory dedicated; FFGPUMemory shared; uint64_t deviceId; diff --git a/src/detection/gpu/gpu_amd.c b/src/detection/gpu/gpu_amd.c index f396def1d..cac00d6a2 100644 --- a/src/detection/gpu/gpu_amd.c +++ b/src/detection/gpu/gpu_amd.c @@ -52,6 +52,7 @@ struct FFAdlData { FF_LIBRARY_SYMBOL(ADL2_Adapter_MemoryInfo2_Get) FF_LIBRARY_SYMBOL(ADL2_Adapter_DedicatedVRAMUsage_Get) FF_LIBRARY_SYMBOL(ADL2_Adapter_ASICFamilyType_Get) + FF_LIBRARY_SYMBOL(ADL2_Adapter_ChipSetInfo_Get) FF_LIBRARY_SYMBOL(ADL2_Overdrive_Caps) FF_LIBRARY_SYMBOL(ADL2_OverdriveN_CapabilitiesX2_Get) FF_LIBRARY_SYMBOL(ADL2_OverdriveN_SystemClocksX2_Get) @@ -89,6 +90,7 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_MemoryInfo2_Get) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_DedicatedVRAMUsage_Get) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ASICFamilyType_Get) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ChipSetInfo_Get) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive_Caps) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_CapabilitiesX2_Get) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_SystemClocksX2_Get) @@ -233,6 +235,26 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu FF_DEBUG("Setting adapter name: %s; UDID: %s, Present: %d, Exist: %d", device->strAdapterName, device->strUDID, device->iPresent, device->iExist); } + if (result.pcieGen || result.pcieLanes) { + ADLChipSetInfo chipSetInfo; + int status = adlData.ffADL2_Adapter_ChipSetInfo_Get(adlData.apiHandle, device->iAdapterIndex, &chipSetInfo); + FF_DEBUG("ADL2_Adapter_ChipSetInfo_Get returned %s (%d)", ffAdlStatusToString(status), status); + + if (status == ADL_OK) { + FF_DEBUG("Chipset info - Bus Type: %d, PCIe Lane Width: %d", chipSetInfo.iBusType, chipSetInfo.iMaxPCIELaneWidth); + if (result.pcieGen && chipSetInfo.iBusType >= 2) { + *result.pcieGen = (uint16_t) (chipSetInfo.iBusType - 2); + FF_DEBUG("Got PCIe Gen: %u", *result.pcieGen); + } + if (result.pcieLanes && chipSetInfo.iMaxPCIELaneWidth > 0) { + *result.pcieLanes = (uint16_t) chipSetInfo.iMaxPCIELaneWidth; + FF_DEBUG("Got PCIe Lanes: %u", *result.pcieLanes); + } + } else { + FF_DEBUG("Failed to get chipset information"); + } + } + int odVersion = 0; { diff --git a/src/detection/gpu/gpu_apple.c b/src/detection/gpu/gpu_apple.c index 3b8de206f..6ae10d269 100644 --- a/src/detection/gpu/gpu_apple.c +++ b/src/detection/gpu/gpu_apple.c @@ -118,6 +118,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) { gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->type = FF_GPU_TYPE_UNKNOWN; gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieGen = gpu->pcieLanes = FF_GPU_PCI_INFO_UNSET; IORegistryEntryGetRegistryEntryID(registryEntry, &gpu->deviceId); ffStrbufInitStatic(&gpu->platformApi, "IOKit"); diff --git a/src/detection/gpu/gpu_bsddrm.c b/src/detection/gpu/gpu_bsddrm.c index 12f650796..d9a66108e 100644 --- a/src/detection/gpu/gpu_bsddrm.c +++ b/src/detection/gpu/gpu_bsddrm.c @@ -148,6 +148,7 @@ const char* ffGPUDetectByDrmBSD(const FFGPUOptions* options, FFlist* gpus) { gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(pciInfo.domain, pciInfo.bus, pciInfo.dev, pciInfo.func); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieGen = gpu->pcieLanes = FF_GPU_PCI_INFO_UNSET; char driverName[64]; driverName[0] = '\0'; diff --git a/src/detection/gpu/gpu_driver_specific.h b/src/detection/gpu/gpu_driver_specific.h index 3ddfb69b7..a291287fe 100644 --- a/src/detection/gpu/gpu_driver_specific.h +++ b/src/detection/gpu/gpu_driver_specific.h @@ -36,6 +36,8 @@ typedef struct FFGpuDriverResult { FFGPUType* type; uint32_t* frequency; FFstrbuf* name; + uint16_t* pcieGen; + uint16_t* pcieLanes; } FFGpuDriverResult; const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName); diff --git a/src/detection/gpu/gpu_drm.c b/src/detection/gpu/gpu_drm.c index 8b7b9a9aa..d3a832626 100644 --- a/src/detection/gpu/gpu_drm.c +++ b/src/detection/gpu/gpu_drm.c @@ -113,6 +113,8 @@ const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, con gpu->frequency = (uint32_t) (devInfo.max_engine_clock / 1000u); gpu->index = FF_GPU_INDEX_UNSET; gpu->type = devInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; + gpu->pcieGen = (uint16_t) devInfo.pcie_gen; + gpu->pcieLanes = (uint16_t) devInfo.pcie_num_lanes; #define FF_VRAM_CASE(name, value) \ case value /* AMDGPU_VRAM_TYPE_ ## name */: \ ffStrbufSetStatic(&gpu->memoryType, #name); \ @@ -373,6 +375,8 @@ const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* .type = &gpu->type, .frequency = options->driverSpecific ? &gpu->frequency : NULL, .name = &gpu->name, + .pcieGen = options->driverSpecific ? &gpu->pcieGen : NULL, + .pcieLanes = options->driverSpecific ? &gpu->pcieLanes : NULL, }, soName); } diff --git a/src/detection/gpu/gpu_gnu.c b/src/detection/gpu/gpu_gnu.c index 27c774b20..d7d27792c 100644 --- a/src/detection/gpu/gpu_gnu.c +++ b/src/detection/gpu/gpu_gnu.c @@ -130,6 +130,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(0, pciBus, pciDev, pciFunc); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieGen = gpu->pcieLanes = FF_GPU_PCI_INFO_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { ffGPUQueryAmdGpuName(deviceId, revision, gpu); diff --git a/src/detection/gpu/gpu_haiku.c b/src/detection/gpu/gpu_haiku.c index f75f03980..86f959e5c 100644 --- a/src/detection/gpu/gpu_haiku.c +++ b/src/detection/gpu/gpu_haiku.c @@ -37,6 +37,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(0, dev.bus, dev.device, dev.function); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieGen = gpu->pcieLanes = FF_GPU_PCI_INFO_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { ffGPUQueryAmdGpuName(dev.device_id, dev.revision, gpu); diff --git a/src/detection/gpu/gpu_intel.c b/src/detection/gpu/gpu_intel.c index 7d94c802a..fe5d57d84 100644 --- a/src/detection/gpu/gpu_intel.c +++ b/src/detection/gpu/gpu_intel.c @@ -16,6 +16,7 @@ struct FFIgclData { FF_LIBRARY_SYMBOL(ctlMemoryGetState) FF_LIBRARY_SYMBOL(ctlEnumFrequencyDomains) FF_LIBRARY_SYMBOL(ctlFrequencyGetProperties) + FF_LIBRARY_SYMBOL(ctlPciGetProperties) bool inited; ctl_api_handle_t apiHandle; @@ -43,6 +44,7 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlMemoryGetState) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumFrequencyDomains) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlFrequencyGetProperties) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlPciGetProperties) if (ffctlInit(&(ctl_init_args_t) { .AppVersion = CTL_IMPL_VERSION, @@ -227,5 +229,17 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe ffStrbufSetS(result.name, properties.name); } + if (result.pcieGen || result.pcieLanes) { + ctl_pci_properties_t pciProps = { .Size = sizeof(pciProps), .Version = 0 }; + if (igclData.ffctlPciGetProperties(device, &pciProps) == CTL_RESULT_SUCCESS) { + if (result.pcieGen && pciProps.maxSpeed.gen > 0) { + *result.pcieGen = (uint16_t) pciProps.maxSpeed.gen; + } + if (result.pcieLanes && pciProps.maxSpeed.width > 0) { + *result.pcieLanes = (uint16_t) pciProps.maxSpeed.width; + } + } + } + return NULL; } diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index c679bb09c..5c0c3be8e 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -368,6 +368,7 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(pciDomain, pciBus, pciDevice, pciFunc); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieGen = gpu->pcieLanes = FF_GPU_PCI_INFO_UNSET; char drmKeyBuffer[8]; if (!drmKey) { @@ -393,6 +394,36 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf pciDetectDriver(&gpu->driver, deviceDir, buffer, drmKey); ffStrbufSubstrBefore(deviceDir, drmDirPathLength); + ffStrbufAppendS(deviceDir, "/max_link_speed"); + if (ffReadFileBuffer(deviceDir->chars, buffer)) { + int32_t maxLinkSpeed = (int32_t) ffStrbufToSInt(buffer, FF_GPU_PCI_INFO_UNSET); + if (maxLinkSpeed >= 64) { + gpu->pcieGen = 6; + } else if (maxLinkSpeed >= 32) { + gpu->pcieGen = 5; + } else if (maxLinkSpeed >= 16) { + gpu->pcieGen = 4; + } else if (maxLinkSpeed >= 8) { + gpu->pcieGen = 3; + } else if (maxLinkSpeed >= 5) { + gpu->pcieGen = 2; + } else if (maxLinkSpeed >= 2) { // 2.5 + gpu->pcieGen = 1; + } + } + ffStrbufSubstrBefore(deviceDir, drmDirPathLength); + + if (gpu->pcieGen != FF_GPU_PCI_INFO_UNSET) { + ffStrbufAppendS(deviceDir, "/max_link_width"); + if (ffReadFileBuffer(deviceDir->chars, buffer)) { + int32_t maxLinkWidth = (int32_t) ffStrbufToSInt(buffer, FF_GPU_PCI_INFO_UNSET); + if (maxLinkWidth > 0 && maxLinkWidth < 255) { // kernel returns 255 if the value is unknown + gpu->pcieLanes = (uint16_t) maxLinkWidth; + } + } + ffStrbufSubstrBefore(deviceDir, drmDirPathLength); + } + if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { bool ok = false; if (drmKey && options->driverSpecific) { diff --git a/src/detection/gpu/gpu_nbsd.c b/src/detection/gpu/gpu_nbsd.c index 4f5dab3c9..065411bd3 100644 --- a/src/detection/gpu/gpu_nbsd.c +++ b/src/detection/gpu/gpu_nbsd.c @@ -97,6 +97,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(0, bus, dev, func); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieGen = gpu->pcieLanes = FF_GPU_PCI_INFO_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { ffGPUQueryAmdGpuName(PCI_PRODUCT(pciid), PCI_REVISION(pciid), gpu); diff --git a/src/detection/gpu/gpu_nvidia.c b/src/detection/gpu/gpu_nvidia.c index 85776dd82..7418801d3 100644 --- a/src/detection/gpu/gpu_nvidia.c +++ b/src/detection/gpu/gpu_nvidia.c @@ -14,6 +14,8 @@ struct FFNvmlData { FF_LIBRARY_SYMBOL(nvmlDeviceGetNumGpuCores) FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxClockInfo) FF_LIBRARY_SYMBOL(nvmlDeviceGetUtilizationRates) + FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxPcieLinkGeneration) + FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxPcieLinkWidth) FF_LIBRARY_SYMBOL(nvmlDeviceGetBrand) FF_LIBRARY_SYMBOL(nvmlDeviceGetIndex) FF_LIBRARY_SYMBOL(nvmlDeviceGetName) @@ -159,6 +161,8 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetNumGpuCores) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxClockInfo) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxPcieLinkGeneration) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxPcieLinkWidth) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetUtilizationRates) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetBrand) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetIndex) @@ -288,6 +292,20 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR } } + if (result.pcieGen) { + unsigned int value; + if (nvmlData.ffnvmlDeviceGetMaxPcieLinkGeneration(device, &value) == NVML_SUCCESS) { + *result.pcieGen = (uint16_t) value; + } + } + + if (result.pcieLanes) { + unsigned int value; + if (nvmlData.ffnvmlDeviceGetMaxPcieLinkWidth(device, &value) == NVML_SUCCESS) { + *result.pcieLanes = (uint16_t) value; + } + } + return NULL; #else diff --git a/src/detection/gpu/gpu_obsd.c b/src/detection/gpu/gpu_obsd.c index bdf19fbe9..b043dd88b 100644 --- a/src/detection/gpu/gpu_obsd.c +++ b/src/detection/gpu/gpu_obsd.c @@ -86,6 +86,7 @@ const char* detectByPci(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpus) { gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(0, bus, dev, func); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieGen = gpu->pcieLanes = FF_GPU_PCI_INFO_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { ffGPUQueryAmdGpuName(PCI_PRODUCT(pciid), PCI_REVISION(pciid), gpu); diff --git a/src/detection/gpu/gpu_sunos.c b/src/detection/gpu/gpu_sunos.c index 13d499815..a7c5509d2 100644 --- a/src/detection/gpu/gpu_sunos.c +++ b/src/detection/gpu/gpu_sunos.c @@ -21,6 +21,7 @@ static int walkDevTree(di_node_t node, FF_A_UNUSED di_minor_t minor, FFlist* gpu gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = strtoul(di_bus_addr(node), NULL, 16); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieGen = gpu->pcieLanes = FF_GPU_PCI_INFO_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { int* revId; diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index 6c542c18e..7945f2b80 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -11,31 +11,26 @@ #if _WIN32 #include "common/windows/unicode.h" #include "common/windows/registry.h" + #include "common/mallocHelper.h" - #if FF_WIN81_COMPAT - #include "common/mallocHelper.h" - #include - #include - #include + #define INITGUID + #include + #include + #include + #include - #define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in + #define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in -static bool queryDeviceIdsFallback(D3DKMT_ADAPTERADDRESS adapterAddress, D3DKMT_DEVICE_IDS* outDeviceIds) { - FF_DEBUG("KMTQAITYPE_PHYSICALADAPTERDEVICEIDS failed. Attempting queryDeviceIdsFallback: bus=%u device=%u function=%u", - adapterAddress.BusNumber, - adapterAddress.DeviceNumber, - adapterAddress.FunctionNumber); - - if (adapterAddress.BusNumber == -1u) { - FF_DEBUG("Invalid adapter address, cannot query device IDs"); - return false; - } +static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds) { + FF_DEBUG("Query PCI device info: %08llX", gpu->deviceId); static FFlist deviceIdsCache; static bool initialized; typedef struct { + uint32_t maxLinkSpeed; + uint32_t maxLinkWidth; D3DKMT_DEVICE_IDS deviceIds; - D3DKMT_ADAPTERADDRESS adapterAddress; + uint64_t adapterAddress; } CacheEntry; if (!initialized) { @@ -79,34 +74,29 @@ static bool queryDeviceIdsFallback(D3DKMT_ADAPTERADDRESS adapterAddress, D3DKMT_ continue; } - uint32_t pciBus = 0; + CacheEntry* entry = FF_LIST_ADD(CacheEntry, deviceIdsCache); + *entry = (CacheEntry) {}; + // L"PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1\\4&3674a6b9&0&0008" + if (swscanf(devId + 4, L"VEN_%x&DEV_%x&SUBSYS_%4x%4x&REV_%x", &entry->deviceIds.VendorID, &entry->deviceIds.DeviceID, &entry->deviceIds.SubSystemID, &entry->deviceIds.SubVendorID, &entry->deviceIds.RevisionID) >= 2) { + FF_DEBUG("Parsed PCI IDs - Vendor: 0x%04x, Device: 0x%04x, SubVendor: 0x%04x, SubSystem: 0x%04x, Rev: 0x%04x", entry->deviceIds.VendorID, entry->deviceIds.DeviceID, entry->deviceIds.SubVendorID, entry->deviceIds.SubSystemID, entry->deviceIds.RevisionID); + // I thought it was DXGKMDT_OPM_BUS_TYPE_PCI, but it turns out to be false + // Who TF knows what 1 actually means. It's just reported by most graphic cards + // And yeah, DXGKMDT_OPM_BUS_TYPE_PCIEXPRESS (3) exists + entry->deviceIds.BusType = 1; + } else { + FF_DEBUG("Failed to parse PCI IDs from device ID string"); + deviceIdsCache.length--; // remove the cache entry since it's not valid + continue; + } + + uint32_t pciBus = 0; ULONG pciBufLen = sizeof(pciBus); if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_BUSNUMBER, NULL, &pciBus, &pciBufLen, 0) == CR_SUCCESS) { uint32_t pciAddr = 0; pciBufLen = sizeof(pciAddr); if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_ADDRESS, NULL, &pciAddr, &pciBufLen, 0) == CR_SUCCESS) { - CacheEntry* entry = FF_LIST_ADD(CacheEntry, deviceIdsCache); - - entry->deviceIds = (D3DKMT_DEVICE_IDS) {}; - // L"PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1\\4&3674a6b9&0&0008" - if (swscanf(devId + 4, L"VEN_%x&DEV_%x&SUBSYS_%4x%4x&REV_%x", &entry->deviceIds.VendorID, &entry->deviceIds.DeviceID, &entry->deviceIds.SubSystemID, &entry->deviceIds.SubVendorID, &entry->deviceIds.RevisionID) >= 2) { - FF_DEBUG("Parsed PCI IDs - Vendor: 0x%04x, Device: 0x%04x, SubVendor: 0x%04x, SubSystem: 0x%04x, Rev: 0x%04x", entry->deviceIds.VendorID, entry->deviceIds.DeviceID, entry->deviceIds.SubVendorID, entry->deviceIds.SubSystemID, entry->deviceIds.RevisionID); - // I thought it was DXGKMDT_OPM_BUS_TYPE_PCI, but it turns out to be false - // Who TF knows what 1 actually means. It's just reported by most graphic cards - // And yeah, DXGKMDT_OPM_BUS_TYPE_PCIEXPRESS (3) exists - entry->deviceIds.BusType = 1; - } else { - FF_DEBUG("Failed to parse PCI IDs from device ID string"); - deviceIdsCache.length--; // remove the cache entry since it's not valid - continue; - } - - entry->adapterAddress = (D3DKMT_ADAPTERADDRESS) { - .BusNumber = pciBus, - .DeviceNumber = (pciAddr >> 16) & 0xFFFF, - .FunctionNumber = pciAddr & 0xFFFF, - }; + entry->adapterAddress = ffGPUPciAddr2Id(0, pciBus, (pciAddr >> 16) & 0xFFFF, pciAddr & 0xFFFF); FF_DEBUG("Cached device IDs for PCI bus %u: vendor=0x%04x device=0x%04x", pciBus, entry->deviceIds.VendorID, entry->deviceIds.DeviceID); } else { FF_DEBUG("Failed to get PCI address"); @@ -114,21 +104,44 @@ static bool queryDeviceIdsFallback(D3DKMT_ADAPTERADDRESS adapterAddress, D3DKMT_ } else { FF_DEBUG("Failed to get PCI bus number"); } + + pciBufLen = sizeof(entry->maxLinkSpeed); + DEVPROPTYPE propType; + // Reports PCEe gen despite the PKEY name + CONFIGRET ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkSpeed, &propType, (PBYTE) &entry->maxLinkSpeed, &pciBufLen, 0); + if (ret == CR_SUCCESS) { + FF_DEBUG("PCIe GEN: %u", entry->maxLinkSpeed); + } else { + FF_DEBUG("Failed to get PCIe GEN: %s", ffDebugConfigRet(ret)); + } + + if (entry->maxLinkSpeed != FF_GPU_PCI_INFO_UNSET) { + pciBufLen = sizeof(entry->maxLinkWidth); + ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkWidth, &propType, (PBYTE) &entry->maxLinkWidth, &pciBufLen, 0); + if (ret == CR_SUCCESS) { + FF_DEBUG("PCIe max link width: %u", entry->maxLinkWidth); + } else { + FF_DEBUG("Failed to get PCIe max link width: %s", ffDebugConfigRet(ret)); + } + } } } FF_LIST_FOR_EACH (CacheEntry, entry, deviceIdsCache) { - if (memcmp(&entry->adapterAddress, &adapterAddress, sizeof(adapterAddress)) == 0) { - FF_DEBUG("Cache hit for adapter address: bus=%u device=%u function=%u", adapterAddress.BusNumber, adapterAddress.DeviceNumber, adapterAddress.FunctionNumber); - *outDeviceIds = entry->deviceIds; + if (gpu->deviceId == entry->adapterAddress) { + FF_DEBUG("Cache hit for adapter address: %08llX", gpu->deviceId); + if (outDeviceIds->VendorID != -1u) { + *outDeviceIds = entry->deviceIds; + } + gpu->pcieGen = (uint16_t) entry->maxLinkSpeed; + gpu->pcieLanes = (uint16_t) entry->maxLinkWidth; return true; } } - FF_DEBUG("Cache miss for adapter address: bus=%u device=%u function=%u", adapterAddress.BusNumber, adapterAddress.DeviceNumber, adapterAddress.FunctionNumber); + FF_DEBUG("Cache miss for adapter address: %08llX", gpu->deviceId); return false; } - #endif // FF_WIN81_COMPAT static bool queryVendorNameViaRegistry(FFstrbuf* vendor, D3DKMT_HANDLE hAdapter) { // `KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID` reports the GUID value used by the adapter's registry key (DirectX and Video) @@ -278,6 +291,7 @@ ffGPUDetectWsl2 : adapterType.HybridDiscrete ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_UNKNOWN; + gpu->pcieGen = gpu->pcieLanes = FF_GPU_PCI_INFO_UNSET; D3DKMT_DRIVERVERSION wddmVersion = KMT_DRIVERVERSION_WDDM_2_0; status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { @@ -323,11 +337,7 @@ ffGPUDetectWsl2 .pPrivateDriverData = &deviceIds, .PrivateDriverDataSize = sizeof(deviceIds), }); - if (NT_SUCCESS(status) -#if FF_WIN81_COMPAT - || queryDeviceIdsFallback(adapterAddress, &deviceIds.DeviceIds) -#endif - ) { + if (NT_SUCCESS(status)) { ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(deviceIds.DeviceIds.VendorID)); FF_DEBUG("Adapter #%u vendor/device IDs: vendor=0x%04x device=0x%04x", i, @@ -338,6 +348,14 @@ ffGPUDetectWsl2 FF_DEBUG("KMTQAITYPE_PHYSICALADAPTERDEVICEIDS query failed for adapter #%u: %s", i, ffDebugNtStatus(status)); } + #if _WIN32 + if (adapterAddress.BusNumber != -1u) { + if (queryPciDeviceInfo(gpu, &deviceIds.DeviceIds) && gpu->vendor.length == 0) { + ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(deviceIds.DeviceIds.VendorID)); + } + } + #endif + D3DKMT_UMD_DRIVER_VERSION umdDriverVersion; status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { .hAdapter = adapter->hAdapter, diff --git a/src/detection/gpu/igcl.h b/src/detection/gpu/igcl.h index 6bf4ffe73..0e570742e 100644 --- a/src/detection/gpu/igcl.h +++ b/src/detection/gpu/igcl.h @@ -5,6 +5,7 @@ // DOCUMENTATION REFERENCED BELOW, IN ORDER TO MAKE FASTFETCH MIT COMPLIANT. #include +#include // https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv412ctl_result_t typedef enum ctl_result_t { @@ -73,7 +74,7 @@ typedef struct ctl_adapter_bdf_t { } ctl_adapter_bdf_t; #define IGCL_CTL_MAX_DEVICE_NAME_LEN 100 -#define IGCL_CTL_MAX_RESERVED_SIZE 112 +#define IGCL_CTL_MAX_RESERVED_SIZE 108 typedef enum ctl_adapter_properties_flag_t { CTL_ADAPTER_PROPERTIES_FLAG_INTEGRATED = 1, @@ -101,6 +102,7 @@ typedef struct ctl_device_adapter_properties_t { uint16_t pci_subsys_id; uint16_t pci_subsys_vendor_id; ctl_adapter_bdf_t adapter_bdf; + uint32_t num_xe_cores; char reserved[IGCL_CTL_MAX_RESERVED_SIZE]; } ctl_device_adapter_properties_t; @@ -214,3 +216,35 @@ typedef struct ctl_freq_properties_t { // https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv425ctlFrequencyGetProperties17ctl_freq_handle_tP21ctl_freq_properties_t extern ctl_result_t ctlFrequencyGetProperties(ctl_freq_handle_t hFrequency, ctl_freq_properties_t* pProperties); + +// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv415ctl_pci_speed_t +typedef struct ctl_pci_speed_t { + uint32_t Size; + uint8_t Version; + int32_t gen; + int32_t width; + int64_t maxBandwidth; +} ctl_pci_speed_t; + +// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv417ctl_pci_address_t +typedef struct ctl_pci_address_t { + uint32_t Size; + uint8_t Version; + uint32_t domain; + uint32_t bus; + uint32_t device; + uint32_t function; +} ctl_pci_address_t; + +// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv420ctl_pci_properties_t +typedef struct ctl_pci_properties_t { + uint32_t Size; + uint8_t Version; + ctl_pci_address_t address; + ctl_pci_speed_t maxSpeed; + bool resizable_bar_supported; + bool resizable_bar_enabled; +} ctl_pci_properties_t; + +// https://intel.github.io/drivers.gpu.control-library/Control/api.html#ctlpcigetproperties +extern ctl_result_t ctlPciGetProperties(ctl_device_adapter_handle_t hDAhandle, ctl_pci_properties_t* pProperties); diff --git a/src/detection/gpu/nvml.h b/src/detection/gpu/nvml.h index 74b184050..1fb3508eb 100644 --- a/src/detection/gpu/nvml.h +++ b/src/detection/gpu/nvml.h @@ -142,6 +142,10 @@ extern nvmlReturn_t nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t* m extern nvmlReturn_t nvmlDeviceGetNumGpuCores(nvmlDevice_t device, unsigned int* numCores); // Retrieves the maximum clock speeds for the device extern nvmlReturn_t nvmlDeviceGetMaxClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int* clock); +// Retrieves the maximum PCIe link generation possible with this device and system +extern nvmlReturn_t nvmlDeviceGetMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int* maxLinkGen); +// Retrieves the maximum PCIe link width possible with this device and system +extern nvmlReturn_t nvmlDeviceGetMaxPcieLinkWidth (nvmlDevice_t device, unsigned int* maxLinkWidth); // Retrieves the brand of this device extern nvmlReturn_t nvmlDeviceGetBrand(nvmlDevice_t device, nvmlBrandType_t* type); // Retrieves the current utilization rates for the device diff --git a/src/modules/gpu/gpu.c b/src/modules/gpu/gpu.c index 5be84426e..d38b841f0 100644 --- a/src/modules/gpu/gpu.c +++ b/src/modules/gpu/gpu.c @@ -139,6 +139,11 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu } } + char pcieSpeed[32] = ""; + if (gpu->pcieGen != FF_GPU_PCI_INFO_UNSET && gpu->pcieLanes != FF_GPU_PCI_INFO_UNSET) { + snprintf(pcieSpeed, sizeof(pcieSpeed), "PCI Gen %d x%d", gpu->pcieGen, gpu->pcieLanes); + } + FF_PRINT_FORMAT_CHECKED(FF_GPU_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_ARG(gpu->vendor, "vendor"), FF_ARG(gpu->name, "name"), @@ -160,6 +165,7 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu FF_ARG(coreUsageNum, "core-usage-num"), FF_ARG(coreUsageBar, "core-usage-bar"), FF_ARG(gpu->memoryType, "memory-type"), + FF_ARG(pcieSpeed, "pcie-speed"), })); } } @@ -420,6 +426,22 @@ bool ffGenerateGPUJsonResult(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_ } yyjson_mut_obj_add_uint(doc, obj, "deviceId", gpu->deviceId); + + if (gpu->pcieGen != FF_GPU_PCI_INFO_UNSET || gpu->pcieLanes != FF_GPU_PCI_INFO_UNSET) { + yyjson_mut_val* pcieSpeed = yyjson_mut_obj_add_obj(doc, obj, "pcieSpeed"); + if (gpu->pcieGen != FF_GPU_PCI_INFO_UNSET) { + yyjson_mut_obj_add_uint(doc, pcieSpeed, "gen", gpu->pcieGen); + } else { + yyjson_mut_obj_add_null(doc, pcieSpeed, "gen"); + } + if (gpu->pcieLanes != FF_GPU_PCI_INFO_UNSET) { + yyjson_mut_obj_add_uint(doc, pcieSpeed, "lanes", gpu->pcieLanes); + } else { + yyjson_mut_obj_add_null(doc, pcieSpeed, "lanes"); + } + } else { + yyjson_mut_obj_add_null(doc, obj, "pcieSpeed"); + } } FF_LIST_FOR_EACH (FFGPUResult, gpu, gpus) { @@ -484,5 +506,6 @@ FFModuleBaseInfo ffGPUModuleInfo = { { "Core usage percentage num", "core-usage-num" }, { "Core usage percentage bar", "core-usage-bar" }, { "Memory type (Windows only)", "memory-type" }, + { "Maximum PCIe speed in gen and lanes", "pcie-speed" }, })), };