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/xen/xenbus/xenbus_probe.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /******************************************************************************
    2  * Talks to Xen Store to figure out what devices we have.
    3  *
    4  * Copyright (C) 2008 Doug Rabson
    5  * Copyright (C) 2005 Rusty Russell, IBM Corporation
    6  * Copyright (C) 2005 Mike Wray, Hewlett-Packard
    7  * Copyright (C) 2005 XenSource Ltd
    8  * 
    9  * This file may be distributed separately from the Linux kernel, or
   10  * incorporated into other software packages, subject to the following license:
   11  * 
   12  * Permission is hereby granted, free of charge, to any person obtaining a copy
   13  * of this source file (the "Software"), to deal in the Software without
   14  * restriction, including without limitation the rights to use, copy, modify,
   15  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   16  * and to permit persons to whom the Software is furnished to do so, subject to
   17  * the following conditions:
   18  * 
   19  * The above copyright notice and this permission notice shall be included in
   20  * all copies or substantial portions of the Software.
   21  * 
   22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   28  * IN THE SOFTWARE.
   29  */
   30 
   31 #if 0
   32 #define DPRINTK(fmt, args...) \
   33     printf("xenbus_probe (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
   34 #else
   35 #define DPRINTK(fmt, args...) ((void)0)
   36 #endif
   37 
   38 #include <sys/cdefs.h>
   39 __FBSDID("$FreeBSD: releng/8.0/sys/xen/xenbus/xenbus_probe.c 196405 2009-08-20 20:23:28Z jhb $");
   40 
   41 #include <sys/param.h>
   42 #include <sys/bus.h>
   43 #include <sys/kernel.h>
   44 #include <sys/lock.h>
   45 #include <sys/malloc.h>
   46 #include <sys/module.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/syslog.h>
   49 #include <sys/systm.h>
   50 #include <sys/sx.h>
   51 #include <sys/taskqueue.h>
   52 
   53 #include <machine/xen/xen-os.h>
   54 #include <machine/stdarg.h>
   55 
   56 #include <xen/gnttab.h>
   57 #include <xen/xenbus/xenbusvar.h>
   58 #include <xen/xenbus/xenbus_comms.h>
   59 
   60 struct xenbus_softc {
   61         struct xenbus_watch xs_devicewatch;
   62         struct task     xs_probechildren;
   63         struct intr_config_hook xs_attachcb;
   64         device_t        xs_dev;
   65 };
   66 
   67 struct xenbus_device_ivars {
   68         struct xenbus_watch xd_otherend_watch; /* must be first */
   69         struct sx       xd_lock;
   70         device_t        xd_dev;
   71         char            *xd_node;       /* node name in xenstore */
   72         char            *xd_type;       /* xen device type */
   73         enum xenbus_state xd_state;
   74         int             xd_otherend_id;
   75         char            *xd_otherend_path;
   76 };
   77 
   78 /* Simplified asprintf. */
   79 char *
   80 kasprintf(const char *fmt, ...)
   81 {
   82         va_list ap;
   83         unsigned int len;
   84         char *p, dummy[1];
   85 
   86         va_start(ap, fmt);
   87         /* FIXME: vsnprintf has a bug, NULL should work */
   88         len = vsnprintf(dummy, 0, fmt, ap);
   89         va_end(ap);
   90 
   91         p = malloc(len + 1, M_DEVBUF, M_WAITOK);
   92         va_start(ap, fmt);
   93         vsprintf(p, fmt, ap);
   94         va_end(ap);
   95         return p;
   96 }
   97 
   98 static void
   99 xenbus_identify(driver_t *driver, device_t parent)
  100 {
  101 
  102         BUS_ADD_CHILD(parent, 0, "xenbus", 0);
  103 }
  104 
  105 static int 
  106 xenbus_probe(device_t dev)
  107 {
  108         int err = 0;
  109 
  110         DPRINTK("");
  111 
  112         /* Initialize the interface to xenstore. */
  113         err = xs_init(); 
  114         if (err) {
  115                 log(LOG_WARNING,
  116                     "XENBUS: Error initializing xenstore comms: %i\n", err);
  117                 return (ENXIO);
  118         }
  119         err = gnttab_init();
  120         if (err) {
  121                 log(LOG_WARNING,
  122                     "XENBUS: Error initializing grant table: %i\n", err);
  123                 return (ENXIO);
  124         }
  125         device_set_desc(dev, "Xen Devices");
  126 
  127         return (0);
  128 }
  129 
  130 static enum xenbus_state
  131 xenbus_otherend_state(struct xenbus_device_ivars *ivars)
  132 {
  133 
  134         return (xenbus_read_driver_state(ivars->xd_otherend_path));
  135 }
  136 
  137 static void
  138 xenbus_backend_changed(struct xenbus_watch *watch, const char **vec,
  139     unsigned int len)
  140 {
  141         struct xenbus_device_ivars *ivars;
  142         device_t dev;
  143         enum xenbus_state newstate;
  144 
  145         ivars = (struct xenbus_device_ivars *) watch;
  146         dev = ivars->xd_dev;
  147 
  148         if (!ivars->xd_otherend_path
  149             || strncmp(ivars->xd_otherend_path, vec[XS_WATCH_PATH],
  150                 strlen(ivars->xd_otherend_path)))
  151                 return;
  152 
  153         newstate = xenbus_otherend_state(ivars);
  154         XENBUS_BACKEND_CHANGED(dev, newstate);
  155 }
  156 
  157 static int
  158 xenbus_device_exists(device_t dev, const char *node)
  159 {
  160         device_t *kids;
  161         struct xenbus_device_ivars *ivars;
  162         int i, count, result;
  163 
  164         if (device_get_children(dev, &kids, &count))
  165                 return (FALSE);
  166 
  167         result = FALSE;
  168         for (i = 0; i < count; i++) {
  169                 ivars = device_get_ivars(kids[i]);
  170                 if (!strcmp(ivars->xd_node, node)) {
  171                         result = TRUE;
  172                         break;
  173                 }
  174         }
  175         free(kids, M_TEMP);
  176 
  177         return (result);
  178 }
  179 
  180 static int
  181 xenbus_add_device(device_t dev, const char *bus,
  182     const char *type, const char *id)
  183 {
  184         device_t child;
  185         struct xenbus_device_ivars *ivars;
  186         enum xenbus_state state;
  187         char *statepath;
  188         int error;
  189 
  190         ivars = malloc(sizeof(struct xenbus_device_ivars),
  191             M_DEVBUF, M_ZERO|M_WAITOK);
  192         ivars->xd_node = kasprintf("%s/%s/%s", bus, type, id);
  193 
  194         if (xenbus_device_exists(dev, ivars->xd_node)) {
  195                 /*
  196                  * We are already tracking this node
  197                  */
  198                 free(ivars->xd_node, M_DEVBUF);
  199                 free(ivars, M_DEVBUF);
  200                 return (0);
  201         }
  202 
  203         state = xenbus_read_driver_state(ivars->xd_node);
  204 
  205         if (state != XenbusStateInitialising) {
  206                 /*
  207                  * Device is not new, so ignore it. This can
  208                  * happen if a device is going away after
  209                  * switching to Closed.
  210                  */
  211                 free(ivars->xd_node, M_DEVBUF);
  212                 free(ivars, M_DEVBUF);
  213                 return (0);
  214         }
  215 
  216         /*
  217          * Find the backend details
  218          */
  219         error = xenbus_gather(XBT_NIL, ivars->xd_node,
  220             "backend-id", "%i", &ivars->xd_otherend_id,
  221             "backend", NULL, &ivars->xd_otherend_path,
  222             NULL);
  223         if (error)
  224                 return (error);
  225 
  226         sx_init(&ivars->xd_lock, "xdlock");
  227         ivars->xd_type = strdup(type, M_DEVBUF);
  228         ivars->xd_state = XenbusStateInitialising;
  229 
  230         statepath = malloc(strlen(ivars->xd_otherend_path)
  231             + strlen("/state") + 1, M_DEVBUF, M_WAITOK);
  232         sprintf(statepath, "%s/state", ivars->xd_otherend_path);
  233 
  234         ivars->xd_otherend_watch.node = statepath;
  235         ivars->xd_otherend_watch.callback = xenbus_backend_changed;
  236 
  237         child = device_add_child(dev, NULL, -1);
  238         ivars->xd_dev = child;
  239         device_set_ivars(child, ivars);
  240 
  241         return (0);
  242 }
  243 
  244 static int
  245 xenbus_enumerate_type(device_t dev, const char *bus, const char *type)
  246 {
  247         char **dir;
  248         unsigned int i, count;
  249         int error;
  250 
  251         error = xenbus_directory(XBT_NIL, bus, type, &count, &dir);
  252         if (error)
  253                 return (error);
  254         for (i = 0; i < count; i++)
  255                 xenbus_add_device(dev, bus, type, dir[i]);
  256 
  257         free(dir, M_DEVBUF);
  258 
  259         return (0);
  260 }
  261 
  262 static int
  263 xenbus_enumerate_bus(device_t dev, const char *bus)
  264 {
  265         char **dir;
  266         unsigned int i, count;
  267         int error;
  268 
  269         error = xenbus_directory(XBT_NIL, bus, "", &count, &dir);
  270         if (error)
  271                 return (error);
  272         for (i = 0; i < count; i++) {
  273                 xenbus_enumerate_type(dev, bus, dir[i]);
  274         }
  275         free(dir, M_DEVBUF);
  276 
  277         return (0);
  278 }
  279 
  280 static int
  281 xenbus_probe_children(device_t dev)
  282 {
  283         device_t *kids;
  284         struct xenbus_device_ivars *ivars;
  285         int i, count;
  286 
  287         /*
  288          * Probe any new devices and register watches for any that
  289          * attach successfully. Since part of the protocol which
  290          * establishes a connection with the other end is interrupt
  291          * driven, we sleep until the device reaches a stable state
  292          * (closed or connected).
  293          */
  294         if (device_get_children(dev, &kids, &count) == 0) {
  295                 for (i = 0; i < count; i++) {
  296                         if (device_get_state(kids[i]) != DS_NOTPRESENT)
  297                                 continue;
  298 
  299                         if (device_probe_and_attach(kids[i]))
  300                                 continue;
  301                         ivars = device_get_ivars(kids[i]);
  302                         register_xenbus_watch(
  303                                 &ivars->xd_otherend_watch);
  304                         sx_xlock(&ivars->xd_lock);
  305                         while (ivars->xd_state != XenbusStateClosed
  306                             && ivars->xd_state != XenbusStateConnected)
  307                                 sx_sleep(&ivars->xd_state, &ivars->xd_lock,
  308                                     0, "xdattach", 0);
  309                         sx_xunlock(&ivars->xd_lock);
  310                 }
  311                 free(kids, M_TEMP);
  312         }
  313 
  314         return (0);
  315 }
  316 
  317 static void
  318 xenbus_probe_children_cb(void *arg, int pending)
  319 {
  320         device_t dev = (device_t) arg;
  321 
  322         xenbus_probe_children(dev);
  323 }
  324 
  325 static void
  326 xenbus_devices_changed(struct xenbus_watch *watch,
  327     const char **vec, unsigned int len)
  328 {
  329         struct xenbus_softc *sc = (struct xenbus_softc *) watch;
  330         device_t dev = sc->xs_dev;
  331         char *node, *bus, *type, *id, *p;
  332 
  333         node = strdup(vec[XS_WATCH_PATH], M_DEVBUF);;
  334         p = strchr(node, '/');
  335         if (!p)
  336                 goto out;
  337         bus = node;
  338         *p = 0;
  339         type = p + 1;
  340 
  341         p = strchr(type, '/');
  342         if (!p)
  343                 goto out;
  344         *p = 0;
  345         id = p + 1;
  346 
  347         p = strchr(id, '/');
  348         if (p)
  349                 *p = 0;
  350 
  351         xenbus_add_device(dev, bus, type, id);
  352         taskqueue_enqueue(taskqueue_thread, &sc->xs_probechildren);
  353 out:
  354         free(node, M_DEVBUF);
  355 }
  356 
  357 static void
  358 xenbus_attach_deferred(void *arg)
  359 {
  360         device_t dev = (device_t) arg;
  361         struct xenbus_softc *sc = device_get_softc(dev);
  362         int error;
  363         
  364         error = xenbus_enumerate_bus(dev, "device");
  365         if (error)
  366                 return;
  367         xenbus_probe_children(dev);
  368 
  369         sc->xs_dev = dev;
  370         sc->xs_devicewatch.node = "device";
  371         sc->xs_devicewatch.callback = xenbus_devices_changed;
  372 
  373         TASK_INIT(&sc->xs_probechildren, 0, xenbus_probe_children_cb, dev);
  374 
  375         register_xenbus_watch(&sc->xs_devicewatch);
  376 
  377         config_intrhook_disestablish(&sc->xs_attachcb);
  378 }
  379 
  380 static int
  381 xenbus_attach(device_t dev)
  382 {
  383         struct xenbus_softc *sc = device_get_softc(dev);
  384 
  385         sc->xs_attachcb.ich_func = xenbus_attach_deferred;
  386         sc->xs_attachcb.ich_arg = dev;
  387         config_intrhook_establish(&sc->xs_attachcb);
  388 
  389         return (0);
  390 }
  391 
  392 static int
  393 xenbus_suspend(device_t dev)
  394 {
  395         int error;
  396 
  397         DPRINTK("");
  398 
  399         error = bus_generic_suspend(dev);
  400         if (error)
  401                 return (error);
  402 
  403         xs_suspend();
  404 
  405         return (0);
  406 }
  407 
  408 static int
  409 xenbus_resume(device_t dev)
  410 {
  411         device_t *kids;
  412         struct xenbus_device_ivars *ivars;
  413         int i, count, error;
  414         char *statepath;
  415 
  416         xb_init_comms();
  417         xs_resume();
  418 
  419         /*
  420          * We must re-examine each device and find the new path for
  421          * its backend.
  422          */
  423         if (device_get_children(dev, &kids, &count) == 0) {
  424                 for (i = 0; i < count; i++) {
  425                         if (device_get_state(kids[i]) == DS_NOTPRESENT)
  426                                 continue;
  427 
  428                         ivars = device_get_ivars(kids[i]);
  429 
  430                         unregister_xenbus_watch(
  431                                 &ivars->xd_otherend_watch);
  432                         ivars->xd_state = XenbusStateInitialising;
  433 
  434                         /*
  435                          * Find the new backend details and
  436                          * re-register our watch.
  437                          */
  438                         free(ivars->xd_otherend_path, M_DEVBUF);
  439                         error = xenbus_gather(XBT_NIL, ivars->xd_node,
  440                             "backend-id", "%i", &ivars->xd_otherend_id,
  441                             "backend", NULL, &ivars->xd_otherend_path,
  442                             NULL);
  443                         if (error)
  444                                 return (error);
  445 
  446                         DEVICE_RESUME(kids[i]);
  447 
  448                         statepath = malloc(strlen(ivars->xd_otherend_path)
  449                             + strlen("/state") + 1, M_DEVBUF, M_WAITOK);
  450                         sprintf(statepath, "%s/state", ivars->xd_otherend_path);
  451 
  452                         free(ivars->xd_otherend_watch.node, M_DEVBUF);
  453                         ivars->xd_otherend_watch.node = statepath;
  454                         register_xenbus_watch(
  455                                 &ivars->xd_otherend_watch);
  456 
  457 #if 0
  458                         /*
  459                          * Can't do this yet since we are running in
  460                          * the xenwatch thread and if we sleep here,
  461                          * we will stop delivering watch notifications
  462                          * and the device will never come back online.
  463                          */
  464                         sx_xlock(&ivars->xd_lock);
  465                         while (ivars->xd_state != XenbusStateClosed
  466                             && ivars->xd_state != XenbusStateConnected)
  467                                 sx_sleep(&ivars->xd_state, &ivars->xd_lock,
  468                                     0, "xdresume", 0);
  469                         sx_xunlock(&ivars->xd_lock);
  470 #endif
  471                 }
  472                 free(kids, M_TEMP);
  473         }
  474 
  475         return (0);
  476 }
  477 
  478 static int
  479 xenbus_print_child(device_t dev, device_t child)
  480 {
  481         struct xenbus_device_ivars *ivars = device_get_ivars(child);
  482         int     retval = 0;
  483 
  484         retval += bus_print_child_header(dev, child);
  485         retval += printf(" at %s", ivars->xd_node);
  486         retval += bus_print_child_footer(dev, child);
  487 
  488         return (retval);
  489 }
  490 
  491 static int
  492 xenbus_read_ivar(device_t dev, device_t child, int index,
  493     uintptr_t * result)
  494 {
  495         struct xenbus_device_ivars *ivars = device_get_ivars(child);
  496 
  497         switch (index) {
  498         case XENBUS_IVAR_NODE:
  499                 *result = (uintptr_t) ivars->xd_node;
  500                 return (0);
  501 
  502         case XENBUS_IVAR_TYPE:
  503                 *result = (uintptr_t) ivars->xd_type;
  504                 return (0);
  505 
  506         case XENBUS_IVAR_STATE:
  507                 *result = (uintptr_t) ivars->xd_state;
  508                 return (0);
  509 
  510         case XENBUS_IVAR_OTHEREND_ID:
  511                 *result = (uintptr_t) ivars->xd_otherend_id;
  512                 return (0);
  513 
  514         case XENBUS_IVAR_OTHEREND_PATH:
  515                 *result = (uintptr_t) ivars->xd_otherend_path;
  516                 return (0);
  517         }
  518 
  519         return (ENOENT);
  520 }
  521 
  522 static int
  523 xenbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
  524 {
  525         struct xenbus_device_ivars *ivars = device_get_ivars(child);
  526         enum xenbus_state newstate;
  527         int currstate;
  528         int error;
  529 
  530         switch (index) {
  531         case XENBUS_IVAR_STATE:
  532                 newstate = (enum xenbus_state) value;
  533                 sx_xlock(&ivars->xd_lock);
  534                 if (ivars->xd_state == newstate)
  535                         goto out;
  536 
  537                 error = xenbus_scanf(XBT_NIL, ivars->xd_node, "state",
  538                     NULL, "%d", &currstate);
  539                 if (error)
  540                         goto out;
  541 
  542                 error = xenbus_printf(XBT_NIL, ivars->xd_node, "state",
  543                     "%d", newstate);
  544                 if (error) {
  545                         if (newstate != XenbusStateClosing) /* Avoid looping */
  546                                 xenbus_dev_fatal(dev, error, "writing new state");
  547                         goto out;
  548                 }
  549                 ivars->xd_state = newstate;
  550                 wakeup(&ivars->xd_state);
  551         out:
  552                 sx_xunlock(&ivars->xd_lock);
  553                 return (0);
  554 
  555         case XENBUS_IVAR_NODE:
  556         case XENBUS_IVAR_TYPE:
  557         case XENBUS_IVAR_OTHEREND_ID:
  558         case XENBUS_IVAR_OTHEREND_PATH:
  559                 /*
  560                  * These variables are read-only.
  561                  */
  562                 return (EINVAL);
  563         }
  564 
  565         return (ENOENT);
  566 }
  567 
  568 SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen");
  569 SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xen_store_evtchn, 0, "");
  570 SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, "");
  571 
  572 static device_method_t xenbus_methods[] = { 
  573         /* Device interface */ 
  574         DEVMETHOD(device_identify,      xenbus_identify),
  575         DEVMETHOD(device_probe,         xenbus_probe), 
  576         DEVMETHOD(device_attach,        xenbus_attach), 
  577         DEVMETHOD(device_detach,        bus_generic_detach), 
  578         DEVMETHOD(device_shutdown,      bus_generic_shutdown), 
  579         DEVMETHOD(device_suspend,       xenbus_suspend), 
  580         DEVMETHOD(device_resume,        xenbus_resume), 
  581  
  582         /* Bus interface */ 
  583         DEVMETHOD(bus_print_child,      xenbus_print_child),
  584         DEVMETHOD(bus_read_ivar,        xenbus_read_ivar), 
  585         DEVMETHOD(bus_write_ivar,       xenbus_write_ivar), 
  586  
  587         { 0, 0 } 
  588 }; 
  589 
  590 static char driver_name[] = "xenbus";
  591 static driver_t xenbus_driver = { 
  592         driver_name, 
  593         xenbus_methods, 
  594         sizeof(struct xenbus_softc),
  595 }; 
  596 devclass_t xenbus_devclass; 
  597  
  598 #ifdef XENHVM
  599 DRIVER_MODULE(xenbus, xenpci, xenbus_driver, xenbus_devclass, 0, 0);
  600 #else
  601 DRIVER_MODULE(xenbus, nexus, xenbus_driver, xenbus_devclass, 0, 0);
  602 #endif

Cache object: 73c8b31ba304dbd0d046e064e83d62a8


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