diff options
Diffstat (limited to 'sys/xen/xenbus/xenbus_probe.c')
-rw-r--r-- | sys/xen/xenbus/xenbus_probe.c | 602 |
1 files changed, 0 insertions, 602 deletions
diff --git a/sys/xen/xenbus/xenbus_probe.c b/sys/xen/xenbus/xenbus_probe.c deleted file mode 100644 index b1e9a21..0000000 --- a/sys/xen/xenbus/xenbus_probe.c +++ /dev/null @@ -1,602 +0,0 @@ -/****************************************************************************** - * Talks to Xen Store to figure out what devices we have. - * - * Copyright (C) 2008 Doug Rabson - * Copyright (C) 2005 Rusty Russell, IBM Corporation - * Copyright (C) 2005 Mike Wray, Hewlett-Packard - * Copyright (C) 2005 XenSource Ltd - * - * This file may be distributed separately from the Linux kernel, or - * incorporated into other software packages, subject to the following license: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this source file (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#if 0 -#define DPRINTK(fmt, args...) \ - printf("xenbus_probe (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args) -#else -#define DPRINTK(fmt, args...) ((void)0) -#endif - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/bus.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/sysctl.h> -#include <sys/syslog.h> -#include <sys/systm.h> -#include <sys/sx.h> -#include <sys/taskqueue.h> - -#include <machine/xen/xen-os.h> -#include <machine/stdarg.h> - -#include <xen/gnttab.h> -#include <xen/xenbus/xenbusvar.h> -#include <xen/xenbus/xenbus_comms.h> - -struct xenbus_softc { - struct xenbus_watch xs_devicewatch; - struct task xs_probechildren; - struct intr_config_hook xs_attachcb; - device_t xs_dev; -}; - -struct xenbus_device_ivars { - struct xenbus_watch xd_otherend_watch; /* must be first */ - struct sx xd_lock; - device_t xd_dev; - char *xd_node; /* node name in xenstore */ - char *xd_type; /* xen device type */ - enum xenbus_state xd_state; - int xd_otherend_id; - char *xd_otherend_path; -}; - -/* Simplified asprintf. */ -char * -kasprintf(const char *fmt, ...) -{ - va_list ap; - unsigned int len; - char *p, dummy[1]; - - va_start(ap, fmt); - /* FIXME: vsnprintf has a bug, NULL should work */ - len = vsnprintf(dummy, 0, fmt, ap); - va_end(ap); - - p = malloc(len + 1, M_DEVBUF, M_WAITOK); - va_start(ap, fmt); - vsprintf(p, fmt, ap); - va_end(ap); - return p; -} - -static void -xenbus_identify(driver_t *driver, device_t parent) -{ - - BUS_ADD_CHILD(parent, 0, "xenbus", 0); -} - -static int -xenbus_probe(device_t dev) -{ - int err = 0; - - DPRINTK(""); - - /* Initialize the interface to xenstore. */ - err = xs_init(); - if (err) { - log(LOG_WARNING, - "XENBUS: Error initializing xenstore comms: %i\n", err); - return (ENXIO); - } - err = gnttab_init(); - if (err) { - log(LOG_WARNING, - "XENBUS: Error initializing grant table: %i\n", err); - return (ENXIO); - } - device_set_desc(dev, "Xen Devices"); - - return (0); -} - -static enum xenbus_state -xenbus_otherend_state(struct xenbus_device_ivars *ivars) -{ - - return (xenbus_read_driver_state(ivars->xd_otherend_path)); -} - -static void -xenbus_backend_changed(struct xenbus_watch *watch, const char **vec, - unsigned int len) -{ - struct xenbus_device_ivars *ivars; - device_t dev; - enum xenbus_state newstate; - - ivars = (struct xenbus_device_ivars *) watch; - dev = ivars->xd_dev; - - if (!ivars->xd_otherend_path - || strncmp(ivars->xd_otherend_path, vec[XS_WATCH_PATH], - strlen(ivars->xd_otherend_path))) - return; - - newstate = xenbus_otherend_state(ivars); - XENBUS_BACKEND_CHANGED(dev, newstate); -} - -static int -xenbus_device_exists(device_t dev, const char *node) -{ - device_t *kids; - struct xenbus_device_ivars *ivars; - int i, count, result; - - if (device_get_children(dev, &kids, &count)) - return (FALSE); - - result = FALSE; - for (i = 0; i < count; i++) { - ivars = device_get_ivars(kids[i]); - if (!strcmp(ivars->xd_node, node)) { - result = TRUE; - break; - } - } - free(kids, M_TEMP); - - return (result); -} - -static int -xenbus_add_device(device_t dev, const char *bus, - const char *type, const char *id) -{ - device_t child; - struct xenbus_device_ivars *ivars; - enum xenbus_state state; - char *statepath; - int error; - - ivars = malloc(sizeof(struct xenbus_device_ivars), - M_DEVBUF, M_ZERO|M_WAITOK); - ivars->xd_node = kasprintf("%s/%s/%s", bus, type, id); - - if (xenbus_device_exists(dev, ivars->xd_node)) { - /* - * We are already tracking this node - */ - free(ivars->xd_node, M_DEVBUF); - free(ivars, M_DEVBUF); - return (0); - } - - state = xenbus_read_driver_state(ivars->xd_node); - - if (state != XenbusStateInitialising) { - /* - * Device is not new, so ignore it. This can - * happen if a device is going away after - * switching to Closed. - */ - free(ivars->xd_node, M_DEVBUF); - free(ivars, M_DEVBUF); - return (0); - } - - /* - * Find the backend details - */ - error = xenbus_gather(XBT_NIL, ivars->xd_node, - "backend-id", "%i", &ivars->xd_otherend_id, - "backend", NULL, &ivars->xd_otherend_path, - NULL); - if (error) - return (error); - - sx_init(&ivars->xd_lock, "xdlock"); - ivars->xd_type = strdup(type, M_DEVBUF); - ivars->xd_state = XenbusStateInitialising; - - statepath = malloc(strlen(ivars->xd_otherend_path) - + strlen("/state") + 1, M_DEVBUF, M_WAITOK); - sprintf(statepath, "%s/state", ivars->xd_otherend_path); - - ivars->xd_otherend_watch.node = statepath; - ivars->xd_otherend_watch.callback = xenbus_backend_changed; - - child = device_add_child(dev, NULL, -1); - ivars->xd_dev = child; - device_set_ivars(child, ivars); - - return (0); -} - -static int -xenbus_enumerate_type(device_t dev, const char *bus, const char *type) -{ - char **dir; - unsigned int i, count; - int error; - - error = xenbus_directory(XBT_NIL, bus, type, &count, &dir); - if (error) - return (error); - for (i = 0; i < count; i++) - xenbus_add_device(dev, bus, type, dir[i]); - - free(dir, M_DEVBUF); - - return (0); -} - -static int -xenbus_enumerate_bus(device_t dev, const char *bus) -{ - char **dir; - unsigned int i, count; - int error; - - error = xenbus_directory(XBT_NIL, bus, "", &count, &dir); - if (error) - return (error); - for (i = 0; i < count; i++) { - xenbus_enumerate_type(dev, bus, dir[i]); - } - free(dir, M_DEVBUF); - - return (0); -} - -static int -xenbus_probe_children(device_t dev) -{ - device_t *kids; - struct xenbus_device_ivars *ivars; - int i, count; - - /* - * Probe any new devices and register watches for any that - * attach successfully. Since part of the protocol which - * establishes a connection with the other end is interrupt - * driven, we sleep until the device reaches a stable state - * (closed or connected). - */ - if (device_get_children(dev, &kids, &count) == 0) { - for (i = 0; i < count; i++) { - if (device_get_state(kids[i]) != DS_NOTPRESENT) - continue; - - if (device_probe_and_attach(kids[i])) - continue; - ivars = device_get_ivars(kids[i]); - register_xenbus_watch( - &ivars->xd_otherend_watch); - sx_xlock(&ivars->xd_lock); - while (ivars->xd_state != XenbusStateClosed - && ivars->xd_state != XenbusStateConnected) - sx_sleep(&ivars->xd_state, &ivars->xd_lock, - 0, "xdattach", 0); - sx_xunlock(&ivars->xd_lock); - } - free(kids, M_TEMP); - } - - return (0); -} - -static void -xenbus_probe_children_cb(void *arg, int pending) -{ - device_t dev = (device_t) arg; - - xenbus_probe_children(dev); -} - -static void -xenbus_devices_changed(struct xenbus_watch *watch, - const char **vec, unsigned int len) -{ - struct xenbus_softc *sc = (struct xenbus_softc *) watch; - device_t dev = sc->xs_dev; - char *node, *bus, *type, *id, *p; - - node = strdup(vec[XS_WATCH_PATH], M_DEVBUF); - p = strchr(node, '/'); - if (!p) - goto out; - bus = node; - *p = 0; - type = p + 1; - - p = strchr(type, '/'); - if (!p) - goto out; - *p = 0; - id = p + 1; - - p = strchr(id, '/'); - if (p) - *p = 0; - - xenbus_add_device(dev, bus, type, id); - taskqueue_enqueue(taskqueue_thread, &sc->xs_probechildren); -out: - free(node, M_DEVBUF); -} - -static void -xenbus_attach_deferred(void *arg) -{ - device_t dev = (device_t) arg; - struct xenbus_softc *sc = device_get_softc(dev); - int error; - - error = xenbus_enumerate_bus(dev, "device"); - if (error) - return; - xenbus_probe_children(dev); - - sc->xs_dev = dev; - sc->xs_devicewatch.node = "device"; - sc->xs_devicewatch.callback = xenbus_devices_changed; - - TASK_INIT(&sc->xs_probechildren, 0, xenbus_probe_children_cb, dev); - - register_xenbus_watch(&sc->xs_devicewatch); - - config_intrhook_disestablish(&sc->xs_attachcb); -} - -static int -xenbus_attach(device_t dev) -{ - struct xenbus_softc *sc = device_get_softc(dev); - - sc->xs_attachcb.ich_func = xenbus_attach_deferred; - sc->xs_attachcb.ich_arg = dev; - config_intrhook_establish(&sc->xs_attachcb); - - return (0); -} - -static int -xenbus_suspend(device_t dev) -{ - int error; - - DPRINTK(""); - - error = bus_generic_suspend(dev); - if (error) - return (error); - - xs_suspend(); - - return (0); -} - -static int -xenbus_resume(device_t dev) -{ - device_t *kids; - struct xenbus_device_ivars *ivars; - int i, count, error; - char *statepath; - - xb_init_comms(); - xs_resume(); - - /* - * We must re-examine each device and find the new path for - * its backend. - */ - if (device_get_children(dev, &kids, &count) == 0) { - for (i = 0; i < count; i++) { - if (device_get_state(kids[i]) == DS_NOTPRESENT) - continue; - - ivars = device_get_ivars(kids[i]); - - unregister_xenbus_watch( - &ivars->xd_otherend_watch); - ivars->xd_state = XenbusStateInitialising; - - /* - * Find the new backend details and - * re-register our watch. - */ - free(ivars->xd_otherend_path, M_DEVBUF); - error = xenbus_gather(XBT_NIL, ivars->xd_node, - "backend-id", "%i", &ivars->xd_otherend_id, - "backend", NULL, &ivars->xd_otherend_path, - NULL); - if (error) - return (error); - - DEVICE_RESUME(kids[i]); - - statepath = malloc(strlen(ivars->xd_otherend_path) - + strlen("/state") + 1, M_DEVBUF, M_WAITOK); - sprintf(statepath, "%s/state", ivars->xd_otherend_path); - - free(ivars->xd_otherend_watch.node, M_DEVBUF); - ivars->xd_otherend_watch.node = statepath; - register_xenbus_watch( - &ivars->xd_otherend_watch); - -#if 0 - /* - * Can't do this yet since we are running in - * the xenwatch thread and if we sleep here, - * we will stop delivering watch notifications - * and the device will never come back online. - */ - sx_xlock(&ivars->xd_lock); - while (ivars->xd_state != XenbusStateClosed - && ivars->xd_state != XenbusStateConnected) - sx_sleep(&ivars->xd_state, &ivars->xd_lock, - 0, "xdresume", 0); - sx_xunlock(&ivars->xd_lock); -#endif - } - free(kids, M_TEMP); - } - - return (0); -} - -static int -xenbus_print_child(device_t dev, device_t child) -{ - struct xenbus_device_ivars *ivars = device_get_ivars(child); - int retval = 0; - - retval += bus_print_child_header(dev, child); - retval += printf(" at %s", ivars->xd_node); - retval += bus_print_child_footer(dev, child); - - return (retval); -} - -static int -xenbus_read_ivar(device_t dev, device_t child, int index, - uintptr_t * result) -{ - struct xenbus_device_ivars *ivars = device_get_ivars(child); - - switch (index) { - case XENBUS_IVAR_NODE: - *result = (uintptr_t) ivars->xd_node; - return (0); - - case XENBUS_IVAR_TYPE: - *result = (uintptr_t) ivars->xd_type; - return (0); - - case XENBUS_IVAR_STATE: - *result = (uintptr_t) ivars->xd_state; - return (0); - - case XENBUS_IVAR_OTHEREND_ID: - *result = (uintptr_t) ivars->xd_otherend_id; - return (0); - - case XENBUS_IVAR_OTHEREND_PATH: - *result = (uintptr_t) ivars->xd_otherend_path; - return (0); - } - - return (ENOENT); -} - -static int -xenbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value) -{ - struct xenbus_device_ivars *ivars = device_get_ivars(child); - enum xenbus_state newstate; - int currstate; - int error; - - switch (index) { - case XENBUS_IVAR_STATE: - newstate = (enum xenbus_state) value; - sx_xlock(&ivars->xd_lock); - if (ivars->xd_state == newstate) - goto out; - - error = xenbus_scanf(XBT_NIL, ivars->xd_node, "state", - NULL, "%d", &currstate); - if (error) - goto out; - - error = xenbus_printf(XBT_NIL, ivars->xd_node, "state", - "%d", newstate); - if (error) { - if (newstate != XenbusStateClosing) /* Avoid looping */ - xenbus_dev_fatal(dev, error, "writing new state"); - goto out; - } - ivars->xd_state = newstate; - wakeup(&ivars->xd_state); - out: - sx_xunlock(&ivars->xd_lock); - return (0); - - case XENBUS_IVAR_NODE: - case XENBUS_IVAR_TYPE: - case XENBUS_IVAR_OTHEREND_ID: - case XENBUS_IVAR_OTHEREND_PATH: - /* - * These variables are read-only. - */ - return (EINVAL); - } - - return (ENOENT); -} - -SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen"); -SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xen_store_evtchn, 0, ""); -SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, ""); - -static device_method_t xenbus_methods[] = { - /* Device interface */ - DEVMETHOD(device_identify, xenbus_identify), - DEVMETHOD(device_probe, xenbus_probe), - DEVMETHOD(device_attach, xenbus_attach), - DEVMETHOD(device_detach, bus_generic_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, xenbus_suspend), - DEVMETHOD(device_resume, xenbus_resume), - - /* Bus interface */ - DEVMETHOD(bus_print_child, xenbus_print_child), - DEVMETHOD(bus_read_ivar, xenbus_read_ivar), - DEVMETHOD(bus_write_ivar, xenbus_write_ivar), - - { 0, 0 } -}; - -static char driver_name[] = "xenbus"; -static driver_t xenbus_driver = { - driver_name, - xenbus_methods, - sizeof(struct xenbus_softc), -}; -devclass_t xenbus_devclass; - -#ifdef XENHVM -DRIVER_MODULE(xenbus, xenpci, xenbus_driver, xenbus_devclass, 0, 0); -#else -DRIVER_MODULE(xenbus, nexus, xenbus_driver, xenbus_devclass, 0, 0); -#endif |