# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1258149510 0
# Node ID dd951d96304a8c036e3f2a076a7b1240696f9032
# Parent 377b7a8e0e0af8367b445cc317203ab1f97f9bdd
pcifront: implement dynamic connections and disconnections
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@xxxxxxxxxxxxx>
---
extras/mini-os/include/pcifront.h | 1
extras/mini-os/main.c | 2
extras/mini-os/pcifront.c | 136 +++++++++++++++++++++++++++++++++++---
extras/mini-os/xenbus/xenbus.c | 5 +
stubdom/pciutils.patch | 20 -----
5 files changed, 135 insertions(+), 29 deletions(-)
diff -r 377b7a8e0e0a -r dd951d96304a extras/mini-os/include/pcifront.h
--- a/extras/mini-os/include/pcifront.h Fri Nov 13 21:54:44 2009 +0000
+++ b/extras/mini-os/include/pcifront.h Fri Nov 13 21:58:30 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 377b7a8e0e0a -r dd951d96304a extras/mini-os/main.c
--- a/extras/mini-os/main.c Fri Nov 13 21:54:44 2009 +0000
+++ b/extras/mini-os/main.c Fri Nov 13 21:58:30 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 @@ static void call_main(void *p)
#endif
init_fs_frontend();
#endif
+ create_thread("pcifront", pcifront_watches, NULL);
#ifdef CONFIG_QEMU
/* Fetch argc, argv from XenStore */
diff -r 377b7a8e0e0a -r dd951d96304a extras/mini-os/pcifront.c
--- a/extras/mini-os/pcifront.c Fri Nov 13 21:54:44 2009 +0000
+++ b/extras/mini-os/pcifront.c Fri Nov 13 21:58:30 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 @@ void pcifront_handler(evtchn_port_t port
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 *init_pcifront(char
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 @@ done:
printk("**************************\n");
+ if (!_nodename)
+ pcidev = dev;
+
return dev;
error:
@@ -182,16 +274,25 @@ error:
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 @@ void pcifront_scan(struct pcifront_dev *
}
free(s);
- func(domain, bus, slot, fun);
- }
+ if (func)
+ func(domain, bus, slot, fun);
+ }
+ free(path);
}
void shutdown_pcifront(struct pcifront_dev *dev)
@@ -270,6 +373,9 @@ int pcifront_physical_to_virtual (struct
int i, n;
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 @@ int pcifront_physical_to_virtual (struct
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 @@ int pcifront_conf_read(struct pcifront_d
{
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 @@ int pcifront_conf_write(struct pcifront_
{
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 @@ int pcifront_enable_msi(struct pcifront_
{
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 @@ int pcifront_disable_msi(struct pcifront
{
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 @@ int pcifront_enable_msix(struct pcifront
{
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 @@ int pcifront_disable_msix(struct pcifron
{
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 377b7a8e0e0a -r dd951d96304a extras/mini-os/xenbus/xenbus.c
--- a/extras/mini-os/xenbus/xenbus.c Fri Nov 13 21:54:44 2009 +0000
+++ b/extras/mini-os/xenbus/xenbus.c Fri Nov 13 21:58:30 2009 +0000
@@ -96,7 +96,10 @@ void xenbus_wait_for_watch(xenbus_event_
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 377b7a8e0e0a -r dd951d96304a stubdom/pciutils.patch
--- a/stubdom/pciutils.patch Fri Nov 13 21:54:44 2009 +0000
+++ b/stubdom/pciutils.patch Fri Nov 13 21:58:30 2009 +0000
@@ -23,14 +23,6 @@ diff -urN pciutils-2.2.9.orig/lib/access
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 @@
@@ -95,24 +87,19 @@ diff -urN pciutils-2.2.9.orig/lib/access
+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 @@ diff -urN pciutils-2.2.9.orig/lib/access
+ pci_link_dev(a, d);
+ }
+
-+ pcifront_scan(a->minios, func);
++ pcifront_scan(NULL, func);
+}
+
+static int
@@ -134,17 +121,17 @@ diff -urN pciutils-2.2.9.orig/lib/access
+ 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 @@ diff -urN pciutils-2.2.9.orig/lib/access
+ 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-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|