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/kern/subr_autoconf.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 /*      $OpenBSD: subr_autoconf.c,v 1.97 2022/11/07 14:25:44 robert Exp $       */
    2 /*      $NetBSD: subr_autoconf.c,v 1.21 1996/04/04 06:06:18 cgd Exp $   */
    3 
    4 /*
    5  * Copyright (c) 1992, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * This software was developed by the Computer Systems Engineering group
    9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
   10  * contributed to Berkeley.
   11  *
   12  * All advertising materials mentioning features or use of this software
   13  * must display the following acknowledgement:
   14  *      This product includes software developed by the University of
   15  *      California, Lawrence Berkeley Laboratories.
   16  *
   17  * Redistribution and use in source and binary forms, with or without
   18  * modification, are permitted provided that the following conditions
   19  * are met:
   20  * 1. Redistributions of source code must retain the above copyright
   21  *    notice, this list of conditions and the following disclaimer.
   22  * 2. Redistributions in binary form must reproduce the above copyright
   23  *    notice, this list of conditions and the following disclaimer in the
   24  *    documentation and/or other materials provided with the distribution.
   25  * 3. Neither the name of the University nor the names of its contributors
   26  *    may be used to endorse or promote products derived from this software
   27  *    without specific prior written permission.
   28  *
   29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   39  * SUCH DAMAGE.
   40  *
   41  * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp  (LBL)
   42  *
   43  *      @(#)subr_autoconf.c     8.1 (Berkeley) 6/10/93
   44  */
   45 
   46 #include <sys/param.h>
   47 #include <sys/device.h>
   48 #include <sys/hotplug.h>
   49 #include <sys/malloc.h>
   50 #include <sys/systm.h>
   51 #include <sys/queue.h>
   52 #include <sys/mutex.h>
   53 #include <sys/atomic.h>
   54 #include <sys/reboot.h>
   55 
   56 #include "hotplug.h"
   57 #include "mpath.h"
   58 
   59 /*
   60  * Autoconfiguration subroutines.
   61  */
   62 
   63 /*
   64  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
   65  * devices and drivers are found via these tables.
   66  */
   67 extern short cfroots[];
   68 
   69 #define ROOT ((struct device *)NULL)
   70 
   71 struct matchinfo {
   72         cfmatch_t fn;
   73         struct  device *parent;
   74         void    *match, *aux;
   75         int     indirect, pri;
   76 };
   77 
   78 #ifndef AUTOCONF_VERBOSE
   79 #define AUTOCONF_VERBOSE 0
   80 #endif /* AUTOCONF_VERBOSE */
   81 int autoconf_verbose = AUTOCONF_VERBOSE;        /* trace probe calls */
   82 
   83 static void mapply(struct matchinfo *, struct cfdata *);
   84 
   85 struct deferred_config {
   86         TAILQ_ENTRY(deferred_config) dc_queue;
   87         struct device *dc_dev;
   88         void (*dc_func)(struct device *);
   89 };
   90 
   91 TAILQ_HEAD(, deferred_config) deferred_config_queue;
   92 TAILQ_HEAD(, deferred_config) mountroot_config_queue;
   93 
   94 void *config_rootsearch(cfmatch_t, char *, void *);
   95 void config_process_deferred_children(struct device *);
   96 
   97 struct devicelist alldevs;              /* list of all devices */
   98 
   99 volatile int config_pending;            /* semaphore for mountroot */
  100 
  101 struct mutex autoconf_attdet_mtx = MUTEX_INITIALIZER(IPL_HIGH);
  102 /*
  103  * If > 0, devices are being attached and any thread which tries to
  104  * detach will sleep; if < 0 devices are being detached and any
  105  * thread which tries to attach will sleep.
  106  */
  107 int     autoconf_attdet;
  108 
  109 /*
  110  * Versioned state of the devices tree so that changes can be detected.
  111  */
  112 unsigned int autoconf_serial = 0;
  113 
  114 /*
  115  * Initialize autoconfiguration data structures.  This occurs before console
  116  * initialization as that might require use of this subsystem.  Furthermore
  117  * this means that malloc et al. isn't yet available.
  118  */
  119 void
  120 config_init(void)
  121 {
  122         TAILQ_INIT(&deferred_config_queue);
  123         TAILQ_INIT(&mountroot_config_queue);
  124         TAILQ_INIT(&alldevs);
  125 }
  126 
  127 /*
  128  * Apply the matching function and choose the best.  This is used
  129  * a few times and we want to keep the code small.
  130  */
  131 void
  132 mapply(struct matchinfo *m, struct cfdata *cf)
  133 {
  134         int pri;
  135         void *match;
  136 
  137         if (m->indirect)
  138                 match = config_make_softc(m->parent, cf);
  139         else
  140                 match = cf;
  141 
  142         if (autoconf_verbose) {
  143                 printf(">>> probing for %s", cf->cf_driver->cd_name);
  144                 if (cf->cf_fstate == FSTATE_STAR)
  145                         printf("*\n");
  146                 else
  147                         printf("%d\n", cf->cf_unit);
  148         }
  149         if (m->fn != NULL)
  150                 pri = (*m->fn)(m->parent, match, m->aux);
  151         else {
  152                 if (cf->cf_attach->ca_match == NULL) {
  153                         panic("mapply: no match function for '%s' device",
  154                             cf->cf_driver->cd_name);
  155                 }
  156                 pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
  157         }
  158         if (autoconf_verbose)
  159                 printf(">>> %s probe returned %d\n", cf->cf_driver->cd_name,
  160                     pri);
  161 
  162         if (pri > m->pri) {
  163                 if (m->indirect && m->match) {
  164                         cf = ((struct device *)m->match)->dv_cfdata;
  165                         free(m->match, M_DEVBUF, cf->cf_attach->ca_devsize);
  166                 }
  167                 m->match = match;
  168                 m->pri = pri;
  169         } else {
  170                 if (m->indirect)
  171                         free(match, M_DEVBUF, cf->cf_attach->ca_devsize);
  172         }
  173 }
  174 
  175 /*
  176  * Iterate over all potential children of some device, calling the given
  177  * function (default being the child's match function) for each one.
  178  * Nonzero returns are matches; the highest value returned is considered
  179  * the best match.  Return the `found child' if we got a match, or NULL
  180  * otherwise.  The `aux' pointer is simply passed on through.
  181  *
  182  * Note that this function is designed so that it can be used to apply
  183  * an arbitrary function to all potential children (its return value
  184  * can be ignored).
  185  */
  186 void *
  187 config_search(cfmatch_t fn, struct device *parent, void *aux)
  188 {
  189         struct cfdata *cf;
  190         short *p;
  191         struct matchinfo m;
  192 
  193         m.fn = fn;
  194         m.parent = parent;
  195         m.match = NULL;
  196         m.aux = aux;
  197         m.indirect = parent && (parent->dv_cfdata->cf_driver->cd_mode & CD_INDIRECT);
  198         m.pri = 0;
  199 
  200         for (cf = cfdata; cf->cf_driver; cf++) {
  201                 /*
  202                  * Skip cf if no longer eligible, otherwise scan
  203                  * through parents for one matching `parent',
  204                  * and try match function.
  205                  */
  206                 if (cf->cf_fstate == FSTATE_FOUND)
  207                         continue;
  208                 if (cf->cf_fstate == FSTATE_DNOTFOUND ||
  209                     cf->cf_fstate == FSTATE_DSTAR)
  210                         continue;
  211                 if (boothowto & RB_UNHIBERNATE) {
  212                         if (cf->cf_driver->cd_mode & CD_SKIPHIBERNATE)
  213                                 continue;
  214                         if (cf->cf_driver->cd_class == DV_IFNET)
  215                                 continue;
  216                         if (cf->cf_driver->cd_class == DV_TAPE)
  217                                 continue;
  218                 }
  219                 for (p = cf->cf_parents; *p >= 0; p++)
  220                         if (parent->dv_cfdata == &cfdata[*p])
  221                                 mapply(&m, cf);
  222         }
  223 
  224         if (autoconf_verbose) {
  225                 if (m.match) {
  226                         if (m.indirect)
  227                                 cf = ((struct device *)m.match)->dv_cfdata;
  228                         else
  229                                 cf = (struct cfdata *)m.match;
  230                         printf(">>> %s probe won\n",
  231                             cf->cf_driver->cd_name);
  232                 } else
  233                         printf(">>> no winning probe\n");
  234         }
  235         return (m.match);
  236 }
  237 
  238 /*
  239  * Iterate over all potential children of some device, calling the given
  240  * function for each one.
  241  *
  242  * Note that this function is designed so that it can be used to apply
  243  * an arbitrary function to all potential children (its return value
  244  * can be ignored).
  245  */
  246 void
  247 config_scan(cfscan_t fn, struct device *parent)
  248 {
  249         struct cfdata *cf;
  250         short *p;
  251         void *match;
  252         int indirect;
  253 
  254         indirect = parent && (parent->dv_cfdata->cf_driver->cd_mode & CD_INDIRECT);
  255 
  256         for (cf = cfdata; cf->cf_driver; cf++) {
  257                 /*
  258                  * Skip cf if no longer eligible, otherwise scan
  259                  * through parents for one matching `parent',
  260                  * and try match function.
  261                  */
  262                 if (cf->cf_fstate == FSTATE_FOUND)
  263                         continue;
  264                 if (cf->cf_fstate == FSTATE_DNOTFOUND ||
  265                     cf->cf_fstate == FSTATE_DSTAR)
  266                         continue;
  267                 for (p = cf->cf_parents; *p >= 0; p++)
  268                         if (parent->dv_cfdata == &cfdata[*p]) {
  269                                 match = indirect?
  270                                     config_make_softc(parent, cf) :
  271                                     (void *)cf;
  272                                 (*fn)(parent, match);
  273                         }
  274         }
  275 }
  276 
  277 /*
  278  * Find the given root device.
  279  * This is much like config_search, but there is no parent.
  280  */
  281 void *
  282 config_rootsearch(cfmatch_t fn, char *rootname, void *aux)
  283 {
  284         struct cfdata *cf;
  285         short *p;
  286         struct matchinfo m;
  287 
  288         m.fn = fn;
  289         m.parent = ROOT;
  290         m.match = NULL;
  291         m.aux = aux;
  292         m.indirect = 0;
  293         m.pri = 0;
  294         /*
  295          * Look at root entries for matching name.  We do not bother
  296          * with found-state here since only one instance of each possible
  297          * root child should ever be searched.
  298          */
  299         for (p = cfroots; *p >= 0; p++) {
  300                 cf = &cfdata[*p];
  301                 if (cf->cf_fstate == FSTATE_DNOTFOUND ||
  302                     cf->cf_fstate == FSTATE_DSTAR)
  303                         continue;
  304                 if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
  305                         mapply(&m, cf);
  306         }
  307         return (m.match);
  308 }
  309 
  310 const char *msgs[3] = { "", " not configured\n", " unsupported\n" };
  311 
  312 /*
  313  * The given `aux' argument describes a device that has been found
  314  * on the given parent, but not necessarily configured.  Locate the
  315  * configuration data for that device (using the submatch function
  316  * provided, or using candidates' cd_match configuration driver
  317  * functions) and attach it, and return true.  If the device was
  318  * not configured, call the given `print' function and return 0.
  319  */
  320 struct device *
  321 config_found_sm(struct device *parent, void *aux, cfprint_t print,
  322     cfmatch_t submatch)
  323 {
  324         void *match;
  325 
  326         if ((match = config_search(submatch, parent, aux)) != NULL)
  327                 return (config_attach(parent, match, aux, print));
  328         if (print)
  329                 printf("%s", msgs[(*print)(aux, parent->dv_xname)]);
  330         return (NULL);
  331 }
  332 
  333 /*
  334  * As above, but for root devices.
  335  */
  336 struct device *
  337 config_rootfound(char *rootname, void *aux)
  338 {
  339         void *match;
  340 
  341         if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
  342                 return (config_attach(ROOT, match, aux, (cfprint_t)NULL));
  343         printf("root device %s not configured\n", rootname);
  344         return (NULL);
  345 }
  346 
  347 /*
  348  * Attach a found device.  Allocates memory for device variables.
  349  */
  350 struct device *
  351 config_attach(struct device *parent, void *match, void *aux, cfprint_t print)
  352 {
  353         struct cfdata *cf;
  354         struct device *dev;
  355         struct cfdriver *cd;
  356         const struct cfattach *ca;
  357 
  358         mtx_enter(&autoconf_attdet_mtx);
  359         while (autoconf_attdet < 0)
  360                 msleep_nsec(&autoconf_attdet, &autoconf_attdet_mtx,
  361                     PWAIT, "autoconf", INFSLP);
  362         autoconf_attdet++;
  363         mtx_leave(&autoconf_attdet_mtx);
  364 
  365         if (parent && (parent->dv_cfdata->cf_driver->cd_mode & CD_INDIRECT)) {
  366                 dev = match;
  367                 cf = dev->dv_cfdata;
  368         } else {
  369                 cf = match;
  370                 dev = config_make_softc(parent, cf);
  371         }
  372 
  373         cd = cf->cf_driver;
  374         ca = cf->cf_attach;
  375 
  376         KASSERT(cd->cd_devs != NULL);
  377         KASSERT(dev->dv_unit < cd->cd_ndevs);
  378         KASSERT(cd->cd_devs[dev->dv_unit] == NULL);
  379         cd->cd_devs[dev->dv_unit] = dev;
  380 
  381         /*
  382          * If this is a "STAR" device and we used the last unit, prepare for
  383          * another one.
  384          */
  385         if (cf->cf_fstate == FSTATE_STAR) {
  386                 if (dev->dv_unit == cf->cf_unit)
  387                         cf->cf_unit++;
  388         } else
  389                 cf->cf_fstate = FSTATE_FOUND;
  390 
  391         TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
  392         device_ref(dev);
  393 
  394         if (parent == ROOT)
  395                 printf("%s at root", dev->dv_xname);
  396         else {
  397                 printf("%s at %s", dev->dv_xname, parent->dv_xname);
  398                 if (print)
  399                         (void) (*print)(aux, NULL);
  400         }
  401 
  402         /*
  403          * Before attaching, clobber any unfound devices that are
  404          * otherwise identical, or bump the unit number on all starred
  405          * cfdata for this device.
  406          */
  407         for (cf = cfdata; cf->cf_driver; cf++) {
  408                 if (cf->cf_driver == cd &&
  409                     cf->cf_unit == dev->dv_unit) {
  410                         if (cf->cf_fstate == FSTATE_NOTFOUND)
  411                                 cf->cf_fstate = FSTATE_FOUND;
  412                         if (cf->cf_fstate == FSTATE_STAR)
  413                                 cf->cf_unit++;
  414                 }
  415         }
  416         device_register(dev, aux);
  417         (*ca->ca_attach)(parent, dev, aux);
  418         config_process_deferred_children(dev);
  419 #if NHOTPLUG > 0
  420         if (!cold)
  421                 hotplug_device_attach(cd->cd_class, dev->dv_xname);
  422 #endif
  423 
  424         mtx_enter(&autoconf_attdet_mtx);
  425         if (--autoconf_attdet == 0)
  426                 wakeup(&autoconf_attdet);
  427         autoconf_serial++;
  428         mtx_leave(&autoconf_attdet_mtx);
  429         return (dev);
  430 }
  431 
  432 struct device *
  433 config_make_softc(struct device *parent, struct cfdata *cf)
  434 {
  435         struct device *dev;
  436         struct cfdriver *cd;
  437         const struct cfattach *ca;
  438 
  439         cd = cf->cf_driver;
  440         ca = cf->cf_attach;
  441         if (ca->ca_devsize < sizeof(struct device))
  442                 panic("config_make_softc");
  443 
  444         /* get memory for all device vars */
  445         dev = malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT|M_ZERO);
  446         if (dev == NULL)
  447                 panic("config_make_softc: allocation for device softc failed");
  448 
  449         dev->dv_class = cd->cd_class;
  450         dev->dv_cfdata = cf;
  451         dev->dv_flags = DVF_ACTIVE;     /* always initially active */
  452 
  453         /* If this is a STAR device, search for a free unit number */
  454         if (cf->cf_fstate == FSTATE_STAR) {
  455                 for (dev->dv_unit = cf->cf_starunit1;
  456                     dev->dv_unit < cf->cf_unit; dev->dv_unit++)
  457                         if (cd->cd_ndevs == 0 ||
  458                             dev->dv_unit >= cd->cd_ndevs ||
  459                             cd->cd_devs[dev->dv_unit] == NULL)
  460                                 break;
  461         } else
  462                 dev->dv_unit = cf->cf_unit;
  463 
  464         /* Build the device name into dv_xname. */
  465         if (snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d",
  466             cd->cd_name, dev->dv_unit) >= sizeof(dev->dv_xname))
  467                 panic("config_make_softc: device name too long");
  468         dev->dv_parent = parent;
  469 
  470         /* put this device in the devices array */
  471         if (dev->dv_unit >= cd->cd_ndevs) {
  472                 /*
  473                  * Need to expand the array.
  474                  */
  475                 int old = cd->cd_ndevs, new;
  476                 void **nsp;
  477 
  478                 if (old == 0)
  479                         new = MINALLOCSIZE / sizeof(void *);
  480                 else
  481                         new = old * 2;
  482                 while (new <= dev->dv_unit)
  483                         new *= 2;
  484                 cd->cd_ndevs = new;
  485                 nsp = mallocarray(new, sizeof(void *), M_DEVBUF, M_NOWAIT|M_ZERO);
  486                 if (nsp == NULL)
  487                         panic("config_make_softc: %sing dev array",
  488                             old != 0 ? "expand" : "creat");
  489                 if (old != 0) {
  490                         bcopy(cd->cd_devs, nsp, old * sizeof(void *));
  491                         free(cd->cd_devs, M_DEVBUF, old * sizeof(void *));
  492                 }
  493                 cd->cd_devs = nsp;
  494         }
  495         if (cd->cd_devs[dev->dv_unit])
  496                 panic("config_make_softc: duplicate %s", dev->dv_xname);
  497 
  498         dev->dv_ref = 1;
  499 
  500         return (dev);
  501 }
  502 
  503 /*
  504  * Detach a device.  Optionally forced (e.g. because of hardware
  505  * removal) and quiet.  Returns zero if successful, non-zero
  506  * (an error code) otherwise.
  507  *
  508  * Note that this code wants to be run from a process context, so
  509  * that the detach can sleep to allow processes which have a device
  510  * open to run and unwind their stacks.
  511  */
  512 int
  513 config_detach(struct device *dev, int flags)
  514 {
  515         struct cfdata *cf;
  516         const struct cfattach *ca;
  517         struct cfdriver *cd;
  518         int rv = 0, i;
  519 #ifdef DIAGNOSTIC
  520         struct device *d;
  521 #endif
  522 #if NHOTPLUG > 0
  523         char devname[16];
  524 #endif
  525 
  526         mtx_enter(&autoconf_attdet_mtx);
  527         while (autoconf_attdet > 0)
  528                 msleep_nsec(&autoconf_attdet, &autoconf_attdet_mtx,
  529                     PWAIT, "autoconf", INFSLP);
  530         autoconf_attdet--;
  531         mtx_leave(&autoconf_attdet_mtx);
  532 
  533 #if NHOTPLUG > 0
  534         strlcpy(devname, dev->dv_xname, sizeof(devname));
  535 #endif
  536 
  537         cf = dev->dv_cfdata;
  538 #ifdef DIAGNOSTIC
  539         if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR)
  540                 panic("config_detach: bad device fstate");
  541 #endif
  542         ca = cf->cf_attach;
  543         cd = cf->cf_driver;
  544 
  545         /*
  546          * Ensure the device is deactivated.  If the device has an
  547          * activation entry point and DVF_ACTIVE is still set, the
  548          * device is busy, and the detach fails.
  549          */
  550         rv = config_deactivate(dev);
  551 
  552         /*
  553          * Try to detach the device.  If that's not possible, then
  554          * we either panic() (for the forced but failed case), or
  555          * return an error.
  556          */
  557         if (rv == 0) {
  558                 if (ca->ca_detach != NULL)
  559                         rv = (*ca->ca_detach)(dev, flags);
  560                 else
  561                         rv = EOPNOTSUPP;
  562         }
  563         if (rv != 0) {
  564                 if ((flags & DETACH_FORCE) == 0)
  565                         goto done;
  566                 else
  567                         panic("config_detach: forced detach of %s failed (%d)",
  568                             dev->dv_xname, rv);
  569         }
  570 
  571         /*
  572          * The device has now been successfully detached.
  573          */
  574 
  575 #ifdef DIAGNOSTIC
  576         /*
  577          * Sanity: If you're successfully detached, you should have no
  578          * children.  (Note that because children must be attached
  579          * after parents, we only need to search the latter part of
  580          * the list.)
  581          */
  582         i = 0;
  583         for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
  584              d = TAILQ_NEXT(d, dv_list)) {
  585                 if (d->dv_parent == dev) {
  586                         printf("config_detach: %s attached at %s\n",
  587                             d->dv_xname, dev->dv_xname);
  588                         i = 1;
  589                 }
  590         }
  591         if (i != 0)
  592                 panic("config_detach: detached device (%s) has children",
  593                     dev->dv_xname);
  594 #endif
  595 
  596         /*
  597          * Mark cfdata to show that the unit can be reused, if possible.
  598          * Note that we can only re-use a starred unit number if the unit
  599          * being detached had the last assigned unit number.
  600          */
  601         for (cf = cfdata; cf->cf_driver; cf++) {
  602                 if (cf->cf_driver == cd) {
  603                         if (cf->cf_fstate == FSTATE_FOUND &&
  604                             cf->cf_unit == dev->dv_unit)
  605                                 cf->cf_fstate = FSTATE_NOTFOUND;
  606                         if (cf->cf_fstate == FSTATE_STAR &&
  607                             cf->cf_unit == dev->dv_unit + 1)
  608                                 cf->cf_unit--;
  609                 }
  610         }
  611 
  612         /*
  613          * Unlink from device list.
  614          */
  615         TAILQ_REMOVE(&alldevs, dev, dv_list);
  616         device_unref(dev);
  617 
  618         /*
  619          * Remove from cfdriver's array, tell the world, and free softc.
  620          */
  621         cd->cd_devs[dev->dv_unit] = NULL;
  622         if ((flags & DETACH_QUIET) == 0)
  623                 printf("%s detached\n", dev->dv_xname);
  624 
  625         device_unref(dev);
  626         /*
  627          * If the device now has no units in use, deallocate its softc array.
  628          */
  629         for (i = 0; i < cd->cd_ndevs; i++)
  630                 if (cd->cd_devs[i] != NULL)
  631                         break;
  632         if (i == cd->cd_ndevs) {                /* nothing found; deallocate */
  633                 free(cd->cd_devs, M_DEVBUF, cd->cd_ndevs * sizeof(void *));
  634                 cd->cd_devs = NULL;
  635                 cd->cd_ndevs = 0;
  636                 cf->cf_unit = 0;
  637         }
  638 
  639 #if NHOTPLUG > 0
  640         if (!cold)
  641                 hotplug_device_detach(cd->cd_class, devname);
  642 #endif
  643 
  644         /*
  645          * Return success.
  646          */
  647 done:
  648         mtx_enter(&autoconf_attdet_mtx);
  649         if (++autoconf_attdet == 0)
  650                 wakeup(&autoconf_attdet);
  651         autoconf_serial++;
  652         mtx_leave(&autoconf_attdet_mtx);
  653         return (rv);
  654 }
  655 
  656 int
  657 config_deactivate(struct device *dev)
  658 {
  659         int rv = 0, oflags = dev->dv_flags;
  660 
  661         if (dev->dv_flags & DVF_ACTIVE) {
  662                 dev->dv_flags &= ~DVF_ACTIVE;
  663                 rv = config_suspend(dev, DVACT_DEACTIVATE);
  664                 if (rv)
  665                         dev->dv_flags = oflags;
  666         }
  667         return (rv);
  668 }
  669 
  670 /*
  671  * Defer the configuration of the specified device until all
  672  * of its parent's devices have been attached.
  673  */
  674 void
  675 config_defer(struct device *dev, void (*func)(struct device *))
  676 {
  677         struct deferred_config *dc;
  678 
  679         if (dev->dv_parent == NULL)
  680                 panic("config_defer: can't defer config of a root device");
  681 
  682 #ifdef DIAGNOSTIC
  683         for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
  684              dc = TAILQ_NEXT(dc, dc_queue)) {
  685                 if (dc->dc_dev == dev)
  686                         panic("config_defer: deferred twice");
  687         }
  688 #endif
  689 
  690         if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
  691                 panic("config_defer: can't allocate defer structure");
  692 
  693         dc->dc_dev = dev;
  694         dc->dc_func = func;
  695         TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
  696         config_pending_incr();
  697 }
  698 
  699 /*
  700  * Defer the configuration of the specified device until after
  701  * root file system is mounted.
  702  */
  703 void
  704 config_mountroot(struct device *dev, void (*func)(struct device *))
  705 {
  706         struct deferred_config *dc;
  707 
  708         /*
  709          * No need to defer if root file system is already mounted.
  710          */
  711         if (rootvp != NULL) {
  712                 (*func)(dev);
  713                 return;
  714         }
  715 
  716 #ifdef DIAGNOSTIC
  717         for (dc = TAILQ_FIRST(&mountroot_config_queue); dc != NULL;
  718              dc = TAILQ_NEXT(dc, dc_queue)) {
  719                 if (dc->dc_dev == dev)
  720                         panic("config_mountroot: deferred twice");
  721         }
  722 #endif
  723 
  724         if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
  725                 panic("config_mountroot: can't allocate defer structure");
  726 
  727         dc->dc_dev = dev;
  728         dc->dc_func = func;
  729         TAILQ_INSERT_TAIL(&mountroot_config_queue, dc, dc_queue);
  730 }
  731 
  732 /*
  733  * Process the deferred configuration queue for a device.
  734  */
  735 void
  736 config_process_deferred_children(struct device *parent)
  737 {
  738         struct deferred_config *dc, *ndc;
  739 
  740         for (dc = TAILQ_FIRST(&deferred_config_queue);
  741              dc != NULL; dc = ndc) {
  742                 ndc = TAILQ_NEXT(dc, dc_queue);
  743                 if (dc->dc_dev->dv_parent == parent) {
  744                         TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);
  745                         (*dc->dc_func)(dc->dc_dev);
  746                         free(dc, M_DEVBUF, sizeof(*dc));
  747                         config_pending_decr();
  748                 }
  749         }
  750 }
  751 
  752 /*
  753  * Process the deferred configuration queue after the root file
  754  * system is mounted .
  755  */
  756 void
  757 config_process_deferred_mountroot(void)
  758 {
  759         struct deferred_config *dc;
  760 
  761         while ((dc = TAILQ_FIRST(&mountroot_config_queue)) != NULL) {
  762                 TAILQ_REMOVE(&mountroot_config_queue, dc, dc_queue);
  763                 (*dc->dc_func)(dc->dc_dev);
  764                 free(dc, M_DEVBUF, sizeof(*dc));
  765         }
  766 }
  767 
  768 /*
  769  * Manipulate the config_pending semaphore.
  770  */
  771 void
  772 config_pending_incr(void)
  773 {
  774 
  775         config_pending++;
  776 }
  777 
  778 void
  779 config_pending_decr(void)
  780 {
  781 
  782 #ifdef DIAGNOSTIC
  783         if (config_pending == 0)
  784                 panic("config_pending_decr: config_pending == 0");
  785 #endif
  786         config_pending--;
  787         if (config_pending == 0)
  788                 wakeup((void *)&config_pending);
  789 }
  790 
  791 int
  792 config_detach_children(struct device *parent, int flags)
  793 {
  794         struct device *dev, *next_dev;
  795         int rv = 0;
  796 
  797         /*
  798          * The config_detach routine may sleep, meaning devices
  799          * may be added to the queue. However, all devices will
  800          * be added to the tail of the queue, the queue won't
  801          * be re-organized, and the subtree of parent here should be locked
  802          * for purposes of adding/removing children.
  803          *
  804          * Note that we can not afford trying to walk the device list
  805          * once - our ``next'' device might be a child of the device
  806          * we are about to detach, so it would disappear.
  807          * Just play it safe and restart from the parent.
  808          */
  809         for (dev = TAILQ_LAST(&alldevs, devicelist);
  810             dev != NULL; dev = next_dev) {
  811                 if (dev->dv_parent == parent) {
  812                         if ((rv = config_detach(dev, flags)) != 0)
  813                                 return (rv);
  814                         next_dev = TAILQ_LAST(&alldevs, devicelist);
  815                 } else {
  816                         next_dev = TAILQ_PREV(dev, devicelist, dv_list);
  817                 }
  818         }
  819 
  820         return (0);
  821 }
  822 
  823 int
  824 config_suspend(struct device *dev, int act)
  825 {
  826         const struct cfattach *ca = dev->dv_cfdata->cf_attach;
  827         int r;
  828 
  829         device_ref(dev);
  830         if (ca->ca_activate)
  831                 r = (*ca->ca_activate)(dev, act);
  832         else
  833                 r = config_activate_children(dev, act);
  834         device_unref(dev);
  835         return (r);
  836 }
  837 
  838 int
  839 config_suspend_all(int act)
  840 {
  841         struct device *mainbus = device_mainbus();
  842         struct device *mpath = device_mpath();
  843         int rv = 0;
  844 
  845         switch (act) {
  846         case DVACT_QUIESCE:
  847         case DVACT_SUSPEND:
  848         case DVACT_POWERDOWN:
  849                 if (mpath) {
  850                         rv = config_suspend(mpath, act);
  851                         if (rv)
  852                                 return rv;
  853                 }
  854                 if (mainbus)
  855                         rv = config_suspend(mainbus, act);
  856                 break;
  857         case DVACT_RESUME:
  858         case DVACT_WAKEUP:
  859                 if (mainbus) {
  860                         rv = config_suspend(mainbus, act);
  861                         if (rv)
  862                                 return rv;
  863                 }
  864                 if (mpath)
  865                         rv = config_suspend(mpath, act);
  866                 break;
  867         }
  868 
  869         return (rv);
  870 }
  871 
  872 /*
  873  * Call the ca_activate for each of our children, letting each
  874  * decide whether they wish to do the same for their children
  875  * and more.
  876  */
  877 int
  878 config_activate_children(struct device *parent, int act)
  879 {
  880         struct device *d;
  881         int rv = 0;
  882 
  883         for (d = TAILQ_NEXT(parent, dv_list); d != NULL;
  884             d = TAILQ_NEXT(d, dv_list)) {
  885                 if (d->dv_parent != parent)
  886                         continue;
  887                 switch (act) {
  888                 case DVACT_QUIESCE:
  889                 case DVACT_SUSPEND:
  890                 case DVACT_RESUME:
  891                 case DVACT_WAKEUP:
  892                 case DVACT_POWERDOWN:
  893                         rv = config_suspend(d, act);
  894                         break;
  895                 case DVACT_DEACTIVATE:
  896                         rv = config_deactivate(d);
  897                         break;
  898                 }
  899                 if (rv == 0)
  900                         continue;
  901 
  902                 /*
  903                  * Found a device that refuses the action.
  904                  * If we were being asked to suspend, we can
  905                  * try to resume all previous devices.
  906                  */
  907 #ifdef DIAGNOSTIC
  908                 printf("config_activate_children: device %s failed %d\n",
  909                     d->dv_xname, act);
  910 #endif
  911                 if (act == DVACT_RESUME)
  912                         printf("failing resume cannot be handled\n");
  913                 if (act == DVACT_POWERDOWN)
  914                         return (rv);
  915                 if (act != DVACT_SUSPEND)
  916                         return (rv);
  917 
  918                 d = TAILQ_PREV(d, devicelist, dv_list);
  919                 for (; d != NULL && d != parent;
  920                     d = TAILQ_PREV(d, devicelist, dv_list)) {
  921                         if (d->dv_parent != parent)
  922                                 continue;
  923                         printf("resume %s\n", d->dv_xname);
  924                         config_suspend(d, DVACT_RESUME);
  925                 }
  926                 return (rv);
  927         }
  928         return (rv);
  929 }
  930 
  931 /* 
  932  * Lookup a device in the cfdriver device array.  Does not return a
  933  * device if it is not active.
  934  *
  935  * Increments ref count on the device by one, reflecting the
  936  * new reference created on the stack.
  937  *
  938  * Context: process only 
  939  */
  940 struct device *
  941 device_lookup(struct cfdriver *cd, int unit)
  942 {
  943         struct device *dv = NULL;
  944 
  945         if (unit >= 0 && unit < cd->cd_ndevs)
  946                 dv = (struct device *)(cd->cd_devs[unit]);
  947 
  948         if (!dv)
  949                 return (NULL);
  950 
  951         if (!(dv->dv_flags & DVF_ACTIVE))
  952                 dv = NULL;
  953 
  954         if (dv != NULL)
  955                 device_ref(dv);
  956 
  957         return (dv);
  958 }
  959 
  960 struct device *
  961 device_mainbus(void)
  962 {
  963         extern struct cfdriver mainbus_cd;
  964 
  965         if (mainbus_cd.cd_ndevs < 1)
  966                 return (NULL);
  967 
  968         return (mainbus_cd.cd_devs[0]);
  969 }
  970 
  971 struct device *
  972 device_mpath(void)
  973 {
  974 #if NMPATH > 0
  975         extern struct cfdriver mpath_cd;
  976 
  977         if (mpath_cd.cd_ndevs < 1)
  978                 return (NULL);
  979 
  980         return (mpath_cd.cd_devs[0]);
  981 #else
  982         return (NULL);
  983 #endif
  984 }
  985 
  986 /*
  987  * Increments the ref count on the device structure. The device
  988  * structure is freed when the ref count hits 0.
  989  *
  990  * Context: process or interrupt
  991  */
  992 void
  993 device_ref(struct device *dv)
  994 {
  995         atomic_inc_int(&dv->dv_ref);
  996 }
  997 
  998 /*
  999  * Decrement the ref count on the device structure.
 1000  *
 1001  * free's the structure when the ref count hits zero.
 1002  *
 1003  * Context: process or interrupt
 1004  */
 1005 void
 1006 device_unref(struct device *dv)
 1007 {
 1008         const struct cfattach *ca;
 1009 
 1010         if (atomic_dec_int_nv(&dv->dv_ref) == 0) {
 1011                 ca = dv->dv_cfdata->cf_attach;
 1012                 free(dv, M_DEVBUF, ca->ca_devsize);
 1013         }
 1014 }

Cache object: a7e8849c9e0d1d800965a3775ab521b1


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