]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/linsysfs/linsysfs.c
Implement pci_enable_msi() and pci_disable_msi() in the LinuxKPI.
[FreeBSD/FreeBSD.git] / sys / compat / linsysfs / linsysfs.c
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
56 struct scsi_host_queue {
57         TAILQ_ENTRY(scsi_host_queue) scsi_host_next;
58         char *path;
59         char *name;
60 };
61
62 TAILQ_HEAD(,scsi_host_queue) scsi_host_q;
63
64 static int host_number = 0;
65
66 static int
67 atoi(const char *str)
68 {
69         return (int)strtol(str, (char **)NULL, 10);
70 }
71
72 static int
73 linsysfs_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
89 static int
90 linsysfs_ifnet_addrlen(PFS_FILL_ARGS)
91 {
92
93         sbuf_printf(sb, "%d\n", LINUX_IFHWADDRLEN);
94         return (0);
95 }
96
97 static int
98 linsysfs_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
111 static int
112 linsysfs_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
123 static int
124 linsysfs_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
135 static int
136 linsysfs_ifnet_tx_queue_len(PFS_FILL_ARGS)
137 {
138
139         /* XXX */
140         sbuf_printf(sb, "1000\n");
141         return (0);
142 }
143
144 static int
145 linsysfs_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
159 static void
160 linsysfs_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  */
215 static int
216 linsysfs_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  */
240 static int
241 linsysfs_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
262 static int
263 linsysfs_fill_data(PFS_FILL_ARGS)
264 {
265         sbuf_printf(sb, "%s", (char *)pn->pn_data);
266         return (0);
267 }
268
269 static int
270 linsysfs_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
276 static int
277 linsysfs_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
283 static int
284 linsysfs_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
290 static int
291 linsysfs_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
297 static int
298 linsysfs_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
304 static int
305 linsysfs_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  */
334 static int
335 linsysfs_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  */
352 static int
353 linsysfs_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
366 static char *
367 get_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  */
389 static int
390 linsysfs_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"
403 static int
404 linsysfs_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                                 sprintf(devname, "226:%d",
524                                     device_get_unit(dev));
525                                 sub_dir = pfs_create_dir(chardev,
526                                     devname, NULL, NULL, NULL, 0);
527                                 cur_file = pfs_create_link(sub_dir,
528                                     "device", &linsysfs_fill_vgapci, NULL,
529                                     NULL, NULL, PFS_RD);
530                                 cur_file->pn_data = (void*)dir;
531                                 cur_file = pfs_create_file(sub_dir,
532                                     "uevent", &linsysfs_fill_uevent_drm, NULL,
533                                     NULL, NULL, PFS_RD);
534                                 cur_file->pn_data = (void*)dev;
535                                 sprintf(devname, "card%d",
536                                     device_get_unit(dev));
537                                 sub_dir = pfs_create_dir(drm,
538                                     devname, NULL, NULL, NULL, 0);
539                                 cur_file = pfs_create_link(sub_dir,
540                                     "device", &linsysfs_fill_vgapci, NULL,
541                                     NULL, NULL, PFS_RD);
542                                 cur_file->pn_data = (void*)dir;
543                         }
544                 }
545         }
546
547         error = device_get_children(dev, &children, &nchildren);
548         if (error == 0) {
549                 for (i = 0; i < nchildren; i++)
550                         if (children[i])
551                                 linsysfs_run_bus(children[i], dir, scsi,
552                                     chardev, drm, new_path, prefix);
553                 free(children, M_TEMP);
554         }
555         if (new_path != path)
556                 free(new_path, M_TEMP);
557         free(devname, M_TEMP);
558
559         return (1);
560 }
561
562 /*
563  * Filler function for sys/devices/system/cpu/{online,possible,present}
564  */
565 static int
566 linsysfs_cpuonline(PFS_FILL_ARGS)
567 {
568
569         sbuf_printf(sb, "%d-%d\n", CPU_FIRST(), mp_maxid);
570         return (0);
571 }
572
573 /*
574  * Filler function for sys/devices/system/cpu/cpuX/online
575  */
576 static int
577 linsysfs_cpuxonline(PFS_FILL_ARGS)
578 {
579
580         sbuf_printf(sb, "1\n");
581         return (0);
582 }
583
584 static void
585 linsysfs_listcpus(struct pfs_node *dir)
586 {
587         struct pfs_node *cpu;
588         char *name;
589         int i, count, len;
590
591         len = 1;
592         count = mp_maxcpus;
593         while (count > 10) {
594                 count /= 10;
595                 len++;
596         }
597         len += sizeof("cpu");
598         name = malloc(len, M_TEMP, M_WAITOK);
599
600         for (i = 0; i < mp_ncpus; ++i) {
601                 /* /sys/devices/system/cpu/cpuX */
602                 sprintf(name, "cpu%d", i);
603                 cpu = pfs_create_dir(dir, name, NULL, NULL, NULL, 0);
604
605                 pfs_create_file(cpu, "online", &linsysfs_cpuxonline,
606                     NULL, NULL, NULL, PFS_RD);
607         }
608         free(name, M_TEMP);
609 }
610
611 /*
612  * Constructor
613  */
614 static int
615 linsysfs_init(PFS_INIT_ARGS)
616 {
617         struct pfs_node *root;
618         struct pfs_node *class;
619         struct pfs_node *dir, *sys, *cpu;
620         struct pfs_node *drm;
621         struct pfs_node *pci;
622         struct pfs_node *scsi;
623         struct pfs_node *net;
624         struct pfs_node *devdir, *chardev;
625         devclass_t devclass;
626         device_t dev;
627
628         TAILQ_INIT(&scsi_host_q);
629
630         root = pi->pi_root;
631
632         /* /sys/class/... */
633         class = pfs_create_dir(root, "class", NULL, NULL, NULL, 0);
634         scsi = pfs_create_dir(class, "scsi_host", NULL, NULL, NULL, 0);
635         drm = pfs_create_dir(class, "drm", NULL, NULL, NULL, 0);
636
637         /* /sys/class/net/.. */
638         net = pfs_create_dir(class, "net", NULL, NULL, NULL, 0);
639
640         /* /sys/dev/... */
641         devdir = pfs_create_dir(root, "dev", NULL, NULL, NULL, 0);
642         chardev = pfs_create_dir(devdir, "char", NULL, NULL, NULL, 0);
643
644         /* /sys/devices/... */
645         dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0);
646         pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0);
647
648         devclass = devclass_find("root");
649         if (devclass == NULL) {
650                 return (0);
651         }
652
653         dev = devclass_get_device(devclass, 0);
654         linsysfs_run_bus(dev, pci, scsi, chardev, drm, "/pci0000:00", "0000");
655
656         /* /sys/devices/system */
657         sys = pfs_create_dir(dir, "system", NULL, NULL, NULL, 0);
658
659         /* /sys/devices/system/cpu */
660         cpu = pfs_create_dir(sys, "cpu", NULL, NULL, NULL, 0);
661
662         pfs_create_file(cpu, "online", &linsysfs_cpuonline,
663             NULL, NULL, NULL, PFS_RD);
664         pfs_create_file(cpu, "possible", &linsysfs_cpuonline,
665             NULL, NULL, NULL, PFS_RD);
666         pfs_create_file(cpu, "present", &linsysfs_cpuonline,
667             NULL, NULL, NULL, PFS_RD);
668
669         linsysfs_listcpus(cpu);
670         linsysfs_listnics(net);
671
672         return (0);
673 }
674
675 /*
676  * Destructor
677  */
678 static int
679 linsysfs_uninit(PFS_INIT_ARGS)
680 {
681         struct scsi_host_queue *scsi_host, *scsi_host_tmp;
682
683         TAILQ_FOREACH_SAFE(scsi_host, &scsi_host_q, scsi_host_next,
684             scsi_host_tmp) {
685                 TAILQ_REMOVE(&scsi_host_q, scsi_host, scsi_host_next);
686                 free(scsi_host->path, M_TEMP);
687                 free(scsi_host, M_TEMP);
688         }
689
690         return (0);
691 }
692
693 PSEUDOFS(linsysfs, 1, VFCF_JAIL);
694 #if defined(__aarch64__) || defined(__amd64__)
695 MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1);
696 #else
697 MODULE_DEPEND(linsysfs, linux, 1, 1, 1);
698 #endif