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/dev/pci/pci_user.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) 1997, Stefan Esser <se@freebsd.org>
    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 unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/11.2/sys/dev/pci/pci_user.c 331922 2018-04-03 09:40:52Z kib $");
   29 
   30 #include "opt_bus.h"    /* XXX trim includes */
   31 #include "opt_compat.h"
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/malloc.h>
   36 #include <sys/module.h>
   37 #include <sys/linker.h>
   38 #include <sys/fcntl.h>
   39 #include <sys/conf.h>
   40 #include <sys/kernel.h>
   41 #include <sys/proc.h>
   42 #include <sys/queue.h>
   43 #include <sys/types.h>
   44 
   45 #include <vm/vm.h>
   46 #include <vm/pmap.h>
   47 #include <vm/vm_extern.h>
   48 
   49 #include <sys/bus.h>
   50 #include <machine/bus.h>
   51 #include <sys/rman.h>
   52 #include <machine/resource.h>
   53 
   54 #include <sys/pciio.h>
   55 #include <dev/pci/pcireg.h>
   56 #include <dev/pci/pcivar.h>
   57 
   58 #include "pcib_if.h"
   59 #include "pci_if.h"
   60 
   61 /*
   62  * This is the user interface to PCI configuration space.
   63  */
   64 
   65 static d_open_t         pci_open;
   66 static d_close_t        pci_close;
   67 static int      pci_conf_match(struct pci_match_conf *matches, int num_matches,
   68                                struct pci_conf *match_buf);
   69 static d_ioctl_t        pci_ioctl;
   70 
   71 struct cdevsw pcicdev = {
   72         .d_version =    D_VERSION,
   73         .d_flags =      D_NEEDGIANT,
   74         .d_open =       pci_open,
   75         .d_close =      pci_close,
   76         .d_ioctl =      pci_ioctl,
   77         .d_name =       "pci",
   78 };
   79   
   80 static int
   81 pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
   82 {
   83         int error;
   84 
   85         if (oflags & FWRITE) {
   86                 error = securelevel_gt(td->td_ucred, 0);
   87                 if (error)
   88                         return (error);
   89         }
   90 
   91         return (0);
   92 }
   93 
   94 static int
   95 pci_close(struct cdev *dev, int flag, int devtype, struct thread *td)
   96 {
   97         return 0;
   98 }
   99 
  100 /*
  101  * Match a single pci_conf structure against an array of pci_match_conf
  102  * structures.  The first argument, 'matches', is an array of num_matches
  103  * pci_match_conf structures.  match_buf is a pointer to the pci_conf
  104  * structure that will be compared to every entry in the matches array.
  105  * This function returns 1 on failure, 0 on success.
  106  */
  107 static int
  108 pci_conf_match(struct pci_match_conf *matches, int num_matches, 
  109                struct pci_conf *match_buf)
  110 {
  111         int i;
  112 
  113         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
  114                 return(1);
  115 
  116         for (i = 0; i < num_matches; i++) {
  117                 /*
  118                  * I'm not sure why someone would do this...but...
  119                  */
  120                 if (matches[i].flags == PCI_GETCONF_NO_MATCH)
  121                         continue;
  122 
  123                 /*
  124                  * Look at each of the match flags.  If it's set, do the
  125                  * comparison.  If the comparison fails, we don't have a
  126                  * match, go on to the next item if there is one.
  127                  */
  128                 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
  129                  && (match_buf->pc_sel.pc_domain !=
  130                  matches[i].pc_sel.pc_domain))
  131                         continue;
  132 
  133                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
  134                  && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
  135                         continue;
  136 
  137                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
  138                  && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
  139                         continue;
  140 
  141                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
  142                  && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
  143                         continue;
  144 
  145                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 
  146                  && (match_buf->pc_vendor != matches[i].pc_vendor))
  147                         continue;
  148 
  149                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
  150                  && (match_buf->pc_device != matches[i].pc_device))
  151                         continue;
  152 
  153                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
  154                  && (match_buf->pc_class != matches[i].pc_class))
  155                         continue;
  156 
  157                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
  158                  && (match_buf->pd_unit != matches[i].pd_unit))
  159                         continue;
  160 
  161                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
  162                  && (strncmp(matches[i].pd_name, match_buf->pd_name,
  163                              sizeof(match_buf->pd_name)) != 0))
  164                         continue;
  165 
  166                 return(0);
  167         }
  168 
  169         return(1);
  170 }
  171 
  172 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
  173     defined(COMPAT_FREEBSD6)
  174 #define PRE7_COMPAT
  175 
  176 typedef enum {
  177         PCI_GETCONF_NO_MATCH_OLD        = 0x00,
  178         PCI_GETCONF_MATCH_BUS_OLD       = 0x01,
  179         PCI_GETCONF_MATCH_DEV_OLD       = 0x02,
  180         PCI_GETCONF_MATCH_FUNC_OLD      = 0x04,
  181         PCI_GETCONF_MATCH_NAME_OLD      = 0x08,
  182         PCI_GETCONF_MATCH_UNIT_OLD      = 0x10,
  183         PCI_GETCONF_MATCH_VENDOR_OLD    = 0x20,
  184         PCI_GETCONF_MATCH_DEVICE_OLD    = 0x40,
  185         PCI_GETCONF_MATCH_CLASS_OLD     = 0x80
  186 } pci_getconf_flags_old;
  187 
  188 struct pcisel_old {
  189         u_int8_t        pc_bus;         /* bus number */
  190         u_int8_t        pc_dev;         /* device on this bus */
  191         u_int8_t        pc_func;        /* function on this device */
  192 };
  193 
  194 struct pci_conf_old {
  195         struct pcisel_old pc_sel;       /* bus+slot+function */
  196         u_int8_t        pc_hdr;         /* PCI header type */
  197         u_int16_t       pc_subvendor;   /* card vendor ID */
  198         u_int16_t       pc_subdevice;   /* card device ID, assigned by
  199                                            card vendor */
  200         u_int16_t       pc_vendor;      /* chip vendor ID */
  201         u_int16_t       pc_device;      /* chip device ID, assigned by
  202                                            chip vendor */
  203         u_int8_t        pc_class;       /* chip PCI class */
  204         u_int8_t        pc_subclass;    /* chip PCI subclass */
  205         u_int8_t        pc_progif;      /* chip PCI programming interface */
  206         u_int8_t        pc_revid;       /* chip revision ID */
  207         char            pd_name[PCI_MAXNAMELEN + 1];  /* device name */
  208         u_long          pd_unit;        /* device unit number */
  209 };
  210 
  211 struct pci_match_conf_old {
  212         struct pcisel_old       pc_sel;         /* bus+slot+function */
  213         char                    pd_name[PCI_MAXNAMELEN + 1];  /* device name */
  214         u_long                  pd_unit;        /* Unit number */
  215         u_int16_t               pc_vendor;      /* PCI Vendor ID */
  216         u_int16_t               pc_device;      /* PCI Device ID */
  217         u_int8_t                pc_class;       /* PCI class */
  218         pci_getconf_flags_old   flags;          /* Matching expression */
  219 };
  220 
  221 struct pci_io_old {
  222         struct pcisel_old pi_sel;       /* device to operate on */
  223         int             pi_reg;         /* configuration register to examine */
  224         int             pi_width;       /* width (in bytes) of read or write */
  225         u_int32_t       pi_data;        /* data to write or result of read */
  226 };
  227 
  228 #ifdef COMPAT_FREEBSD32
  229 struct pci_conf_old32 {
  230         struct pcisel_old pc_sel;       /* bus+slot+function */
  231         uint8_t         pc_hdr;         /* PCI header type */
  232         uint16_t        pc_subvendor;   /* card vendor ID */
  233         uint16_t        pc_subdevice;   /* card device ID, assigned by
  234                                            card vendor */
  235         uint16_t        pc_vendor;      /* chip vendor ID */
  236         uint16_t        pc_device;      /* chip device ID, assigned by
  237                                            chip vendor */
  238         uint8_t         pc_class;       /* chip PCI class */
  239         uint8_t         pc_subclass;    /* chip PCI subclass */
  240         uint8_t         pc_progif;      /* chip PCI programming interface */
  241         uint8_t         pc_revid;       /* chip revision ID */
  242         char            pd_name[PCI_MAXNAMELEN + 1]; /* device name */
  243         uint32_t        pd_unit;        /* device unit number (u_long) */
  244 };
  245 
  246 struct pci_match_conf_old32 {
  247         struct pcisel_old pc_sel;       /* bus+slot+function */
  248         char            pd_name[PCI_MAXNAMELEN + 1]; /* device name */
  249         uint32_t        pd_unit;        /* Unit number (u_long) */
  250         uint16_t        pc_vendor;      /* PCI Vendor ID */
  251         uint16_t        pc_device;      /* PCI Device ID */
  252         uint8_t         pc_class;       /* PCI class */
  253         pci_getconf_flags_old flags;    /* Matching expression */
  254 };
  255 
  256 struct pci_conf_io32 {
  257         uint32_t        pat_buf_len;    /* pattern buffer length */
  258         uint32_t        num_patterns;   /* number of patterns */
  259         uint32_t        patterns;       /* pattern buffer
  260                                            (struct pci_match_conf_old32 *) */
  261         uint32_t        match_buf_len;  /* match buffer length */
  262         uint32_t        num_matches;    /* number of matches returned */
  263         uint32_t        matches;        /* match buffer
  264                                            (struct pci_conf_old32 *) */
  265         uint32_t        offset;         /* offset into device list */
  266         uint32_t        generation;     /* device list generation */
  267         pci_getconf_status status;      /* request status */
  268 };
  269 
  270 #define PCIOCGETCONF_OLD32      _IOWR('p', 1, struct pci_conf_io32)
  271 #endif  /* COMPAT_FREEBSD32 */
  272 
  273 #define PCIOCGETCONF_OLD        _IOWR('p', 1, struct pci_conf_io)
  274 #define PCIOCREAD_OLD           _IOWR('p', 2, struct pci_io_old)
  275 #define PCIOCWRITE_OLD          _IOWR('p', 3, struct pci_io_old)
  276 
  277 static int      pci_conf_match_old(struct pci_match_conf_old *matches,
  278                     int num_matches, struct pci_conf *match_buf);
  279 
  280 static int
  281 pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches,
  282     struct pci_conf *match_buf)
  283 {
  284         int i;
  285 
  286         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
  287                 return(1);
  288 
  289         for (i = 0; i < num_matches; i++) {
  290                 if (match_buf->pc_sel.pc_domain != 0)
  291                         continue;
  292 
  293                 /*
  294                  * I'm not sure why someone would do this...but...
  295                  */
  296                 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
  297                         continue;
  298 
  299                 /*
  300                  * Look at each of the match flags.  If it's set, do the
  301                  * comparison.  If the comparison fails, we don't have a
  302                  * match, go on to the next item if there is one.
  303                  */
  304                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0)
  305                  && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
  306                         continue;
  307 
  308                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0)
  309                  && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
  310                         continue;
  311 
  312                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0)
  313                  && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
  314                         continue;
  315 
  316                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0)
  317                  && (match_buf->pc_vendor != matches[i].pc_vendor))
  318                         continue;
  319 
  320                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0)
  321                  && (match_buf->pc_device != matches[i].pc_device))
  322                         continue;
  323 
  324                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0)
  325                  && (match_buf->pc_class != matches[i].pc_class))
  326                         continue;
  327 
  328                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0)
  329                  && (match_buf->pd_unit != matches[i].pd_unit))
  330                         continue;
  331 
  332                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0)
  333                  && (strncmp(matches[i].pd_name, match_buf->pd_name,
  334                              sizeof(match_buf->pd_name)) != 0))
  335                         continue;
  336 
  337                 return(0);
  338         }
  339 
  340         return(1);
  341 }
  342 
  343 #ifdef COMPAT_FREEBSD32
  344 static int
  345 pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches,
  346     struct pci_conf *match_buf)
  347 {
  348         int i;
  349 
  350         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
  351                 return(1);
  352 
  353         for (i = 0; i < num_matches; i++) {
  354                 if (match_buf->pc_sel.pc_domain != 0)
  355                         continue;
  356 
  357                 /*
  358                  * I'm not sure why someone would do this...but...
  359                  */
  360                 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
  361                         continue;
  362 
  363                 /*
  364                  * Look at each of the match flags.  If it's set, do the
  365                  * comparison.  If the comparison fails, we don't have a
  366                  * match, go on to the next item if there is one.
  367                  */
  368                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) &&
  369                     (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
  370                         continue;
  371 
  372                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) &&
  373                     (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
  374                         continue;
  375 
  376                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) &&
  377                     (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
  378                         continue;
  379 
  380                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) &&
  381                     (match_buf->pc_vendor != matches[i].pc_vendor))
  382                         continue;
  383 
  384                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) &&
  385                     (match_buf->pc_device != matches[i].pc_device))
  386                         continue;
  387 
  388                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) &&
  389                     (match_buf->pc_class != matches[i].pc_class))
  390                         continue;
  391 
  392                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) &&
  393                     ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit))
  394                         continue;
  395 
  396                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) &&
  397                     (strncmp(matches[i].pd_name, match_buf->pd_name,
  398                     sizeof(match_buf->pd_name)) != 0))
  399                         continue;
  400 
  401                 return (0);
  402         }
  403 
  404         return (1);
  405 }
  406 #endif  /* COMPAT_FREEBSD32 */
  407 #endif  /* PRE7_COMPAT */
  408 
  409 static int
  410 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
  411 {
  412         struct pci_vpd_element vpd_element, *vpd_user;
  413         struct pcicfg_vpd *vpd;
  414         size_t len;
  415         int error, i;
  416 
  417         vpd = pci_fetch_vpd_list(dev);
  418         if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL)
  419                 return (ENXIO);
  420 
  421         /*
  422          * Calculate the amount of space needed in the data buffer.  An
  423          * identifier element is always present followed by the read-only
  424          * and read-write keywords.
  425          */
  426         len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident);
  427         for (i = 0; i < vpd->vpd_rocnt; i++)
  428                 len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len;
  429         for (i = 0; i < vpd->vpd_wcnt; i++)
  430                 len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len;
  431 
  432         if (lvio->plvi_len == 0) {
  433                 lvio->plvi_len = len;
  434                 return (0);
  435         }
  436         if (lvio->plvi_len < len) {
  437                 lvio->plvi_len = len;
  438                 return (ENOMEM);
  439         }
  440 
  441         /*
  442          * Copyout the identifier string followed by each keyword and
  443          * value.
  444          */
  445         vpd_user = lvio->plvi_data;
  446         vpd_element.pve_keyword[0] = '\0';
  447         vpd_element.pve_keyword[1] = '\0';
  448         vpd_element.pve_flags = PVE_FLAG_IDENT;
  449         vpd_element.pve_datalen = strlen(vpd->vpd_ident);
  450         error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
  451         if (error)
  452                 return (error);
  453         error = copyout(vpd->vpd_ident, vpd_user->pve_data,
  454             strlen(vpd->vpd_ident));
  455         if (error)
  456                 return (error);
  457         vpd_user = PVE_NEXT(vpd_user);
  458         vpd_element.pve_flags = 0;
  459         for (i = 0; i < vpd->vpd_rocnt; i++) {
  460                 vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0];
  461                 vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1];
  462                 vpd_element.pve_datalen = vpd->vpd_ros[i].len;
  463                 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
  464                 if (error)
  465                         return (error);
  466                 error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data,
  467                     vpd->vpd_ros[i].len);
  468                 if (error)
  469                         return (error);
  470                 vpd_user = PVE_NEXT(vpd_user);
  471         }
  472         vpd_element.pve_flags = PVE_FLAG_RW;
  473         for (i = 0; i < vpd->vpd_wcnt; i++) {
  474                 vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0];
  475                 vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1];
  476                 vpd_element.pve_datalen = vpd->vpd_w[i].len;
  477                 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
  478                 if (error)
  479                         return (error);
  480                 error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data,
  481                     vpd->vpd_w[i].len);
  482                 if (error)
  483                         return (error);
  484                 vpd_user = PVE_NEXT(vpd_user);
  485         }
  486         KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len,
  487             ("length mismatch"));
  488         lvio->plvi_len = len;
  489         return (0);
  490 }
  491 
  492 static int
  493 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
  494 {
  495         device_t pcidev;
  496         void *confdata;
  497         const char *name;
  498         struct devlist *devlist_head;
  499         struct pci_conf_io *cio = NULL;
  500         struct pci_devinfo *dinfo;
  501         struct pci_io *io;
  502         struct pci_bar_io *bio;
  503         struct pci_list_vpd_io *lvio;
  504         struct pci_match_conf *pattern_buf;
  505         struct pci_map *pm;
  506         size_t confsz, iolen, pbufsz;
  507         int error, ionum, i, num_patterns;
  508 #ifdef PRE7_COMPAT
  509 #ifdef COMPAT_FREEBSD32
  510         struct pci_conf_io32 *cio32 = NULL;
  511         struct pci_conf_old32 conf_old32;
  512         struct pci_match_conf_old32 *pattern_buf_old32 = NULL;
  513 #endif
  514         struct pci_conf_old conf_old;
  515         struct pci_io iodata;
  516         struct pci_io_old *io_old;
  517         struct pci_match_conf_old *pattern_buf_old = NULL;
  518 
  519         io_old = NULL;
  520 #endif
  521 
  522         if (!(flag & FWRITE)) {
  523                 switch (cmd) {
  524 #ifdef PRE7_COMPAT
  525 #ifdef COMPAT_FREEBSD32
  526                 case PCIOCGETCONF_OLD32:
  527 #endif
  528                 case PCIOCGETCONF_OLD:
  529 #endif
  530                 case PCIOCGETCONF:
  531                 case PCIOCGETBAR:
  532                 case PCIOCLISTVPD:
  533                         break;
  534                 default:
  535                         return (EPERM);
  536                 }
  537         }
  538 
  539         switch (cmd) {
  540 #ifdef PRE7_COMPAT
  541 #ifdef COMPAT_FREEBSD32
  542         case PCIOCGETCONF_OLD32:
  543                cio32 = (struct pci_conf_io32 *)data;
  544                cio = malloc(sizeof(struct pci_conf_io), M_TEMP, M_WAITOK);
  545                cio->pat_buf_len = cio32->pat_buf_len;
  546                cio->num_patterns = cio32->num_patterns;
  547                cio->patterns = (void *)(uintptr_t)cio32->patterns;
  548                cio->match_buf_len = cio32->match_buf_len;
  549                cio->num_matches = cio32->num_matches;
  550                cio->matches = (void *)(uintptr_t)cio32->matches;
  551                cio->offset = cio32->offset;
  552                cio->generation = cio32->generation;
  553                cio->status = cio32->status;
  554                cio32->num_matches = 0;
  555                break;
  556 #endif
  557         case PCIOCGETCONF_OLD:
  558 #endif
  559         case PCIOCGETCONF:
  560                 cio = (struct pci_conf_io *)data;
  561         }
  562 
  563         switch (cmd) {
  564 #ifdef PRE7_COMPAT
  565 #ifdef COMPAT_FREEBSD32
  566         case PCIOCGETCONF_OLD32:
  567 #endif
  568         case PCIOCGETCONF_OLD:
  569 #endif
  570         case PCIOCGETCONF:
  571 
  572                 pattern_buf = NULL;
  573                 num_patterns = 0;
  574                 dinfo = NULL;
  575 
  576                 cio->num_matches = 0;
  577 
  578                 /*
  579                  * If the user specified an offset into the device list,
  580                  * but the list has changed since they last called this
  581                  * ioctl, tell them that the list has changed.  They will
  582                  * have to get the list from the beginning.
  583                  */
  584                 if ((cio->offset != 0)
  585                  && (cio->generation != pci_generation)){
  586                         cio->status = PCI_GETCONF_LIST_CHANGED;
  587                         error = 0;
  588                         goto getconfexit;
  589                 }
  590 
  591                 /*
  592                  * Check to see whether the user has asked for an offset
  593                  * past the end of our list.
  594                  */
  595                 if (cio->offset >= pci_numdevs) {
  596                         cio->status = PCI_GETCONF_LAST_DEVICE;
  597                         error = 0;
  598                         goto getconfexit;
  599                 }
  600 
  601                 /* get the head of the device queue */
  602                 devlist_head = &pci_devq;
  603 
  604                 /*
  605                  * Determine how much room we have for pci_conf structures.
  606                  * Round the user's buffer size down to the nearest
  607                  * multiple of sizeof(struct pci_conf) in case the user
  608                  * didn't specify a multiple of that size.
  609                  */
  610 #ifdef PRE7_COMPAT
  611 #ifdef COMPAT_FREEBSD32
  612                 if (cmd == PCIOCGETCONF_OLD32)
  613                         confsz = sizeof(struct pci_conf_old32);
  614                 else
  615 #endif
  616                 if (cmd == PCIOCGETCONF_OLD)
  617                         confsz = sizeof(struct pci_conf_old);
  618                 else
  619 #endif
  620                         confsz = sizeof(struct pci_conf);
  621                 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
  622                     pci_numdevs * confsz);
  623 
  624                 /*
  625                  * Since we know that iolen is a multiple of the size of
  626                  * the pciconf union, it's okay to do this.
  627                  */
  628                 ionum = iolen / confsz;
  629 
  630                 /*
  631                  * If this test is true, the user wants the pci_conf
  632                  * structures returned to match the supplied entries.
  633                  */
  634                 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
  635                  && (cio->pat_buf_len > 0)) {
  636                         /*
  637                          * pat_buf_len needs to be:
  638                          * num_patterns * sizeof(struct pci_match_conf)
  639                          * While it is certainly possible the user just
  640                          * allocated a large buffer, but set the number of
  641                          * matches correctly, it is far more likely that
  642                          * their kernel doesn't match the userland utility
  643                          * they're using.  It's also possible that the user
  644                          * forgot to initialize some variables.  Yes, this
  645                          * may be overly picky, but I hazard to guess that
  646                          * it's far more likely to just catch folks that
  647                          * updated their kernel but not their userland.
  648                          */
  649 #ifdef PRE7_COMPAT
  650 #ifdef COMPAT_FREEBSD32
  651                         if (cmd == PCIOCGETCONF_OLD32)
  652                                 pbufsz = sizeof(struct pci_match_conf_old32);
  653                         else
  654 #endif
  655                         if (cmd == PCIOCGETCONF_OLD)
  656                                 pbufsz = sizeof(struct pci_match_conf_old);
  657                         else
  658 #endif
  659                                 pbufsz = sizeof(struct pci_match_conf);
  660                         if (cio->num_patterns * pbufsz != cio->pat_buf_len) {
  661                                 /* The user made a mistake, return an error. */
  662                                 cio->status = PCI_GETCONF_ERROR;
  663                                 error = EINVAL;
  664                                 goto getconfexit;
  665                         }
  666 
  667                         /*
  668                          * Allocate a buffer to hold the patterns.
  669                          */
  670 #ifdef PRE7_COMPAT
  671 #ifdef COMPAT_FREEBSD32
  672                         if (cmd == PCIOCGETCONF_OLD32) {
  673                                 pattern_buf_old32 = malloc(cio->pat_buf_len,
  674                                     M_TEMP, M_WAITOK);
  675                                 error = copyin(cio->patterns,
  676                                     pattern_buf_old32, cio->pat_buf_len);
  677                         } else
  678 #endif /* COMPAT_FREEBSD32 */
  679                         if (cmd == PCIOCGETCONF_OLD) {
  680                                 pattern_buf_old = malloc(cio->pat_buf_len,
  681                                     M_TEMP, M_WAITOK);
  682                                 error = copyin(cio->patterns,
  683                                     pattern_buf_old, cio->pat_buf_len);
  684                         } else
  685 #endif /* PRE7_COMPAT */
  686                         {
  687                                 pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
  688                                     M_WAITOK);
  689                                 error = copyin(cio->patterns, pattern_buf,
  690                                     cio->pat_buf_len);
  691                         }
  692                         if (error != 0) {
  693                                 error = EINVAL;
  694                                 goto getconfexit;
  695                         }
  696                         num_patterns = cio->num_patterns;
  697                 } else if ((cio->num_patterns > 0)
  698                         || (cio->pat_buf_len > 0)) {
  699                         /*
  700                          * The user made a mistake, spit out an error.
  701                          */
  702                         cio->status = PCI_GETCONF_ERROR;
  703                         error = EINVAL;
  704                        goto getconfexit;
  705                 }
  706 
  707                 /*
  708                  * Go through the list of devices and copy out the devices
  709                  * that match the user's criteria.
  710                  */
  711                 for (cio->num_matches = 0, i = 0,
  712                                  dinfo = STAILQ_FIRST(devlist_head);
  713                      dinfo != NULL;
  714                      dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
  715 
  716                         if (i < cio->offset)
  717                                 continue;
  718 
  719                         /* Populate pd_name and pd_unit */
  720                         name = NULL;
  721                         if (dinfo->cfg.dev)
  722                                 name = device_get_name(dinfo->cfg.dev);
  723                         if (name) {
  724                                 strncpy(dinfo->conf.pd_name, name,
  725                                         sizeof(dinfo->conf.pd_name));
  726                                 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
  727                                 dinfo->conf.pd_unit =
  728                                         device_get_unit(dinfo->cfg.dev);
  729                         } else {
  730                                 dinfo->conf.pd_name[0] = '\0';
  731                                 dinfo->conf.pd_unit = 0;
  732                         }
  733 
  734 #ifdef PRE7_COMPAT
  735                         if (
  736 #ifdef COMPAT_FREEBSD32
  737                             (cmd == PCIOCGETCONF_OLD32 &&
  738                             (pattern_buf_old32 == NULL ||
  739                             pci_conf_match_old32(pattern_buf_old32,
  740                             num_patterns, &dinfo->conf) == 0)) ||
  741 #endif
  742                             (cmd == PCIOCGETCONF_OLD &&
  743                             (pattern_buf_old == NULL ||
  744                             pci_conf_match_old(pattern_buf_old, num_patterns,
  745                             &dinfo->conf) == 0)) ||
  746                             (cmd == PCIOCGETCONF &&
  747                             (pattern_buf == NULL ||
  748                             pci_conf_match(pattern_buf, num_patterns,
  749                             &dinfo->conf) == 0))) {
  750 #else
  751                         if (pattern_buf == NULL ||
  752                             pci_conf_match(pattern_buf, num_patterns,
  753                             &dinfo->conf) == 0) {
  754 #endif
  755                                 /*
  756                                  * If we've filled up the user's buffer,
  757                                  * break out at this point.  Since we've
  758                                  * got a match here, we'll pick right back
  759                                  * up at the matching entry.  We can also
  760                                  * tell the user that there are more matches
  761                                  * left.
  762                                  */
  763                                 if (cio->num_matches >= ionum)
  764                                         break;
  765 
  766 #ifdef PRE7_COMPAT
  767 #ifdef COMPAT_FREEBSD32
  768                                 if (cmd == PCIOCGETCONF_OLD32) {
  769                                         memset(&conf_old32, 0,
  770                                             sizeof(conf_old32));
  771                                         conf_old32.pc_sel.pc_bus =
  772                                             dinfo->conf.pc_sel.pc_bus;
  773                                         conf_old32.pc_sel.pc_dev =
  774                                             dinfo->conf.pc_sel.pc_dev;
  775                                         conf_old32.pc_sel.pc_func =
  776                                             dinfo->conf.pc_sel.pc_func;
  777                                         conf_old32.pc_hdr = dinfo->conf.pc_hdr;
  778                                         conf_old32.pc_subvendor =
  779                                             dinfo->conf.pc_subvendor;
  780                                         conf_old32.pc_subdevice =
  781                                             dinfo->conf.pc_subdevice;
  782                                         conf_old32.pc_vendor =
  783                                             dinfo->conf.pc_vendor;
  784                                         conf_old32.pc_device =
  785                                             dinfo->conf.pc_device;
  786                                         conf_old32.pc_class =
  787                                             dinfo->conf.pc_class;
  788                                         conf_old32.pc_subclass =
  789                                             dinfo->conf.pc_subclass;
  790                                         conf_old32.pc_progif =
  791                                             dinfo->conf.pc_progif;
  792                                         conf_old32.pc_revid =
  793                                             dinfo->conf.pc_revid;
  794                                         strncpy(conf_old32.pd_name,
  795                                             dinfo->conf.pd_name,
  796                                             sizeof(conf_old32.pd_name));
  797                                         conf_old32.pd_name[PCI_MAXNAMELEN] = 0;
  798                                         conf_old32.pd_unit =
  799                                             (uint32_t)dinfo->conf.pd_unit;
  800                                         confdata = &conf_old32;
  801                                 } else
  802 #endif /* COMPAT_FREEBSD32 */
  803                                 if (cmd == PCIOCGETCONF_OLD) {
  804                                         memset(&conf_old, 0, sizeof(conf_old));
  805                                         conf_old.pc_sel.pc_bus =
  806                                             dinfo->conf.pc_sel.pc_bus;
  807                                         conf_old.pc_sel.pc_dev =
  808                                             dinfo->conf.pc_sel.pc_dev;
  809                                         conf_old.pc_sel.pc_func =
  810                                             dinfo->conf.pc_sel.pc_func;
  811                                         conf_old.pc_hdr = dinfo->conf.pc_hdr;
  812                                         conf_old.pc_subvendor =
  813                                             dinfo->conf.pc_subvendor;
  814                                         conf_old.pc_subdevice =
  815                                             dinfo->conf.pc_subdevice;
  816                                         conf_old.pc_vendor =
  817                                             dinfo->conf.pc_vendor;
  818                                         conf_old.pc_device =
  819                                             dinfo->conf.pc_device;
  820                                         conf_old.pc_class =
  821                                             dinfo->conf.pc_class;
  822                                         conf_old.pc_subclass =
  823                                             dinfo->conf.pc_subclass;
  824                                         conf_old.pc_progif =
  825                                             dinfo->conf.pc_progif;
  826                                         conf_old.pc_revid =
  827                                             dinfo->conf.pc_revid;
  828                                         strncpy(conf_old.pd_name,
  829                                             dinfo->conf.pd_name,
  830                                             sizeof(conf_old.pd_name));
  831                                         conf_old.pd_name[PCI_MAXNAMELEN] = 0;
  832                                         conf_old.pd_unit =
  833                                             dinfo->conf.pd_unit;
  834                                         confdata = &conf_old;
  835                                 } else
  836 #endif /* PRE7_COMPAT */
  837                                         confdata = &dinfo->conf;
  838                                 error = copyout(confdata,
  839                                     (caddr_t)cio->matches +
  840                                     confsz * cio->num_matches, confsz);
  841                                 if (error)
  842                                         break;
  843                                 cio->num_matches++;
  844                         }
  845                 }
  846 
  847                 /*
  848                  * Set the pointer into the list, so if the user is getting
  849                  * n records at a time, where n < pci_numdevs,
  850                  */
  851                 cio->offset = i;
  852 
  853                 /*
  854                  * Set the generation, the user will need this if they make
  855                  * another ioctl call with offset != 0.
  856                  */
  857                 cio->generation = pci_generation;
  858 
  859                 /*
  860                  * If this is the last device, inform the user so he won't
  861                  * bother asking for more devices.  If dinfo isn't NULL, we
  862                  * know that there are more matches in the list because of
  863                  * the way the traversal is done.
  864                  */
  865                 if (dinfo == NULL)
  866                         cio->status = PCI_GETCONF_LAST_DEVICE;
  867                 else
  868                         cio->status = PCI_GETCONF_MORE_DEVS;
  869 
  870 getconfexit:
  871 #ifdef PRE7_COMPAT
  872 #ifdef COMPAT_FREEBSD32
  873                 if (cmd == PCIOCGETCONF_OLD32) {
  874                         cio32->status = cio->status;
  875                         cio32->generation = cio->generation;
  876                         cio32->offset = cio->offset;
  877                         cio32->num_matches = cio->num_matches;
  878                         free(cio, M_TEMP);
  879                 }
  880                 if (pattern_buf_old32 != NULL)
  881                         free(pattern_buf_old32, M_TEMP);
  882 #endif
  883                 if (pattern_buf_old != NULL)
  884                         free(pattern_buf_old, M_TEMP);
  885 #endif
  886                 if (pattern_buf != NULL)
  887                         free(pattern_buf, M_TEMP);
  888 
  889                 break;
  890 
  891 #ifdef PRE7_COMPAT
  892         case PCIOCREAD_OLD:
  893         case PCIOCWRITE_OLD:
  894                 io_old = (struct pci_io_old *)data;
  895                 iodata.pi_sel.pc_domain = 0;
  896                 iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus;
  897                 iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev;
  898                 iodata.pi_sel.pc_func = io_old->pi_sel.pc_func;
  899                 iodata.pi_reg = io_old->pi_reg;
  900                 iodata.pi_width = io_old->pi_width;
  901                 iodata.pi_data = io_old->pi_data;
  902                 data = (caddr_t)&iodata;
  903                 /* FALLTHROUGH */
  904 #endif
  905         case PCIOCREAD:
  906         case PCIOCWRITE:
  907                 io = (struct pci_io *)data;
  908                 switch(io->pi_width) {
  909                 case 4:
  910                 case 2:
  911                 case 1:
  912                         /* Make sure register is not negative and aligned. */
  913                         if (io->pi_reg < 0 ||
  914                             io->pi_reg & (io->pi_width - 1)) {
  915                                 error = EINVAL;
  916                                 break;
  917                         }
  918                         /*
  919                          * Assume that the user-level bus number is
  920                          * in fact the physical PCI bus number.
  921                          * Look up the grandparent, i.e. the bridge device,
  922                          * so that we can issue configuration space cycles.
  923                          */
  924                         pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
  925                             io->pi_sel.pc_bus, io->pi_sel.pc_dev,
  926                             io->pi_sel.pc_func);
  927                         if (pcidev) {
  928 #ifdef PRE7_COMPAT
  929                                 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
  930 #else
  931                                 if (cmd == PCIOCWRITE)
  932 #endif
  933                                         pci_write_config(pcidev,
  934                                                           io->pi_reg,
  935                                                           io->pi_data,
  936                                                           io->pi_width);
  937 #ifdef PRE7_COMPAT
  938                                 else if (cmd == PCIOCREAD_OLD)
  939                                         io_old->pi_data =
  940                                                 pci_read_config(pcidev,
  941                                                           io->pi_reg,
  942                                                           io->pi_width);
  943 #endif
  944                                 else
  945                                         io->pi_data =
  946                                                 pci_read_config(pcidev,
  947                                                           io->pi_reg,
  948                                                           io->pi_width);
  949                                 error = 0;
  950                         } else {
  951 #ifdef COMPAT_FREEBSD4
  952                                 if (cmd == PCIOCREAD_OLD) {
  953                                         io_old->pi_data = -1;
  954                                         error = 0;
  955                                 } else
  956 #endif
  957                                         error = ENODEV;
  958                         }
  959                         break;
  960                 default:
  961                         error = EINVAL;
  962                         break;
  963                 }
  964                 break;
  965 
  966         case PCIOCGETBAR:
  967                 bio = (struct pci_bar_io *)data;
  968 
  969                 /*
  970                  * Assume that the user-level bus number is
  971                  * in fact the physical PCI bus number.
  972                  */
  973                 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
  974                     bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
  975                     bio->pbi_sel.pc_func);
  976                 if (pcidev == NULL) {
  977                         error = ENODEV;
  978                         break;
  979                 }
  980                 pm = pci_find_bar(pcidev, bio->pbi_reg);
  981                 if (pm == NULL) {
  982                         error = EINVAL;
  983                         break;
  984                 }
  985                 bio->pbi_base = pm->pm_value;
  986                 bio->pbi_length = (pci_addr_t)1 << pm->pm_size;
  987                 bio->pbi_enabled = pci_bar_enabled(pcidev, pm);
  988                 error = 0;
  989                 break;
  990         case PCIOCATTACHED:
  991                 error = 0;
  992                 io = (struct pci_io *)data;
  993                 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus,
  994                                        io->pi_sel.pc_dev, io->pi_sel.pc_func);
  995                 if (pcidev != NULL)
  996                         io->pi_data = device_is_attached(pcidev);
  997                 else
  998                         error = ENODEV;
  999                 break;
 1000         case PCIOCLISTVPD:
 1001                 lvio = (struct pci_list_vpd_io *)data;
 1002 
 1003                 /*
 1004                  * Assume that the user-level bus number is
 1005                  * in fact the physical PCI bus number.
 1006                  */
 1007                 pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain,
 1008                     lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev,
 1009                     lvio->plvi_sel.pc_func);
 1010                 if (pcidev == NULL) {
 1011                         error = ENODEV;
 1012                         break;
 1013                 }
 1014                 error = pci_list_vpd(pcidev, lvio);
 1015                 break;
 1016         default:
 1017                 error = ENOTTY;
 1018                 break;
 1019         }
 1020 
 1021         return (error);
 1022 }

Cache object: caabaf1b3f855daddb4c58903ff26ad8


[ 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.