|
| 1 | +#include "gpu.h" |
| 2 | +#include "common/io/io.h" |
| 3 | + |
| 4 | +#include <sys/param.h> |
| 5 | +#include <sys/ioctl.h> |
| 6 | +#include <fcntl.h> |
| 7 | +#include <dev/pci/pcireg.h> |
| 8 | +#include <dev/pci/pcidevs.h> |
| 9 | +#include <sys/pciio.h> |
| 10 | + |
| 11 | +static inline int pciReadConf(int fd, uint32_t bus, uint32_t device, uint32_t func, uint32_t reg, uint32_t* result) |
| 12 | +{ |
| 13 | + struct pci_io bdfr = { |
| 14 | + .pi_sel = { |
| 15 | + .pc_bus = bus, |
| 16 | + .pc_dev = device, |
| 17 | + .pc_func = func, |
| 18 | + }, |
| 19 | + .pi_reg = reg, |
| 20 | + .pi_width = 4, |
| 21 | + }; |
| 22 | + |
| 23 | + if (ioctl(fd, PCIOCREAD, &bdfr) == -1) |
| 24 | + return -1; |
| 25 | + |
| 26 | + *result = bdfr.pi_data; |
| 27 | + return 0; |
| 28 | +} |
| 29 | + |
| 30 | +const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus) |
| 31 | +{ |
| 32 | + char pciDevPath[] = "/dev/pci0"; |
| 33 | + FF_AUTO_CLOSE_FD int pcifd = open(pciDevPath, O_RDONLY | O_CLOEXEC); |
| 34 | + if (pcifd < 0) |
| 35 | + return "open(\"/dev/pci0\", O_RDONLY | O_CLOEXEC) failed"; |
| 36 | + |
| 37 | + for (uint32_t bus = 0; bus <= 255; bus++) |
| 38 | + { |
| 39 | + for (uint32_t dev = 0; dev < 32; dev++) |
| 40 | + { |
| 41 | + uint32_t maxfuncs = 0; |
| 42 | + for (uint32_t func = 0; func <= maxfuncs; func++) |
| 43 | + { |
| 44 | + uint32_t pciid, pciclass; |
| 45 | + if (pciReadConf(pcifd, bus, dev, func, PCI_ID_REG, &pciid) != 0) |
| 46 | + continue; |
| 47 | + |
| 48 | + if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID || PCI_VENDOR(pciid) == 0) |
| 49 | + continue; |
| 50 | + |
| 51 | + if (pciReadConf(pcifd, bus, dev, func, PCI_CLASS_REG, &pciclass) != 0) |
| 52 | + continue; |
| 53 | + |
| 54 | + if (func == 0) |
| 55 | + { |
| 56 | + // For some reason, pciReadConf returns success even for non-existing devices. |
| 57 | + // So we need to check for `PCI_VENDOR(pciid) == PCI_VENDOR_INVALID` above to filter them out. |
| 58 | + uint32_t bhlcr; |
| 59 | + if (pciReadConf(pcifd, bus, dev, 0, PCI_BHLC_REG, &bhlcr) != 0) |
| 60 | + continue; |
| 61 | + |
| 62 | + if (PCI_HDRTYPE_MULTIFN(bhlcr)) maxfuncs = 7; |
| 63 | + } |
| 64 | + |
| 65 | + if (PCI_CLASS(pciclass) != PCI_CLASS_DISPLAY) |
| 66 | + continue; |
| 67 | + |
| 68 | + if (func > 0 && PCI_SUBCLASS(pciclass) == PCI_SUBCLASS_DISPLAY_MISC) |
| 69 | + continue; // Likely an auxiliary display controller (#2034) |
| 70 | + |
| 71 | + FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus); |
| 72 | + ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(PCI_VENDOR(pciid))); |
| 73 | + ffStrbufInit(&gpu->name); |
| 74 | + ffStrbufInit(&gpu->driver); |
| 75 | + ffStrbufInitS(&gpu->platformApi, "/dev/pci0"); |
| 76 | + ffStrbufInit(&gpu->memoryType); |
| 77 | + gpu->index = FF_GPU_INDEX_UNSET; |
| 78 | + gpu->temperature = FF_GPU_TEMP_UNSET; |
| 79 | + gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; |
| 80 | + gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET; |
| 81 | + gpu->type = FF_GPU_TYPE_UNKNOWN; |
| 82 | + gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; |
| 83 | + gpu->deviceId = ffGPUPciAddr2Id(0, bus, dev, func); |
| 84 | + gpu->frequency = FF_GPU_FREQUENCY_UNSET; |
| 85 | + |
| 86 | + if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) |
| 87 | + ffGPUQueryAmdGpuName(PCI_PRODUCT(pciid), PCI_REVISION(pciid), gpu); |
| 88 | + if (gpu->name.length == 0) |
| 89 | + ffGPUFillVendorAndName(PCI_SUBCLASS(pciclass), PCI_VENDOR(pciid), PCI_PRODUCT(pciid), gpu); |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + return NULL; |
| 95 | +} |
0 commit comments