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/9.0/sys/dev/pci/pci_user.c 220195 2011-03-31 13:22:12Z jhb $");
   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 #define PCIOCGETCONF_OLD        _IOWR('p', 1, struct pci_conf_io)
  229 #define PCIOCREAD_OLD           _IOWR('p', 2, struct pci_io_old)
  230 #define PCIOCWRITE_OLD          _IOWR('p', 3, struct pci_io_old)
  231 
  232 static int      pci_conf_match_old(struct pci_match_conf_old *matches,
  233                     int num_matches, struct pci_conf *match_buf);
  234 
  235 static int
  236 pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches,
  237     struct pci_conf *match_buf)
  238 {
  239         int i;
  240 
  241         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
  242                 return(1);
  243 
  244         for (i = 0; i < num_matches; i++) {
  245                 if (match_buf->pc_sel.pc_domain != 0)
  246                         continue;
  247 
  248                 /*
  249                  * I'm not sure why someone would do this...but...
  250                  */
  251                 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
  252                         continue;
  253 
  254                 /*
  255                  * Look at each of the match flags.  If it's set, do the
  256                  * comparison.  If the comparison fails, we don't have a
  257                  * match, go on to the next item if there is one.
  258                  */
  259                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0)
  260                  && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
  261                         continue;
  262 
  263                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0)
  264                  && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
  265                         continue;
  266 
  267                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0)
  268                  && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
  269                         continue;
  270 
  271                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0)
  272                  && (match_buf->pc_vendor != matches[i].pc_vendor))
  273                         continue;
  274 
  275                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0)
  276                  && (match_buf->pc_device != matches[i].pc_device))
  277                         continue;
  278 
  279                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0)
  280                  && (match_buf->pc_class != matches[i].pc_class))
  281                         continue;
  282 
  283                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0)
  284                  && (match_buf->pd_unit != matches[i].pd_unit))
  285                         continue;
  286 
  287                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0)
  288                  && (strncmp(matches[i].pd_name, match_buf->pd_name,
  289                              sizeof(match_buf->pd_name)) != 0))
  290                         continue;
  291 
  292                 return(0);
  293         }
  294 
  295         return(1);
  296 }
  297 
  298 #endif
  299 
  300 static int
  301 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
  302 {
  303         device_t pcidev, brdev;
  304         void *confdata;
  305         const char *name;
  306         struct devlist *devlist_head;
  307         struct pci_conf_io *cio;
  308         struct pci_devinfo *dinfo;
  309         struct pci_io *io;
  310         struct pci_bar_io *bio;
  311         struct pci_match_conf *pattern_buf;
  312         struct pci_map *pm;
  313         size_t confsz, iolen, pbufsz;
  314         int error, ionum, i, num_patterns;
  315 #ifdef PRE7_COMPAT
  316         struct pci_conf_old conf_old;
  317         struct pci_io iodata;
  318         struct pci_io_old *io_old;
  319         struct pci_match_conf_old *pattern_buf_old;
  320 
  321         io_old = NULL;
  322         pattern_buf_old = NULL;
  323 
  324         if (!(flag & FWRITE) && cmd != PCIOCGETBAR &&
  325             cmd != PCIOCGETCONF && cmd != PCIOCGETCONF_OLD)
  326                 return EPERM;
  327 #else
  328         if (!(flag & FWRITE) && cmd != PCIOCGETBAR && cmd != PCIOCGETCONF)
  329                 return EPERM;
  330 #endif
  331 
  332         switch(cmd) {
  333 #ifdef PRE7_COMPAT
  334         case PCIOCGETCONF_OLD:
  335                 /* FALLTHROUGH */
  336 #endif
  337         case PCIOCGETCONF:
  338                 cio = (struct pci_conf_io *)data;
  339 
  340                 pattern_buf = NULL;
  341                 num_patterns = 0;
  342                 dinfo = NULL;
  343 
  344                 cio->num_matches = 0;
  345 
  346                 /*
  347                  * If the user specified an offset into the device list,
  348                  * but the list has changed since they last called this
  349                  * ioctl, tell them that the list has changed.  They will
  350                  * have to get the list from the beginning.
  351                  */
  352                 if ((cio->offset != 0)
  353                  && (cio->generation != pci_generation)){
  354                         cio->status = PCI_GETCONF_LIST_CHANGED;
  355                         error = 0;
  356                         break;
  357                 }
  358 
  359                 /*
  360                  * Check to see whether the user has asked for an offset
  361                  * past the end of our list.
  362                  */
  363                 if (cio->offset >= pci_numdevs) {
  364                         cio->status = PCI_GETCONF_LAST_DEVICE;
  365                         error = 0;
  366                         break;
  367                 }
  368 
  369                 /* get the head of the device queue */
  370                 devlist_head = &pci_devq;
  371 
  372                 /*
  373                  * Determine how much room we have for pci_conf structures.
  374                  * Round the user's buffer size down to the nearest
  375                  * multiple of sizeof(struct pci_conf) in case the user
  376                  * didn't specify a multiple of that size.
  377                  */
  378 #ifdef PRE7_COMPAT
  379                 if (cmd == PCIOCGETCONF_OLD)
  380                         confsz = sizeof(struct pci_conf_old);
  381                 else
  382 #endif
  383                         confsz = sizeof(struct pci_conf);
  384                 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
  385                     pci_numdevs * confsz);
  386 
  387                 /*
  388                  * Since we know that iolen is a multiple of the size of
  389                  * the pciconf union, it's okay to do this.
  390                  */
  391                 ionum = iolen / confsz;
  392 
  393                 /*
  394                  * If this test is true, the user wants the pci_conf
  395                  * structures returned to match the supplied entries.
  396                  */
  397                 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
  398                  && (cio->pat_buf_len > 0)) {
  399                         /*
  400                          * pat_buf_len needs to be:
  401                          * num_patterns * sizeof(struct pci_match_conf)
  402                          * While it is certainly possible the user just
  403                          * allocated a large buffer, but set the number of
  404                          * matches correctly, it is far more likely that
  405                          * their kernel doesn't match the userland utility
  406                          * they're using.  It's also possible that the user
  407                          * forgot to initialize some variables.  Yes, this
  408                          * may be overly picky, but I hazard to guess that
  409                          * it's far more likely to just catch folks that
  410                          * updated their kernel but not their userland.
  411                          */
  412 #ifdef PRE7_COMPAT
  413                         if (cmd == PCIOCGETCONF_OLD)
  414                                 pbufsz = sizeof(struct pci_match_conf_old);
  415                         else
  416 #endif
  417                                 pbufsz = sizeof(struct pci_match_conf);
  418                         if (cio->num_patterns * pbufsz != cio->pat_buf_len) {
  419                                 /* The user made a mistake, return an error. */
  420                                 cio->status = PCI_GETCONF_ERROR;
  421                                 error = EINVAL;
  422                                 break;
  423                         }
  424 
  425                         /*
  426                          * Allocate a buffer to hold the patterns.
  427                          */
  428 #ifdef PRE7_COMPAT
  429                         if (cmd == PCIOCGETCONF_OLD) {
  430                                 pattern_buf_old = malloc(cio->pat_buf_len,
  431                                     M_TEMP, M_WAITOK);
  432                                 error = copyin(cio->patterns,
  433                                     pattern_buf_old, cio->pat_buf_len);
  434                         } else
  435 #endif
  436                         {
  437                                 pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
  438                                     M_WAITOK);
  439                                 error = copyin(cio->patterns, pattern_buf,
  440                                     cio->pat_buf_len);
  441                         }
  442                         if (error != 0) {
  443                                 error = EINVAL;
  444                                 goto getconfexit;
  445                         }
  446                         num_patterns = cio->num_patterns;
  447                 } else if ((cio->num_patterns > 0)
  448                         || (cio->pat_buf_len > 0)) {
  449                         /*
  450                          * The user made a mistake, spit out an error.
  451                          */
  452                         cio->status = PCI_GETCONF_ERROR;
  453                         error = EINVAL;
  454                         break;
  455                 }
  456 
  457                 /*
  458                  * Go through the list of devices and copy out the devices
  459                  * that match the user's criteria.
  460                  */
  461                 for (cio->num_matches = 0, error = 0, i = 0,
  462                      dinfo = STAILQ_FIRST(devlist_head);
  463                      (dinfo != NULL) && (cio->num_matches < ionum)
  464                      && (error == 0) && (i < pci_numdevs) && (dinfo != NULL);
  465                      dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
  466 
  467                         if (i < cio->offset)
  468                                 continue;
  469 
  470                         /* Populate pd_name and pd_unit */
  471                         name = NULL;
  472                         if (dinfo->cfg.dev)
  473                                 name = device_get_name(dinfo->cfg.dev);
  474                         if (name) {
  475                                 strncpy(dinfo->conf.pd_name, name,
  476                                         sizeof(dinfo->conf.pd_name));
  477                                 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
  478                                 dinfo->conf.pd_unit =
  479                                         device_get_unit(dinfo->cfg.dev);
  480                         } else {
  481                                 dinfo->conf.pd_name[0] = '\0';
  482                                 dinfo->conf.pd_unit = 0;
  483                         }
  484 
  485 #ifdef PRE7_COMPAT
  486                         if ((cmd == PCIOCGETCONF_OLD &&
  487                             (pattern_buf_old == NULL ||
  488                             pci_conf_match_old(pattern_buf_old, num_patterns,
  489                             &dinfo->conf) == 0)) ||
  490                             (cmd == PCIOCGETCONF &&
  491                             (pattern_buf == NULL ||
  492                             pci_conf_match(pattern_buf, num_patterns,
  493                             &dinfo->conf) == 0))) {
  494 #else
  495                         if (pattern_buf == NULL ||
  496                             pci_conf_match(pattern_buf, num_patterns,
  497                             &dinfo->conf) == 0) {
  498 #endif
  499                                 /*
  500                                  * If we've filled up the user's buffer,
  501                                  * break out at this point.  Since we've
  502                                  * got a match here, we'll pick right back
  503                                  * up at the matching entry.  We can also
  504                                  * tell the user that there are more matches
  505                                  * left.
  506                                  */
  507                                 if (cio->num_matches >= ionum)
  508                                         break;
  509 
  510 #ifdef PRE7_COMPAT
  511                                 if (cmd == PCIOCGETCONF_OLD) {
  512                                         conf_old.pc_sel.pc_bus =
  513                                             dinfo->conf.pc_sel.pc_bus;
  514                                         conf_old.pc_sel.pc_dev =
  515                                             dinfo->conf.pc_sel.pc_dev;
  516                                         conf_old.pc_sel.pc_func =
  517                                             dinfo->conf.pc_sel.pc_func;
  518                                         conf_old.pc_hdr = dinfo->conf.pc_hdr;
  519                                         conf_old.pc_subvendor =
  520                                             dinfo->conf.pc_subvendor;
  521                                         conf_old.pc_subdevice =
  522                                             dinfo->conf.pc_subdevice;
  523                                         conf_old.pc_vendor =
  524                                             dinfo->conf.pc_vendor;
  525                                         conf_old.pc_device =
  526                                             dinfo->conf.pc_device;
  527                                         conf_old.pc_class =
  528                                             dinfo->conf.pc_class;
  529                                         conf_old.pc_subclass =
  530                                             dinfo->conf.pc_subclass;
  531                                         conf_old.pc_progif =
  532                                             dinfo->conf.pc_progif;
  533                                         conf_old.pc_revid =
  534                                             dinfo->conf.pc_revid;
  535                                         strncpy(conf_old.pd_name,
  536                                             dinfo->conf.pd_name,
  537                                             sizeof(conf_old.pd_name));
  538                                         conf_old.pd_name[PCI_MAXNAMELEN] = 0;
  539                                         conf_old.pd_unit =
  540                                             dinfo->conf.pd_unit;
  541                                         confdata = &conf_old;
  542                                 } else
  543 #endif
  544                                         confdata = &dinfo->conf;
  545                                 /* Only if we can copy it out do we count it. */
  546                                 if (!(error = copyout(confdata,
  547                                     (caddr_t)cio->matches +
  548                                     confsz * cio->num_matches, confsz)))
  549                                         cio->num_matches++;
  550                         }
  551                 }
  552 
  553                 /*
  554                  * Set the pointer into the list, so if the user is getting
  555                  * n records at a time, where n < pci_numdevs,
  556                  */
  557                 cio->offset = i;
  558 
  559                 /*
  560                  * Set the generation, the user will need this if they make
  561                  * another ioctl call with offset != 0.
  562                  */
  563                 cio->generation = pci_generation;
  564 
  565                 /*
  566                  * If this is the last device, inform the user so he won't
  567                  * bother asking for more devices.  If dinfo isn't NULL, we
  568                  * know that there are more matches in the list because of
  569                  * the way the traversal is done.
  570                  */
  571                 if (dinfo == NULL)
  572                         cio->status = PCI_GETCONF_LAST_DEVICE;
  573                 else
  574                         cio->status = PCI_GETCONF_MORE_DEVS;
  575 
  576 getconfexit:
  577                 if (pattern_buf != NULL)
  578                         free(pattern_buf, M_TEMP);
  579 #ifdef PRE7_COMPAT
  580                 if (pattern_buf_old != NULL)
  581                         free(pattern_buf_old, M_TEMP);
  582 #endif
  583 
  584                 break;
  585 
  586 #ifdef PRE7_COMPAT
  587         case PCIOCREAD_OLD:
  588         case PCIOCWRITE_OLD:
  589                 io_old = (struct pci_io_old *)data;
  590                 iodata.pi_sel.pc_domain = 0;
  591                 iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus;
  592                 iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev;
  593                 iodata.pi_sel.pc_func = io_old->pi_sel.pc_func;
  594                 iodata.pi_reg = io_old->pi_reg;
  595                 iodata.pi_width = io_old->pi_width;
  596                 iodata.pi_data = io_old->pi_data;
  597                 data = (caddr_t)&iodata;
  598                 /* FALLTHROUGH */
  599 #endif
  600         case PCIOCREAD:
  601         case PCIOCWRITE:
  602                 io = (struct pci_io *)data;
  603                 switch(io->pi_width) {
  604                 case 4:
  605                 case 2:
  606                 case 1:
  607                         /* Make sure register is not negative and aligned. */
  608                         if (io->pi_reg < 0 ||
  609                             io->pi_reg & (io->pi_width - 1)) {
  610                                 error = EINVAL;
  611                                 break;
  612                         }
  613                         /*
  614                          * Assume that the user-level bus number is
  615                          * in fact the physical PCI bus number.
  616                          * Look up the grandparent, i.e. the bridge device,
  617                          * so that we can issue configuration space cycles.
  618                          */
  619                         pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
  620                             io->pi_sel.pc_bus, io->pi_sel.pc_dev,
  621                             io->pi_sel.pc_func);
  622                         if (pcidev) {
  623                                 brdev = device_get_parent(
  624                                     device_get_parent(pcidev));
  625 
  626 #ifdef PRE7_COMPAT
  627                                 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
  628 #else
  629                                 if (cmd == PCIOCWRITE)
  630 #endif
  631                                         PCIB_WRITE_CONFIG(brdev,
  632                                                           io->pi_sel.pc_bus,
  633                                                           io->pi_sel.pc_dev,
  634                                                           io->pi_sel.pc_func,
  635                                                           io->pi_reg,
  636                                                           io->pi_data,
  637                                                           io->pi_width);
  638 #ifdef PRE7_COMPAT
  639                                 else if (cmd == PCIOCREAD_OLD)
  640                                         io_old->pi_data =
  641                                                 PCIB_READ_CONFIG(brdev,
  642                                                           io->pi_sel.pc_bus,
  643                                                           io->pi_sel.pc_dev,
  644                                                           io->pi_sel.pc_func,
  645                                                           io->pi_reg,
  646                                                           io->pi_width);
  647 #endif
  648                                 else
  649                                         io->pi_data =
  650                                                 PCIB_READ_CONFIG(brdev,
  651                                                           io->pi_sel.pc_bus,
  652                                                           io->pi_sel.pc_dev,
  653                                                           io->pi_sel.pc_func,
  654                                                           io->pi_reg,
  655                                                           io->pi_width);
  656                                 error = 0;
  657                         } else {
  658 #ifdef COMPAT_FREEBSD4
  659                                 if (cmd == PCIOCREAD_OLD) {
  660                                         io_old->pi_data = -1;
  661                                         error = 0;
  662                                 } else
  663 #endif
  664                                         error = ENODEV;
  665                         }
  666                         break;
  667                 default:
  668                         error = EINVAL;
  669                         break;
  670                 }
  671                 break;
  672 
  673         case PCIOCGETBAR:
  674                 bio = (struct pci_bar_io *)data;
  675 
  676                 /*
  677                  * Assume that the user-level bus number is
  678                  * in fact the physical PCI bus number.
  679                  */
  680                 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
  681                     bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
  682                     bio->pbi_sel.pc_func);
  683                 if (pcidev == NULL) {
  684                         error = ENODEV;
  685                         break;
  686                 }
  687                 pm = pci_find_bar(pcidev, bio->pbi_reg);
  688                 if (pm == NULL) {
  689                         error = EINVAL;
  690                         break;
  691                 }
  692                 bio->pbi_base = pm->pm_value;
  693                 bio->pbi_length = (pci_addr_t)1 << pm->pm_size;
  694                 bio->pbi_enabled = pci_bar_enabled(pcidev, pm);
  695                 error = 0;
  696                 break;
  697         case PCIOCATTACHED:
  698                 error = 0;
  699                 io = (struct pci_io *)data;
  700                 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus,
  701                                        io->pi_sel.pc_dev, io->pi_sel.pc_func);
  702                 if (pcidev != NULL)
  703                         io->pi_data = device_is_attached(pcidev);
  704                 else
  705                         error = ENODEV;
  706                 break;
  707         default:
  708                 error = ENOTTY;
  709                 break;
  710         }
  711 
  712         return (error);
  713 }

Cache object: 278fb3ef5349d39a0f73b5ddfba4ed36


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