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 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 */ 566 static int 567 linsysfs_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 */ 577 static int 578 linsysfs_cpuxonline(PFS_FILL_ARGS) 579 { 580 581 sbuf_printf(sb, "1\n"); 582 return (0); 583 } 584 585 static void 586 linsysfs_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 */ 615 static int 616 linsysfs_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 *devdir, *chardev; 626 devclass_t devclass; 627 device_t dev; 628 629 TAILQ_INIT(&scsi_host_q); 630 631 root = pi->pi_root; 632 633 /* /sys/class/... */ 634 class = pfs_create_dir(root, "class", NULL, NULL, NULL, 0); 635 scsi = pfs_create_dir(class, "scsi_host", NULL, NULL, NULL, 0); 636 drm = pfs_create_dir(class, "drm", NULL, NULL, NULL, 0); 637 638 /* /sys/class/net/.. */ 639 net = pfs_create_dir(class, "net", NULL, NULL, NULL, 0); 640 641 /* /sys/dev/... */ 642 devdir = pfs_create_dir(root, "dev", NULL, NULL, NULL, 0); 643 chardev = pfs_create_dir(devdir, "char", NULL, NULL, NULL, 0); 644 645 /* /sys/devices/... */ 646 dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0); 647 pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0); 648 649 devclass = devclass_find("root"); 650 if (devclass == NULL) { 651 return (0); 652 } 653 654 dev = devclass_get_device(devclass, 0); 655 linsysfs_run_bus(dev, pci, scsi, chardev, drm, "/pci0000:00", "0000"); 656 657 /* /sys/devices/system */ 658 sys = pfs_create_dir(dir, "system", NULL, NULL, NULL, 0); 659 660 /* /sys/devices/system/cpu */ 661 cpu = pfs_create_dir(sys, "cpu", NULL, NULL, NULL, 0); 662 663 pfs_create_file(cpu, "online", &linsysfs_cpuonline, 664 NULL, NULL, NULL, PFS_RD); 665 pfs_create_file(cpu, "possible", &linsysfs_cpuonline, 666 NULL, NULL, NULL, PFS_RD); 667 pfs_create_file(cpu, "present", &linsysfs_cpuonline, 668 NULL, NULL, NULL, PFS_RD); 669 670 linsysfs_listcpus(cpu); 671 linsysfs_listnics(net); 672 673 return (0); 674 } 675 676 /* 677 * Destructor 678 */ 679 static int 680 linsysfs_uninit(PFS_INIT_ARGS) 681 { 682 struct scsi_host_queue *scsi_host, *scsi_host_tmp; 683 684 TAILQ_FOREACH_SAFE(scsi_host, &scsi_host_q, scsi_host_next, 685 scsi_host_tmp) { 686 TAILQ_REMOVE(&scsi_host_q, scsi_host, scsi_host_next); 687 free(scsi_host->path, M_TEMP); 688 free(scsi_host, M_TEMP); 689 } 690 691 return (0); 692 } 693 694 PSEUDOFS(linsysfs, 1, VFCF_JAIL); 695 #if defined(__aarch64__) || defined(__amd64__) 696 MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1); 697 #else 698 MODULE_DEPEND(linsysfs, linux, 1, 1, 1); 699 #endif 700