Page MenuHomeFreeBSD

D38545.diff
No OneTemporary

D38545.diff

diff --git a/sys/compat/linsysfs/linsysfs.h b/sys/compat/linsysfs/linsysfs.h
new file mode 100644
--- /dev/null
+++ b/sys/compat/linsysfs/linsysfs.h
@@ -0,0 +1,51 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2006 IronPort Systems
+ * All rights reserved.
+ * Copyright (c) 2023 Dmitry Chagin <dchagin@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _COMPAT_LINSYSFS_LINSYSFS_H_
+#define _COMPAT_LINSYSFS_LINSYSFS_H_
+
+typedef struct pfs_node *linsysfs_bus_cb_t(device_t, device_t,
+ struct pfs_node *, struct pfs_node *);
+
+void linsysfs_bus_drm(struct pfs_node *, struct pfs_node *, device_t);
+
+int linsysfs_fill_data(PFS_FILL_ARGS);
+char *linsysfs_full_pfs_path(const struct pfs_node *);
+
+struct pfs_node *linsysfs_create_dir(struct pfs_node *, const char *,
+ pfs_attr_t, pfs_vis_t, pfs_destroy_t);
+struct pfs_node *linsysfs_create_file(struct pfs_node *, const char *,
+ pfs_fill_t, pfs_attr_t, pfs_vis_t,
+ pfs_destroy_t, int, void *);
+struct pfs_node *linsysfs_create_link(struct pfs_node *, const char *,
+ pfs_fill_t, pfs_attr_t, pfs_vis_t,
+ pfs_destroy_t, int, void *);
+struct pfs_node *linsysfs_find_pcinode(device_t);
+
+#endif /* _COMPAT_LINSYSFS_LINSYSFS_H_ */
diff --git a/sys/compat/linsysfs/linsysfs.c b/sys/compat/linsysfs/linsysfs.c
--- a/sys/compat/linsysfs/linsysfs.c
+++ b/sys/compat/linsysfs/linsysfs.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2006 IronPort Systems
* All rights reserved.
+ * Copyright (c) 2023 Dmitry Chagin <dchagin@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,8 +34,10 @@
#include <sys/systm.h>
#include <sys/ctype.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mount.h>
+#include <sys/mutex.h>
#include <sys/sbuf.h>
#include <sys/smp.h>
#include <sys/socket.h>
@@ -53,20 +56,102 @@
#include <compat/linux/linux_util.h>
#include <fs/pseudofs/pseudofs.h>
-struct scsi_host_queue {
- TAILQ_ENTRY(scsi_host_queue) scsi_host_next;
- char *path;
- char *name;
+#include <compat/linsysfs/linsysfs.h>
+
+static MALLOC_DEFINE(M_LINSYSFS, "linsysfs", "linsysfs");
+
+struct pci_nodes_queue {
+ TAILQ_ENTRY(pci_nodes_queue) pci_nodes_next;
+ device_t dev;
+ struct pfs_node *node;;
};
+TAILQ_HEAD(,pci_nodes_queue) pci_nodes_q;
-TAILQ_HEAD(,scsi_host_queue) scsi_host_q;
+/* Mutex for pci_nodes_queue. */
+static struct mtx pci_nodes_mtx;
+MTX_SYSINIT(pci_nodes_mtx, &pci_nodes_mtx, "linsysfs", MTX_DEF);
-static int host_number = 0;
+/*
+ * Create pci device node.
+ */
+static struct pfs_node *
+linsysfs_create_pcidev_node(struct pfs_node *dir, struct pci_devinfo *dinfo,
+ pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy, int flags,
+ device_t dev)
+{
+ char device[PCI_MAXNAMELEN + 1];
+ struct pci_nodes_queue *nq;
+ struct pfs_node *node;
+
+ nq = malloc(sizeof(*nq), M_LINSYSFS, M_WAITOK);
+
+ sprintf(device, "0000:%02x:%02x.%x",
+ dinfo->cfg.bus,
+ dinfo->cfg.slot,
+ dinfo->cfg.func);
+ node = pfs_create_dir(dir, device, attr, vis, destroy, flags);
+ node->pn_data = dev;
+ nq->node = node;
+ nq->dev= dev;
+ mtx_lock(&pci_nodes_mtx);
+ TAILQ_INSERT_TAIL(&pci_nodes_q, nq, pci_nodes_next);
+ mtx_unlock(&pci_nodes_mtx);
+ return (node);
+}
-static int
-atoi(const char *str)
+/*
+ * Locate a node by dev.
+ */
+struct pfs_node *
+linsysfs_find_pcinode(device_t dev)
{
- return (int)strtol(str, (char **)NULL, 10);
+ struct pci_nodes_queue *nq, *nq_tmp;
+
+ mtx_lock(&pci_nodes_mtx);
+ TAILQ_FOREACH_SAFE(nq, &pci_nodes_q, pci_nodes_next, nq_tmp) {
+ if (nq->dev == dev) {
+ mtx_unlock(&pci_nodes_mtx);
+ return (nq->node);
+ }
+ }
+ mtx_unlock(&pci_nodes_mtx);
+ return (NULL);
+}
+
+struct pfs_node *
+linsysfs_create_dir(struct pfs_node *parent, const char *name,
+ pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy)
+{
+ struct pfs_node *node;
+
+ if (parent == NULL)
+ return (NULL);
+ node = pfs_create_dir(parent, name, attr, vis, destroy, 0);
+ return (node);
+}
+
+struct pfs_node *
+linsysfs_create_file(struct pfs_node *parent, const char *name,
+ pfs_fill_t fill, pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
+ int flags, void *data)
+{
+ struct pfs_node *node;
+
+ node = pfs_create_file(parent, name, fill, attr, vis, destroy, flags);
+ node->pn_data = data;
+ return (node);
+}
+
+struct pfs_node *
+linsysfs_create_link(struct pfs_node *parent, const char *name,
+ pfs_fill_t fill, pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
+ int flags, void *data)
+{
+ struct pfs_node *node;
+
+ node = pfs_create_link(parent, name, fill, attr, vis, destroy, flags);
+ node->pn_data = data;
+ return (node);
}
static int
@@ -215,22 +300,14 @@
static int
linsysfs_scsiname(PFS_FILL_ARGS)
{
- struct scsi_host_queue *scsi_host;
- int index;
+ device_t dev = pn->pn_data;
+ char *name;
- if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
- index = atoi(&pn->pn_parent->pn_name[4]);
- } else {
- sbuf_printf(sb, "unknown\n");
- return (0);
- }
- TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
- if (index-- == 0) {
- sbuf_printf(sb, "%s\n", scsi_host->name);
- return (0);
- }
- }
- sbuf_printf(sb, "unknown\n");
+ name = linux_driver_get_name_dev(dev);
+ if (name != NULL)
+ sbuf_printf(sb, "%s", name);
+ else
+ sbuf_printf(sb, "%s", device_get_nameunit(dev));
return (0);
}
@@ -240,26 +317,16 @@
static int
linsysfs_link_scsi_host(PFS_FILL_ARGS)
{
- struct scsi_host_queue *scsi_host;
- int index;
+ struct pfs_node *node = pn->pn_data;
+ char *path;
- if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
- index = atoi(&pn->pn_parent->pn_name[4]);
- } else {
- sbuf_printf(sb, "unknown\n");
- return (0);
- }
- TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
- if (index-- == 0) {
- sbuf_printf(sb, "../../../devices%s", scsi_host->path);
- return(0);
- }
- }
- sbuf_printf(sb, "unknown\n");
+ path = linsysfs_full_pfs_path(node);
+ sbuf_printf(sb, "../../../%s", path);
+ free(path, M_TEMP);
return (0);
}
-static int
+int
linsysfs_fill_data(PFS_FILL_ARGS)
{
sbuf_printf(sb, "%s", (char *)pn->pn_data);
@@ -346,25 +413,8 @@
return (0);
}
-/*
- * Filler function for drm uevent file
- */
-static int
-linsysfs_fill_uevent_drm(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/card%d\nDEVTYPE=dri_minor\n",
- unit, unit);
- return (0);
-}
-
-static char *
-get_full_pfs_path(struct pfs_node *cur)
+char *
+linsysfs_full_pfs_path(const struct pfs_node *cur)
{
char *temp, *path;
@@ -383,183 +433,6 @@
return (path);
}
-/*
- * Filler function for symlink from drm char device to PCI device
- */
-static int
-linsysfs_fill_vgapci(PFS_FILL_ARGS)
-{
- char *path;
-
- path = get_full_pfs_path((struct pfs_node*)pn->pn_data);
- sbuf_printf(sb, "../../../%s", path);
- free(path, M_TEMP);
- return (0);
-}
-
-#undef PCI_DEV
-#define PCI_DEV "pci"
-#define DRMN_DEV "drmn"
-static int
-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;
- int i, nchildren, error;
- device_t *children, parent;
- devclass_t devclass;
- const char *name = NULL;
- struct pci_devinfo *dinfo;
- char *device, *host, *new_path, *devname;
-
- new_path = path;
- devname = malloc(16, M_TEMP, M_WAITOK);
-
- parent = device_get_parent(dev);
- if (parent) {
- devclass = device_get_devclass(parent);
- if (devclass != NULL)
- name = devclass_get_name(devclass);
- if (name && strcmp(name, PCI_DEV) == 0) {
- dinfo = device_get_ivars(dev);
- if (dinfo) {
- device = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
- new_path = malloc(MAXPATHLEN, M_TEMP,
- M_WAITOK);
- new_path[0] = '\000';
- strcpy(new_path, path);
- host = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
- device[0] = '\000';
- sprintf(device, "%s:%02x:%02x.%x",
- prefix,
- dinfo->cfg.bus,
- dinfo->cfg.slot,
- dinfo->cfg.func);
- strcat(new_path, "/");
- strcat(new_path, device);
- dir = pfs_create_dir(dir, device,
- NULL, NULL, NULL, 0);
- cur_file = pfs_create_file(dir, "vendor",
- &linsysfs_fill_vendor, NULL, NULL, NULL,
- PFS_RD);
- cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir, "device",
- &linsysfs_fill_device, NULL, NULL, NULL,
- PFS_RD);
- cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir,
- "subsystem_vendor",
- &linsysfs_fill_subvendor, NULL, NULL, NULL,
- PFS_RD);
- cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir,
- "subsystem_device",
- &linsysfs_fill_subdevice, NULL, NULL, NULL,
- PFS_RD);
- cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir, "revision",
- &linsysfs_fill_revid, NULL, NULL, NULL,
- PFS_RD);
- cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir, "config",
- &linsysfs_fill_config, NULL, NULL, NULL,
- PFS_RD);
- cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir, "uevent",
- &linsysfs_fill_uevent_pci, NULL, NULL,
- NULL, PFS_RD);
- cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_link(dir, "subsystem",
- &linsysfs_fill_data, NULL, NULL, NULL, 0);
- /* libdrm just checks that the link ends in "/pci" */
- cur_file->pn_data = "/sys/bus/pci";
-
- if (dinfo->cfg.baseclass == PCIC_STORAGE) {
- /* DJA only make this if needed */
- sprintf(host, "host%d", host_number++);
- strcat(new_path, "/");
- strcat(new_path, host);
- pfs_create_dir(dir, host,
- NULL, NULL, NULL, 0);
- scsi_host = malloc(sizeof(
- struct scsi_host_queue),
- M_DEVBUF, M_NOWAIT);
- scsi_host->path = malloc(
- strlen(new_path) + 1,
- M_DEVBUF, M_NOWAIT);
- scsi_host->path[0] = '\000';
- bcopy(new_path, scsi_host->path,
- strlen(new_path) + 1);
- scsi_host->name = "unknown";
-
- sub_dir = pfs_create_dir(scsi, host,
- NULL, NULL, NULL, 0);
- pfs_create_link(sub_dir, "device",
- &linsysfs_link_scsi_host,
- NULL, NULL, NULL, 0);
- pfs_create_file(sub_dir, "proc_name",
- &linsysfs_scsiname,
- NULL, NULL, NULL, PFS_RD);
- scsi_host->name
- = linux_driver_get_name_dev(dev);
- TAILQ_INSERT_TAIL(&scsi_host_q,
- scsi_host, scsi_host_next);
- }
- free(device, M_TEMP);
- free(host, M_TEMP);
- }
- }
-
- devclass = device_get_devclass(dev);
- if (devclass != NULL)
- name = devclass_get_name(devclass);
- else
- name = NULL;
- if (name != NULL && strcmp(name, DRMN_DEV) == 0 &&
- device_get_unit(dev) >= 0) {
- dinfo = device_get_ivars(parent);
- if (dinfo != NULL && dinfo->cfg.baseclass == PCIC_DISPLAY) {
- pfs_create_dir(dir, "drm", NULL, NULL, NULL, 0);
- sprintf(devname, "226:%d",
- device_get_unit(dev));
- sub_dir = pfs_create_dir(chardev,
- devname, NULL, NULL, NULL, 0);
- cur_file = pfs_create_link(sub_dir,
- "device", &linsysfs_fill_vgapci, NULL,
- NULL, NULL, PFS_RD);
- cur_file->pn_data = (void*)dir;
- cur_file = pfs_create_file(sub_dir,
- "uevent", &linsysfs_fill_uevent_drm, NULL,
- NULL, NULL, PFS_RD);
- cur_file->pn_data = (void*)dev;
- sprintf(devname, "card%d",
- device_get_unit(dev));
- sub_dir = pfs_create_dir(drm,
- devname, NULL, NULL, NULL, 0);
- cur_file = pfs_create_link(sub_dir,
- "device", &linsysfs_fill_vgapci, NULL,
- NULL, NULL, PFS_RD);
- cur_file->pn_data = (void*)dir;
- }
- }
- }
-
- error = device_get_children(dev, &children, &nchildren);
- if (error == 0) {
- for (i = 0; i < nchildren; i++)
- if (children[i])
- linsysfs_run_bus(children[i], dir, scsi,
- chardev, drm, new_path, prefix);
- free(children, M_TEMP);
- }
- if (new_path != path)
- free(new_path, M_TEMP);
- free(devname, M_TEMP);
-
- return (1);
-}
-
/*
* Filler function for sys/devices/system/cpu/{online,possible,present}
*/
@@ -609,6 +482,143 @@
free(name, M_TEMP);
}
+#undef PCI_DEV
+#define PCI_DEV "pci"
+#define DRMN_DEV "drmn"
+/*
+ * Filler callback for sys/devices/pci0000:00.
+ */
+static struct pfs_node *
+linsysfs_pcibus_cb(device_t parent, device_t dev, struct pfs_node *pci,
+ struct pfs_node *dir)
+{
+ struct pci_devinfo *dinfo;
+ const char *classname;
+ devclass_t dc;
+
+ dinfo = NULL;
+ classname = NULL;
+ dc = device_get_devclass(parent);
+ if (dc != NULL)
+ classname = devclass_get_name(dc);
+ if (strcmp(classname, PCI_DEV) == 0)
+ dinfo = device_get_ivars(dev);
+
+ /* PCI tree. */
+ if (dinfo != NULL) {
+ pci = linsysfs_create_pcidev_node(pci, dinfo,
+ NULL, NULL, NULL, 0, dev);
+ linsysfs_create_file(pci, "vendor",
+ &linsysfs_fill_vendor, NULL, NULL, NULL, PFS_RD, dev);
+ linsysfs_create_file(pci, "device",
+ &linsysfs_fill_device, NULL, NULL, NULL, PFS_RD, dev);
+ linsysfs_create_file(pci, "subsystem_vendor",
+ &linsysfs_fill_subvendor, NULL, NULL, NULL, PFS_RD, dev);
+ linsysfs_create_file(pci, "subsystem_device",
+ &linsysfs_fill_subdevice, NULL, NULL, NULL, PFS_RD, dev);
+ linsysfs_create_file(pci, "revision",
+ &linsysfs_fill_revid, NULL, NULL, NULL, PFS_RD, dev);
+ linsysfs_create_file(pci, "config",
+ &linsysfs_fill_config, NULL, NULL, NULL, PFS_RD, dev);
+ linsysfs_create_file(pci, "uevent",
+ &linsysfs_fill_uevent_pci, NULL, NULL, NULL, PFS_RD, dev);
+ linsysfs_create_link(pci, "subsystem",
+ &linsysfs_fill_data, NULL, NULL, NULL, 0, "/sys/bus/pci");
+ /* TODO: libdrm just checks that the link ends in "/pci" */
+ }
+ /* vgapci/drmn childrens. */
+ if (strcmp(classname, DRMN_DEV) == 0)
+ linsysfs_bus_drm(pci, dir, dev);
+ return (pci);
+}
+
+/*
+ * Filler callback for scsi in sys/devices/pci0000:00.
+ */
+static struct pfs_node *
+linsysfs_scsi_cb(device_t parent, device_t dev, struct pfs_node *pci,
+ struct pfs_node *scsi)
+{
+ char host[PCI_MAXNAMELEN + 1];
+ struct pci_devinfo *dinfo;
+ const char *classname;
+ struct pfs_node *pdir, *sdir;
+ devclass_t dc;
+
+ dinfo = NULL;
+ classname = NULL;
+ dc = device_get_devclass(parent);
+ if (dc != NULL)
+ classname = devclass_get_name(dc);
+ if (strcmp(classname, PCI_DEV) == 0)
+ dinfo = device_get_ivars(dev);
+
+ if (dinfo != NULL &&
+ dinfo->cfg.baseclass == PCIC_STORAGE) {
+ /* DJA only make this if needed */
+ pdir = linsysfs_find_pcinode(dev);
+ KASSERT(pdir != NULL, ("Inconsistent dev %p node", dev));
+ if (pdir == NULL)
+ return (pci);
+ host[0] = '\000';
+ snprintf(host, sizeof(host), "host%d",
+ device_get_unit(dev));
+ sdir = linsysfs_create_dir(scsi, host, NULL, NULL, NULL);
+ pdir = linsysfs_create_dir(pdir, host, NULL, NULL, NULL);
+ linsysfs_create_link(sdir, "device",
+ &linsysfs_link_scsi_host, NULL, NULL, NULL, PFS_RD, pdir);
+ linsysfs_create_file(sdir, "proc_name",
+ &linsysfs_scsiname, NULL, NULL, NULL, PFS_RD, dev);
+ }
+ return (pci);
+}
+
+/*
+ * Traverse the device tree.
+ */
+static int
+linsysfs_bus_foreach(device_t dev, linsysfs_bus_cb_t cb,
+ struct pfs_node *pci, struct pfs_node *dir)
+{
+ device_t *ch, parent;
+ int n, count, error;
+
+ parent = device_get_parent(dev);
+ if (parent != NULL)
+ pci = (*cb)(parent, dev, pci, dir);
+ error = device_get_children(dev, &ch, &count);
+ if (error != 0)
+ return (error);
+ for (n = 0; n < count; n++) {
+ error = linsysfs_bus_foreach(ch[n], cb, pci, dir);
+ if (error != 0)
+ break;
+ }
+ free(ch, M_TEMP);
+ return (error);
+}
+
+/*
+ * Scan device tree starting from root.
+ */
+static int
+linsysfs_bus_scan(const char *root, linsysfs_bus_cb_t cb,
+ struct pfs_node *pci, struct pfs_node *dir)
+{
+ devclass_t dc;
+ device_t dev;
+ int error;
+
+ bus_topo_lock();
+ dc = devclass_find(root);
+ KASSERT(dc != NULL, ("Invalid %s class", root));
+ dev = devclass_get_device(dc, 0);
+ KASSERT(dev != NULL, ("Scan of %s failed", root));
+ error = linsysfs_bus_foreach(dev, cb, pci, dir);
+ bus_topo_unlock();
+ return (error);
+}
+
/*
* Constructor
*/
@@ -618,17 +628,14 @@
struct pfs_node *root;
struct pfs_node *class;
struct pfs_node *dir, *sys, *cpu;
- struct pfs_node *drm;
struct pfs_node *pci;
struct pfs_node *scsi;
struct pfs_node *net;
struct pfs_node *devdir, *chardev;
struct pfs_node *kernel;
- devclass_t devclass;
- device_t dev;
-
- TAILQ_INIT(&scsi_host_q);
+ int error;
+ TAILQ_INIT(&pci_nodes_q);
root = pi->pi_root;
/* /sys/bus/... */
@@ -637,7 +644,7 @@
/* /sys/class/... */
class = pfs_create_dir(root, "class", NULL, NULL, NULL, 0);
scsi = pfs_create_dir(class, "scsi_host", NULL, NULL, NULL, 0);
- drm = pfs_create_dir(class, "drm", NULL, NULL, NULL, 0);
+ pfs_create_dir(class, "drm", NULL, NULL, NULL, 0);
pfs_create_dir(class, "power_supply", NULL, NULL, NULL, 0);
/* /sys/class/net/.. */
@@ -651,14 +658,6 @@
dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0);
pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0);
- devclass = devclass_find("root");
- if (devclass == NULL) {
- return (0);
- }
-
- dev = devclass_get_device(devclass, 0);
- linsysfs_run_bus(dev, pci, scsi, chardev, drm, "/pci0000:00", "0000");
-
/* /sys/devices/system */
sys = pfs_create_dir(dir, "system", NULL, NULL, NULL, 0);
@@ -683,7 +682,12 @@
/* /sys/subsystem/... */
dir = pfs_create_dir(root, "subsystem", NULL, NULL, NULL, 0);
- return (0);
+ /* /sys/devices/pci0000:00 */
+ error = linsysfs_bus_scan("root", linsysfs_pcibus_cb, pci, chardev);
+ if (error == 0)
+ error = linsysfs_bus_scan("root", linsysfs_scsi_cb, pci, scsi);
+
+ return (error);
}
/*
@@ -692,14 +696,14 @@
static int
linsysfs_uninit(PFS_INIT_ARGS)
{
- struct scsi_host_queue *scsi_host, *scsi_host_tmp;
+ struct pci_nodes_queue *nq, *nq_tmp;
- TAILQ_FOREACH_SAFE(scsi_host, &scsi_host_q, scsi_host_next,
- scsi_host_tmp) {
- TAILQ_REMOVE(&scsi_host_q, scsi_host, scsi_host_next);
- free(scsi_host->path, M_TEMP);
- free(scsi_host, M_TEMP);
+ mtx_lock(&pci_nodes_mtx);
+ TAILQ_FOREACH_SAFE(nq, &pci_nodes_q, pci_nodes_next, nq_tmp) {
+ TAILQ_REMOVE(&pci_nodes_q, nq, pci_nodes_next);
+ free(nq, M_LINSYSFS);
}
+ mtx_unlock(&pci_nodes_mtx);
return (0);
}
diff --git a/sys/compat/linsysfs/linsysfs_drm.c b/sys/compat/linsysfs/linsysfs_drm.c
new file mode 100644
--- /dev/null
+++ b/sys/compat/linsysfs/linsysfs_drm.c
@@ -0,0 +1,146 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2023 Dmitry Chagin <dchagin@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sbuf.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <fs/pseudofs/pseudofs.h>
+
+#include <compat/linsysfs/linsysfs.h>
+#include <linux/device.h>
+
+/*
+ * Filler function for drm uevent file.
+ */
+static int
+linsysfs_drm_fill_uevent(PFS_FILL_ARGS)
+{
+ device_t bsddev = pn->pn_data;
+ struct device *dev;
+
+ /*
+ * XXX. bsddev can die, drm-kmod will delete it on unregister path.
+ */
+ dev = device_get_softc(bsddev);
+ if (dev == NULL)
+ return (-1);
+ return (sbuf_printf(sb,
+ "MAJOR=%d\nMINOR=%d\nDEVNAME=dri/%s\nDEVTYPE=drm_minor\n",
+ MAJOR(dev->devt), MINOR(dev->devt), dev_name(dev)));
+}
+
+/*
+ * Filler function for drm dev file.
+ */
+static int
+linsysfs_drm_fill_dev(PFS_FILL_ARGS)
+{
+ device_t bsddev = pn->pn_data;
+ struct device *dev;
+
+ /*
+ * XXX. bsddev can die, drm-kmod will delete it on unregister path.
+ */
+ dev = device_get_softc(bsddev);
+ if (dev == NULL)
+ return (-1);
+ return (sbuf_printf(sb, "%d:%d", MAJOR(dev->devt), MINOR(dev->devt)));
+}
+
+/*
+ * Filler function for symlink from drm/device to PCI device.
+ */
+static int
+linsysfs_drm_fill_vgapci(PFS_FILL_ARGS)
+{
+ struct pfs_node *node = pn->pn_data;
+ char *path;
+
+ path = linsysfs_full_pfs_path(node);
+ sbuf_printf(sb, "../../../../../%s", path);
+ free(path, M_TEMP);
+ return (0);
+}
+
+/*
+ * Filler function for symlink from dev/char to drm device.
+ */
+static int
+linsysfs_drm_fill_charlink(PFS_FILL_ARGS)
+{
+ struct pfs_node *node = pn->pn_data;
+ char *path;
+
+ path = linsysfs_full_pfs_path(node);
+ sbuf_printf(sb, "../../%s", path);
+ free(path, M_TEMP);
+ return (0);
+}
+
+/*
+ * Filler function for drm childrens.
+ */
+#define DRM_DEV "drm"
+void
+linsysfs_bus_drm(struct pfs_node *devdir, struct pfs_node *chardir,
+ device_t bsddev)
+{
+ const char *classname;
+ struct pfs_node *dir;
+ struct device *dev;
+ char charlink[16]; /* Major:Minor */
+
+ classname = devclass_get_name(device_get_devclass(bsddev));
+
+ if (strcmp(classname, DRM_DEV) == 0 &&
+ (dev = device_get_softc(bsddev)) != NULL) {
+ dir = pfs_find_node(devdir, DRM_DEV);
+ if (dir == NULL)
+ dir = linsysfs_create_dir(devdir, DRM_DEV,
+ NULL, NULL, NULL);
+ dir = linsysfs_create_dir(dir, dev_name(dev), NULL, NULL, NULL);
+ linsysfs_create_file(dir, "uevent",
+ &linsysfs_drm_fill_uevent, NULL, NULL, NULL, PFS_RD, bsddev);
+ linsysfs_create_link(dir, "device",
+ &linsysfs_drm_fill_vgapci, NULL, NULL, NULL, PFS_RD, devdir);
+ linsysfs_create_link(dir, "subsystem",
+ &linsysfs_fill_data, NULL, NULL, NULL, PFS_RD,
+ "/sys/class/drm");
+ snprintf(charlink, sizeof(charlink), "%d:%d",
+ MAJOR(dev->devt), MINOR(dev->devt));
+ linsysfs_create_link(chardir, charlink,
+ &linsysfs_drm_fill_charlink, NULL, NULL, NULL, PFS_RD, dir);
+ linsysfs_create_file(dir, "dev",
+ &linsysfs_drm_fill_dev, NULL, NULL, NULL, PFS_RD, bsddev);
+ linsysfs_create_dir(dir, "power", NULL, NULL, NULL);
+ }
+}
diff --git a/sys/modules/linsysfs/Makefile b/sys/modules/linsysfs/Makefile
--- a/sys/modules/linsysfs/Makefile
+++ b/sys/modules/linsysfs/Makefile
@@ -5,7 +5,9 @@
KMOD= linsysfs
SRCS= vnode_if.h \
device_if.h bus_if.h pci_if.h \
- linsysfs.c
+ linsysfs.c linsysfs_drm.c
+
+CFLAGS+= ${LINUXKPI_INCLUDES}
.if !defined(KERNBUILDDIR)
.warning Building Linuxulator outside of a kernel does not make sense

File Metadata

Mime Type
text/plain
Expires
Wed, Oct 22, 3:06 PM (5 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24058856
Default Alt Text
D38545.diff (24 KB)

Event Timeline