git: 102adf88e6e8 - main - linux: Exposes renderD nodes and chardev in sysfs

From: ShengYi Hung <aokblast_at_FreeBSD.org>
Date: Sat, 26 Sep 2026 06:36:55 UTC
The branch main has been updated by aokblast:

URL: https://cgit.FreeBSD.org/src/commit/?id=102adf88e6e8f83a9ab9769732d168c501f8eb6c

commit 102adf88e6e8f83a9ab9769732d168c501f8eb6c
Author:     ShengYi Hung <aokblast@FreeBSD.org>
AuthorDate: 2026-08-26 07:02:49 +0000
Commit:     ShengYi Hung <aokblast@FreeBSD.org>
CommitDate: 2026-09-26 06:36:46 +0000

    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/<major>:<minor> and <pcidev>/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;
 			}
 		}
 	}