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