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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright 1997, Stefan Esser <se@freebsd.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice unmodified, this list of conditions, and the following
   11  *    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 ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include "opt_bus.h"    /* XXX trim includes */
   32 
   33 #include <sys/types.h>
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/malloc.h>
   37 #include <sys/module.h>
   38 #include <sys/linker.h>
   39 #include <sys/fcntl.h>
   40 #include <sys/conf.h>
   41 #include <sys/kernel.h>
   42 #include <sys/mman.h>
   43 #include <sys/proc.h>
   44 #include <sys/queue.h>
   45 #include <sys/rwlock.h>
   46 #include <sys/sglist.h>
   47 
   48 #include <vm/vm.h>
   49 #include <vm/pmap.h>
   50 #include <vm/vm_extern.h>
   51 #include <vm/vm_map.h>
   52 #include <vm/vm_object.h>
   53 #include <vm/vm_page.h>
   54 #include <vm/vm_pager.h>
   55 
   56 #include <sys/bus.h>
   57 #include <machine/bus.h>
   58 #include <sys/rman.h>
   59 #include <machine/resource.h>
   60 
   61 #include <sys/pciio.h>
   62 #include <dev/pci/pcireg.h>
   63 #include <dev/pci/pcivar.h>
   64 
   65 #include "pcib_if.h"
   66 #include "pci_if.h"
   67 
   68 #ifdef COMPAT_FREEBSD32
   69 struct pci_conf32 {
   70         struct pcisel   pc_sel;         /* domain+bus+slot+function */
   71         u_int8_t        pc_hdr;         /* PCI header type */
   72         u_int16_t       pc_subvendor;   /* card vendor ID */
   73         u_int16_t       pc_subdevice;   /* card device ID, assigned by
   74                                            card vendor */
   75         u_int16_t       pc_vendor;      /* chip vendor ID */
   76         u_int16_t       pc_device;      /* chip device ID, assigned by
   77                                            chip vendor */
   78         u_int8_t        pc_class;       /* chip PCI class */
   79         u_int8_t        pc_subclass;    /* chip PCI subclass */
   80         u_int8_t        pc_progif;      /* chip PCI programming interface */
   81         u_int8_t        pc_revid;       /* chip revision ID */
   82         char            pd_name[PCI_MAXNAMELEN + 1];  /* device name */
   83         u_int32_t       pd_unit;        /* device unit number */
   84 };
   85 
   86 struct pci_match_conf32 {
   87         struct pcisel           pc_sel;         /* domain+bus+slot+function */
   88         char                    pd_name[PCI_MAXNAMELEN + 1];  /* device name */
   89         u_int32_t               pd_unit;        /* Unit number */
   90         u_int16_t               pc_vendor;      /* PCI Vendor ID */
   91         u_int16_t               pc_device;      /* PCI Device ID */
   92         u_int8_t                pc_class;       /* PCI class */
   93         u_int32_t               flags;          /* Matching expression */
   94 };
   95 
   96 struct pci_conf_io32 {
   97         u_int32_t               pat_buf_len;    /* pattern buffer length */
   98         u_int32_t               num_patterns;   /* number of patterns */
   99         u_int32_t               patterns;       /* struct pci_match_conf ptr */
  100         u_int32_t               match_buf_len;  /* match buffer length */
  101         u_int32_t               num_matches;    /* number of matches returned */
  102         u_int32_t               matches;        /* struct pci_conf ptr */
  103         u_int32_t               offset;         /* offset into device list */
  104         u_int32_t               generation;     /* device list generation */
  105         u_int32_t               status;         /* request status */
  106 };
  107 
  108 #define PCIOCGETCONF32  _IOC_NEWTYPE(PCIOCGETCONF, struct pci_conf_io32)
  109 #endif
  110 
  111 /*
  112  * This is the user interface to PCI configuration space.
  113  */
  114 
  115 static d_open_t         pci_open;
  116 static d_close_t        pci_close;
  117 static d_ioctl_t        pci_ioctl;
  118 
  119 struct cdevsw pcicdev = {
  120         .d_version =    D_VERSION,
  121         .d_flags =      0,
  122         .d_open =       pci_open,
  123         .d_close =      pci_close,
  124         .d_ioctl =      pci_ioctl,
  125         .d_name =       "pci",
  126 };
  127   
  128 static int
  129 pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
  130 {
  131         int error;
  132 
  133         if (oflags & FWRITE) {
  134                 error = securelevel_gt(td->td_ucred, 0);
  135                 if (error)
  136                         return (error);
  137         }
  138 
  139         return (0);
  140 }
  141 
  142 static int
  143 pci_close(struct cdev *dev, int flag, int devtype, struct thread *td)
  144 {
  145         return 0;
  146 }
  147 
  148 /*
  149  * Match a single pci_conf structure against an array of pci_match_conf
  150  * structures.  The first argument, 'matches', is an array of num_matches
  151  * pci_match_conf structures.  match_buf is a pointer to the pci_conf
  152  * structure that will be compared to every entry in the matches array.
  153  * This function returns 1 on failure, 0 on success.
  154  */
  155 static int
  156 pci_conf_match_native(struct pci_match_conf *matches, int num_matches,
  157                struct pci_conf *match_buf)
  158 {
  159         int i;
  160 
  161         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
  162                 return(1);
  163 
  164         for (i = 0; i < num_matches; i++) {
  165                 /*
  166                  * I'm not sure why someone would do this...but...
  167                  */
  168                 if (matches[i].flags == PCI_GETCONF_NO_MATCH)
  169                         continue;
  170 
  171                 /*
  172                  * Look at each of the match flags.  If it's set, do the
  173                  * comparison.  If the comparison fails, we don't have a
  174                  * match, go on to the next item if there is one.
  175                  */
  176                 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
  177                  && (match_buf->pc_sel.pc_domain !=
  178                  matches[i].pc_sel.pc_domain))
  179                         continue;
  180 
  181                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
  182                  && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
  183                         continue;
  184 
  185                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
  186                  && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
  187                         continue;
  188 
  189                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
  190                  && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
  191                         continue;
  192 
  193                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 
  194                  && (match_buf->pc_vendor != matches[i].pc_vendor))
  195                         continue;
  196 
  197                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
  198                  && (match_buf->pc_device != matches[i].pc_device))
  199                         continue;
  200 
  201                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
  202                  && (match_buf->pc_class != matches[i].pc_class))
  203                         continue;
  204 
  205                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
  206                  && (match_buf->pd_unit != matches[i].pd_unit))
  207                         continue;
  208 
  209                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
  210                  && (strncmp(matches[i].pd_name, match_buf->pd_name,
  211                              sizeof(match_buf->pd_name)) != 0))
  212                         continue;
  213 
  214                 return(0);
  215         }
  216 
  217         return(1);
  218 }
  219 
  220 #ifdef COMPAT_FREEBSD32
  221 static int
  222 pci_conf_match32(struct pci_match_conf32 *matches, int num_matches,
  223                struct pci_conf *match_buf)
  224 {
  225         int i;
  226 
  227         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
  228                 return(1);
  229 
  230         for (i = 0; i < num_matches; i++) {
  231                 /*
  232                  * I'm not sure why someone would do this...but...
  233                  */
  234                 if (matches[i].flags == PCI_GETCONF_NO_MATCH)
  235                         continue;
  236 
  237                 /*
  238                  * Look at each of the match flags.  If it's set, do the
  239                  * comparison.  If the comparison fails, we don't have a
  240                  * match, go on to the next item if there is one.
  241                  */
  242                 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
  243                  && (match_buf->pc_sel.pc_domain !=
  244                  matches[i].pc_sel.pc_domain))
  245                         continue;
  246 
  247                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
  248                  && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
  249                         continue;
  250 
  251                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
  252                  && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
  253                         continue;
  254 
  255                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
  256                  && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
  257                         continue;
  258 
  259                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0)
  260                  && (match_buf->pc_vendor != matches[i].pc_vendor))
  261                         continue;
  262 
  263                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
  264                  && (match_buf->pc_device != matches[i].pc_device))
  265                         continue;
  266 
  267                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
  268                  && (match_buf->pc_class != matches[i].pc_class))
  269                         continue;
  270 
  271                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
  272                  && (match_buf->pd_unit != matches[i].pd_unit))
  273                         continue;
  274 
  275                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
  276                  && (strncmp(matches[i].pd_name, match_buf->pd_name,
  277                              sizeof(match_buf->pd_name)) != 0))
  278                         continue;
  279 
  280                 return(0);
  281         }
  282 
  283         return(1);
  284 }
  285 #endif  /* COMPAT_FREEBSD32 */
  286 
  287 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
  288     defined(COMPAT_FREEBSD6)
  289 #define PRE7_COMPAT
  290 
  291 typedef enum {
  292         PCI_GETCONF_NO_MATCH_OLD        = 0x00,
  293         PCI_GETCONF_MATCH_BUS_OLD       = 0x01,
  294         PCI_GETCONF_MATCH_DEV_OLD       = 0x02,
  295         PCI_GETCONF_MATCH_FUNC_OLD      = 0x04,
  296         PCI_GETCONF_MATCH_NAME_OLD      = 0x08,
  297         PCI_GETCONF_MATCH_UNIT_OLD      = 0x10,
  298         PCI_GETCONF_MATCH_VENDOR_OLD    = 0x20,
  299         PCI_GETCONF_MATCH_DEVICE_OLD    = 0x40,
  300         PCI_GETCONF_MATCH_CLASS_OLD     = 0x80
  301 } pci_getconf_flags_old;
  302 
  303 struct pcisel_old {
  304         u_int8_t        pc_bus;         /* bus number */
  305         u_int8_t        pc_dev;         /* device on this bus */
  306         u_int8_t        pc_func;        /* function on this device */
  307 };
  308 
  309 struct pci_conf_old {
  310         struct pcisel_old pc_sel;       /* bus+slot+function */
  311         u_int8_t        pc_hdr;         /* PCI header type */
  312         u_int16_t       pc_subvendor;   /* card vendor ID */
  313         u_int16_t       pc_subdevice;   /* card device ID, assigned by
  314                                            card vendor */
  315         u_int16_t       pc_vendor;      /* chip vendor ID */
  316         u_int16_t       pc_device;      /* chip device ID, assigned by
  317                                            chip vendor */
  318         u_int8_t        pc_class;       /* chip PCI class */
  319         u_int8_t        pc_subclass;    /* chip PCI subclass */
  320         u_int8_t        pc_progif;      /* chip PCI programming interface */
  321         u_int8_t        pc_revid;       /* chip revision ID */
  322         char            pd_name[PCI_MAXNAMELEN + 1];  /* device name */
  323         u_long          pd_unit;        /* device unit number */
  324 };
  325 
  326 struct pci_match_conf_old {
  327         struct pcisel_old       pc_sel;         /* bus+slot+function */
  328         char                    pd_name[PCI_MAXNAMELEN + 1];  /* device name */
  329         u_long                  pd_unit;        /* Unit number */
  330         u_int16_t               pc_vendor;      /* PCI Vendor ID */
  331         u_int16_t               pc_device;      /* PCI Device ID */
  332         u_int8_t                pc_class;       /* PCI class */
  333         pci_getconf_flags_old   flags;          /* Matching expression */
  334 };
  335 
  336 struct pci_io_old {
  337         struct pcisel_old pi_sel;       /* device to operate on */
  338         int             pi_reg;         /* configuration register to examine */
  339         int             pi_width;       /* width (in bytes) of read or write */
  340         u_int32_t       pi_data;        /* data to write or result of read */
  341 };
  342 
  343 #ifdef COMPAT_FREEBSD32
  344 struct pci_conf_old32 {
  345         struct pcisel_old pc_sel;       /* bus+slot+function */
  346         uint8_t         pc_hdr;         /* PCI header type */
  347         uint16_t        pc_subvendor;   /* card vendor ID */
  348         uint16_t        pc_subdevice;   /* card device ID, assigned by
  349                                            card vendor */
  350         uint16_t        pc_vendor;      /* chip vendor ID */
  351         uint16_t        pc_device;      /* chip device ID, assigned by
  352                                            chip vendor */
  353         uint8_t         pc_class;       /* chip PCI class */
  354         uint8_t         pc_subclass;    /* chip PCI subclass */
  355         uint8_t         pc_progif;      /* chip PCI programming interface */
  356         uint8_t         pc_revid;       /* chip revision ID */
  357         char            pd_name[PCI_MAXNAMELEN + 1]; /* device name */
  358         uint32_t        pd_unit;        /* device unit number (u_long) */
  359 };
  360 
  361 struct pci_match_conf_old32 {
  362         struct pcisel_old pc_sel;       /* bus+slot+function */
  363         char            pd_name[PCI_MAXNAMELEN + 1]; /* device name */
  364         uint32_t        pd_unit;        /* Unit number (u_long) */
  365         uint16_t        pc_vendor;      /* PCI Vendor ID */
  366         uint16_t        pc_device;      /* PCI Device ID */
  367         uint8_t         pc_class;       /* PCI class */
  368         pci_getconf_flags_old flags;    /* Matching expression */
  369 };
  370 
  371 #define PCIOCGETCONF_OLD32      _IOWR('p', 1, struct pci_conf_io32)
  372 #endif  /* COMPAT_FREEBSD32 */
  373 
  374 #define PCIOCGETCONF_OLD        _IOWR('p', 1, struct pci_conf_io)
  375 #define PCIOCREAD_OLD           _IOWR('p', 2, struct pci_io_old)
  376 #define PCIOCWRITE_OLD          _IOWR('p', 3, struct pci_io_old)
  377 
  378 static int
  379 pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches,
  380     struct pci_conf *match_buf)
  381 {
  382         int i;
  383 
  384         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
  385                 return(1);
  386 
  387         for (i = 0; i < num_matches; i++) {
  388                 if (match_buf->pc_sel.pc_domain != 0)
  389                         continue;
  390 
  391                 /*
  392                  * I'm not sure why someone would do this...but...
  393                  */
  394                 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
  395                         continue;
  396 
  397                 /*
  398                  * Look at each of the match flags.  If it's set, do the
  399                  * comparison.  If the comparison fails, we don't have a
  400                  * match, go on to the next item if there is one.
  401                  */
  402                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0)
  403                  && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
  404                         continue;
  405 
  406                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0)
  407                  && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
  408                         continue;
  409 
  410                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0)
  411                  && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
  412                         continue;
  413 
  414                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0)
  415                  && (match_buf->pc_vendor != matches[i].pc_vendor))
  416                         continue;
  417 
  418                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0)
  419                  && (match_buf->pc_device != matches[i].pc_device))
  420                         continue;
  421 
  422                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0)
  423                  && (match_buf->pc_class != matches[i].pc_class))
  424                         continue;
  425 
  426                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0)
  427                  && (match_buf->pd_unit != matches[i].pd_unit))
  428                         continue;
  429 
  430                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0)
  431                  && (strncmp(matches[i].pd_name, match_buf->pd_name,
  432                              sizeof(match_buf->pd_name)) != 0))
  433                         continue;
  434 
  435                 return(0);
  436         }
  437 
  438         return(1);
  439 }
  440 
  441 #ifdef COMPAT_FREEBSD32
  442 static int
  443 pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches,
  444     struct pci_conf *match_buf)
  445 {
  446         int i;
  447 
  448         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
  449                 return(1);
  450 
  451         for (i = 0; i < num_matches; i++) {
  452                 if (match_buf->pc_sel.pc_domain != 0)
  453                         continue;
  454 
  455                 /*
  456                  * I'm not sure why someone would do this...but...
  457                  */
  458                 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
  459                         continue;
  460 
  461                 /*
  462                  * Look at each of the match flags.  If it's set, do the
  463                  * comparison.  If the comparison fails, we don't have a
  464                  * match, go on to the next item if there is one.
  465                  */
  466                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) &&
  467                     (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
  468                         continue;
  469 
  470                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) &&
  471                     (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
  472                         continue;
  473 
  474                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) &&
  475                     (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
  476                         continue;
  477 
  478                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) &&
  479                     (match_buf->pc_vendor != matches[i].pc_vendor))
  480                         continue;
  481 
  482                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) &&
  483                     (match_buf->pc_device != matches[i].pc_device))
  484                         continue;
  485 
  486                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) &&
  487                     (match_buf->pc_class != matches[i].pc_class))
  488                         continue;
  489 
  490                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) &&
  491                     ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit))
  492                         continue;
  493 
  494                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) &&
  495                     (strncmp(matches[i].pd_name, match_buf->pd_name,
  496                     sizeof(match_buf->pd_name)) != 0))
  497                         continue;
  498 
  499                 return (0);
  500         }
  501 
  502         return (1);
  503 }
  504 #endif  /* COMPAT_FREEBSD32 */
  505 #endif  /* !PRE7_COMPAT */
  506 
  507 union pci_conf_union {
  508         struct pci_conf         pc;
  509 #ifdef COMPAT_FREEBSD32
  510         struct pci_conf32       pc32;
  511 #endif
  512 #ifdef PRE7_COMPAT
  513         struct pci_conf_old     pco;
  514 #ifdef COMPAT_FREEBSD32
  515         struct pci_conf_old32   pco32;
  516 #endif
  517 #endif
  518 };
  519 
  520 static int
  521 pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches,
  522     struct pci_conf *match_buf)
  523 {
  524 
  525         switch (cmd) {
  526         case PCIOCGETCONF:
  527                 return (pci_conf_match_native(
  528                     (struct pci_match_conf *)matches, num_matches, match_buf));
  529 #ifdef COMPAT_FREEBSD32
  530         case PCIOCGETCONF32:
  531                 return (pci_conf_match32((struct pci_match_conf32 *)matches,
  532                     num_matches, match_buf));
  533 #endif
  534 #ifdef PRE7_COMPAT
  535         case PCIOCGETCONF_OLD:
  536                 return (pci_conf_match_old(
  537                     (struct pci_match_conf_old *)matches, num_matches,
  538                     match_buf));
  539 #ifdef COMPAT_FREEBSD32
  540         case PCIOCGETCONF_OLD32:
  541                 return (pci_conf_match_old32(
  542                     (struct pci_match_conf_old32 *)matches, num_matches,
  543                     match_buf));
  544 #endif
  545 #endif
  546         default:
  547                 /* programmer error */
  548                 return (0);
  549         }
  550 }
  551 
  552 /*
  553  * Like PVE_NEXT but takes an explicit length since 'pve' is a user
  554  * pointer that cannot be dereferenced.
  555  */
  556 #define PVE_NEXT_LEN(pve, datalen)                                      \
  557         ((struct pci_vpd_element *)((char *)(pve) +                     \
  558             sizeof(struct pci_vpd_element) + (datalen)))
  559 
  560 static int
  561 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
  562 {
  563         struct pci_vpd_element vpd_element, *vpd_user;
  564         struct pcicfg_vpd *vpd;
  565         size_t len, datalen;
  566         int error, i;
  567 
  568         vpd = pci_fetch_vpd_list(dev);
  569         if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL)
  570                 return (ENXIO);
  571 
  572         /*
  573          * Calculate the amount of space needed in the data buffer.  An
  574          * identifier element is always present followed by the read-only
  575          * and read-write keywords.
  576          */
  577         len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident);
  578         for (i = 0; i < vpd->vpd_rocnt; i++)
  579                 len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len;
  580         for (i = 0; i < vpd->vpd_wcnt; i++)
  581                 len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len;
  582 
  583         if (lvio->plvi_len == 0) {
  584                 lvio->plvi_len = len;
  585                 return (0);
  586         }
  587         if (lvio->plvi_len < len) {
  588                 lvio->plvi_len = len;
  589                 return (ENOMEM);
  590         }
  591 
  592         /*
  593          * Copyout the identifier string followed by each keyword and
  594          * value.
  595          */
  596         datalen = strlen(vpd->vpd_ident);
  597         KASSERT(datalen <= 255, ("invalid VPD ident length"));
  598         vpd_user = lvio->plvi_data;
  599         vpd_element.pve_keyword[0] = '\0';
  600         vpd_element.pve_keyword[1] = '\0';
  601         vpd_element.pve_flags = PVE_FLAG_IDENT;
  602         vpd_element.pve_datalen = datalen;
  603         error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
  604         if (error)
  605                 return (error);
  606         error = copyout(vpd->vpd_ident, vpd_user->pve_data, datalen);
  607         if (error)
  608                 return (error);
  609         vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
  610         vpd_element.pve_flags = 0;
  611         for (i = 0; i < vpd->vpd_rocnt; i++) {
  612                 vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0];
  613                 vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1];
  614                 vpd_element.pve_datalen = vpd->vpd_ros[i].len;
  615                 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
  616                 if (error)
  617                         return (error);
  618                 error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data,
  619                     vpd->vpd_ros[i].len);
  620                 if (error)
  621                         return (error);
  622                 vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
  623         }
  624         vpd_element.pve_flags = PVE_FLAG_RW;
  625         for (i = 0; i < vpd->vpd_wcnt; i++) {
  626                 vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0];
  627                 vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1];
  628                 vpd_element.pve_datalen = vpd->vpd_w[i].len;
  629                 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
  630                 if (error)
  631                         return (error);
  632                 error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data,
  633                     vpd->vpd_w[i].len);
  634                 if (error)
  635                         return (error);
  636                 vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
  637         }
  638         KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len,
  639             ("length mismatch"));
  640         lvio->plvi_len = len;
  641         return (0);
  642 }
  643 
  644 static size_t
  645 pci_match_conf_size(u_long cmd)
  646 {
  647 
  648         switch (cmd) {
  649         case PCIOCGETCONF:
  650                 return (sizeof(struct pci_match_conf));
  651 #ifdef COMPAT_FREEBSD32
  652         case PCIOCGETCONF32:
  653                 return (sizeof(struct pci_match_conf32));
  654 #endif
  655 #ifdef PRE7_COMPAT
  656         case PCIOCGETCONF_OLD:
  657                 return (sizeof(struct pci_match_conf_old));
  658 #ifdef COMPAT_FREEBSD32
  659         case PCIOCGETCONF_OLD32:
  660                 return (sizeof(struct pci_match_conf_old32));
  661 #endif
  662 #endif
  663         default:
  664                 /* programmer error */
  665                 return (0);
  666         }
  667 }
  668 
  669 static size_t
  670 pci_conf_size(u_long cmd)
  671 {
  672 
  673         switch (cmd) {
  674         case PCIOCGETCONF:
  675                 return (sizeof(struct pci_conf));
  676 #ifdef COMPAT_FREEBSD32
  677         case PCIOCGETCONF32:
  678                 return (sizeof(struct pci_conf32));
  679 #endif
  680 #ifdef PRE7_COMPAT
  681         case PCIOCGETCONF_OLD:
  682                 return (sizeof(struct pci_conf_old));
  683 #ifdef COMPAT_FREEBSD32
  684         case PCIOCGETCONF_OLD32:
  685                 return (sizeof(struct pci_conf_old32));
  686 #endif
  687 #endif
  688         default:
  689                 /* programmer error */
  690                 return (0);
  691         }
  692 }
  693 
  694 static void
  695 pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd)
  696 {
  697 #if defined(COMPAT_FREEBSD32)
  698         struct pci_conf_io32 *cio32;
  699 #endif
  700 
  701         switch (cmd) {
  702         case PCIOCGETCONF:
  703 #ifdef PRE7_COMPAT
  704         case PCIOCGETCONF_OLD:
  705 #endif
  706                 *cio = *(struct pci_conf_io *)data;
  707                 return;
  708 
  709 #ifdef COMPAT_FREEBSD32
  710         case PCIOCGETCONF32:
  711 #ifdef PRE7_COMPAT
  712         case PCIOCGETCONF_OLD32:
  713 #endif
  714                cio32 = (struct pci_conf_io32 *)data;
  715                cio->pat_buf_len = cio32->pat_buf_len;
  716                cio->num_patterns = cio32->num_patterns;
  717                cio->patterns = (void *)(uintptr_t)cio32->patterns;
  718                cio->match_buf_len = cio32->match_buf_len;
  719                cio->num_matches = cio32->num_matches;
  720                cio->matches = (void *)(uintptr_t)cio32->matches;
  721                cio->offset = cio32->offset;
  722                cio->generation = cio32->generation;
  723                cio->status = cio32->status;
  724                return;
  725 #endif
  726 
  727         default:
  728                 /* programmer error */
  729                 return;
  730         }
  731 }
  732 
  733 static void
  734 pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data,
  735     u_long cmd)
  736 {
  737         struct pci_conf_io *d_cio;
  738 #if defined(COMPAT_FREEBSD32)
  739         struct pci_conf_io32 *cio32;
  740 #endif
  741 
  742         switch (cmd) {
  743         case PCIOCGETCONF:
  744 #ifdef PRE7_COMPAT
  745         case PCIOCGETCONF_OLD:
  746 #endif
  747                 d_cio = (struct pci_conf_io *)data;
  748                 d_cio->status = cio->status;
  749                 d_cio->generation = cio->generation;
  750                 d_cio->offset = cio->offset;
  751                 d_cio->num_matches = cio->num_matches;
  752                 return;
  753 
  754 #ifdef COMPAT_FREEBSD32
  755         case PCIOCGETCONF32:
  756 #ifdef PRE7_COMPAT
  757         case PCIOCGETCONF_OLD32:
  758 #endif
  759                 cio32 = (struct pci_conf_io32 *)data;
  760 
  761                 cio32->status = cio->status;
  762                 cio32->generation = cio->generation;
  763                 cio32->offset = cio->offset;
  764                 cio32->num_matches = cio->num_matches;
  765                 return;
  766 #endif
  767 
  768         default:
  769                 /* programmer error */
  770                 return;
  771         }
  772 }
  773 
  774 static void
  775 pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup,
  776     u_long cmd)
  777 {
  778 
  779         memset(pcup, 0, sizeof(*pcup));
  780 
  781         switch (cmd) {
  782         case PCIOCGETCONF:
  783                 pcup->pc = *pcp;
  784                 return;
  785 
  786 #ifdef COMPAT_FREEBSD32
  787         case PCIOCGETCONF32:
  788                 pcup->pc32.pc_sel = pcp->pc_sel;
  789                 pcup->pc32.pc_hdr = pcp->pc_hdr;
  790                 pcup->pc32.pc_subvendor = pcp->pc_subvendor;
  791                 pcup->pc32.pc_subdevice = pcp->pc_subdevice;
  792                 pcup->pc32.pc_vendor = pcp->pc_vendor;
  793                 pcup->pc32.pc_device = pcp->pc_device;
  794                 pcup->pc32.pc_class = pcp->pc_class;
  795                 pcup->pc32.pc_subclass = pcp->pc_subclass;
  796                 pcup->pc32.pc_progif = pcp->pc_progif;
  797                 pcup->pc32.pc_revid = pcp->pc_revid;
  798                 strlcpy(pcup->pc32.pd_name, pcp->pd_name,
  799                     sizeof(pcup->pc32.pd_name));
  800                 pcup->pc32.pd_unit = (uint32_t)pcp->pd_unit;
  801                 return;
  802 #endif
  803 
  804 #ifdef PRE7_COMPAT
  805 #ifdef COMPAT_FREEBSD32
  806         case PCIOCGETCONF_OLD32:
  807                 pcup->pco32.pc_sel.pc_bus = pcp->pc_sel.pc_bus;
  808                 pcup->pco32.pc_sel.pc_dev = pcp->pc_sel.pc_dev;
  809                 pcup->pco32.pc_sel.pc_func = pcp->pc_sel.pc_func;
  810                 pcup->pco32.pc_hdr = pcp->pc_hdr;
  811                 pcup->pco32.pc_subvendor = pcp->pc_subvendor;
  812                 pcup->pco32.pc_subdevice = pcp->pc_subdevice;
  813                 pcup->pco32.pc_vendor = pcp->pc_vendor;
  814                 pcup->pco32.pc_device = pcp->pc_device;
  815                 pcup->pco32.pc_class = pcp->pc_class;
  816                 pcup->pco32.pc_subclass = pcp->pc_subclass;
  817                 pcup->pco32.pc_progif = pcp->pc_progif;
  818                 pcup->pco32.pc_revid = pcp->pc_revid;
  819                 strlcpy(pcup->pco32.pd_name, pcp->pd_name,
  820                     sizeof(pcup->pco32.pd_name));
  821                 pcup->pco32.pd_unit = (uint32_t)pcp->pd_unit;
  822                 return;
  823 
  824 #endif /* COMPAT_FREEBSD32 */
  825         case PCIOCGETCONF_OLD:
  826                 pcup->pco.pc_sel.pc_bus = pcp->pc_sel.pc_bus;
  827                 pcup->pco.pc_sel.pc_dev = pcp->pc_sel.pc_dev;
  828                 pcup->pco.pc_sel.pc_func = pcp->pc_sel.pc_func;
  829                 pcup->pco.pc_hdr = pcp->pc_hdr;
  830                 pcup->pco.pc_subvendor = pcp->pc_subvendor;
  831                 pcup->pco.pc_subdevice = pcp->pc_subdevice;
  832                 pcup->pco.pc_vendor = pcp->pc_vendor;
  833                 pcup->pco.pc_device = pcp->pc_device;
  834                 pcup->pco.pc_class = pcp->pc_class;
  835                 pcup->pco.pc_subclass = pcp->pc_subclass;
  836                 pcup->pco.pc_progif = pcp->pc_progif;
  837                 pcup->pco.pc_revid = pcp->pc_revid;
  838                 strlcpy(pcup->pco.pd_name, pcp->pd_name,
  839                     sizeof(pcup->pco.pd_name));
  840                 pcup->pco.pd_unit = pcp->pd_unit;
  841                 return;
  842 #endif /* PRE7_COMPAT */
  843 
  844         default:
  845                 /* programmer error */
  846                 return;
  847         }
  848 }
  849 
  850 static int
  851 pci_bar_mmap(device_t pcidev, struct pci_bar_mmap *pbm)
  852 {
  853         vm_map_t map;
  854         vm_object_t obj;
  855         struct thread *td;
  856         struct sglist *sg;
  857         struct pci_map *pm;
  858         rman_res_t membase;
  859         vm_paddr_t pbase;
  860         vm_size_t plen;
  861         vm_offset_t addr;
  862         vm_prot_t prot;
  863         int error, flags;
  864 
  865         td = curthread;
  866         map = &td->td_proc->p_vmspace->vm_map;
  867         if ((pbm->pbm_flags & ~(PCIIO_BAR_MMAP_FIXED | PCIIO_BAR_MMAP_EXCL |
  868             PCIIO_BAR_MMAP_RW | PCIIO_BAR_MMAP_ACTIVATE)) != 0 ||
  869             pbm->pbm_memattr != (vm_memattr_t)pbm->pbm_memattr ||
  870             !pmap_is_valid_memattr(map->pmap, pbm->pbm_memattr))
  871                 return (EINVAL);
  872 
  873         /* Fetch the BAR physical base and length. */
  874         pm = pci_find_bar(pcidev, pbm->pbm_reg);
  875         if (pm == NULL)
  876                 return (EINVAL);
  877         if (!pci_bar_enabled(pcidev, pm))
  878                 return (EBUSY); /* XXXKIB enable if _ACTIVATE */
  879         if (!PCI_BAR_MEM(pm->pm_value))
  880                 return (EIO);
  881         error = bus_translate_resource(pcidev, SYS_RES_MEMORY,
  882             pm->pm_value & PCIM_BAR_MEM_BASE, &membase);
  883         if (error != 0)
  884                 return (error);
  885 
  886         pbase = trunc_page(membase);
  887         plen = round_page(membase + ((pci_addr_t)1 << pm->pm_size)) -
  888             pbase;
  889         prot = VM_PROT_READ | (((pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) ?
  890             VM_PROT_WRITE : 0);
  891 
  892         /* Create vm structures and mmap. */
  893         sg = sglist_alloc(1, M_WAITOK);
  894         error = sglist_append_phys(sg, pbase, plen);
  895         if (error != 0)
  896                 goto out;
  897         obj = vm_pager_allocate(OBJT_SG, sg, plen, prot, 0, td->td_ucred);
  898         if (obj == NULL) {
  899                 error = EIO;
  900                 goto out;
  901         }
  902         obj->memattr = pbm->pbm_memattr;
  903         flags = MAP_SHARED;
  904         addr = 0;
  905         if ((pbm->pbm_flags & PCIIO_BAR_MMAP_FIXED) != 0) {
  906                 addr = (uintptr_t)pbm->pbm_map_base;
  907                 flags |= MAP_FIXED;
  908         }
  909         if ((pbm->pbm_flags & PCIIO_BAR_MMAP_EXCL) != 0)
  910                 flags |= MAP_CHECK_EXCL;
  911         error = vm_mmap_object(map, &addr, plen, prot, prot, flags, obj, 0,
  912             FALSE, td);
  913         if (error != 0) {
  914                 vm_object_deallocate(obj);
  915                 goto out;
  916         }
  917         pbm->pbm_map_base = (void *)addr;
  918         pbm->pbm_map_length = plen;
  919         pbm->pbm_bar_off = membase - pbase;
  920         pbm->pbm_bar_length = (pci_addr_t)1 << pm->pm_size;
  921 
  922 out:
  923         sglist_free(sg);
  924         return (error);
  925 }
  926 
  927 static int
  928 pci_bar_io(device_t pcidev, struct pci_bar_ioreq *pbi)
  929 {
  930         struct pci_map *pm;
  931         struct resource *res;
  932         uint32_t offset, width;
  933         int bar, error, type;
  934 
  935         if (pbi->pbi_op != PCIBARIO_READ &&
  936             pbi->pbi_op != PCIBARIO_WRITE)
  937                 return (EINVAL);
  938 
  939         bar = PCIR_BAR(pbi->pbi_bar);
  940         pm = pci_find_bar(pcidev, bar);
  941         if (pm == NULL)
  942                 return (EINVAL);
  943 
  944         offset = pbi->pbi_offset;
  945         width = pbi->pbi_width;
  946 
  947         if (offset + width < offset ||
  948             ((pci_addr_t)1 << pm->pm_size) < offset + width)
  949                 return (EINVAL);
  950 
  951         type = PCI_BAR_MEM(pm->pm_value) ? SYS_RES_MEMORY : SYS_RES_IOPORT;
  952 
  953         /*
  954          * This will fail if a driver has allocated the resource.  This could be
  955          * worked around by detecting that case and using bus_map_resource() to
  956          * populate the handle, but so far this is not needed.
  957          */
  958         res = bus_alloc_resource_any(pcidev, type, &bar, RF_ACTIVE);
  959         if (res == NULL)
  960                 return (ENOENT);
  961 
  962         error = 0;
  963         switch (pbi->pbi_op) {
  964         case PCIBARIO_READ:
  965                 switch (pbi->pbi_width) {
  966                 case 1:
  967                         pbi->pbi_value = bus_read_1(res, offset);
  968                         break;
  969                 case 2:
  970                         pbi->pbi_value = bus_read_2(res, offset);
  971                         break;
  972                 case 4:
  973                         pbi->pbi_value = bus_read_4(res, offset);
  974                         break;
  975 #ifndef __i386__
  976                 case 8:
  977                         pbi->pbi_value = bus_read_8(res, offset);
  978                         break;
  979 #endif
  980                 default:
  981                         error = EINVAL;
  982                         break;
  983                 }
  984                 break;
  985         case PCIBARIO_WRITE:
  986                 switch (pbi->pbi_width) {
  987                 case 1:
  988                         bus_write_1(res, offset, pbi->pbi_value);
  989                         break;
  990                 case 2:
  991                         bus_write_2(res, offset, pbi->pbi_value);
  992                         break;
  993                 case 4:
  994                         bus_write_4(res, offset, pbi->pbi_value);
  995                         break;
  996 #ifndef __i386__
  997                 case 8:
  998                         bus_write_8(res, offset, pbi->pbi_value);
  999                         break;
 1000 #endif
 1001                 default:
 1002                         error = EINVAL;
 1003                         break;
 1004                 }
 1005                 break;
 1006         }
 1007 
 1008         bus_release_resource(pcidev, type, bar, res);
 1009 
 1010         return (error);
 1011 }
 1012 
 1013 static int
 1014 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
 1015 {
 1016         device_t pcidev;
 1017         const char *name;
 1018         struct devlist *devlist_head;
 1019         struct pci_conf_io *cio = NULL;
 1020         struct pci_devinfo *dinfo;
 1021         struct pci_io *io;
 1022         struct pci_bar_ioreq *pbi;
 1023         struct pci_bar_io *bio;
 1024         struct pci_list_vpd_io *lvio;
 1025         struct pci_match_conf *pattern_buf;
 1026         struct pci_map *pm;
 1027         struct pci_bar_mmap *pbm;
 1028         size_t confsz, iolen;
 1029         int error, ionum, i, num_patterns;
 1030         union pci_conf_union pcu;
 1031 #ifdef PRE7_COMPAT
 1032         struct pci_io iodata;
 1033         struct pci_io_old *io_old;
 1034 
 1035         io_old = NULL;
 1036 #endif
 1037 
 1038         /*
 1039          * Interpret read-only opened /dev/pci as a promise that no
 1040          * operation of the file descriptor could modify system state,
 1041          * including side-effects due to reading devices registers.
 1042          */
 1043         if ((flag & FWRITE) == 0) {
 1044                 switch (cmd) {
 1045                 case PCIOCGETCONF:
 1046 #ifdef COMPAT_FREEBSD32
 1047                 case PCIOCGETCONF32:
 1048 #endif
 1049 #ifdef PRE7_COMPAT
 1050                 case PCIOCGETCONF_OLD:
 1051 #ifdef COMPAT_FREEBSD32
 1052                 case PCIOCGETCONF_OLD32:
 1053 #endif
 1054 #endif
 1055                 case PCIOCGETBAR:
 1056                 case PCIOCLISTVPD:
 1057                         break;
 1058                 default:
 1059                         return (EPERM);
 1060                 }
 1061         }
 1062 
 1063         /*
 1064          * Use bus topology lock to ensure that the pci list of devies doesn't
 1065          * change while we're traversing the list, in some cases multiple times.
 1066          */
 1067         bus_topo_lock();
 1068 
 1069         switch (cmd) {
 1070         case PCIOCGETCONF:
 1071 #ifdef COMPAT_FREEBSD32
 1072         case PCIOCGETCONF32:
 1073 #endif
 1074 #ifdef PRE7_COMPAT
 1075         case PCIOCGETCONF_OLD:
 1076 #ifdef COMPAT_FREEBSD32
 1077         case PCIOCGETCONF_OLD32:
 1078 #endif
 1079 #endif
 1080                 cio = malloc(sizeof(struct pci_conf_io), M_TEMP,
 1081                     M_WAITOK | M_ZERO);
 1082                 pci_conf_io_init(cio, data, cmd);
 1083                 pattern_buf = NULL;
 1084                 num_patterns = 0;
 1085                 dinfo = NULL;
 1086 
 1087                 cio->num_matches = 0;
 1088 
 1089                 /*
 1090                  * If the user specified an offset into the device list,
 1091                  * but the list has changed since they last called this
 1092                  * ioctl, tell them that the list has changed.  They will
 1093                  * have to get the list from the beginning.
 1094                  */
 1095                 if ((cio->offset != 0)
 1096                  && (cio->generation != pci_generation)){
 1097                         cio->status = PCI_GETCONF_LIST_CHANGED;
 1098                         error = 0;
 1099                         goto getconfexit;
 1100                 }
 1101 
 1102                 /*
 1103                  * Check to see whether the user has asked for an offset
 1104                  * past the end of our list.
 1105                  */
 1106                 if (cio->offset >= pci_numdevs) {
 1107                         cio->status = PCI_GETCONF_LAST_DEVICE;
 1108                         error = 0;
 1109                         goto getconfexit;
 1110                 }
 1111 
 1112                 /* get the head of the device queue */
 1113                 devlist_head = &pci_devq;
 1114 
 1115                 /*
 1116                  * Determine how much room we have for pci_conf structures.
 1117                  * Round the user's buffer size down to the nearest
 1118                  * multiple of sizeof(struct pci_conf) in case the user
 1119                  * didn't specify a multiple of that size.
 1120                  */
 1121                 confsz = pci_conf_size(cmd);
 1122                 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
 1123                     pci_numdevs * confsz);
 1124 
 1125                 /*
 1126                  * Since we know that iolen is a multiple of the size of
 1127                  * the pciconf union, it's okay to do this.
 1128                  */
 1129                 ionum = iolen / confsz;
 1130 
 1131                 /*
 1132                  * If this test is true, the user wants the pci_conf
 1133                  * structures returned to match the supplied entries.
 1134                  */
 1135                 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
 1136                  && (cio->pat_buf_len > 0)) {
 1137                         /*
 1138                          * pat_buf_len needs to be:
 1139                          * num_patterns * sizeof(struct pci_match_conf)
 1140                          * While it is certainly possible the user just
 1141                          * allocated a large buffer, but set the number of
 1142                          * matches correctly, it is far more likely that
 1143                          * their kernel doesn't match the userland utility
 1144                          * they're using.  It's also possible that the user
 1145                          * forgot to initialize some variables.  Yes, this
 1146                          * may be overly picky, but I hazard to guess that
 1147                          * it's far more likely to just catch folks that
 1148                          * updated their kernel but not their userland.
 1149                          */
 1150                         if (cio->num_patterns * pci_match_conf_size(cmd) !=
 1151                             cio->pat_buf_len) {
 1152                                 /* The user made a mistake, return an error. */
 1153                                 cio->status = PCI_GETCONF_ERROR;
 1154                                 error = EINVAL;
 1155                                 goto getconfexit;
 1156                         }
 1157 
 1158                         /*
 1159                          * Allocate a buffer to hold the patterns.
 1160                          */
 1161                         pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
 1162                             M_WAITOK);
 1163                         error = copyin(cio->patterns, pattern_buf,
 1164                             cio->pat_buf_len);
 1165                         if (error != 0) {
 1166                                 error = EINVAL;
 1167                                 goto getconfexit;
 1168                         }
 1169                         num_patterns = cio->num_patterns;
 1170                 } else if ((cio->num_patterns > 0)
 1171                         || (cio->pat_buf_len > 0)) {
 1172                         /*
 1173                          * The user made a mistake, spit out an error.
 1174                          */
 1175                         cio->status = PCI_GETCONF_ERROR;
 1176                         error = EINVAL;
 1177                        goto getconfexit;
 1178                 }
 1179 
 1180                 /*
 1181                  * Go through the list of devices and copy out the devices
 1182                  * that match the user's criteria.
 1183                  */
 1184                 for (cio->num_matches = 0, i = 0,
 1185                                  dinfo = STAILQ_FIRST(devlist_head);
 1186                      dinfo != NULL;
 1187                      dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
 1188                         if (i < cio->offset)
 1189                                 continue;
 1190 
 1191                         /* Populate pd_name and pd_unit */
 1192                         name = NULL;
 1193                         if (dinfo->cfg.dev)
 1194                                 name = device_get_name(dinfo->cfg.dev);
 1195                         if (name) {
 1196                                 strncpy(dinfo->conf.pd_name, name,
 1197                                         sizeof(dinfo->conf.pd_name));
 1198                                 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
 1199                                 dinfo->conf.pd_unit =
 1200                                         device_get_unit(dinfo->cfg.dev);
 1201                         } else {
 1202                                 dinfo->conf.pd_name[0] = '\0';
 1203                                 dinfo->conf.pd_unit = 0;
 1204                         }
 1205 
 1206                         if (pattern_buf == NULL ||
 1207                             pci_conf_match(cmd, pattern_buf, num_patterns,
 1208                             &dinfo->conf) == 0) {
 1209                                 /*
 1210                                  * If we've filled up the user's buffer,
 1211                                  * break out at this point.  Since we've
 1212                                  * got a match here, we'll pick right back
 1213                                  * up at the matching entry.  We can also
 1214                                  * tell the user that there are more matches
 1215                                  * left.
 1216                                  */
 1217                                 if (cio->num_matches >= ionum) {
 1218                                         error = 0;
 1219                                         break;
 1220                                 }
 1221 
 1222                                 pci_conf_for_copyout(&dinfo->conf, &pcu, cmd);
 1223                                 error = copyout(&pcu,
 1224                                     (caddr_t)cio->matches +
 1225                                     confsz * cio->num_matches, confsz);
 1226                                 if (error)
 1227                                         break;
 1228                                 cio->num_matches++;
 1229                         }
 1230                 }
 1231 
 1232                 /*
 1233                  * Set the pointer into the list, so if the user is getting
 1234                  * n records at a time, where n < pci_numdevs,
 1235                  */
 1236                 cio->offset = i;
 1237 
 1238                 /*
 1239                  * Set the generation, the user will need this if they make
 1240                  * another ioctl call with offset != 0.
 1241                  */
 1242                 cio->generation = pci_generation;
 1243 
 1244                 /*
 1245                  * If this is the last device, inform the user so he won't
 1246                  * bother asking for more devices.  If dinfo isn't NULL, we
 1247                  * know that there are more matches in the list because of
 1248                  * the way the traversal is done.
 1249                  */
 1250                 if (dinfo == NULL)
 1251                         cio->status = PCI_GETCONF_LAST_DEVICE;
 1252                 else
 1253                         cio->status = PCI_GETCONF_MORE_DEVS;
 1254 
 1255 getconfexit:
 1256                 pci_conf_io_update_data(cio, data, cmd);
 1257                 free(cio, M_TEMP);
 1258                 free(pattern_buf, M_TEMP);
 1259 
 1260                 break;
 1261 
 1262 #ifdef PRE7_COMPAT
 1263         case PCIOCREAD_OLD:
 1264         case PCIOCWRITE_OLD:
 1265                 io_old = (struct pci_io_old *)data;
 1266                 iodata.pi_sel.pc_domain = 0;
 1267                 iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus;
 1268                 iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev;
 1269                 iodata.pi_sel.pc_func = io_old->pi_sel.pc_func;
 1270                 iodata.pi_reg = io_old->pi_reg;
 1271                 iodata.pi_width = io_old->pi_width;
 1272                 iodata.pi_data = io_old->pi_data;
 1273                 data = (caddr_t)&iodata;
 1274                 /* FALLTHROUGH */
 1275 #endif
 1276         case PCIOCREAD:
 1277         case PCIOCWRITE:
 1278                 io = (struct pci_io *)data;
 1279                 switch(io->pi_width) {
 1280                 case 4:
 1281                 case 2:
 1282                 case 1:
 1283                         /* Make sure register is not negative and aligned. */
 1284                         if (io->pi_reg < 0 ||
 1285                             io->pi_reg & (io->pi_width - 1)) {
 1286                                 error = EINVAL;
 1287                                 break;
 1288                         }
 1289                         /*
 1290                          * Assume that the user-level bus number is
 1291                          * in fact the physical PCI bus number.
 1292                          * Look up the grandparent, i.e. the bridge device,
 1293                          * so that we can issue configuration space cycles.
 1294                          */
 1295                         pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
 1296                             io->pi_sel.pc_bus, io->pi_sel.pc_dev,
 1297                             io->pi_sel.pc_func);
 1298                         if (pcidev) {
 1299 #ifdef PRE7_COMPAT
 1300                                 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
 1301 #else
 1302                                 if (cmd == PCIOCWRITE)
 1303 #endif
 1304                                         pci_write_config(pcidev,
 1305                                                           io->pi_reg,
 1306                                                           io->pi_data,
 1307                                                           io->pi_width);
 1308 #ifdef PRE7_COMPAT
 1309                                 else if (cmd == PCIOCREAD_OLD)
 1310                                         io_old->pi_data =
 1311                                                 pci_read_config(pcidev,
 1312                                                           io->pi_reg,
 1313                                                           io->pi_width);
 1314 #endif
 1315                                 else
 1316                                         io->pi_data =
 1317                                                 pci_read_config(pcidev,
 1318                                                           io->pi_reg,
 1319                                                           io->pi_width);
 1320                                 error = 0;
 1321                         } else {
 1322 #ifdef COMPAT_FREEBSD4
 1323                                 if (cmd == PCIOCREAD_OLD) {
 1324                                         io_old->pi_data = -1;
 1325                                         error = 0;
 1326                                 } else
 1327 #endif
 1328                                         error = ENODEV;
 1329                         }
 1330                         break;
 1331                 default:
 1332                         error = EINVAL;
 1333                         break;
 1334                 }
 1335                 break;
 1336 
 1337         case PCIOCGETBAR:
 1338                 bio = (struct pci_bar_io *)data;
 1339 
 1340                 /*
 1341                  * Assume that the user-level bus number is
 1342                  * in fact the physical PCI bus number.
 1343                  */
 1344                 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
 1345                     bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
 1346                     bio->pbi_sel.pc_func);
 1347                 if (pcidev == NULL) {
 1348                         error = ENODEV;
 1349                         break;
 1350                 }
 1351                 pm = pci_find_bar(pcidev, bio->pbi_reg);
 1352                 if (pm == NULL) {
 1353                         error = EINVAL;
 1354                         break;
 1355                 }
 1356                 bio->pbi_base = pm->pm_value;
 1357                 bio->pbi_length = (pci_addr_t)1 << pm->pm_size;
 1358                 bio->pbi_enabled = pci_bar_enabled(pcidev, pm);
 1359                 error = 0;
 1360                 break;
 1361         case PCIOCATTACHED:
 1362                 error = 0;
 1363                 io = (struct pci_io *)data;
 1364                 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus,
 1365                                        io->pi_sel.pc_dev, io->pi_sel.pc_func);
 1366                 if (pcidev != NULL)
 1367                         io->pi_data = device_is_attached(pcidev);
 1368                 else
 1369                         error = ENODEV;
 1370                 break;
 1371         case PCIOCLISTVPD:
 1372                 lvio = (struct pci_list_vpd_io *)data;
 1373 
 1374                 /*
 1375                  * Assume that the user-level bus number is
 1376                  * in fact the physical PCI bus number.
 1377                  */
 1378                 pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain,
 1379                     lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev,
 1380                     lvio->plvi_sel.pc_func);
 1381                 if (pcidev == NULL) {
 1382                         error = ENODEV;
 1383                         break;
 1384                 }
 1385                 error = pci_list_vpd(pcidev, lvio);
 1386                 break;
 1387 
 1388         case PCIOCBARMMAP:
 1389                 pbm = (struct pci_bar_mmap *)data;
 1390                 if ((flag & FWRITE) == 0 &&
 1391                     (pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) {
 1392                         error = EPERM;
 1393                         break;
 1394                 }
 1395                 pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain,
 1396                     pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev,
 1397                     pbm->pbm_sel.pc_func);
 1398                 error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm);
 1399                 break;
 1400 
 1401         case PCIOCBARIO:
 1402                 pbi = (struct pci_bar_ioreq *)data;
 1403 
 1404                 pcidev = pci_find_dbsf(pbi->pbi_sel.pc_domain,
 1405                     pbi->pbi_sel.pc_bus, pbi->pbi_sel.pc_dev,
 1406                     pbi->pbi_sel.pc_func);
 1407                 if (pcidev == NULL) {
 1408                         error = ENODEV;
 1409                         break;
 1410                 }
 1411                 error = pci_bar_io(pcidev, pbi);
 1412                 break;
 1413 
 1414         default:
 1415                 error = ENOTTY;
 1416                 break;
 1417         }
 1418 
 1419         bus_topo_unlock();
 1420 
 1421         return (error);
 1422 }

Cache object: 0333a2263975026ec4924e410ced786d


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