ohmu
·
2026-10-15
1#include "gpu.h"
2#include "gpu_driver_specific.h"
3
4#include "common/debug.h"
5#include "common/io.h"
6
7#include <string.h>
8#include <sys/pciio.h>
9#include <fcntl.h>
10#if __has_include(<dev/pci/pcireg.h>)
11 #include <dev/pci/pcireg.h> // FreeBSD
12#else
13 #include <bus/pci/pcireg.h> // DragonFly
14#endif
15
16static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) {
17 FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY | O_CLOEXEC);
18 if (fd < 0) {
19 FF_DEBUG("open(\"/dev/pci\") failed: %s", strerror(errno));
20 return "open(\"/dev/pci\", O_RDONLY | O_CLOEXEC, 0) failed";
21 }
22
23 struct pci_conf confs[128];
24 struct pci_match_conf match = {
25 .pc_class = PCIC_DISPLAY,
26 .flags = PCI_GETCONF_MATCH_CLASS,
27 };
28 struct pci_conf_io pcio = {
29 .pat_buf_len = sizeof(match),
30 .num_patterns = 1,
31 .patterns = &match,
32 .match_buf_len = sizeof(confs),
33 .matches = confs,
34 };
35
36 if (ioctl(fd, PCIOCGETCONF, &pcio) < 0) {
37 FF_DEBUG("ioctl(PCIOCGETCONF) failed: %s", strerror(errno));
38 return "ioctl(fd, PCIOCGETCONF, &pc) failed";
39 }
40
41 if (pcio.status == PCI_GETCONF_ERROR) {
42 FF_DEBUG("ioctl(fd, PCIOCGETCONF, &pc) returned error");
43 return "ioctl(fd, PCIOCGETCONF, &pc) returned error";
44 }
45
46 for (uint32_t i = 0; i < pcio.num_matches; ++i) {
47 struct pci_conf* pc = &confs[i];
48
49 if (pc->pc_sel.pc_func > 0 && pc->pc_subclass == 0x80 /*PCI_CLASS_DISPLAY_OTHER*/) {
50 continue; // Likely an auxiliary display controller (#2034)
51 }
52
53 FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus);
54 ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(pc->pc_vendor));
55 ffStrbufInit(&gpu->name);
56 ffStrbufInitS(&gpu->driver, pc->pd_name);
57 ffStrbufInitStatic(&gpu->platformApi, "/dev/pci");
58 ffStrbufInit(&gpu->memoryType);
59 gpu->index = FF_GPU_INDEX_UNSET;
60 gpu->temperature = FF_GPU_TEMP_UNSET;
61 gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
62 gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
63 gpu->type = FF_GPU_TYPE_UNKNOWN;
64 gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
65 gpu->deviceId = ffGPUPciAddr2Id(pc->pc_sel.pc_domain, pc->pc_sel.pc_bus, pc->pc_sel.pc_dev, pc->pc_sel.pc_func);
66 gpu->frequency = FF_GPU_FREQUENCY_UNSET;
67 gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
68
69 ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
70 .domain = (uint32_t) pc->pc_sel.pc_domain,
71 .bus = pc->pc_sel.pc_bus,
72 .device = pc->pc_sel.pc_dev,
73 .func = pc->pc_sel.pc_func,
74 });
75
76 if (gpu->name.length == 0) {
77 if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
78 ffGPUQueryAmdGpuName(pc->pc_device, pc->pc_revid, gpu);
79 }
80 if (gpu->name.length == 0) {
81 ffGPUFillVendorAndName(pc->pc_subclass, pc->pc_vendor, pc->pc_device, gpu);
82 }
83 }
84
85 ffGPUDetectTypeByVendorAndName(gpu);
86 }
87
88 return nullptr;
89}
90
91const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) {
92#if FF_HAVE_DRM
93 if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO) {
94 ffGPUDetectByDrmBSD(options, gpus);
95 if (gpus->length > 0) {
96 return nullptr;
97 }
98 }
99#endif
100
101 return detectByPci(options, gpus);
102}