#include "gpu.h" #include "common/io.h" #include #include #include #include #include #include static inline int pciReadConf(int fd, uint8_t bus, uint8_t device, uint8_t func, uint8_t reg, uint32_t* result) { struct pci_io bdfr = { .pi_sel = { .pc_bus = bus, .pc_dev = device, .pc_func = func, }, .pi_reg = reg, .pi_width = 4, }; if (ioctl(fd, PCIOCREAD, &bdfr) == -1) { return -1; } *result = bdfr.pi_data; return 0; } const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpus) { char pciDevPath[] = "/dev/pci0"; FF_AUTO_CLOSE_FD int pcifd = open(pciDevPath, O_RDONLY | O_CLOEXEC); if (pcifd < 0) { return "open(\"/dev/pci0\", O_RDONLY | O_CLOEXEC) failed"; } for (uint16_t bus = 0; bus <= 255; bus++) { for (uint8_t dev = 0; dev < 32; dev++) { uint8_t maxfuncs = 0; for (uint8_t func = 0; func <= maxfuncs; func++) { uint32_t pciid, pciclass; if (pciReadConf(pcifd, (uint8_t) bus, dev, func, PCI_ID_REG, &pciid) != 0) { continue; } if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID || PCI_VENDOR(pciid) == 0) { continue; } if (pciReadConf(pcifd, (uint8_t) bus, dev, func, PCI_CLASS_REG, &pciclass) != 0) { continue; } if (func == 0) { // For some reason, pciReadConf returns success even for non-existing devices. // So we need to check for `PCI_VENDOR(pciid) == PCI_VENDOR_INVALID` above to filter them out. uint32_t bhlcr; if (pciReadConf(pcifd, (uint8_t) bus, dev, 0, PCI_BHLC_REG, &bhlcr) != 0) { continue; } if (PCI_HDRTYPE_MULTIFN(bhlcr)) { maxfuncs = 7; } } if (PCI_CLASS(pciclass) != PCI_CLASS_DISPLAY) { continue; } if (func > 0 && PCI_SUBCLASS(pciclass) == PCI_SUBCLASS_DISPLAY_MISC) { continue; // Likely an auxiliary display controller (#2034) } FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus); ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(PCI_VENDOR(pciid))); ffStrbufInit(&gpu->name); ffStrbufInit(&gpu->driver); ffStrbufInitS(&gpu->platformApi, "/dev/pci0"); ffStrbufInit(&gpu->memoryType); gpu->index = FF_GPU_INDEX_UNSET; gpu->temperature = FF_GPU_TEMP_UNSET; gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET; gpu->type = FF_GPU_TYPE_UNKNOWN; 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; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { ffGPUQueryAmdGpuName(PCI_PRODUCT(pciid), PCI_REVISION(pciid), gpu); } if (gpu->name.length == 0) { ffGPUFillVendorAndName(PCI_SUBCLASS(pciclass), PCI_VENDOR(pciid), PCI_PRODUCT(pciid), gpu); } } } } return NULL; }