From 265c33439975d58b49b8034218e00f4138015feb Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 12 Jun 2026 16:11:35 +0800 Subject: [PATCH] GPU (FreeBSD): moves DRM detection to global space for OpenBSD use --- CMakeLists.txt | 1 + src/detection/gpu/gpu.h | 3 + src/detection/gpu/gpu_bsd.c | 161 +------------------------ src/detection/gpu/gpu_bsddrm.c | 210 +++++++++++++++++++++++++++++++++ 4 files changed, 216 insertions(+), 159 deletions(-) create mode 100644 src/detection/gpu/gpu_bsddrm.c diff --git a/CMakeLists.txt b/CMakeLists.txt index fdb746e29..485cd40eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -766,6 +766,7 @@ elseif(FreeBSD) src/detection/gpu/gpu_bsd.c src/detection/gpu/gpu_drm.c src/detection/gpu/gpu_pci.c + src/detection/gpu/gpu_bsddrm.c src/detection/gtk_qt/gtk.c src/detection/host/host_bsd.c src/detection/lm/lm_linux.c diff --git a/src/detection/gpu/gpu.h b/src/detection/gpu/gpu.h index b4d66b267..43caee312 100644 --- a/src/detection/gpu/gpu.h +++ b/src/detection/gpu/gpu.h @@ -74,6 +74,9 @@ const char* ffDrmDetectI915(FFGPUResult* gpu, int fd); const char* ffDrmDetectXe(FFGPUResult* gpu, int fd); const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd); const char* ffDrmDetectNouveau(FFGPUResult* gpu, int fd); + #if __FreeBSD__ || __OpenBSD__ // DRM is not available on NetBSD +const char* ffGPUDetectByDrmBSD(const FFGPUOptions* options, FFlist* gpus); + #endif #endif // FF_HAVE_DRM const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId); diff --git a/src/detection/gpu/gpu_bsd.c b/src/detection/gpu/gpu_bsd.c index be4ebd677..922d95f16 100644 --- a/src/detection/gpu/gpu_bsd.c +++ b/src/detection/gpu/gpu_bsd.c @@ -1,7 +1,7 @@ +#include "gpu.h" #include "gpu_driver_specific.h" #include "common/io.h" -#include "common/mallocHelper.h" #include #include @@ -11,163 +11,6 @@ #include // DragonFly #endif -#if FF_HAVE_DRM - #include "common/library.h" - #include "common/strutil.h" - - #include - - // https://github.com/freebsd/drm-kmod/blob/8fea1f06b3ac3fa24217e24ba7b2133abad705a9/include/uapi/drm/drm.h#L1095 - struct drm_pciinfo { - uint16_t domain; - uint8_t bus; - uint8_t dev; - uint8_t func; - uint16_t vendor_id; - uint16_t device_id; - uint16_t subvendor_id; - uint16_t subdevice_id; - uint8_t revision_id; - }; - - #define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo) - -static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus) { - const char* drmDirPath = "/dev/dri/"; - FF_AUTO_CLOSE_DIR DIR* dirp = opendir(drmDirPath); - if (dirp == NULL) { - return "opendir(/dev/dri/) failed"; - } - - FF_STRBUF_AUTO_DESTROY pathBuf = ffStrbufCreateA(64); - ffStrbufAppendS(&pathBuf, drmDirPath); - uint32_t pathLen = pathBuf.length; - - struct dirent* entry; - while ((entry = readdir(dirp)) != NULL) { - if (entry->d_name[0] == '.' || !ffStrStartsWith(entry->d_name, "render")) { - continue; - } - - ffStrbufAppendS(&pathBuf, entry->d_name); - - FF_AUTO_CLOSE_FD int fd = open(pathBuf.chars, O_RDWR | O_CLOEXEC); - ffStrbufSubstrBefore(&pathBuf, pathLen); - if (fd < 0) { - continue; - } - - // Currently, DRM_BUS_PCI is the only bus type supported by drm-kmod on BSD (hard-coded in libdrm source tree) - struct drm_pciinfo pciInfo = {}; - if (ioctl(fd, DRM_IOCTL_GET_PCIINFO, &pciInfo) < 0) { - continue; - } - // dev.drm.0.PCI_ID: 10de:2782 - // dev.drm.128.PCI_ID: 10de:2782 - // dev.drm.drm_debug_persist: 0 - // dev.drm.skip_ddb: 0 - // dev.drm.__drm_debug: 0 - - // hw.dri.timestamp_precision: 20 - // hw.dri.vblank_offdelay: 5000 - // hw.dri.0.modesetting: 1 - // hw.dri.0.busid: pci:0000:01:00.0 - // hw.dri.0.vblank: - // crtc ref count last enabled inmodeset - // hw.dri.0.clients: - // a dev pid uid magic ioctls - // y drm/128 101655 0 0 0 - // n drm/128 101655 0 0 0 - // y drm/128 101234 0 0 0 - // n drm/128 101234 0 0 0 - // n drm/128 101784 0 0 0 - // n drm/128 107428 0 0 0 - // y drm/128 100891 0 0 0 - // y drm/128 100891 0 0 0 - - // hw.dri.0.name: nvidia-drm 0x85 - // hw.dri.dp_aux_i2c_transfer_size: 16 - // hw.dri.dp_aux_i2c_speed_khz: 10 - // hw.dri.sched_policy: 1 - // hw.dri.drm_fbdev_overalloc: 100 - // hw.dri.fbdev_emulation: 1 - // hw.dri.timestamp_precision_usec: 20 - // hw.dri.vblankoffdelay: 5000 - // hw.dri.poll: 1 - // hw.dri.debug: 0 - // hw.dri.drm_debug_persist: 0 - // hw.dri.skip_ddb: 0 - // hw.dri.__drm_debug: 0 - // hw.dri.edid_fixup: 6 - - - FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus); - ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(pciInfo.vendor_id)); - ffStrbufInit(&gpu->name); - ffStrbufInit(&gpu->driver); - ffStrbufInitF(&gpu->platformApi, "/dev/dri/%s", entry->d_name); - 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(pciInfo.domain, pciInfo.bus, pciInfo.dev, pciInfo.func); - gpu->frequency = FF_GPU_FREQUENCY_UNSET; - - char driverName[64]; - driverName[0] = '\0'; - struct drm_version ver = { - .name = driverName, - .name_len = ARRAY_SIZE(driverName), - }; - if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0) { - driverName[ver.name_len] = '\0'; - ffStrbufSetF(&gpu->driver, "%s %d.%d.%d", ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel); - } - - if (ffStrStartsWith(driverName, "i915")) { - ffDrmDetectI915(gpu, fd); - } else if (ffStrStartsWith(driverName, "amdgpu")) { - uint32_t primaryNodeId = (uint32_t) strtoul(entry->d_name + strlen("card"), NULL, 10); - FF_STRBUF_AUTO_DESTROY renderNode = ffStrbufCreateF("/dev/dri/renderD%d", primaryNodeId + 128); - ffDrmDetectAmdgpu(options, gpu, renderNode.chars); - } else if (ffStrStartsWith(driverName, "radeon")) { - uint32_t primaryNodeId = (uint32_t) strtoul(entry->d_name + strlen("card"), NULL, 10); - FF_STRBUF_AUTO_DESTROY renderNode = ffStrbufCreateF("/dev/dri/renderD%d", primaryNodeId + 128); - ffDrmDetectRadeon(options, gpu, renderNode.chars); - } else if (ffStrStartsWith(driverName, "xe")) { - ffDrmDetectXe(gpu, fd); - } else if (ffStrStartsWith(driverName, "asahi")) { - ffDrmDetectAsahi(gpu, fd); - } else if (ffStrStartsWith(driverName, "nouveau")) { - ffDrmDetectNouveau(gpu, fd); - } else { - ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) { - .domain = pciInfo.domain, - .bus = pciInfo.bus, - .device = pciInfo.dev, - .func = pciInfo.func, - }); - } - - if (gpu->name.length == 0) { - if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { - ffGPUQueryAmdGpuName(pciInfo.device_id, pciInfo.revision_id, gpu); - } - if (gpu->name.length == 0) { - ffGPUFillVendorAndName(0, pciInfo.vendor_id, pciInfo.device_id, gpu); - } - } - - ffGPUFillVendorByDeviceName(gpu); - } - - return NULL; -} -#endif - static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) { FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY | O_CLOEXEC); if (fd < 0) { @@ -242,7 +85,7 @@ static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) { const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) { #if FF_HAVE_DRM if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO) { - detectByDrm(options, gpus); + ffGPUDetectByDrmBSD(options, gpus); if (gpus->length > 0) { return NULL; } diff --git a/src/detection/gpu/gpu_bsddrm.c b/src/detection/gpu/gpu_bsddrm.c new file mode 100644 index 000000000..12f650796 --- /dev/null +++ b/src/detection/gpu/gpu_bsddrm.c @@ -0,0 +1,210 @@ +#if FF_HAVE_DRM + + #include "gpu.h" + #include "common/strutil.h" + #include "common/io.h" + + #include + #include + #if __FreeBSD__ + #include + #include + #include + #include + #if __has_include() + #include // FreeBSD + #else + #include // DragonFly + #endif + #endif + +// https://github.com/freebsd/drm-kmod/blob/8fea1f06b3ac3fa24217e24ba7b2133abad705a9/include/uapi/drm/drm.h#L1095 +struct drm_pciinfo { + uint16_t domain; + uint8_t bus; + uint8_t dev; + uint8_t func; + uint16_t vendor_id; + uint16_t device_id; + uint16_t subvendor_id; + uint16_t subdevice_id; + uint8_t revision_id; +}; + + #define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo) + +static const char* drmGetPciinfo(int drmfd, const char* drmId, struct drm_pciinfo* result) { + #if !__FreeBSD__ + FF_UNUSED(drmId); + if (ioctl(drmfd, DRM_IOCTL_GET_PCIINFO, result) < 0) { + return "ioctl(DRM_IOCTL_GET_PCIINFO) failed"; + } + #else + FF_UNUSED(drmfd); + char requestBuf[64]; + snprintf(requestBuf, ARRAY_SIZE(requestBuf), "hw.dri.%s.busid", drmId); + char pciidBuf[64]; + size_t pciidLen = ARRAY_SIZE(pciidBuf); + if (sysctlbyname(requestBuf, pciidBuf, &pciidLen, NULL, 0) < 0) { + return "sysctlbyname(hw.dri.%s.busid) failed"; + } + // hw.dri.0.busid: pci:0000:01:00.0 + struct pci_match_conf match = { + .pc_class = PCIC_DISPLAY, + .flags = PCI_GETCONF_MATCH_CLASS | PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC, + }; + if (sscanf(pciidBuf, "pci:%" SCNx32 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8, &match.pc_sel.pc_domain, &match.pc_sel.pc_bus, &match.pc_sel.pc_dev, &match.pc_sel.pc_func) != 4) { + return "Invalid PCI busid found"; + } + + FF_AUTO_CLOSE_FD int pcifd = open("/dev/pci", O_RDONLY | O_CLOEXEC); + if (pcifd < 0) { + return "open(\"/dev/pci\", O_RDONLY | O_CLOEXEC, 0) failed"; + } + + struct pci_conf conf; + struct pci_conf_io pcio = { + .pat_buf_len = sizeof(match), + .num_patterns = 1, + .patterns = &match, + .match_buf_len = sizeof(conf), + .matches = &conf, + }; + + if (ioctl(pcifd, PCIOCGETCONF, &pcio) < 0) { + perror("ioctl"); + return "ioctl(pcifd, PCIOCGETCONF, &pc) failed"; + } + + if (pcio.status == PCI_GETCONF_ERROR) { + return "ioctl(pcifd, PCIOCGETCONF, &pc) returned error"; + } + + if (pcio.num_matches != 1) { + return "ioctl(pcifd, PCIOCGETCONF, &pc) returned no results"; + } + + *result = (struct drm_pciinfo){ + .domain = (uint16_t) conf.pc_sel.pc_domain, + .bus = conf.pc_sel.pc_bus, + .dev = conf.pc_sel.pc_dev, + .func = conf.pc_sel.pc_func, + .vendor_id = conf.pc_vendor, + .device_id = conf.pc_device, + .subvendor_id = conf.pc_subvendor, + .subdevice_id = conf.pc_subdevice, + .revision_id = conf.pc_revid, + }; + + // This sysctl can also be useful + // dev.drm.0.PCI_ID: 10de:2782 + #endif + + return NULL; +} + +const char* ffGPUDetectByDrmBSD(const FFGPUOptions* options, FFlist* gpus) { + const char* drmDirPath = "/dev/dri/"; + FF_AUTO_CLOSE_DIR DIR* dirp = opendir(drmDirPath); + if (dirp == NULL) { + return "opendir(/dev/dri/) failed"; + } + + FF_STRBUF_AUTO_DESTROY pathBuf = ffStrbufCreateA(64); + ffStrbufAppendS(&pathBuf, drmDirPath); + uint32_t pathLen = pathBuf.length; + + struct dirent* entry; + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_name[0] == '.' || !ffStrStartsWith(entry->d_name, "card")) { + continue; + } + + ffStrbufAppendS(&pathBuf, entry->d_name); + + FF_AUTO_CLOSE_FD int fd = open(pathBuf.chars, O_RDWR | O_CLOEXEC); + ffStrbufSubstrBefore(&pathBuf, pathLen); + if (fd < 0) { + continue; + } + + // Currently, DRM_BUS_PCI is the only bus type supported by drm-kmod on BSD (hard-coded in libdrm source tree) + struct drm_pciinfo pciInfo; + if (drmGetPciinfo(fd, entry->d_name + strlen("card"), &pciInfo) != NULL) { + continue; + } + + FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus); + ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(pciInfo.vendor_id)); + ffStrbufInit(&gpu->name); + ffStrbufInit(&gpu->driver); + ffStrbufInitF(&gpu->platformApi, "/dev/dri/%s", entry->d_name); + 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(pciInfo.domain, pciInfo.bus, pciInfo.dev, pciInfo.func); + gpu->frequency = FF_GPU_FREQUENCY_UNSET; + + char driverName[64]; + driverName[0] = '\0'; + struct drm_version ver = { + .name = driverName, + .name_len = ARRAY_SIZE(driverName), + }; + if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0) { + driverName[ver.name_len] = '\0'; + ffStrbufSetF(&gpu->driver, "%s %d.%d.%d", ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel); + } + + if (ffStrStartsWith(driverName, "i915")) { + ffDrmDetectI915(gpu, fd); + } else if (ffStrStartsWith(driverName, "amdgpu")) { + uint32_t primaryNodeId = (uint32_t) strtoul(entry->d_name + strlen("card"), NULL, 10); + FF_STRBUF_AUTO_DESTROY renderNode = ffStrbufCreateF("/dev/dri/renderD%d", primaryNodeId + 128); + ffDrmDetectAmdgpu(options, gpu, renderNode.chars); + } else if (ffStrStartsWith(driverName, "radeon")) { + uint32_t primaryNodeId = (uint32_t) strtoul(entry->d_name + strlen("card"), NULL, 10); + FF_STRBUF_AUTO_DESTROY renderNode = ffStrbufCreateF("/dev/dri/renderD%d", primaryNodeId + 128); + ffDrmDetectRadeon(options, gpu, renderNode.chars); + } else if (ffStrStartsWith(driverName, "xe")) { + ffDrmDetectXe(gpu, fd); + } else if (ffStrStartsWith(driverName, "asahi")) { + ffDrmDetectAsahi(gpu, fd); + } else if (ffStrStartsWith(driverName, "nouveau")) { + ffDrmDetectNouveau(gpu, fd); + } else { + ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId){ + .domain = pciInfo.domain, + .bus = pciInfo.bus, + .device = pciInfo.dev, + .func = pciInfo.func, + }); + } + + if (gpu->name.length == 0) { + if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { + ffGPUQueryAmdGpuName(pciInfo.device_id, pciInfo.revision_id, gpu); + } + if (gpu->name.length == 0) { + ffGPUFillVendorAndName(0, pciInfo.vendor_id, pciInfo.device_id, gpu); + } + } + + ffGPUFillVendorByDeviceName(gpu); + } + + return NULL; +} + +#else + +const char* ffGPUDetectByDrmBSD(const FFGPUOptions* options, FFlist* gpus) { + FF_UNUSED(options, gpus); + return "Fastfetch was built without libdrm support"; +} + +#endif // __FreeBSD__ || __OpenBSD__