1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2006 IronPort Systems
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/ctype.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
37#include <sys/mount.h>
38#include <sys/sbuf.h>
39#include <sys/smp.h>
40#include <sys/socket.h>
41#include <sys/bus.h>
42#include <sys/pciio.h>
43
44#include <dev/pci/pcivar.h>
45#include <dev/pci/pcireg.h>
46
47#include <net/if.h>
48#include <net/if_var.h>
49#include <net/if_dl.h>
50
51#include <compat/linux/linux.h>
52#include <compat/linux/linux_common.h>
53#include <compat/linux/linux_util.h>
54#include <fs/pseudofs/pseudofs.h>
55
56struct scsi_host_queue {
57	TAILQ_ENTRY(scsi_host_queue) scsi_host_next;
58	char *path;
59	char *name;
60};
61
62TAILQ_HEAD(,scsi_host_queue) scsi_host_q;
63
64static int host_number = 0;
65
66static int
67atoi(const char *str)
68{
69	return (int)strtol(str, (char **)NULL, 10);
70}
71
72static int
73linsysfs_ifnet_addr(PFS_FILL_ARGS)
74{
75	struct l_sockaddr lsa;
76	struct ifnet *ifp;
77
78	ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
79	if (ifp == NULL)
80		return (ENOENT);
81	if (linux_ifhwaddr(ifp, &lsa) != 0)
82		return (ENOENT);
83	sbuf_printf(sb, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
84	    lsa.sa_data[0], lsa.sa_data[1], lsa.sa_data[2],
85	    lsa.sa_data[3], lsa.sa_data[4], lsa.sa_data[5]);
86	return (0);
87}
88
89static int
90linsysfs_ifnet_addrlen(PFS_FILL_ARGS)
91{
92
93	sbuf_printf(sb, "%d\n", LINUX_IFHWADDRLEN);
94	return (0);
95}
96
97static int
98linsysfs_ifnet_flags(PFS_FILL_ARGS)
99{
100	struct ifnet *ifp;
101	unsigned short flags;
102
103	ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
104	if (ifp == NULL)
105		return (ENOENT);
106	linux_ifflags(ifp, &flags);
107	sbuf_printf(sb, "0x%x\n", flags);
108	return (0);
109}
110
111static int
112linsysfs_ifnet_ifindex(PFS_FILL_ARGS)
113{
114	struct ifnet *ifp;
115
116	ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
117	if (ifp == NULL)
118		return (ENOENT);
119	sbuf_printf(sb, "%u\n", ifp->if_index);
120	return (0);
121}
122
123static int
124linsysfs_ifnet_mtu(PFS_FILL_ARGS)
125{
126	struct ifnet *ifp;
127
128	ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
129	if (ifp == NULL)
130		return (ENOENT);
131	sbuf_printf(sb, "%u\n", ifp->if_mtu);
132	return (0);
133}
134
135static int
136linsysfs_ifnet_tx_queue_len(PFS_FILL_ARGS)
137{
138
139	/* XXX */
140	sbuf_printf(sb, "1000\n");
141	return (0);
142}
143
144static int
145linsysfs_ifnet_type(PFS_FILL_ARGS)
146{
147	struct l_sockaddr lsa;
148	struct ifnet *ifp;
149
150	ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
151	if (ifp == NULL)
152		return (ENOENT);
153	if (linux_ifhwaddr(ifp, &lsa) != 0)
154		return (ENOENT);
155	sbuf_printf(sb, "%d\n", lsa.sa_family);
156	return (0);
157}
158
159static void
160linsysfs_listnics(struct pfs_node *dir)
161{
162	struct pfs_node *nic;
163	struct pfs_node *lo;
164
165	nic = pfs_create_dir(dir, "eth0", NULL, NULL, NULL, 0);
166
167	pfs_create_file(nic, "address", &linsysfs_ifnet_addr,
168	    NULL, NULL, NULL, PFS_RD);
169
170	pfs_create_file(nic, "addr_len", &linsysfs_ifnet_addrlen,
171	    NULL, NULL, NULL, PFS_RD);
172
173	pfs_create_file(nic, "flags", &linsysfs_ifnet_flags,
174	    NULL, NULL, NULL, PFS_RD);
175
176	pfs_create_file(nic, "ifindex", &linsysfs_ifnet_ifindex,
177	    NULL, NULL, NULL, PFS_RD);
178
179	pfs_create_file(nic, "mtu", &linsysfs_ifnet_mtu,
180	    NULL, NULL, NULL, PFS_RD);
181
182	pfs_create_file(nic, "tx_queue_len", &linsysfs_ifnet_tx_queue_len,
183	    NULL, NULL, NULL, PFS_RD);
184
185	pfs_create_file(nic, "type", &linsysfs_ifnet_type,
186	    NULL, NULL, NULL, PFS_RD);
187
188	lo = pfs_create_dir(dir, "lo", NULL, NULL, NULL, 0);
189
190	pfs_create_file(lo, "address", &linsysfs_ifnet_addr,
191	    NULL, NULL, NULL, PFS_RD);
192
193	pfs_create_file(lo, "addr_len", &linsysfs_ifnet_addrlen,
194	    NULL, NULL, NULL, PFS_RD);
195
196	pfs_create_file(lo, "flags", &linsysfs_ifnet_flags,
197	    NULL, NULL, NULL, PFS_RD);
198
199	pfs_create_file(lo, "ifindex", &linsysfs_ifnet_ifindex,
200	    NULL, NULL, NULL, PFS_RD);
201
202	pfs_create_file(lo, "mtu", &linsysfs_ifnet_mtu,
203	    NULL, NULL, NULL, PFS_RD);
204
205	pfs_create_file(lo, "tx_queue_len", &linsysfs_ifnet_tx_queue_len,
206	    NULL, NULL, NULL, PFS_RD);
207
208	pfs_create_file(lo, "type", &linsysfs_ifnet_type,
209	    NULL, NULL, NULL, PFS_RD);
210}
211
212/*
213 * Filler function for proc_name
214 */
215static int
216linsysfs_scsiname(PFS_FILL_ARGS)
217{
218	struct scsi_host_queue *scsi_host;
219	int index;
220
221	if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
222		index = atoi(&pn->pn_parent->pn_name[4]);
223	} else {
224		sbuf_printf(sb, "unknown\n");
225		return (0);
226	}
227	TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
228		if (index-- == 0) {
229			sbuf_printf(sb, "%s\n", scsi_host->name);
230			return (0);
231		}
232	}
233	sbuf_printf(sb, "unknown\n");
234	return (0);
235}
236
237/*
238 * Filler function for device sym-link
239 */
240static int
241linsysfs_link_scsi_host(PFS_FILL_ARGS)
242{
243	struct scsi_host_queue *scsi_host;
244	int index;
245
246	if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
247		index = atoi(&pn->pn_parent->pn_name[4]);
248	} else {
249		sbuf_printf(sb, "unknown\n");
250		return (0);
251	}
252	TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
253		if (index-- == 0) {
254			sbuf_printf(sb, "../../../devices%s", scsi_host->path);
255			return(0);
256		}
257	}
258	sbuf_printf(sb, "unknown\n");
259	return (0);
260}
261
262static int
263linsysfs_fill_data(PFS_FILL_ARGS)
264{
265	sbuf_printf(sb, "%s", (char *)pn->pn_data);
266	return (0);
267}
268
269static int
270linsysfs_fill_vendor(PFS_FILL_ARGS)
271{
272	sbuf_printf(sb, "0x%04x\n", pci_get_vendor((device_t)pn->pn_data));
273	return (0);
274}
275
276static int
277linsysfs_fill_device(PFS_FILL_ARGS)
278{
279	sbuf_printf(sb, "0x%04x\n", pci_get_device((device_t)pn->pn_data));
280	return (0);
281}
282
283static int
284linsysfs_fill_subvendor(PFS_FILL_ARGS)
285{
286	sbuf_printf(sb, "0x%04x\n", pci_get_subvendor((device_t)pn->pn_data));
287	return (0);
288}
289
290static int
291linsysfs_fill_subdevice(PFS_FILL_ARGS)
292{
293	sbuf_printf(sb, "0x%04x\n", pci_get_subdevice((device_t)pn->pn_data));
294	return (0);
295}
296
297static int
298linsysfs_fill_revid(PFS_FILL_ARGS)
299{
300	sbuf_printf(sb, "0x%x\n", pci_get_revid((device_t)pn->pn_data));
301	return (0);
302}
303
304static int
305linsysfs_fill_config(PFS_FILL_ARGS)
306{
307	uint8_t config[48];
308	device_t dev;
309	uint32_t reg;
310
311	dev = (device_t)pn->pn_data;
312	bzero(config, sizeof(config));
313	reg = pci_get_vendor(dev);
314	config[0] = reg;
315	config[1] = reg >> 8;
316	reg = pci_get_device(dev);
317	config[2] = reg;
318	config[3] = reg >> 8;
319	reg = pci_get_revid(dev);
320	config[8] = reg;
321	reg = pci_get_subvendor(dev);
322	config[44] = reg;
323	config[45] = reg >> 8;
324	reg = pci_get_subdevice(dev);
325	config[46] = reg;
326	config[47] = reg >> 8;
327	sbuf_bcat(sb, config, sizeof(config));
328	return (0);
329}
330
331/*
332 * Filler function for PCI uevent file
333 */
334static int
335linsysfs_fill_uevent_pci(PFS_FILL_ARGS)
336{
337	device_t dev;
338
339	dev = (device_t)pn->pn_data;
340	sbuf_printf(sb, "DRIVER=%s\nPCI_CLASS=%X\nPCI_ID=%04X:%04X\n"
341	    "PCI_SUBSYS_ID=%04X:%04X\nPCI_SLOT_NAME=%04d:%02x:%02x.%x\n",
342	    linux_driver_get_name_dev(dev), pci_get_class(dev),
343	    pci_get_vendor(dev), pci_get_device(dev), pci_get_subvendor(dev),
344	    pci_get_subdevice(dev), pci_get_domain(dev), pci_get_bus(dev),
345	    pci_get_slot(dev), pci_get_function(dev));
346	return (0);
347}
348
349/*
350 * Filler function for drm uevent file
351 */
352static int
353linsysfs_fill_uevent_drm(PFS_FILL_ARGS)
354{
355	device_t dev;
356	int unit;
357
358	dev = (device_t)pn->pn_data;
359	unit = device_get_unit(dev);
360	sbuf_printf(sb,
361	    "MAJOR=226\nMINOR=%d\nDEVNAME=dri/card%d\nDEVTYPE=dri_minor\n",
362	    unit, unit);
363	return (0);
364}
365
366static char *
367get_full_pfs_path(struct pfs_node *cur)
368{
369	char *temp, *path;
370
371	temp = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
372	path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
373	path[0] = '\0';
374
375	do {
376		snprintf(temp, MAXPATHLEN, "%s/%s", cur->pn_name, path);
377		strlcpy(path, temp, MAXPATHLEN);
378		cur = cur->pn_parent;
379	} while (cur->pn_parent != NULL);
380
381	path[strlen(path) - 1] = '\0'; /* remove extra slash */
382	free(temp, M_TEMP);
383	return (path);
384}
385
386/*
387 * Filler function for symlink from drm char device to PCI device
388 */
389static int
390linsysfs_fill_vgapci(PFS_FILL_ARGS)
391{
392	char *path;
393
394	path = get_full_pfs_path((struct pfs_node*)pn->pn_data);
395	sbuf_printf(sb, "../../../%s", path);
396	free(path, M_TEMP);
397	return (0);
398}
399
400#undef PCI_DEV
401#define PCI_DEV "pci"
402#define DRMN_DEV "drmn"
403static int
404linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi,
405    struct pfs_node *chardev, struct pfs_node *drm, char *path, char *prefix)
406{
407	struct scsi_host_queue *scsi_host;
408	struct pfs_node *sub_dir, *cur_file;
409	int i, nchildren, error;
410	device_t *children, parent;
411	devclass_t devclass;
412	const char *name = NULL;
413	struct pci_devinfo *dinfo;
414	char *device, *host, *new_path, *devname;
415
416	new_path = path;
417	devname = malloc(16, M_TEMP, M_WAITOK);
418
419	parent = device_get_parent(dev);
420	if (parent) {
421		devclass = device_get_devclass(parent);
422		if (devclass != NULL)
423			name = devclass_get_name(devclass);
424		if (name && strcmp(name, PCI_DEV) == 0) {
425			dinfo = device_get_ivars(dev);
426			if (dinfo) {
427				device = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
428				new_path = malloc(MAXPATHLEN, M_TEMP,
429				    M_WAITOK);
430				new_path[0] = '\000';
431				strcpy(new_path, path);
432				host = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
433				device[0] = '\000';
434				sprintf(device, "%s:%02x:%02x.%x",
435				    prefix,
436				    dinfo->cfg.bus,
437				    dinfo->cfg.slot,
438				    dinfo->cfg.func);
439				strcat(new_path, "/");
440				strcat(new_path, device);
441				dir = pfs_create_dir(dir, device,
442				    NULL, NULL, NULL, 0);
443				cur_file = pfs_create_file(dir, "vendor",
444				    &linsysfs_fill_vendor, NULL, NULL, NULL,
445				    PFS_RD);
446				cur_file->pn_data = (void*)dev;
447				cur_file = pfs_create_file(dir, "device",
448				    &linsysfs_fill_device, NULL, NULL, NULL,
449				    PFS_RD);
450				cur_file->pn_data = (void*)dev;
451				cur_file = pfs_create_file(dir,
452				    "subsystem_vendor",
453				    &linsysfs_fill_subvendor, NULL, NULL, NULL,
454				    PFS_RD);
455				cur_file->pn_data = (void*)dev;
456				cur_file = pfs_create_file(dir,
457				    "subsystem_device",
458				    &linsysfs_fill_subdevice, NULL, NULL, NULL,
459				    PFS_RD);
460				cur_file->pn_data = (void*)dev;
461				cur_file = pfs_create_file(dir, "revision",
462				    &linsysfs_fill_revid, NULL, NULL, NULL,
463				    PFS_RD);
464				cur_file->pn_data = (void*)dev;
465				cur_file = pfs_create_file(dir, "config",
466				    &linsysfs_fill_config, NULL, NULL, NULL,
467				    PFS_RD);
468				cur_file->pn_data = (void*)dev;
469				cur_file = pfs_create_file(dir, "uevent",
470				    &linsysfs_fill_uevent_pci, NULL, NULL,
471				    NULL, PFS_RD);
472				cur_file->pn_data = (void*)dev;
473				cur_file = pfs_create_link(dir, "subsystem",
474				    &linsysfs_fill_data, NULL, NULL, NULL, 0);
475				/* libdrm just checks that the link ends in "/pci" */
476				cur_file->pn_data = "/sys/bus/pci";
477
478				if (dinfo->cfg.baseclass == PCIC_STORAGE) {
479					/* DJA only make this if needed */
480					sprintf(host, "host%d", host_number++);
481					strcat(new_path, "/");
482					strcat(new_path, host);
483					pfs_create_dir(dir, host,
484					    NULL, NULL, NULL, 0);
485					scsi_host = malloc(sizeof(
486					    struct scsi_host_queue),
487					    M_DEVBUF, M_NOWAIT);
488					scsi_host->path = malloc(
489					    strlen(new_path) + 1,
490					    M_DEVBUF, M_NOWAIT);
491					scsi_host->path[0] = '\000';
492					bcopy(new_path, scsi_host->path,
493					    strlen(new_path) + 1);
494					scsi_host->name = "unknown";
495
496					sub_dir = pfs_create_dir(scsi, host,
497					    NULL, NULL, NULL, 0);
498					pfs_create_link(sub_dir, "device",
499					    &linsysfs_link_scsi_host,
500					    NULL, NULL, NULL, 0);
501					pfs_create_file(sub_dir, "proc_name",
502					    &linsysfs_scsiname,
503					    NULL, NULL, NULL, PFS_RD);
504					scsi_host->name
505					    = linux_driver_get_name_dev(dev);
506					TAILQ_INSERT_TAIL(&scsi_host_q,
507					    scsi_host, scsi_host_next);
508				}
509				free(device, M_TEMP);
510				free(host, M_TEMP);
511			}
512		}
513
514		devclass = device_get_devclass(dev);
515		if (devclass != NULL)
516			name = devclass_get_name(devclass);
517		else
518			name = NULL;
519		if (name != NULL && strcmp(name, DRMN_DEV) == 0 &&
520		    device_get_unit(dev) >= 0) {
521			dinfo = device_get_ivars(parent);
522			if (dinfo != NULL && dinfo->cfg.baseclass == PCIC_DISPLAY) {
523				pfs_create_dir(dir, "drm", NULL, NULL, NULL, 0);
524				sprintf(devname, "226:%d",
525				    device_get_unit(dev));
526				sub_dir = pfs_create_dir(chardev,
527				    devname, NULL, NULL, NULL, 0);
528				cur_file = pfs_create_link(sub_dir,
529				    "device", &linsysfs_fill_vgapci, NULL,
530				    NULL, NULL, PFS_RD);
531				cur_file->pn_data = (void*)dir;
532				cur_file = pfs_create_file(sub_dir,
533				    "uevent", &linsysfs_fill_uevent_drm, NULL,
534				    NULL, NULL, PFS_RD);
535				cur_file->pn_data = (void*)dev;
536				sprintf(devname, "card%d",
537				    device_get_unit(dev));
538				sub_dir = pfs_create_dir(drm,
539				    devname, NULL, NULL, NULL, 0);
540				cur_file = pfs_create_link(sub_dir,
541				    "device", &linsysfs_fill_vgapci, NULL,
542				    NULL, NULL, PFS_RD);
543				cur_file->pn_data = (void*)dir;
544			}
545		}
546	}
547
548	error = device_get_children(dev, &children, &nchildren);
549	if (error == 0) {
550		for (i = 0; i < nchildren; i++)
551			if (children[i])
552				linsysfs_run_bus(children[i], dir, scsi,
553				    chardev, drm, new_path, prefix);
554		free(children, M_TEMP);
555	}
556	if (new_path != path)
557		free(new_path, M_TEMP);
558	free(devname, M_TEMP);
559
560	return (1);
561}
562
563/*
564 * Filler function for sys/devices/system/cpu/{online,possible,present}
565 */
566static int
567linsysfs_cpuonline(PFS_FILL_ARGS)
568{
569
570	sbuf_printf(sb, "%d-%d\n", CPU_FIRST(), mp_maxid);
571	return (0);
572}
573
574/*
575 * Filler function for sys/devices/system/cpu/cpuX/online
576 */
577static int
578linsysfs_cpuxonline(PFS_FILL_ARGS)
579{
580
581	sbuf_printf(sb, "1\n");
582	return (0);
583}
584
585static void
586linsysfs_listcpus(struct pfs_node *dir)
587{
588	struct pfs_node *cpu;
589	char *name;
590	int i, count, len;
591
592	len = 1;
593	count = mp_maxcpus;
594	while (count > 10) {
595		count /= 10;
596		len++;
597	}
598	len += sizeof("cpu");
599	name = malloc(len, M_TEMP, M_WAITOK);
600
601	for (i = 0; i < mp_ncpus; ++i) {
602		/* /sys/devices/system/cpu/cpuX */
603		sprintf(name, "cpu%d", i);
604		cpu = pfs_create_dir(dir, name, NULL, NULL, NULL, 0);
605
606		pfs_create_file(cpu, "online", &linsysfs_cpuxonline,
607		    NULL, NULL, NULL, PFS_RD);
608	}
609	free(name, M_TEMP);
610}
611
612/*
613 * Constructor
614 */
615static int
616linsysfs_init(PFS_INIT_ARGS)
617{
618	struct pfs_node *root;
619	struct pfs_node *class;
620	struct pfs_node *dir, *sys, *cpu;
621	struct pfs_node *drm;
622	struct pfs_node *pci;
623	struct pfs_node *scsi;
624	struct pfs_node *net;
625	struct pfs_node *power_supply;
626	struct pfs_node *devdir, *chardev;
627	struct pfs_node *kernel;
628	struct pfs_node *debug;
629	devclass_t devclass;
630	device_t dev;
631
632	TAILQ_INIT(&scsi_host_q);
633
634	root = pi->pi_root;
635
636	/* /sys/class/... */
637	class = pfs_create_dir(root, "class", NULL, NULL, NULL, 0);
638	scsi = pfs_create_dir(class, "scsi_host", NULL, NULL, NULL, 0);
639	drm = pfs_create_dir(class, "drm", NULL, NULL, NULL, 0);
640	power_supply = pfs_create_dir(class, "power_supply", NULL, NULL, NULL, 0);
641
642	/* /sys/class/net/.. */
643	net = pfs_create_dir(class, "net", NULL, NULL, NULL, 0);
644
645	/* /sys/dev/... */
646	devdir = pfs_create_dir(root, "dev", NULL, NULL, NULL, 0);
647	chardev = pfs_create_dir(devdir, "char", NULL, NULL, NULL, 0);
648
649	/* /sys/devices/... */
650	dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0);
651	pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0);
652
653	devclass = devclass_find("root");
654	if (devclass == NULL) {
655		return (0);
656	}
657
658	dev = devclass_get_device(devclass, 0);
659	linsysfs_run_bus(dev, pci, scsi, chardev, drm, "/pci0000:00", "0000");
660
661	/* /sys/devices/system */
662	sys = pfs_create_dir(dir, "system", NULL, NULL, NULL, 0);
663
664	/* /sys/devices/system/cpu */
665	cpu = pfs_create_dir(sys, "cpu", NULL, NULL, NULL, 0);
666
667	pfs_create_file(cpu, "online", &linsysfs_cpuonline,
668	    NULL, NULL, NULL, PFS_RD);
669	pfs_create_file(cpu, "possible", &linsysfs_cpuonline,
670	    NULL, NULL, NULL, PFS_RD);
671	pfs_create_file(cpu, "present", &linsysfs_cpuonline,
672	    NULL, NULL, NULL, PFS_RD);
673
674	linsysfs_listcpus(cpu);
675	linsysfs_listnics(net);
676
677	/* /sys/kernel */
678	kernel = pfs_create_dir(root, "kernel", NULL, NULL, NULL, 0);
679	/* /sys/kernel/debug, mountpoint for lindebugfs. */
680	debug = pfs_create_dir(kernel, "debug", NULL, NULL, NULL, 0);
681
682	return (0);
683}
684
685/*
686 * Destructor
687 */
688static int
689linsysfs_uninit(PFS_INIT_ARGS)
690{
691	struct scsi_host_queue *scsi_host, *scsi_host_tmp;
692
693	TAILQ_FOREACH_SAFE(scsi_host, &scsi_host_q, scsi_host_next,
694	    scsi_host_tmp) {
695		TAILQ_REMOVE(&scsi_host_q, scsi_host, scsi_host_next);
696		free(scsi_host->path, M_TEMP);
697		free(scsi_host, M_TEMP);
698	}
699
700	return (0);
701}
702
703PSEUDOFS(linsysfs, 1, VFCF_JAIL);
704#if defined(__aarch64__) || defined(__amd64__)
705MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1);
706#else
707MODULE_DEPEND(linsysfs, linux, 1, 1, 1);
708#endif
709