From 102adf88e6e8f83a9ab9769732d168c501f8eb6c Mon Sep 17 00:00:00 2001 From: ShengYi Hung Date: Wed, 26 Aug 2026 02:02:49 -0500 Subject: [PATCH] linux: Exposes renderD nodes and chardev in sysfs To allow normal users to render through the render device, we expose the renderD node. This enables Wayland applications to use hardware acceleration when running under the Linux emulator. Additionally, libdrm and Mesa need to look up /sys/dev/char/: and /drm to identify the corresponding renderer device (e.g., a renderD device). We expose this path as well so that libdrm can locate the renderer. Differential Revision: https://reviews.freebsd.org/D59190 --- sys/compat/linsysfs/linsysfs.c | 58 ++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/sys/compat/linsysfs/linsysfs.c b/sys/compat/linsysfs/linsysfs.c index 5a41c5193415..0c4bf078415f 100644 --- a/sys/compat/linsysfs/linsysfs.c +++ b/sys/compat/linsysfs/linsysfs.c @@ -200,6 +200,9 @@ linsysfs_fill_uevent_pci(PFS_FILL_ARGS) return (0); } +/* Linux DRM render nodes start at minor 128. */ +#define DRM_RENDER_MINOR_BASE 128 + /* * Filler function for drm uevent file */ @@ -217,6 +220,19 @@ linsysfs_fill_uevent_drm(PFS_FILL_ARGS) return (0); } +static int +linsysfs_fill_uevent_drm_render(PFS_FILL_ARGS) +{ + device_t dev; + int unit; + + dev = (device_t)pn->pn_data; + unit = device_get_unit(dev); + sbuf_printf(sb, "MAJOR=226\nMINOR=%d\nDEVNAME=dri/renderD%d\n", + unit + DRM_RENDER_MINOR_BASE, unit + DRM_RENDER_MINOR_BASE); + return (0); +} + static char * get_full_pfs_path(struct pfs_node *cur) { @@ -259,7 +275,7 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, struct pfs_node *chardev, struct pfs_node *drm, char *path, char *prefix) { struct scsi_host_queue *scsi_host; - struct pfs_node *sub_dir, *cur_file; + struct pfs_node *sub_dir, *cur_file, *drm_dir, *drm_minor; int i, nchildren, error; device_t *children, parent; devclass_t devclass; @@ -378,7 +394,7 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, device_get_unit(dev) >= 0) { dinfo = device_get_ivars(parent); if (dinfo != NULL && dinfo->cfg.baseclass == PCIC_DISPLAY) { - pfs_create_dir(dir, NULL, "drm", NULL, NULL, + pfs_create_dir(dir, &drm_dir, "drm", NULL, NULL, NULL, 0); sprintf(devname, "226:%d", device_get_unit(dev)); @@ -400,6 +416,44 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, &linsysfs_fill_vgapci, NULL, NULL, NULL, PFS_RD); cur_file->pn_data = (void*)dir; + + pfs_create_dir(drm_dir, &drm_minor, devname, + NULL, NULL, NULL, 0); + pfs_create_file(drm_minor, &cur_file, "uevent", + &linsysfs_fill_uevent_drm, NULL, NULL, NULL, + PFS_RD); + cur_file->pn_data = (void *)dev; + + sprintf(devname, "226:%d", + device_get_unit(dev) + + DRM_RENDER_MINOR_BASE); + pfs_create_dir(chardev, &sub_dir, devname, NULL, + NULL, NULL, 0); + pfs_create_link(sub_dir, &cur_file, "device", + &linsysfs_fill_vgapci, NULL, NULL, NULL, + PFS_RD); + cur_file->pn_data = (void *)dir; + pfs_create_file(sub_dir, &cur_file, "uevent", + &linsysfs_fill_uevent_drm_render, NULL, + NULL, NULL, PFS_RD); + cur_file->pn_data = (void *)dev; + + sprintf(devname, "renderD%d", + device_get_unit(dev) + + DRM_RENDER_MINOR_BASE); + pfs_create_dir(drm, &sub_dir, devname, NULL, + NULL, NULL, 0); + pfs_create_link(sub_dir, &cur_file, "device", + &linsysfs_fill_vgapci, NULL, NULL, NULL, + PFS_RD); + cur_file->pn_data = (void *)dir; + + pfs_create_dir(drm_dir, &drm_minor, devname, + NULL, NULL, NULL, 0); + pfs_create_file(drm_minor, &cur_file, "uevent", + &linsysfs_fill_uevent_drm_render, NULL, + NULL, NULL, PFS_RD); + cur_file->pn_data = (void *)dev; } } }