diff options
author | kmacy <kmacy@FreeBSD.org> | 2008-12-04 07:59:05 +0000 |
---|---|---|
committer | kmacy <kmacy@FreeBSD.org> | 2008-12-04 07:59:05 +0000 |
commit | 77ba713706a3fffb53f651616e1a3d43caffe7ac (patch) | |
tree | ff76f522d9d91397c9adee09cba8d5e6b0f32df5 /sys/xen | |
parent | 0db39db0278da23ed458007116b629ab4a578a3e (diff) | |
download | FreeBSD-src-77ba713706a3fffb53f651616e1a3d43caffe7ac.zip FreeBSD-src-77ba713706a3fffb53f651616e1a3d43caffe7ac.tar.gz |
Integrate 185578 from dfr
Use newbus to managed devices
Diffstat (limited to 'sys/xen')
-rw-r--r-- | sys/xen/gnttab.c | 6 | ||||
-rw-r--r-- | sys/xen/gnttab.h | 2 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_client.c | 80 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_comms.c | 8 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_comms.h | 9 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_dev.c | 7 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_if.m | 37 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_probe.c | 1245 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_probe_backend.c | 1 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbus_xs.c | 4 | ||||
-rw-r--r-- | sys/xen/xenbus/xenbusvar.h | 248 |
11 files changed, 640 insertions, 1007 deletions
diff --git a/sys/xen/gnttab.c b/sys/xen/gnttab.c index 896af7b..fdd3d1b 100644 --- a/sys/xen/gnttab.c +++ b/sys/xen/gnttab.c @@ -537,8 +537,8 @@ gnttab_expand(unsigned int req_entries) return rc; } -static int -gnttab_init(void *unused) +int +gnttab_init() { int i; unsigned int max_nr_glist_frames; @@ -593,4 +593,4 @@ ini_nomem: } MTX_SYSINIT(gnttab, &gnttab_list_lock, "GNTTAB LOCK", MTX_DEF); -SYSINIT(gnttab, SI_SUB_PSEUDO, SI_ORDER_FIRST, gnttab_init, NULL); +//SYSINIT(gnttab, SI_SUB_PSEUDO, SI_ORDER_FIRST, gnttab_init, NULL); diff --git a/sys/xen/gnttab.h b/sys/xen/gnttab.h index 6a24dd2..d1abe14 100644 --- a/sys/xen/gnttab.h +++ b/sys/xen/gnttab.h @@ -49,6 +49,8 @@ struct gnttab_free_callback { uint16_t count; }; +int gnttab_init(void); + int gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int flags); diff --git a/sys/xen/xenbus/xenbus_client.c b/sys/xen/xenbus/xenbus_client.c index a6f9e6b..d8a1a3f 100644 --- a/sys/xen/xenbus/xenbus_client.c +++ b/sys/xen/xenbus/xenbus_client.c @@ -46,7 +46,7 @@ __FBSDID("$FreeBSD$"); #include <machine/xen/xen-os.h> #include <machine/xen/evtchn.h> #include <xen/gnttab.h> -#include <machine/xen/xenbus.h> +#include <xen/xenbus/xenbusvar.h> #include <machine/stdarg.h> @@ -71,7 +71,7 @@ const char *xenbus_strstate(XenbusState state) } int -xenbus_watch_path(struct xenbus_device *dev, char *path, +xenbus_watch_path(device_t dev, char *path, struct xenbus_watch *watch, void (*callback)(struct xenbus_watch *, const char **, unsigned int)) @@ -94,7 +94,7 @@ xenbus_watch_path(struct xenbus_device *dev, char *path, EXPORT_SYMBOL(xenbus_watch_path); -int xenbus_watch_path2(struct xenbus_device *dev, const char *path, +int xenbus_watch_path2(device_t dev, const char *path, const char *path2, struct xenbus_watch *watch, void (*callback)(struct xenbus_watch *, const char **, unsigned int)) @@ -119,70 +119,27 @@ int xenbus_watch_path2(struct xenbus_device *dev, const char *path, } EXPORT_SYMBOL(xenbus_watch_path2); - -int xenbus_switch_state(struct xenbus_device *dev, - XenbusState state) -{ - /* We check whether the state is currently set to the given value, and - if not, then the state is set. We don't want to unconditionally - write the given state, because we don't want to fire watches - unnecessarily. Furthermore, if the node has gone, we don't write - to it, as the device will be tearing down, and we don't want to - resurrect that directory. - */ - - int current_state; - int err; - - if (state == dev->state) - return (0); - - err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d", - ¤t_state); - if (err != 1) - return 0; - - err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state); - if (err) { - if (state != XenbusStateClosing) /* Avoid looping */ - xenbus_dev_fatal(dev, err, "writing new state"); - return err; - } - - dev->state = state; - return 0; - -} - -int xenbus_frontend_closed(struct xenbus_device *dev) -{ - xenbus_switch_state(dev, XenbusStateClosed); -#if 0 - complete(&dev->down); -#endif - return 0; -} - /** * Return the path to the error node for the given device, or NULL on failure. * If the value returned is non-NULL, then it is the caller's to kfree. */ -static char *error_path(struct xenbus_device *dev) +static char *error_path(device_t dev) { - char *path_buffer = kmalloc(strlen("error/") + strlen(dev->nodename) + + char *path_buffer = kmalloc(strlen("error/") + + strlen(xenbus_get_node(dev)) + 1, GFP_KERNEL); if (path_buffer == NULL) { return NULL; } strcpy(path_buffer, "error/"); - strcpy(path_buffer + strlen("error/"), dev->nodename); + strcpy(path_buffer + strlen("error/"), xenbus_get_node(dev)); return path_buffer; } -static void _dev_error(struct xenbus_device *dev, int err, const char *fmt, +static void _dev_error(device_t dev, int err, const char *fmt, va_list ap) { int ret; @@ -205,13 +162,13 @@ static void _dev_error(struct xenbus_device *dev, int err, const char *fmt, if (path_buffer == NULL) { printk("xenbus: failed to write error node for %s (%s)\n", - dev->nodename, printf_buffer); + xenbus_get_node(dev), printf_buffer); goto fail; } if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) { printk("xenbus: failed to write error node for %s (%s)\n", - dev->nodename, printf_buffer); + xenbus_get_node(dev), printf_buffer); goto fail; } @@ -223,7 +180,7 @@ static void _dev_error(struct xenbus_device *dev, int err, const char *fmt, } -void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, +void xenbus_dev_error(device_t dev, int err, const char *fmt, ...) { va_list ap; @@ -235,7 +192,7 @@ void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, EXPORT_SYMBOL(xenbus_dev_error); -void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, +void xenbus_dev_fatal(device_t dev, int err, const char *fmt, ...) { va_list ap; @@ -244,14 +201,15 @@ void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, _dev_error(dev, err, fmt, ap); va_end(ap); - xenbus_switch_state(dev, XenbusStateClosing); + xenbus_set_state(dev, XenbusStateClosing); } EXPORT_SYMBOL(xenbus_dev_fatal); -int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn) +int xenbus_grant_ring(device_t dev, unsigned long ring_mfn) { - int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0); + int err = gnttab_grant_foreign_access( + xenbus_get_otherend_id(dev), ring_mfn, 0); if (err < 0) xenbus_dev_fatal(dev, err, "granting access to ring page"); return err; @@ -259,13 +217,13 @@ int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn) EXPORT_SYMBOL(xenbus_grant_ring); -int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port) +int xenbus_alloc_evtchn(device_t dev, int *port) { struct evtchn_alloc_unbound alloc_unbound; int err; alloc_unbound.dom = DOMID_SELF; - alloc_unbound.remote_dom = dev->otherend_id; + alloc_unbound.remote_dom = xenbus_get_otherend_id(dev); err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound); @@ -279,7 +237,7 @@ int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port) EXPORT_SYMBOL(xenbus_alloc_evtchn); -int xenbus_free_evtchn(struct xenbus_device *dev, int port) +int xenbus_free_evtchn(device_t dev, int port) { struct evtchn_close close; int err; diff --git a/sys/xen/xenbus/xenbus_comms.c b/sys/xen/xenbus/xenbus_comms.c index 8f0f171..90f0ea9 100644 --- a/sys/xen/xenbus/xenbus_comms.c +++ b/sys/xen/xenbus/xenbus_comms.c @@ -31,8 +31,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/types.h> -#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/bus.h> #include <sys/time.h> #include <sys/errno.h> #include <sys/param.h> @@ -41,14 +41,12 @@ __FBSDID("$FreeBSD$"); #include <sys/proc.h> #include <sys/kernel.h> - - #include <machine/xen/xen-os.h> #include <machine/xen/hypervisor.h> #include <machine/xen/evtchn.h> -#include <machine/xen/xenbus.h> #include <machine/xen/xen_intr.h> #include <xen/xenbus/xenbus_comms.h> +#include <xen/interface/io/xs_wire.h> static int xenbus_irq; diff --git a/sys/xen/xenbus/xenbus_comms.h b/sys/xen/xenbus/xenbus_comms.h index 871afd5..94a57dc 100644 --- a/sys/xen/xenbus/xenbus_comms.h +++ b/sys/xen/xenbus/xenbus_comms.h @@ -125,19 +125,14 @@ struct xen_bus_type }; -extern void xenbus_backend_probe_and_watch(void); -int xenbus_probe_node(struct xen_bus_type *bus, const char *type, - const char *nodename); -int xenbus_probe_devices(struct xen_bus_type *bus); - -int xenbus_register_driver_common(struct xenbus_driver *drv, - struct xen_bus_type *bus); +#if 0 void dev_changed(const char *node, struct xen_bus_type *bus); int read_otherend_details(struct xenbus_device *xendev, char *id_node, char *path_node); +#endif char *kasprintf(const char *fmt, ...); diff --git a/sys/xen/xenbus/xenbus_dev.c b/sys/xen/xenbus/xenbus_dev.c index 8a13322..52e0b67 100644 --- a/sys/xen/xenbus/xenbus_dev.c +++ b/sys/xen/xenbus/xenbus_dev.c @@ -44,16 +44,11 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/conf.h> - #include <machine/xen/xen-os.h> #include <machine/xen/hypervisor.h> -#include <machine/xen/xenbus.h> -#include <machine/xen/hypervisor.h> +#include <xen/xenbus/xenbusvar.h> #include <xen/xenbus/xenbus_comms.h> - - - #define kmalloc(size, unused) malloc(size, M_DEVBUF, M_WAITOK) #define BUG_ON PANIC_IF #define semaphore sema diff --git a/sys/xen/xenbus/xenbus_if.m b/sys/xen/xenbus/xenbus_if.m new file mode 100644 index 0000000..018a2bb --- /dev/null +++ b/sys/xen/xenbus/xenbus_if.m @@ -0,0 +1,37 @@ +#- +# Copyright (c) 2008 Doug Rabson +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#include <sys/bus.h> +#include <xen/interface/io/xenbus.h> + +INTERFACE xenbus; + +METHOD int backend_changed { + device_t dev; + enum xenbus_state newstate; +}; diff --git a/sys/xen/xenbus/xenbus_probe.c b/sys/xen/xenbus/xenbus_probe.c index c45a375..e57e6e3 100644 --- a/sys/xen/xenbus/xenbus_probe.c +++ b/sys/xen/xenbus/xenbus_probe.c @@ -1,6 +1,7 @@ /****************************************************************************** * 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 @@ -38,838 +39,355 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/types.h> -#include <sys/cdefs.h> -#include <sys/time.h> -#include <sys/sema.h> -#include <sys/eventhandler.h> -#include <sys/errno.h> +#include <sys/bus.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/malloc.h> #include <sys/module.h> -#include <sys/conf.h> -#include <sys/systm.h> +#include <sys/sysctl.h> #include <sys/syslog.h> -#include <sys/proc.h> -#include <sys/bus.h> +#include <sys/systm.h> #include <sys/sx.h> +#include <sys/taskqueue.h> #include <machine/xen/xen-os.h> -#include <machine/xen/hypervisor.h> -#include <machine/xen/xenbus.h> -#include <machine/xen/evtchn.h> #include <machine/stdarg.h> +#include <xen/gnttab.h> +#include <xen/xenbus/xenbusvar.h> #include <xen/xenbus/xenbus_comms.h> -struct xendev_list_head xenbus_device_frontend_list; -struct xendev_list_head xenbus_device_backend_list; -static LIST_HEAD(, xenbus_driver) xendrv_list; - -extern struct sx xenwatch_mutex; - -EVENTHANDLER_DECLARE(xenstore_event, xenstore_event_handler_t); -static struct eventhandler_list *xenstore_chain; -device_t xenbus_dev; -device_t xenbus_backend_dev; -static MALLOC_DEFINE(M_XENDEV, "xenintrdrv", "xen system device"); - -#define streq(a, b) (strcmp((a), (b)) == 0) - -static int watch_otherend(struct xenbus_device *dev); - - -/* If something in array of ids matches this device, return it. */ -static const struct xenbus_device_id * -match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) -{ - for (; !streq(arr->devicetype, ""); arr++) { - if (streq(arr->devicetype, dev->devicetype)) - return arr; - } - return NULL; -} - -#if 0 -static int xenbus_match(device_t _dev) -{ - struct xenbus_driver *drv; - struct xenbus_device *dev; - - dev = device_get_softc(_dev); - drv = dev->driver; - - if (!drv->ids) - return 0; - - return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; -} -#endif - - -/* device/<type>/<id> => <type>-<id> */ -static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) -{ - nodename = strchr(nodename, '/'); - if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) { - log(LOG_WARNING, "XENBUS: bad frontend %s\n", nodename); - return -EINVAL; - } - - strlcpy(bus_id, nodename + 1, BUS_ID_SIZE); - if (!strchr(bus_id, '/')) { - log(LOG_WARNING, "XENBUS: bus_id %s no slash\n", bus_id); - return -EINVAL; - } - *strchr(bus_id, '/') = '-'; - return 0; -} - - -static void free_otherend_details(struct xenbus_device *dev) -{ - kfree((void*)(uintptr_t)dev->otherend); - dev->otherend = NULL; -} - - -static void free_otherend_watch(struct xenbus_device *dev) -{ - if (dev->otherend_watch.node) { - unregister_xenbus_watch(&dev->otherend_watch); - kfree(dev->otherend_watch.node); - dev->otherend_watch.node = NULL; - } -} - -int -read_otherend_details(struct xenbus_device *xendev, char *id_node, - char *path_node) -{ - int err = xenbus_gather(XBT_NIL, xendev->nodename, - id_node, "%i", &xendev->otherend_id, - path_node, NULL, &xendev->otherend, - NULL); - if (err) { - xenbus_dev_fatal(xendev, err, - "reading other end details from %s", - xendev->nodename); - return err; - } - if (strlen(xendev->otherend) == 0 || - !xenbus_exists(XBT_NIL, xendev->otherend, "")) { - xenbus_dev_fatal(xendev, -ENOENT, "missing other end from %s", - xendev->nodename); - kfree((void *)(uintptr_t)xendev->otherend); - xendev->otherend = NULL; - return -ENOENT; - } - - return 0; -} - - -static int read_backend_details(struct xenbus_device *xendev) -{ - return read_otherend_details(xendev, "backend-id", "backend"); -} - -#ifdef notyet -/* XXX - move to probe backend */ -static int read_frontend_details(struct xenbus_device *xendev) -{ - if (strncmp(xendev->nodename, "backend", 7)) - return -ENOENT; - return read_otherend_details(xendev, "frontend-id", "frontend"); -} -#endif - -/* Bus type for frontend drivers. */ -static int xenbus_probe_frontend(const char *type, const char *name); -static struct xen_bus_type xenbus_frontend = { - .root = "device", - .levels = 2, /* device/type/<id> */ - .get_bus_id = frontend_bus_id, - .probe = xenbus_probe_frontend, - .bus = &xenbus_device_frontend_list, -#if 0 - /* this initialization needs to happen dynamically */ - .bus = { - .name = "xen", - .match = xenbus_match, - }, - .dev = { - .bus_id = "xen", - }, -#endif +struct xenbus_softc { + struct xenbus_watch xs_devicewatch; + struct task xs_probechildren; + struct intr_config_hook xs_attachcb; + device_t xs_dev; }; -#if 0 -static int xenbus_hotplug_backend(device_t dev, char **envp, - int num_envp, char *buffer, int buffer_size) -{ - panic("implement me"); -#if 0 - struct xenbus_device *xdev; - struct xenbus_driver *drv = NULL; - int i = 0; - int length = 0; - char *basepath_end; - char *frontend_id; - - DPRINTK(""); - - if (dev == NULL) - return -ENODEV; - - xdev = to_xenbus_device(dev); - if (xdev == NULL) - return -ENODEV; - - if (dev->driver) - drv = to_xenbus_driver(dev->driver); - - /* stuff we want to pass to /sbin/hotplug */ - add_hotplug_env_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "XENBUS_TYPE=%s", xdev->devicetype); - - add_hotplug_env_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "XENBUS_PATH=%s", xdev->nodename); - - add_hotplug_env_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "XENBUS_BASE_PATH=%s", xdev->nodename); - - basepath_end = strrchr(envp[i - 1], '/'); - length -= strlen(basepath_end); - *basepath_end = '\0'; - basepath_end = strrchr(envp[i - 1], '/'); - length -= strlen(basepath_end); - *basepath_end = '\0'; - - basepath_end++; - frontend_id = kmalloc(strlen(basepath_end) + 1, GFP_KERNEL); - strcpy(frontend_id, basepath_end); - add_hotplug_env_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "XENBUS_FRONTEND_ID=%s", frontend_id); - kfree(frontend_id); - - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - - if (drv && drv->hotplug) - return drv->hotplug(xdev, envp, num_envp, buffer, buffer_size); - -#endif - return 0; -} -#endif - -#if 0 -static int xenbus_probe_backend(const char *type, const char *domid, int unit); -static struct xen_bus_type xenbus_backend = { - .root = "backend", - .levels = 3, /* backend/type/<frontend>/<id> */ - .get_bus_id = backend_bus_id, - .probe = xenbus_probe_backend, - /* at init time */ - .bus = &xenbus_device_backend_list, -#if 0 - .bus = { - .name = "xen-backend", - .match = xenbus_match, - .hotplug = xenbus_hotplug_backend, - }, - .dev = { - .bus_id = "xen-backend", - }, -#endif +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; }; -#endif -static void otherend_changed(struct xenbus_watch *watch, - const char **vec, unsigned int len) +/* Simplified asprintf. */ +char * +kasprintf(const char *fmt, ...) { + va_list ap; + unsigned int len; + char *p, dummy[1]; - struct xenbus_device *dev = (struct xenbus_device *)watch; - struct xenbus_driver *drv = dev->driver; - XenbusState state; - - /* Protect us against watches firing on old details when the otherend - details change, say immediately after a resume. */ - if (!dev->otherend || strncmp(dev->otherend, vec[XS_WATCH_PATH], - strlen(dev->otherend))) { - DPRINTK("Ignoring watch at %s", vec[XS_WATCH_PATH]); - return; - } - - state = xenbus_read_driver_state(dev->otherend); - - DPRINTK("state is %d, %s, %s", state, dev->otherend_watch.node, - vec[XS_WATCH_PATH]); - - /* - * Ignore xenbus transitions during shutdown. This prevents us doing - * work that can fail e.g., when the rootfs is gone. - */ -#if 0 - if (system_state > SYSTEM_RUNNING) { - struct xen_bus_type *bus = bus; - bus = container_of(dev->dev.bus, struct xen_bus_type, bus); - /* If we're frontend, drive the state machine to Closed. */ - /* This should cause the backend to release our resources. */ - if ((bus == &xenbus_frontend) && (state == XenbusStateClosing)) - xenbus_frontend_closed(dev); - return; - } -#endif - if (drv->otherend_changed) - drv->otherend_changed(dev, state); + va_start(ap, fmt); + /* FIXME: vsnprintf has a bug, NULL should work */ + len = vsnprintf(dummy, 0, fmt, ap); + va_end(ap); + p = kmalloc(len + 1, GFP_KERNEL); + if (!p) + return NULL; + va_start(ap, fmt); + vsprintf(p, fmt, ap); + va_end(ap); + return p; } - -static int talk_to_otherend(struct xenbus_device *dev) +static void +xenbus_identify(driver_t *driver, device_t parent) { - struct xenbus_driver *drv; - - drv = dev->driver; - - free_otherend_watch(dev); - free_otherend_details(dev); - - return drv->read_otherend_details(dev); -} -static int watch_otherend(struct xenbus_device *dev) -{ - return xenbus_watch_path2(dev, dev->otherend, "state", - &dev->otherend_watch, otherend_changed); + BUS_ADD_CHILD(parent, 0, "xenbus", 0); } static int -xenbus_dev_probe(struct xenbus_device *dev) +xenbus_probe(device_t dev) { - struct xenbus_driver *drv = dev->driver; - const struct xenbus_device_id *id; - int err; - + int err = 0; + DPRINTK(""); - - if (!drv->probe) { - err = -ENODEV; - goto fail; - } - - id = match_device(drv->ids, dev); - if (!id) { - err = -ENODEV; - goto fail; - } - - err = talk_to_otherend(dev); + + /* Initialize the interface to xenstore. */ + err = xs_init(); if (err) { - log(LOG_WARNING, - "xenbus_probe: talk_to_otherend on %s failed.\n", - dev->nodename); - return err; + log(LOG_WARNING, + "XENBUS: Error initializing xenstore comms: %i\n", err); + return (ENXIO); } - - err = drv->probe(dev, id); - if (err) - goto fail; - - err = watch_otherend(dev); + err = gnttab_init(); if (err) { - log(LOG_WARNING, - "xenbus_probe: watch_otherend on %s failed.\n", - dev->nodename); - return err; + log(LOG_WARNING, + "XENBUS: Error initializing grant table: %i\n", err); + return (ENXIO); } - - return 0; - fail: - xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename); - xenbus_switch_state(dev, XenbusStateClosed); - return -ENODEV; -} + device_set_desc(dev, "Xen Devices"); -static void xenbus_dev_free(struct xenbus_device *xendev) -{ - LIST_REMOVE(xendev, list); - kfree(xendev); + return (0); } -int -xenbus_remove_device(struct xenbus_device *dev) +static enum xenbus_state +xenbus_otherend_state(struct xenbus_device_ivars *ivars) { - struct xenbus_driver *drv = dev->driver; - - DPRINTK(""); - - free_otherend_watch(dev); - free_otherend_details(dev); - if (drv->remove) - drv->remove(dev); - - xenbus_switch_state(dev, XenbusStateClosed); - - if (drv->cleanup_device) - return drv->cleanup_device(dev); - - xenbus_dev_free(dev); - - return 0; -} - -#if 0 -static int -xenbus_dev_remove(device_t _dev) -{ - return xenbus_remove_device(to_xenbus_device(_dev)); + return (xenbus_read_driver_state(ivars->xd_otherend_path)); } -#endif -int xenbus_register_driver_common(struct xenbus_driver *drv, - struct xen_bus_type *bus) +static void +xenbus_backend_changed(struct xenbus_watch *watch, const char **vec, + unsigned int len) { - struct xenbus_device *xdev; - -#if 0 - int ret; - /* this all happens in the driver itself - * doing this here simple serves to obfuscate - */ + struct xenbus_device_ivars *ivars; + device_t dev; + enum xenbus_state newstate; - drv->driver.name = drv->name; - drv->driver.bus = &bus->bus; - drv->driver.owner = drv->owner; - drv->driver.probe = xenbus_dev_probe; - drv->driver.remove = xenbus_dev_remove; + ivars = (struct xenbus_device_ivars *) watch; + dev = ivars->xd_dev; - return ret; -#endif - sx_xlock(&xenwatch_mutex); - LIST_INSERT_HEAD(&xendrv_list, drv, list); - sx_xunlock(&xenwatch_mutex); - LIST_FOREACH(xdev, bus->bus, list) { - if (match_device(drv->ids, xdev)) { - xdev->driver = drv; - xenbus_dev_probe(xdev); - } - } - return 0; -} - -int xenbus_register_frontend(struct xenbus_driver *drv) -{ - drv->read_otherend_details = read_backend_details; + if (!ivars->xd_otherend_path + || strncmp(ivars->xd_otherend_path, vec[XS_WATCH_PATH], + strlen(ivars->xd_otherend_path))) + return; - return xenbus_register_driver_common(drv, &xenbus_frontend); + newstate = xenbus_otherend_state(ivars); + XENBUS_BACKEND_CHANGED(dev, newstate); } -EXPORT_SYMBOL(xenbus_register_frontend); - -void xenbus_unregister_driver(struct xenbus_driver *drv) +static int +xenbus_device_exists(device_t dev, const char *node) { -#if 0 - driver_unregister(&drv->driver); -#endif -} -EXPORT_SYMBOL(xenbus_unregister_driver); + device_t *kids; + struct xenbus_device_ivars *ivars; + int i, count, result; -struct xb_find_info -{ - struct xenbus_device *dev; - const char *nodename; -}; + if (device_get_children(dev, &kids, &count)) + return (FALSE); -static struct xenbus_device * -xenbus_device_find(const char *nodename, struct xendev_list_head *bus) -{ - struct xenbus_device *xdev; - LIST_FOREACH(xdev, bus, list) { - if (streq(xdev->nodename, nodename)) { - return xdev; -#if 0 - get_device(dev); -#endif + result = FALSE; + for (i = 0; i < count; i++) { + ivars = device_get_ivars(kids[i]); + if (!strcmp(ivars->xd_node, node)) { + result = TRUE; + break; } } - return NULL; -} -#if 0 -static int cleanup_dev(device_t dev, void *data) -{ - struct xenbus_device *xendev = device_get_softc(dev); - struct xb_find_info *info = data; - int len = strlen(info->nodename); + free(kids, M_TEMP); - DPRINTK("%s", info->nodename); - - if (!strncmp(xendev->nodename, info->nodename, len)) { - info->dev = xendev; -#if 0 - get_device(dev); -#endif - return 1; - } - return 0; + return (result); } -#endif -static void xenbus_cleanup_devices(const char *path, struct xendev_list_head * bus) +static int +xenbus_add_device(device_t dev, const char *bus, + const char *type, const char *id) { -#if 0 - struct xb_find_info info = { .nodename = path }; - - do { - info.dev = NULL; - bus_for_each_dev(bus, NULL, &info, cleanup_dev); - if (info.dev) { - device_unregister(&info.dev->dev); - put_device(&info.dev->dev); - } - } while (info.dev); -#endif -} + device_t child; + struct xenbus_device_ivars *ivars; + enum xenbus_state state; + char *statepath; -#if 0 -void xenbus_dev_release(device_t dev) -{ - /* - * nothing to do softc gets freed with the device - */ - -} -#endif -/* Simplified asprintf. */ -char *kasprintf(const char *fmt, ...) -{ - va_list ap; - unsigned int len; - char *p, dummy[1]; + ivars = malloc(sizeof(struct xenbus_device_ivars), + M_DEVBUF, M_ZERO|M_WAITOK); + ivars->xd_node = kasprintf("%s/%s/%s", bus, type, id); - va_start(ap, fmt); - /* FIXME: vsnprintf has a bug, NULL should work */ - len = vsnprintf(dummy, 0, fmt, ap); - va_end(ap); - - p = kmalloc(len + 1, GFP_KERNEL); - if (!p) - return NULL; - va_start(ap, fmt); - vsprintf(p, fmt, ap); - va_end(ap); - return p; -} - -#if 0 -static ssize_t xendev_show_nodename(struct device *dev, char *buf) -{ - return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename); -} -DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL); - -static ssize_t xendev_show_devtype(struct device *dev, char *buf) -{ - return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype); -} -DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL); -#endif - -int xenbus_probe_node(struct xen_bus_type *bus, const char *type, - const char *nodename) -{ -#define CHECK_FAIL \ - do { \ - if (err) \ - goto fail; \ - } while (0) \ - - - - int err; - struct xenbus_device *xendev; - struct xenbus_driver *xdrv; - size_t stringlen; - char *tmpstring; + 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); + } - XenbusState state = xenbus_read_driver_state(nodename); + state = xenbus_read_driver_state(ivars->xd_node); - if (bus->error) - return (bus->error); - - if (state != XenbusStateInitialising) { - /* Device is not new, so ignore it. This can happen if a - device is going away after switching to Closed. */ - return 0; + /* + * 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); } - - stringlen = strlen(nodename) + 1 + strlen(type) + 1; - xendev = kmalloc(sizeof(*xendev) + stringlen, GFP_KERNEL); - if (!xendev) - return -ENOMEM; - memset(xendev, 0, sizeof(*xendev)); - xendev->state = XenbusStateInitialising; - - /* Copy the strings into the extra space. */ - - tmpstring = (char *)(xendev + 1); - strcpy(tmpstring, nodename); - xendev->nodename = tmpstring; - - tmpstring += strlen(tmpstring) + 1; - strcpy(tmpstring, type); - xendev->devicetype = tmpstring; + /* - * equivalent to device registration - * events + * Find the backend details */ - LIST_INSERT_HEAD(bus->bus, xendev, list); - LIST_FOREACH(xdrv, &xendrv_list, list) { - if (match_device(xdrv->ids, xendev)) { - xendev->driver = xdrv; - if (!xenbus_dev_probe(xendev)) - break; - } - } + xenbus_gather(XBT_NIL, ivars->xd_node, + "backend-id", "%i", &ivars->xd_otherend_id, + "backend", NULL, &ivars->xd_otherend_path, + NULL); -#if 0 - xendev->dev.parent = &bus->dev; - xendev->dev.bus = &bus->bus; - xendev->dev.release = xenbus_dev_release; - - err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename); - CHECK_FAIL; - - /* Register with generic device framework. */ - err = device_register(&xendev->dev); - CHECK_FAIL; - - device_create_file(&xendev->dev, &dev_attr_nodename); - device_create_file(&xendev->dev, &dev_attr_devtype); -#endif - return 0; - -#undef CHECK_FAIL -#if 0 - fail: - xenbus_dev_free(xendev); -#endif - return err; -} + sx_init(&ivars->xd_lock, "xdlock"); + ivars->xd_type = strdup(type, M_DEVBUF); + ivars->xd_state = XenbusStateInitialising; -/* device/<typename>/<name> */ -static int xenbus_probe_frontend(const char *type, const char *name) -{ - char *nodename; - int err; + statepath = malloc(strlen(ivars->xd_otherend_path) + + strlen("/state") + 1, M_DEVBUF, M_NOWAIT); + sprintf(statepath, "%s/state", ivars->xd_otherend_path); - nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name); - if (!nodename) - return -ENOMEM; + ivars->xd_otherend_watch.node = statepath; + ivars->xd_otherend_watch.callback = xenbus_backend_changed; - DPRINTK("%s", nodename); + child = device_add_child(dev, NULL, -1); + ivars->xd_dev = child; + device_set_ivars(child, ivars); - err = xenbus_probe_node(&xenbus_frontend, type, nodename); - kfree(nodename); - return err; + return (0); } -static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type) +static int +xenbus_enumerate_type(device_t dev, const char *bus, const char *type) { - int err = 0; char **dir; - unsigned int dir_n = 0; - int i; + unsigned int i, count; - dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n); + dir = xenbus_directory(XBT_NIL, bus, type, &count); if (IS_ERR(dir)) - return PTR_ERR(dir); + return (EINVAL); + for (i = 0; i < count; i++) + xenbus_add_device(dev, bus, type, dir[i]); - for (i = 0; i < dir_n; i++) { - err = bus->probe(type, dir[i]); - if (err) - break; - } - kfree(dir); - return err; + free(dir, M_DEVBUF); + + return (0); } -int xenbus_probe_devices(struct xen_bus_type *bus) +static int +xenbus_enumerate_bus(device_t dev, const char *bus) { - int err = 0; char **dir; - unsigned int i, dir_n; + unsigned int i, count; - dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n); + dir = xenbus_directory(XBT_NIL, bus, "", &count); if (IS_ERR(dir)) - return PTR_ERR(dir); - - for (i = 0; i < dir_n; i++) { - err = xenbus_probe_device_type(bus, dir[i]); - if (err) - break; + return (EINVAL); + for (i = 0; i < count; i++) { + xenbus_enumerate_type(dev, bus, dir[i]); } - kfree(dir); + free(dir, M_DEVBUF); - return err; + return (0); } -static unsigned int char_count(const char *str, char c) +static int +xenbus_probe_children(device_t dev) { - unsigned int i, ret = 0; + 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); + } - for (i = 0; str[i]; i++) - if (str[i] == c) - ret++; - return ret; + return (0); } -static int strsep_len(const char *str, char c, unsigned int len) +static void +xenbus_probe_children_cb(void *arg, int pending) { - unsigned int i; + device_t dev = (device_t) arg; - for (i = 0; str[i]; i++) - if (str[i] == c) { - if (len == 0) - return i; - len--; - } - return (len == 0) ? i : -ERANGE; + xenbus_probe_children(dev); } -void dev_changed(const char *node, struct xen_bus_type *bus) +static void +xenbus_devices_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) { - int exists, rootlen; - struct xenbus_device *dev; - char type[BUS_ID_SIZE]; - const char *p; - char *root; - - DPRINTK(""); - if (char_count(node, '/') < 2) - return; - - exists = xenbus_exists(XBT_NIL, node, ""); - if (!exists) { - xenbus_cleanup_devices(node, bus->bus); - return; - } - - /* backend/<type>/... or device/<type>/... */ - p = strchr(node, '/') + 1; - snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p); - type[BUS_ID_SIZE-1] = '\0'; + struct xenbus_softc *sc = (struct xenbus_softc *) watch; + device_t dev = sc->xs_dev; + char *node, *bus, *type, *id, *p; - rootlen = strsep_len(node, '/', bus->levels); - if (rootlen < 0) - return; - root = kasprintf("%.*s", rootlen, node); - if (!root) - return; + node = strdup(vec[XS_WATCH_PATH], M_DEVBUF);; + p = strchr(node, '/'); + if (!p) + goto out; + bus = node; + *p = 0; + type = p + 1; - dev = xenbus_device_find(root, bus->bus); - if (!dev) - xenbus_probe_node(bus, type, root); -#if 0 - else - put_device(&dev->dev); -#endif - kfree(root); -} + p = strchr(type, '/'); + if (!p) + goto out; + *p = 0; + id = p + 1; -static void frontend_changed(struct xenbus_watch *watch, - const char **vec, unsigned int len) -{ - DPRINTK(""); + p = strchr(id, '/'); + if (p) + *p = 0; - dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend); + xenbus_add_device(dev, bus, type, id); + taskqueue_enqueue(taskqueue_thread, &sc->xs_probechildren); +out: + free(node, M_DEVBUF); } -/* We watch for devices appearing and vanishing. */ -static struct xenbus_watch fe_watch = { - .node = "device", - .callback = frontend_changed, -}; - -#ifdef notyet - -static int suspend_dev(device_t dev, void *data) +static void +xenbus_attach_deferred(void *arg) { - int err = 0; - struct xenbus_driver *drv; - struct xenbus_device *xdev; - - DPRINTK(""); + 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); - xdev = device_get_softc(dev); + sc->xs_dev = dev; + sc->xs_devicewatch.node = "device"; + sc->xs_devicewatch.callback = xenbus_devices_changed; - drv = xdev->driver; + TASK_INIT(&sc->xs_probechildren, 0, xenbus_probe_children_cb, dev); - if (device_get_driver(dev) == NULL) - return 0; + register_xenbus_watch(&sc->xs_devicewatch); - if (drv->suspend) - err = drv->suspend(xdev); -#if 0 - /* bus_id ? */ - if (err) - log(LOG_WARNING, "xenbus: suspend %s failed: %i\n", - dev->bus_id, err); -#endif - return 0; + config_intrhook_disestablish(&sc->xs_attachcb); } - - -static int resume_dev(device_t dev, void *data) +static int +xenbus_attach(device_t dev) { - int err; - struct xenbus_driver *drv; - struct xenbus_device *xdev; + struct xenbus_softc *sc = device_get_softc(dev); - DPRINTK(""); + sc->xs_attachcb.ich_func = xenbus_attach_deferred; + sc->xs_attachcb.ich_arg = dev; + config_intrhook_establish(&sc->xs_attachcb); - if (device_get_driver(dev) == NULL) - return 0; - xdev = device_get_softc(dev); - drv = xdev->driver; - - err = talk_to_otherend(xdev); -#if 0 - if (err) { - log(LOG_WARNING, - "xenbus: resume (talk_to_otherend) %s failed: %i\n", - dev->bus_id, err); - return err; - } -#endif - if (drv->resume) - err = drv->resume(xdev); - - err = watch_otherend(xdev); -#if 0 - /* bus_id? */ - if (err) - log(LOG_WARNING, - "xenbus: resume %s failed: %i\n", dev->bus_id, err); -#endif - return err; + return (0); } -#endif -void xenbus_suspend(void) +static void +xenbus_suspend(device_t dev) { DPRINTK(""); panic("implement me"); @@ -879,9 +397,9 @@ void xenbus_suspend(void) #endif xs_suspend(); } -EXPORT_SYMBOL(xenbus_suspend); -void xenbus_resume(void) +static void +xenbus_resume(device_t dev) { xb_init_comms(); xs_resume(); @@ -891,218 +409,115 @@ void xenbus_resume(void) bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev); #endif } -EXPORT_SYMBOL(xenbus_resume); - -#if 0 -static device_t -xenbus_add_child(device_t bus, int order, const char *name, int unit) -{ - device_t child; - - child = device_add_child_ordered(bus, order, name, unit); - - return(child); -} -#endif - -/* A flag to determine if xenstored is 'ready' (i.e. has started) */ -int xenstored_ready = 0; - -int register_xenstore_notifier(xenstore_event_handler_t func, void *arg, int priority) +static int +xenbus_print_child(device_t dev, device_t child) { - int ret = 0; + struct xenbus_device_ivars *ivars = device_get_ivars(child); + int retval = 0; - if (xenstored_ready > 0) - ret = func(NULL); - else - eventhandler_register(xenstore_chain, "xenstore", func, arg, priority); + retval += bus_print_child_header(dev, child); + retval += printf(" at %s", ivars->xd_node); + retval += bus_print_child_footer(dev, child); - return ret; + return (retval); } -EXPORT_SYMBOL(register_xenstore_notifier); -#if 0 -void unregister_xenstore_notifier(struct notifier_block *nb) -{ - notifier_chain_unregister(&xenstore_chain, nb); -} -EXPORT_SYMBOL(unregister_xenstore_notifier); -#endif - - -#ifdef DOM0 -static struct proc_dir_entry *xsd_mfn_intf; -static struct proc_dir_entry *xsd_port_intf; - - -static int xsd_mfn_read(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int +xenbus_read_ivar(device_t dev, device_t child, int index, + uintptr_t * result) { - int len; - len = sprintf(page, "%ld", xen_start_info->store_mfn); - *eof = 1; - return len; -} + struct xenbus_device_ivars *ivars = device_get_ivars(child); -static int xsd_port_read(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len; + 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); - len = sprintf(page, "%d", xen_start_info->store_evtchn); - *eof = 1; - return len; -} + case XENBUS_IVAR_OTHEREND_ID: + *result = (uintptr_t) ivars->xd_otherend_id; + return (0); -#endif - -static int dom0 = 0; - -static int -xenbus_probe_sysinit(void *unused) -{ - int err = 0; - - DPRINTK(""); - - LIST_INIT(&xenbus_device_frontend_list); - LIST_INIT(&xenbus_device_backend_list); - LIST_INIT(&xendrv_list); -#if 0 - if (xen_init() < 0) { - DPRINTK("failed"); - return -ENODEV; + case XENBUS_IVAR_OTHEREND_PATH: + *result = (uintptr_t) ivars->xd_otherend_path; + return (0); } + return (ENOENT); +} - /* Register ourselves with the kernel bus & device subsystems */ - bus_register(&xenbus_frontend.bus); - bus_register(&xenbus_backend.bus); - device_register(&xenbus_frontend.dev); - device_register(&xenbus_backend.dev); -#endif - - /* - ** Domain0 doesn't have a store_evtchn or store_mfn yet. - */ - dom0 = (xen_start_info->store_evtchn == 0); - - -#ifdef DOM0 - if (dom0) { - - unsigned long page; - evtchn_op_t op = { 0 }; - int ret; - +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; - /* Allocate page. */ - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; + switch (index) { + case XENBUS_IVAR_STATE: + newstate = (enum xenbus_state) value; + sx_xlock(&ivars->xd_lock); + if (ivars->xd_state == newstate) + goto out; - /* We don't refcnt properly, so set reserved on page. - * (this allocation is permanent) */ - SetPageReserved(virt_to_page(page)); + error = xenbus_scanf(XBT_NIL, ivars->xd_node, "state", + "%d", &currstate); + if (error < 0) + goto out; - xen_start_info->store_mfn = - pfn_to_mfn(virt_to_phys((void *)page) >> - PAGE_SHIFT); - - /* Next allocate a local port which xenstored can bind to */ - op.cmd = EVTCHNOP_alloc_unbound; - op.u.alloc_unbound.dom = DOMID_SELF; - op.u.alloc_unbound.remote_dom = 0; - - ret = HYPERVISOR_event_channel_op(&op); - BUG_ON(ret); - xen_start_info->store_evtchn = op.u.alloc_unbound.port; - - /* And finally publish the above info in /proc/xen */ - if((xsd_mfn_intf = create_xen_proc_entry("xsd_mfn", 0400))) - xsd_mfn_intf->read_proc = xsd_mfn_read; - if((xsd_port_intf = create_xen_proc_entry("xsd_port", 0400))) - xsd_port_intf->read_proc = xsd_port_read; - } -#endif - /* Initialize the interface to xenstore. */ - err = xs_init(); - if (err) { - log(LOG_WARNING, - "XENBUS: Error initializing xenstore comms: %i\n", err); - return err; + 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 0; + return (ENOENT); } - -static int -xenbus_probe_sysinit2(void *unused) -{ - if (!dom0) { - xenstored_ready = 1; +SYSCTL_DECL(_dev); +SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen"); #if 0 - xenbus_dev = BUS_ADD_CHILD(parent, 0, "xenbus", 0); - if (xenbus_dev == NULL) - panic("xenbus: could not attach"); - xenbus_backend_dev = BUS_ADD_CHILD(parent, 0, "xb_be", 0); - if (xenbus_backend_dev == NULL) - panic("xenbus: could not attach"); +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, ""); #endif - BUG_ON((xenstored_ready <= 0)); - - - /* Enumerate devices in xenstore. */ - xenbus_probe_devices(&xenbus_frontend); - register_xenbus_watch(&fe_watch); - xenbus_backend_probe_and_watch(); - - /* Notify others that xenstore is up */ - EVENTHANDLER_INVOKE(xenstore_event); - } - return (0); -} - - -SYSINIT(xenbus_probe_sysinit, SI_SUB_PSEUDO, SI_ORDER_FIRST, xenbus_probe_sysinit, NULL); -SYSINIT(xenbus_probe_sysinit2, SI_SUB_PSEUDO, SI_ORDER_ANY, - xenbus_probe_sysinit2, NULL); - -#if 0 static device_method_t xenbus_methods[] = { /* Device interface */ -#if 0 - DEVMETHOD(device_identify, xenbus_identify), + 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), -#endif DEVMETHOD(device_suspend, xenbus_suspend), DEVMETHOD(device_resume, xenbus_resume), /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_add_child, xenbus_add_child), - DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), - DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), -#if 0 - DEVMETHOD(bus_set_resource, bus_generic_set_resource), - DEVMETHOD(bus_get_resource, bus_generic_get_resource), -#endif - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), -#if 0 - DEVMETHOD(bus_delete_resource, bus_generic_delete_resource), -#endif - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_print_child, xenbus_print_child), + DEVMETHOD(bus_read_ivar, xenbus_read_ivar), + DEVMETHOD(bus_write_ivar, xenbus_write_ivar), { 0, 0 } }; @@ -1111,24 +526,12 @@ static char driver_name[] = "xenbus"; static driver_t xenbus_driver = { driver_name, xenbus_methods, - sizeof(struct xenbus_device), + sizeof(struct xenbus_softc), }; devclass_t xenbus_devclass; -DRIVER_MODULE(xenbus, nexus, xenbus_driver, xenbus_devclass, 0, 0); - +#ifdef XENHVM +DRIVER_MODULE(xenbus, xenpci, xenbus_driver, xenbus_devclass, 0, 0); +#else +DRIVER_MODULE(xenbus, nexus, xenbus_driver, xenbus_devclass, 0, 0); #endif - - - - - -/* - * Local variables: - * c-file-style: "bsd" - * indent-tabs-mode: t - * c-indent-level: 4 - * c-basic-offset: 8 - * tab-width: 4 - * End: - */ diff --git a/sys/xen/xenbus/xenbus_probe_backend.c b/sys/xen/xenbus/xenbus_probe_backend.c index 3cb8e67..af83fe6 100644 --- a/sys/xen/xenbus/xenbus_probe_backend.c +++ b/sys/xen/xenbus/xenbus_probe_backend.c @@ -58,7 +58,6 @@ __FBSDID("$FreeBSD$"); #include <machine/xen/xen-os.h> #include <machine/xen/hypervisor.h> -#include <machine/xen/xenbus.h> #include <machine/xen/evtchn.h> #include <machine/stdarg.h> diff --git a/sys/xen/xenbus/xenbus_xs.c b/sys/xen/xenbus/xenbus_xs.c index a5d8a34..332a509 100644 --- a/sys/xen/xenbus/xenbus_xs.c +++ b/sys/xen/xenbus/xenbus_xs.c @@ -53,9 +53,9 @@ __FBSDID("$FreeBSD$"); #include <machine/xen/xen-os.h> #include <machine/xen/hypervisor.h> -#include <machine/xen/xenbus.h> #include <machine/stdarg.h> +#include <xen/xenbus/xenbusvar.h> #include <xen/xenbus/xenbus_comms.h> static int xs_process_msg(enum xsd_sockmsg_type *type); @@ -788,8 +788,6 @@ static void xenwatch_thread(void *unused) { struct xs_stored_msg *msg; - xenwatch_running = 1; - DELAY(100000); while (xenwatch_inline) { printf("xenwatch inline still running\n"); diff --git a/sys/xen/xenbus/xenbusvar.h b/sys/xen/xenbus/xenbusvar.h new file mode 100644 index 0000000..1331c43 --- /dev/null +++ b/sys/xen/xenbus/xenbusvar.h @@ -0,0 +1,248 @@ +/****************************************************************************** + * xenbus.h + * + * Talks to Xen Store to figure out what devices we have. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * 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. + * + * $FreeBSD$ + */ + +#ifndef _XEN_XENBUS_XENBUSVAR_H +#define _XEN_XENBUS_XENBUSVAR_H + +#include <sys/queue.h> +#include <sys/bus.h> +#include <sys/eventhandler.h> +#include <machine/xen/xen-os.h> +#include <xen/interface/io/xenbus.h> +#include <xen/interface/io/xs_wire.h> + +#include "xenbus_if.h" + +enum { + /* + * Path of this device node. + */ + XENBUS_IVAR_NODE, + + /* + * The device type (e.g. vif, vbd). + */ + XENBUS_IVAR_TYPE, + + /* + * The state of this device (not the otherend's state). + */ + XENBUS_IVAR_STATE, + + /* + * Domain ID of the other end device. + */ + XENBUS_IVAR_OTHEREND_ID, + + /* + * Path of the other end device. + */ + XENBUS_IVAR_OTHEREND_PATH +}; + +/* + * Simplified accessors for xenbus devices + */ +#define XENBUS_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(xenbus, var, XENBUS, ivar, type) + +XENBUS_ACCESSOR(node, NODE, const char *) +XENBUS_ACCESSOR(type, TYPE, const char *) +XENBUS_ACCESSOR(state, STATE, enum xenbus_state) +XENBUS_ACCESSOR(otherend_id, OTHEREND_ID, int) +XENBUS_ACCESSOR(otherend_path, OTHEREND_PATH, const char *) + +/* Register callback to watch this node. */ +struct xenbus_watch +{ + LIST_ENTRY(xenbus_watch) list; + + /* Path being watched. */ + char *node; + + /* Callback (executed in a process context with no locks held). */ + void (*callback)(struct xenbus_watch *, + const char **vec, unsigned int len); +}; + +typedef int (*xenstore_event_handler_t)(void *); + +struct xenbus_transaction +{ + uint32_t id; +}; + +#define XBT_NIL ((struct xenbus_transaction) { 0 }) + +char **xenbus_directory(struct xenbus_transaction t, + const char *dir, const char *node, unsigned int *num); +void *xenbus_read(struct xenbus_transaction t, + const char *dir, const char *node, unsigned int *len); +int xenbus_write(struct xenbus_transaction t, + const char *dir, const char *node, const char *string); +int xenbus_mkdir(struct xenbus_transaction t, + const char *dir, const char *node); +int xenbus_exists(struct xenbus_transaction t, + const char *dir, const char *node); +int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node); +int xenbus_transaction_start(struct xenbus_transaction *t); +int xenbus_transaction_end(struct xenbus_transaction t, int abort); + +/* Single read and scanf: returns -errno or num scanned if > 0. */ +int xenbus_scanf(struct xenbus_transaction t, + const char *dir, const char *node, const char *fmt, ...) + __attribute__((format(scanf, 4, 5))); + +/* Single printf and write: returns -errno or 0. */ +int xenbus_printf(struct xenbus_transaction t, + const char *dir, const char *node, const char *fmt, ...) + __attribute__((format(printf, 4, 5))); + +/* Generic read function: NULL-terminated triples of name, + * sprintf-style type string, and pointer. Returns 0 or errno.*/ +int xenbus_gather(struct xenbus_transaction t, const char *dir, ...); + +/* notifer routines for when the xenstore comes up */ +int register_xenstore_notifier(xenstore_event_handler_t func, void *arg, int priority); +#if 0 +void unregister_xenstore_notifier(); +#endif +int register_xenbus_watch(struct xenbus_watch *watch); +void unregister_xenbus_watch(struct xenbus_watch *watch); +void xs_suspend(void); +void xs_resume(void); + +/* Used by xenbus_dev to borrow kernel's store connection. */ +void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg); + +#define XENBUS_IS_ERR_READ(str) ({ \ + if (!IS_ERR(str) && strlen(str) == 0) { \ + free(str, M_DEVBUF); \ + str = ERR_PTR(-ERANGE); \ + } \ + IS_ERR(str); \ +}) + +#define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE) + +/** + * Register a watch on the given path, using the given xenbus_watch structure + * for storage, and the given callback function as the callback. Return 0 on + * success, or -errno on error. On success, the given path will be saved as + * watch->node, and remains the caller's to free. On error, watch->node will + * be NULL, the device will switch to XenbusStateClosing, and the error will + * be saved in the store. + */ +int xenbus_watch_path(device_t dev, char *path, + struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, + const char **, unsigned int)); + + +/** + * Register a watch on the given path/path2, using the given xenbus_watch + * structure for storage, and the given callback function as the callback. + * Return 0 on success, or -errno on error. On success, the watched path + * (path/path2) will be saved as watch->node, and becomes the caller's to + * kfree(). On error, watch->node will be NULL, so the caller has nothing to + * free, the device will switch to XenbusStateClosing, and the error will be + * saved in the store. + */ +int xenbus_watch_path2(device_t dev, const char *path, + const char *path2, struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, + const char **, unsigned int)); + + +/** + * Advertise in the store a change of the given driver to the given new_state. + * which case this is performed inside its own transaction. Return 0 on + * success, or -errno on error. On error, the device will switch to + * XenbusStateClosing, and the error will be saved in the store. + */ +int xenbus_switch_state(device_t dev, + XenbusState new_state); + + +/** + * Grant access to the given ring_mfn to the peer of the given device. Return + * 0 on success, or -errno on error. On error, the device will switch to + * XenbusStateClosing, and the error will be saved in the store. + */ +int xenbus_grant_ring(device_t dev, unsigned long ring_mfn); + + +/** + * Allocate an event channel for the given xenbus_device, assigning the newly + * created local port to *port. Return 0 on success, or -errno on error. On + * error, the device will switch to XenbusStateClosing, and the error will be + * saved in the store. + */ +int xenbus_alloc_evtchn(device_t dev, int *port); + + +/** + * Free an existing event channel. Returns 0 on success or -errno on error. + */ +int xenbus_free_evtchn(device_t dev, int port); + + +/** + * Return the state of the driver rooted at the given store path, or + * XenbusStateClosed if no state can be read. + */ +XenbusState xenbus_read_driver_state(const char *path); + + +/*** + * Report the given negative errno into the store, along with the given + * formatted message. + */ +void xenbus_dev_error(device_t dev, int err, const char *fmt, + ...); + + +/*** + * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by + * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly + * closedown of this driver and its peer. + */ +void xenbus_dev_fatal(device_t dev, int err, const char *fmt, + ...); + +int xenbus_dev_init(void); + +const char *xenbus_strstate(enum xenbus_state state); +int xenbus_dev_is_online(device_t dev); +int xenbus_frontend_closed(device_t dev); + +#endif /* _XEN_XENBUS_XENBUSVAR_H */ |