The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linsysfs/linsysfs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: d1b21f62eefee0a98f14f4e85418f7b5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.