Stefano Stabellini
2009-Nov-13 17:54 UTC
[Xen-devel] [PATCH] pcifront: implement dynamic connections and disconnections
Hi all, this patch implements dynamic connections and disconnections in pcifront. This feature is required to properly support pci hotplug, because when no pci devices are assigned to a guest, xend will remove the pci backend altogether. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- diff -r ac9d4ba48b83 extras/mini-os/include/pcifront.h --- a/extras/mini-os/include/pcifront.h Thu Nov 05 12:00:58 2009 +0000 +++ b/extras/mini-os/include/pcifront.h Fri Nov 13 17:53:03 2009 +0000 @@ -1,6 +1,7 @@ #include <mini-os/types.h> #include <xen/io/pciif.h> struct pcifront_dev; +void pcifront_watches(void *opaque); struct pcifront_dev *init_pcifront(char *nodename); void pcifront_op(struct pcifront_dev *dev, struct xen_pci_op *op); void pcifront_scan(struct pcifront_dev *dev, void (*fun)(unsigned int domain, unsigned int bus, unsigned slot, unsigned int fun)); diff -r ac9d4ba48b83 extras/mini-os/main.c --- a/extras/mini-os/main.c Thu Nov 05 12:00:58 2009 +0000 +++ b/extras/mini-os/main.c Fri Nov 13 17:53:03 2009 +0000 @@ -9,6 +9,7 @@ #include <sched.h> #include <console.h> #include <netfront.h> +#include <pcifront.h> #include <time.h> #include <stdlib.h> #include <unistd.h> @@ -67,6 +68,7 @@ #endif init_fs_frontend(); #endif + create_thread("pcifront", pcifront_watches, NULL); #ifdef CONFIG_QEMU /* Fetch argc, argv from XenStore */ diff -r ac9d4ba48b83 extras/mini-os/pcifront.c --- a/extras/mini-os/pcifront.c Thu Nov 05 12:00:58 2009 +0000 +++ b/extras/mini-os/pcifront.c Fri Nov 13 17:53:03 2009 +0000 @@ -13,10 +13,12 @@ #include <mini-os/xmalloc.h> #include <mini-os/wait.h> #include <mini-os/pcifront.h> +#include <mini-os/sched.h> #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) DECLARE_WAIT_QUEUE_HEAD(pcifront_queue); +static struct pcifront_dev *pcidev; struct pcifront_dev { domid_t dom; @@ -38,17 +40,101 @@ static void free_pcifront(struct pcifront_dev *dev) { + if (!dev) + dev = pcidev; + mask_evtchn(dev->evtchn); - - free(dev->backend); gnttab_end_access(dev->info_ref); free_page(dev->info); unbind_evtchn(dev->evtchn); + free(dev->backend); free(dev->nodename); free(dev); +} + +void pcifront_watches(void *opaque) +{ + XenbusState state; + char *err = NULL, *msg = NULL; + char *be_path, *be_state; + char* nodename = opaque ? opaque : "device/pci/0"; + char path[strlen(nodename) + 9]; + char fe_state[strlen(nodename) + 7]; + xenbus_event_queue events = NULL; + + snprintf(path, sizeof(path), "%s/backend", nodename); + snprintf(fe_state, sizeof(fe_state), "%s/state", nodename); + + while (1) { + printk("pcifront_watches: waiting for backend path to happear %s\n", path); + xenbus_watch_path_token(XBT_NIL, path, path, &events); + while ((err = xenbus_read(XBT_NIL, path, &be_path)) != NULL) { + free(err); + xenbus_wait_for_watch(&events); + } + xenbus_unwatch_path_token(XBT_NIL, path, path); + printk("pcifront_watches: waiting for backend to get into the right state %s\n", be_path); + be_state = (char *) malloc(strlen(be_path) + 7); + snprintf(be_state, strlen(be_path) + 7, "%s/state", be_path); + xenbus_watch_path_token(XBT_NIL, be_state, be_state, &events); + while ((err = xenbus_read(XBT_NIL, be_state, &msg)) != NULL || msg[0] > ''4'') { + free(msg); + free(err); + xenbus_wait_for_watch(&events); + } + xenbus_unwatch_path_token(XBT_NIL, be_state, be_state); + if (init_pcifront(NULL) == NULL) { + free(be_state); + free(be_path); + continue; + } + xenbus_watch_path_token(XBT_NIL, be_state, be_state, &events); + state = XenbusStateConnected; + printk("pcifront_watches: waiting for backend events %s\n", be_state); + while ((err = xenbus_wait_for_state_change(be_state, &state, &events)) == NULL && + (err = xenbus_read(XBT_NIL, pcidev->backend, &msg)) == NULL) { + free(msg); + printk("pcifront_watches: backend state changed: %s %d\n", be_state, state); + if (state == XenbusStateReconfiguring) { + printk("pcifront_watches: writing %s %d\n", fe_state, XenbusStateReconfiguring); + if ((err = xenbus_switch_state(XBT_NIL, fe_state, XenbusStateReconfiguring)) != NULL) { + printk("pcifront_watches: error changing state to %d: %s\n", + XenbusStateReconfiguring, err); + if (!strcmp(err, "ENOENT")) { + xenbus_write(XBT_NIL, fe_state, "7"); + free(err); + } + } + } else if (state == XenbusStateReconfigured) { + printk("pcifront_watches: writing %s %d\n", fe_state, XenbusStateConnected); + printk("pcifront_watches: changing state to %d\n", XenbusStateConnected); + if ((err = xenbus_switch_state(XBT_NIL, fe_state, XenbusStateConnected)) != NULL) { + printk("pcifront_watches: error changing state to %d: %s\n", + XenbusStateConnected, err); + if (!strcmp(err, "ENOENT")) { + xenbus_write(XBT_NIL, fe_state, "4"); + free(err); + } + } + } else if (state == XenbusStateClosing) + break; + } + if (err) + printk("pcifront_watches: done waiting err=%s\n", err); + else + printk("pcifront_watches: done waiting\n"); + xenbus_unwatch_path_token(XBT_NIL, be_state, be_state); + shutdown_pcifront(pcidev); + free(be_state); + free(be_path); + free(err); + pcidev = NULL; + } + + xenbus_unwatch_path_token(XBT_NIL, path, path); } struct pcifront_dev *init_pcifront(char *_nodename) @@ -64,6 +150,9 @@ struct pcifront_dev *dev; char path[strlen(nodename) + 1 + 10 + 1]; + + if (!_nodename && pcidev) + return pcidev; printk("******************* PCIFRONT for %s **********\n\n\n", nodename); @@ -173,6 +262,9 @@ printk("**************************\n"); + if (!_nodename) + pcidev = dev; + return dev; error: @@ -182,16 +274,25 @@ void pcifront_scan(struct pcifront_dev *dev, void (*func)(unsigned int domain, unsigned int bus, unsigned slot, unsigned int fun)) { - char path[strlen(dev->backend) + 1 + 5 + 10 + 1]; - int i, n; + char *path; + int i, n, len; char *s, *msg; unsigned int domain, bus, slot, fun; - snprintf(path, sizeof(path), "%s/num_devs", dev->backend); + if (!dev) + dev = pcidev; + if (!dev) + dev = init_pcifront(NULL); + if (!dev) + return; + + len = strlen(dev->backend) + 1 + 5 + 10 + 1; + path = (char *) malloc(len); + snprintf(path, len, "%s/num_devs", dev->backend); n = xenbus_read_integer(path); for (i = 0; i < n; i++) { - snprintf(path, sizeof(path), "%s/dev-%d", dev->backend, i); + snprintf(path, len, "%s/dev-%d", dev->backend, i); msg = xenbus_read(XBT_NIL, path, &s); if (msg) { printk("Error %s when reading the PCI root name at %s\n", msg, path); @@ -205,8 +306,10 @@ } free(s); - func(domain, bus, slot, fun); + if (func) + func(domain, bus, slot, fun); } + free(path); } void shutdown_pcifront(struct pcifront_dev *dev) @@ -271,6 +374,9 @@ char *s, *msg = NULL; unsigned int dom1, bus1, slot1, fun1; + if (!dev) + dev = pcidev; + snprintf(path, sizeof(path), "%s/num_devs", dev->backend); n = xenbus_read_integer(path); @@ -312,6 +418,8 @@ void pcifront_op(struct pcifront_dev *dev, struct xen_pci_op *op) { + if (!dev) + dev = pcidev; dev->info->op = *op; /* Make sure info is written before the flag */ wmb(); @@ -332,6 +440,8 @@ { struct xen_pci_op op; + if (!dev) + dev = pcidev; if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0) return XEN_PCI_ERR_dev_not_found; memset(&op, 0, sizeof(op)); @@ -360,6 +470,8 @@ { struct xen_pci_op op; + if (!dev) + dev = pcidev; if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0) return XEN_PCI_ERR_dev_not_found; memset(&op, 0, sizeof(op)); @@ -384,6 +496,8 @@ { struct xen_pci_op op; + if (!dev) + dev = pcidev; if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0) return XEN_PCI_ERR_dev_not_found; memset(&op, 0, sizeof(op)); @@ -407,6 +521,8 @@ { struct xen_pci_op op; + if (!dev) + dev = pcidev; if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0) return XEN_PCI_ERR_dev_not_found; memset(&op, 0, sizeof(op)); @@ -428,6 +544,8 @@ { struct xen_pci_op op; + if (!dev) + dev = pcidev; if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0) return XEN_PCI_ERR_dev_not_found; if (n > SH_INFO_MAX_VEC) @@ -460,6 +578,8 @@ { struct xen_pci_op op; + if (!dev) + dev = pcidev; if (pcifront_physical_to_virtual(dev, &dom, &bus, &slot, &fun) < 0) return XEN_PCI_ERR_dev_not_found; memset(&op, 0, sizeof(op)); diff -r ac9d4ba48b83 extras/mini-os/xenbus/xenbus.c --- a/extras/mini-os/xenbus/xenbus.c Thu Nov 05 12:00:58 2009 +0000 +++ b/extras/mini-os/xenbus/xenbus.c Fri Nov 13 17:53:03 2009 +0000 @@ -96,7 +96,10 @@ if (!queue) queue = &xenbus_events; ret = xenbus_wait_for_watch_return(queue); - free(ret); + if (ret) + free(ret); + else + printk("unexpected path returned by watch\n"); } char* xenbus_wait_for_value(const char* path, const char* value, xenbus_event_queue *queue) diff -r ac9d4ba48b83 stubdom/pciutils.patch --- a/stubdom/pciutils.patch Thu Nov 05 12:00:58 2009 +0000 +++ b/stubdom/pciutils.patch Fri Nov 13 17:53:03 2009 +0000 @@ -23,14 +23,6 @@ PCI_ACCESS_MAX }; -@@ -63,6 +64,7 @@ - int fd_rw; /* proc: fd opened read-write */ - struct pci_dev *cached_dev; /* proc: device the fd is for */ - int fd_pos; /* proc: current position */ -+ void *minios; - }; - - /* Initialize PCI access */ --- pciutils-2.2.9.orig/lib/internal.h 2006-09-09 11:52:47.000000000 +0100 +++ pciutils-2.2.9/lib/internal.h 2008-07-01 10:46:24.968202000 +0100 @@ -37,4 +37,4 @@ @@ -72,7 +64,7 @@ --- pciutils-2.2.9.orig/lib/minios.c 1970-01-01 01:00:00.000000000 +0100 +++ pciutils-2.2.9/lib/minios.c 2008-07-01 12:31:40.554260000 +0100 -@@ -0,0 +1,113 @@ +@@ -0,0 +1,108 @@ +/* + * The PCI Library -- MiniOS PCI frontend access + * @@ -95,24 +87,19 @@ +static void +minios_init(struct pci_access *a) +{ -+ a->minios = init_pcifront(NULL); -+ if (!a->minios) ++ if (!init_pcifront(NULL)) + a->warning("minios_init open failed"); +} + +static void +minios_cleanup(struct pci_access *a) +{ -+ if (a->minios) -+ shutdown_pcifront(a->minios); ++ shutdown_pcifront(NULL); +} + +static void +minios_scan(struct pci_access *a) +{ -+ if (!a->minios) -+ return; -+ + void func(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun) + { + struct pci_dev *d = pci_alloc_dev(a); @@ -125,7 +112,7 @@ + pci_link_dev(a, d); + } + -+ pcifront_scan(a->minios, func); ++ pcifront_scan(NULL, func); +} + +static int @@ -134,17 +121,17 @@ + unsigned int val; + switch (len) { + case 1: -+ if (pcifront_conf_read(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, &val)) ++ if (pcifront_conf_read(NULL, d->domain, d->bus, d->dev, d->func, pos, len, &val)) + return 0; + * buf = val; + return 1; + case 2: -+ if (pcifront_conf_read(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, &val)) ++ if (pcifront_conf_read(NULL, d->domain, d->bus, d->dev, d->func, pos, len, &val)) + return 0; + *(u16 *) buf = cpu_to_le16((u16) val); + return 1; + case 4: -+ if (pcifront_conf_read(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, &val)) ++ if (pcifront_conf_read(NULL, d->domain, d->bus, d->dev, d->func, pos, len, &val)) + return 0; + *(u32 *) buf = cpu_to_le32((u32) val); + return 1; @@ -170,7 +157,7 @@ + default: + return pci_generic_block_write(d, pos, buf, len); + } -+ return !pcifront_conf_write(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, val); ++ return !pcifront_conf_write(NULL, d->domain, d->bus, d->dev, d->func, pos, len, val); +} + +struct pci_methods pm_minios = { _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel