WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] libxenlight: implement pci passthrough

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] libxenlight: implement pci passthrough
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 13 Nov 2009 07:50:19 -0800
Delivery-date: Fri, 13 Nov 2009 07:50:40 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1258126276 0
# Node ID 8a1d2e35edfa5d56688b99f8bc8df29b572f1ddd
# Parent  d714386b668fd4082f708ee1e417719901a095eb
libxenlight: implement pci passthrough

This patch implements pci passthrough (hotplug and coldplug) in
libxenlight, it also adds three new commands to xl: pci-attach,
pci-detach and pci-list.
Currently flr on a device is done writing to
/sys/bus/pci/drivers/pciback/do_flr
pciback do_flr is present in both XCI and XCP 2.6.27 kernels.

Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
---
 tools/libxl/libxl.c          |  432 +++++++++++++++++++++++++++++++++++++++++--
 tools/libxl/libxl.h          |   31 ++-
 tools/libxl/libxl_device.c   |   77 +++++++
 tools/libxl/libxl_internal.h |   16 +
 tools/libxl/xl.c             |  231 ++++++++++++++++++++++
 5 files changed, 759 insertions(+), 28 deletions(-)

diff -r d714386b668f -r 8a1d2e35edfa tools/libxl/libxl.c
--- a/tools/libxl/libxl.c       Fri Nov 13 15:30:24 2009 +0000
+++ b/tools/libxl/libxl.c       Fri Nov 13 15:31:16 2009 +0000
@@ -156,6 +156,7 @@ retry_transaction:
 
     xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/uuid", vm_path), uuid_string, 
strlen(uuid_string));
     xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", vm_path), info->name, 
strlen(info->name));
+    xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/image/ostype", vm_path), 
"hvm", strlen("hvm"));
 
     libxl_xs_writev(ctx, t, dom_path, info->xsdata);
     libxl_xs_writev(ctx, t, libxl_sprintf(ctx, "%s/platform", dom_path), 
info->platformdata);
@@ -368,6 +369,8 @@ int libxl_domain_destroy(struct libxl_ct
         XL_LOG(ctx, XL_LOG_ERROR, "failed ot get uuid for %d\n", domid);
         return -1;
     }
+    if (libxl_device_pci_shutdown(ctx, domid) < 0)
+        XL_LOG(ctx, XL_LOG_ERROR, "pci shutdown failed for domid %d\n", domid);
     xs_write(ctx->xsh, XBT_NULL,
              libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", 
domid),
              "shutdown", strlen("shutdown"));
@@ -375,7 +378,6 @@ int libxl_domain_destroy(struct libxl_ct
         XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_pause failed for %d\n", domid);
         return -1;
     }
-    /* do_FLR */
     if (xc_domain_destroy(ctx->xch, domid) < 0) {
         XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_destroy failed for %d\n", domid);
         return -1;
@@ -746,17 +748,417 @@ int libxl_device_vfb_hard_shutdown(struc
 }
 
 
/******************************************************************************/
-int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid)
-{
-    return ERROR_NI;
-}
-
-int libxl_device_pci_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
-{
-    return ERROR_NI;
-}
-
-int libxl_device_pci_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
-{
-    return ERROR_NI;
-}
+
+int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
+                          unsigned int bus, unsigned int dev,
+                          unsigned int func, unsigned int vdevfn)
+{
+    pcidev->domain = domain;
+    pcidev->bus = bus;
+    pcidev->dev = dev;
+    pcidev->func = func;
+    pcidev->vdevfn = vdevfn;
+    return 0;
+}
+
+static int libxl_create_pci_backend(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_pci *pcidev, int num)
+{
+    flexarray_t *front;
+    flexarray_t *back;
+    unsigned int boffset = 0;
+    unsigned int foffset = 0;
+    libxl_device device;
+    int i;
+
+    front = flexarray_make(16, 1);
+    if (!front)
+        return ERROR_NOMEM;
+    back = flexarray_make(16, 1);
+    if (!back)
+        return ERROR_NOMEM;
+
+    XL_LOG(ctx, XL_LOG_DEBUG, "Creating pci backend\n");
+
+    /* add pci device */
+    device.backend_devid = 0;
+    device.backend_domid = 0;
+    device.backend_kind = DEVICE_PCI;
+    device.devid = 0;
+    device.domid = domid;
+    device.kind = DEVICE_PCI;
+
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", domid));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "domain"));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", 
libxl_domid_to_name(ctx, domid)));
+    for (i = 0; i < num; i++) {
+        flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", i));
+        flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, 
pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
+        flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", i));
+        flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, 
pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
+        if (pcidev->vdevfn) {
+            flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", i));
+            flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", 
pcidev->vdevfn));
+        }
+        flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", i));
+        flexarray_set(back, boffset++, libxl_sprintf(ctx, 
"msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
+        flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", i));
+        flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
+    }
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs"));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num));
+
+    flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
+    flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 0));
+    flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
+    flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
+
+    libxl_device_generic_add(ctx, &device,
+                             libxl_xs_kvs_of_flexarray(ctx, back, boffset),
+                             libxl_xs_kvs_of_flexarray(ctx, front, foffset));
+
+    flexarray_free(back);
+    flexarray_free(front);
+    return 0;
+}
+
+static int libxl_device_pci_add_xenstore(struct libxl_ctx *ctx, uint32_t 
domid, libxl_device_pci *pcidev)
+{
+    flexarray_t *back;
+    char *num_devs, *be_path;
+    int num = 0;
+    unsigned int boffset = 0;
+    xs_transaction_t t;
+
+    be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", 
xs_get_domain_path(ctx->xsh, 0), domid);
+    num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", 
be_path));
+    if (!num_devs)
+        return libxl_create_pci_backend(ctx, domid, pcidev, 1);
+
+    if (!is_hvm(ctx, domid)) {
+        if (libxl_wait_for_backend(ctx, be_path, "4") < 0)
+            return -1;
+    }
+
+    back = flexarray_make(16, 1);
+    if (!back)
+        return ERROR_NOMEM;
+
+    XL_LOG(ctx, XL_LOG_DEBUG, "Adding new pci device to xenstore\n");
+    num = atoi(num_devs);
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", num));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, 
pcidev->bus, pcidev->dev, pcidev->func));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", num));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, 
pcidev->bus, pcidev->dev, pcidev->func));
+    if (pcidev->vdevfn) {
+        flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", num));
+        flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", 
pcidev->vdevfn));
+    }
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", num));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, 
"msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", num));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs"));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num + 1));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 7));
+
+retry_transaction:
+    t = xs_transaction_start(ctx->xsh);
+    libxl_xs_writev(ctx, t, be_path,
+                    libxl_xs_kvs_of_flexarray(ctx, back, boffset));
+    if (!xs_transaction_end(ctx->xsh, t, 0))
+        if (errno == EAGAIN)
+            goto retry_transaction;
+
+    flexarray_free(back);
+    return 0;
+}
+
+static int libxl_device_pci_remove_xenstore(struct libxl_ctx *ctx, uint32_t 
domid, libxl_device_pci *pcidev)
+{
+    char *be_path, *num_devs_path, *num_devs, *xsdev;
+    int num, i;
+    xs_transaction_t t;
+    unsigned int domain = 0, bus = 0, dev = 0, func = 0;
+
+    be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", 
xs_get_domain_path(ctx->xsh, 0), domid);
+    num_devs_path = libxl_sprintf(ctx, "%s/num_devs", be_path);
+    num_devs = libxl_xs_read(ctx, XBT_NULL, num_devs_path);
+    if (!num_devs)
+        return -1;
+    num = atoi(num_devs);
+    if (num == 1) {
+        libxl_device_destroy(ctx, be_path, 1);
+        xs_rm(ctx->xsh, XBT_NULL, be_path);
+        return 0;
+    }
+
+    if (!is_hvm(ctx, domid)) {
+        if (libxl_wait_for_backend(ctx, be_path, "4") < 0) {
+            XL_LOG(ctx, XL_LOG_DEBUG, "pci backend at %s is not ready\n");
+            return -1;
+        }
+    }
+
+    for (i = 0; i < num; i++) {
+        xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", 
be_path, i));
+        sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
+        if (domain == pcidev->domain && bus == pcidev->bus &&
+            pcidev->dev == dev && pcidev->func == func) {
+            break;
+        }
+    }
+    if (i == num) {
+        XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find the device on xenstore\n");
+        return -1;
+    }
+
+retry_transaction:
+    t = xs_transaction_start(ctx->xsh);
+    libxl_xs_write(ctx, t, num_devs_path, "%d", num - 1);
+    xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, i), "6", 
strlen("6"));
+    xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state", be_path), "7", 
strlen("7"));
+    if (!xs_transaction_end(ctx->xsh, t, 0))
+        if (errno == EAGAIN)
+            goto retry_transaction;
+    return 0;
+}
+
+int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_pci *pcidev)
+{
+    char path[50];
+    char *state, *vdevfn;
+    int rc, hvm;
+
+    /* TODO: check if the device can be assigned */
+
+    libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, 
pcidev->func);
+
+    hvm = is_hvm(ctx, domid);
+    if (hvm) {
+        if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
+            return -1;
+        }
+        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", 
domid);
+        state = libxl_xs_read(ctx, XBT_NULL, path);
+        snprintf(path, sizeof(path), 
"/local/domain/0/device-model/%d/parameter", domid);
+        if (pcidev->vdevfn)
+            libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF_VDEVFN, pcidev->domain,
+                           pcidev->bus, pcidev->dev, pcidev->func, 
pcidev->vdevfn);
+        else
+            libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
+                           pcidev->bus, pcidev->dev, pcidev->func);
+        snprintf(path, sizeof(path), 
"/local/domain/0/device-model/%d/command", domid);
+        xs_write(ctx->xsh, XBT_NULL, path, "pci-ins", strlen("pci-ins"));
+        if (libxl_wait_for_device_model(ctx, domid, "pci-inserted") < 0)
+            XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n");
+        snprintf(path, sizeof(path), 
"/local/domain/0/device-model/%d/parameter", domid);
+        vdevfn = libxl_xs_read(ctx, XBT_NULL, path);
+        sscanf(vdevfn + 2, "%x", &pcidev->vdevfn);
+        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", 
domid);
+        xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
+    } else {
+        char *sysfs_path = libxl_sprintf(ctx, 
"SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain,
+                                         pcidev->bus, pcidev->dev, 
pcidev->func);
+        FILE *f = fopen(sysfs_path, "r");
+        unsigned int start = 0, end = 0, flags = 0, size = 0;
+        int irq = 0;
+        int i;
+
+        if (f == NULL) {
+            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
+            return -1;
+        }
+        for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
+            fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
+            size = end - start + 1;
+            if (start) {
+                if (flags & PCI_BAR_IO) {
+                    rc = xc_domain_ioport_permission(ctx->xch, domid, start, 
size, 1);
+                    if (rc < 0)
+                        XL_LOG(ctx, XL_LOG_ERROR, "Error: 
xc_domain_ioport_permission error 0x%x/0x%x:  %d\n", start, size, rc);
+                } else {
+                    rc = xc_domain_iomem_permission(ctx->xch, domid, 
start>>XC_PAGE_SHIFT,
+                                                    
(size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 1);
+                    if (rc < 0)
+                        XL_LOG(ctx, XL_LOG_ERROR, "Error: 
xc_domain_iomem_permission error 0x%x/0x%x:  %d\n", start, size, rc);
+                }
+            }
+        }
+        fclose(f);
+        sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", 
pcidev->domain,
+                                   pcidev->bus, pcidev->dev, pcidev->func);
+        f = fopen(sysfs_path, "r");
+        if (f == NULL) {
+            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
+            goto out;
+        }
+        fscanf(f, "%u", &irq);
+        if (irq) {
+            rc = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq);
+            if (rc < 0) {
+                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: 
%d\n", irq, rc);
+            }
+            rc = xc_domain_irq_permission(ctx->xch, domid, irq, 1);
+            if (rc < 0) {
+                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission 
irq=%d: %d\n", irq, rc);
+            }
+        }
+        fclose(f);
+    }
+out:
+    if ((rc = xc_assign_device(ctx->xch, domid, pcidev->value)) < 0)
+        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_assign_device error %d\n", rc);
+
+    libxl_device_pci_add_xenstore(ctx, domid, pcidev);
+    return 0;
+}
+
+int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_pci *pcidev)
+{
+    char path[50];
+    char *state;
+    int hvm, rc;
+
+    /* TODO: check if the device can be detached */
+
+    hvm = is_hvm(ctx, domid);
+    if (hvm) {
+        if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
+            return -1;
+        }
+        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", 
domid);
+        state = libxl_xs_read(ctx, XBT_NULL, path);
+        snprintf(path, sizeof(path), 
"/local/domain/0/device-model/%d/parameter", domid);
+        libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
+                       pcidev->bus, pcidev->dev, pcidev->func);
+        snprintf(path, sizeof(path), 
"/local/domain/0/device-model/%d/command", domid);
+        xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem"));
+        if (libxl_wait_for_device_model(ctx, domid, "pci-removed") < 0) {
+            XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n");
+            return -1;
+        }
+        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", 
domid);
+        xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
+    } else {
+        char *sysfs_path = libxl_sprintf(ctx, 
"SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain,
+                                         pcidev->bus, pcidev->dev, 
pcidev->func);
+        FILE *f = fopen(sysfs_path, "r");
+        unsigned int start = 0, end = 0, flags = 0, size = 0;
+        int irq = 0;
+        int i;
+
+        if (f == NULL) {
+            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
+            goto skip1;
+        }
+        for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
+            fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
+            size = end - start + 1;
+            if (start) {
+                if (flags & PCI_BAR_IO) {
+                    rc = xc_domain_ioport_permission(ctx->xch, domid, start, 
size, 0);
+                    if (rc < 0)
+                        XL_LOG(ctx, XL_LOG_ERROR, "Error: 
xc_domain_ioport_permission error 0x%x/0x%x:  %d\n", start, size, rc);
+                } else {
+                    rc = xc_domain_iomem_permission(ctx->xch, domid, 
start>>XC_PAGE_SHIFT,
+                                                    
(size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 0);
+                    if (rc < 0)
+                        XL_LOG(ctx, XL_LOG_ERROR, "Error: 
xc_domain_iomem_permission error 0x%x/0x%x:  %d\n", start, size, rc);
+                }
+            }
+        }
+        fclose(f);
+skip1:
+        sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", 
pcidev->domain,
+                                   pcidev->bus, pcidev->dev, pcidev->func);
+        f = fopen(sysfs_path, "r");
+        if (f == NULL) {
+            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
+            goto out;
+        }
+        fscanf(f, "%u", &irq);
+        if (irq) {
+            rc = xc_physdev_unmap_pirq(ctx->xch, domid, irq);
+            if (rc < 0) {
+                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: 
%d\n", irq, rc);
+            }
+            rc = xc_domain_irq_permission(ctx->xch, domid, irq, 0);
+            if (rc < 0) {
+                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission 
irq=%d: %d\n", irq, rc);
+            }
+        }
+        fclose(f);
+    }
+out:
+    libxl_device_pci_remove_xenstore(ctx, domid, pcidev);
+
+    libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, 
pcidev->func);
+
+    if ((rc = xc_deassign_device(ctx->xch, domid, pcidev->value)) < 0)
+        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_deassign_device error %d\n", rc);
+    return 0;
+}
+
+libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t domid, 
int *num)
+{
+    char *be_path, *num_devs, *xsdev, *xsvdevfn, *xsopts;
+    int n, i;
+    unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
+    libxl_device_pci *pcidevs;
+
+    be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", 
xs_get_domain_path(ctx->xsh, 0), domid);
+    num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", 
be_path));
+    if (!num_devs) {
+        *num = 0;
+        return NULL;
+    }
+    n = atoi(num_devs);
+    pcidevs = (libxl_device_pci *) libxl_calloc(ctx, n, 
sizeof(libxl_device_pci));
+    *num = n;
+
+    for (i = 0; i < n; i++) {
+        xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", 
be_path, i));
+        sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
+        xsvdevfn = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/vdevfn-%d", be_path, i));
+        if (xsvdevfn)
+            vdevfn = strtol(xsvdevfn, (char **) NULL, 16);
+        libxl_device_pci_init(pcidevs + i, domain, bus, dev, func, vdevfn);
+        xsopts = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/opts-%d", 
be_path, i));
+        if (xsopts) {
+            char *saveptr;
+            char *p = strtok_r(xsopts, ",=", &saveptr);
+            do {
+                while (*p == ' ')
+                    p++;
+                if (!strcmp(p, "msitranslate")) {
+                    p = strtok_r(NULL, ",=", &saveptr);
+                    pcidevs[i].msitranslate = atoi(p);
+                } else if (!strcmp(p, "power_mgmt")) {
+                    p = strtok_r(NULL, ",=", &saveptr);
+                    pcidevs[i].power_mgmt = atoi(p);
+                }
+            } while ((p = strtok_r(NULL, ",=", &saveptr)) != NULL);
+        }
+    }
+    return pcidevs;
+}
+
+int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+    libxl_device_pci *pcidevs;
+    int num, i;
+
+    pcidevs = libxl_device_pci_list(ctx, domid, &num);
+    for (i = 0; i < num; i++) {
+        if (libxl_device_pci_remove(ctx, domid, pcidevs + i) < 0)
+            return -1;
+    }
+    return 0;
+}
+
diff -r d714386b668f -r 8a1d2e35edfa tools/libxl/libxl.h
--- a/tools/libxl/libxl.h       Fri Nov 13 15:30:24 2009 +0000
+++ b/tools/libxl/libxl.h       Fri Nov 13 15:31:16 2009 +0000
@@ -148,6 +148,25 @@ typedef struct {
     libxl_nic_type nictype;
 } libxl_device_nic;
 
+typedef struct  {
+    union {
+        unsigned int value;
+        struct {
+            unsigned int reserved1:2;
+            unsigned int reg:6;
+            unsigned int func:3;
+            unsigned int dev:5;
+            unsigned int bus:8;
+            unsigned int reserved2:7;
+            unsigned int enable:1;
+        };
+    };
+    unsigned int domain;
+    unsigned int vdevfn;
+    bool msitranslate;
+    bool power_mgmt;
+} libxl_device_pci;
+
 #define ERROR_FAIL (-2)
 #define ERROR_NI (-101)
 #define ERROR_NOMEM (-1032)
@@ -194,8 +213,14 @@ int libxl_device_vfb_clean_shutdown(stru
 int libxl_device_vfb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid);
 int libxl_device_vfb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid);
 
-int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid);
-int libxl_device_pci_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid);
-int libxl_device_pci_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+#define PCI_BDF                "%04x:%02x:%02x.%01x"
+#define PCI_BDF_VDEVFN         "%04x:%02x:%02x.%01x@%02x"
+int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_pci *pcidev);
+int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_pci *pcidev);
+int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t domid, 
int *num);
+int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
+                          unsigned int bus, unsigned int dev,
+                          unsigned int func, unsigned int vdevfn);
 
 #endif
diff -r d714386b668f -r 8a1d2e35edfa tools/libxl/libxl_device.c
--- a/tools/libxl/libxl_device.c        Fri Nov 13 15:30:24 2009 +0000
+++ b/tools/libxl/libxl_device.c        Fri Nov 13 15:31:16 2009 +0000
@@ -15,6 +15,7 @@
  */
 
 #include <string.h>
+#include <stdio.h>
 #include "libxl.h"
 #include "libxl_internal.h"
 #include <sys/time.h> /* for struct timeval */
@@ -83,9 +84,12 @@ retry_transaction:
     libxl_xs_writev(ctx, t, backend_path, bents);
     libxl_xs_writev(ctx, t, frontend_path, fents);
 
-    if (!xs_transaction_end(ctx->xsh, t, 0))
+    if (!xs_transaction_end(ctx->xsh, t, 0)) {
         if (errno == EAGAIN)
             goto retry_transaction;
+        else
+            XL_LOG(ctx, XL_LOG_ERROR, "xs transaction failed errno=%d\n", 
errno);
+    }
     return 0;
 }
 
@@ -154,7 +158,7 @@ int libxl_device_destroy(struct libxl_ct
     char *state = libxl_xs_read(ctx, XBT_NULL, state_path);
     if (!state)
         return 0;
-    if (atoi(state) <= 3) {
+    if (atoi(state) != 4) {
         xs_rm(ctx->xsh, XBT_NULL, be_path);
         return 0;
     }
@@ -240,3 +244,72 @@ int libxl_devices_destroy(struct libxl_c
     flexarray_free(toremove);
     return 0;
 }
+
+int libxl_device_pci_flr(struct libxl_ctx *ctx, unsigned int domain, unsigned 
int bus,
+                         unsigned int dev, unsigned int func)
+{
+    FILE *fd;
+
+    fd = fopen("/sys/bus/pci/drivers/pciback/do_flr", "w");
+    if (fd != NULL) {
+        fprintf(fd, PCI_BDF, domain, bus, dev, func);
+        fclose(fd);
+        return 0;
+    }
+    XL_LOG(ctx, XL_LOG_ERROR, "Pciback doesn't support do_flr, cannot flr the 
device\n");
+    return -1;
+}
+
+int libxl_wait_for_device_model(struct libxl_ctx *ctx, uint32_t domid, char 
*state)
+{
+    char path[50];
+    char *p;
+    int watchdog = 100;
+    unsigned int len;
+
+    snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", 
domid);
+    while (watchdog > 0) {
+        p = xs_read(ctx->xsh, XBT_NULL, path, &len);
+        if (p == NULL) {
+            usleep(100000);
+            watchdog--;
+        } else {
+            if (state == NULL || !strcmp(state, p)) {
+                free(p);
+                return 0;
+            } else {
+                free(p);
+                usleep(100000);
+                watchdog--;
+            }
+        }
+    }
+    XL_LOG(ctx, XL_LOG_ERROR, "Device Model not ready\n");
+    return -1;
+}
+
+int libxl_wait_for_backend(struct libxl_ctx *ctx, char *be_path, char *state)
+{
+    int watchdog = 100;
+    unsigned int len;
+    char *p;
+    char *path = libxl_sprintf(ctx, "%s/state", be_path);
+
+    while (watchdog > 0) {
+        p = xs_read(ctx->xsh, XBT_NULL, path, &len);
+        if (p == NULL) {
+            XL_LOG(ctx, XL_LOG_ERROR, "Backend %s does not exist\n", be_path);
+            return -1;
+        } else {
+            if (!strcmp(p, state)) {
+                return 0;
+            } else {
+                usleep(100000);
+                watchdog--;
+            }
+        }
+    }
+    XL_LOG(ctx, XL_LOG_ERROR, "Backend %s not ready\n", be_path);
+    return -1;
+}
+
diff -r d714386b668f -r 8a1d2e35edfa tools/libxl/libxl_internal.h
--- a/tools/libxl/libxl_internal.h      Fri Nov 13 15:30:24 2009 +0000
+++ b/tools/libxl/libxl_internal.h      Fri Nov 13 15:31:16 2009 +0000
@@ -72,6 +72,12 @@ typedef struct {
     libxl_device_kinds kind;
 } libxl_device;
 
+#define XC_PCI_BDF             "0x%x, 0x%x, 0x%x, 0x%x"
+#define AUTO_PHP_SLOT          0x100
+#define SYSFS_PCI_DEV          /sys/bus/pci/devices
+#define PROC_PCI_NUM_RESOURCES 7
+#define PCI_BAR_IO             0x01
+
 #define PRINTF_ATTRIBUTE(x, y) __attribute__((format(printf, x, y)))
 
 /* memory allocation tracking/helpers */
@@ -92,7 +98,7 @@ char *libxl_xs_read(struct libxl_ctx *ct
 char *libxl_xs_read(struct libxl_ctx *ctx, xs_transaction_t t, char *path);
 char **libxl_xs_directory(struct libxl_ctx *ctx, xs_transaction_t t, char 
*path, unsigned int *nb);
 
-/* from xd_dom */
+/* from xl_dom */
 int is_hvm(struct libxl_ctx *ctx, uint32_t domid);
 int build_pre(struct libxl_ctx *ctx, uint32_t domid,
               libxl_domain_build_info *info, libxl_domain_build_state *state);
@@ -109,7 +115,7 @@ int restore_common(struct libxl_ctx *ctx
                    libxl_domain_build_info *info, libxl_domain_build_state 
*state, int fd);
 int core_suspend(struct libxl_ctx *ctx, uint32_t domid, int fd, int hvm, int 
live, int debug);
 
-/* from xd_device */
+/* from xl_device */
 char *device_disk_backend_type_of_phystype(libxl_disk_phystype phystype);
 char *device_disk_string_of_phystype(libxl_disk_phystype phystype);
 
@@ -120,13 +126,17 @@ int libxl_device_generic_add(struct libx
                              char **bents, char **fents);
 int libxl_device_destroy(struct libxl_ctx *ctx, char *be_path, int force);
 int libxl_devices_destroy(struct libxl_ctx *ctx, uint32_t domid, int force);
+int libxl_wait_for_device_model(struct libxl_ctx *ctx, uint32_t domid, char 
*state);
+int libxl_wait_for_backend(struct libxl_ctx *ctx, char *be_path, char *state);
+int libxl_device_pci_flr(struct libxl_ctx *ctx, unsigned int domain, unsigned 
int bus,
+                         unsigned int dev, unsigned int func);
 
 /* from xenguest (helper */
 int hvm_build_set_params(int handle, uint32_t domid,
                          int apic, int acpi, int pae, int nx, int viridian,
                          int vcpus, int store_evtchn, unsigned long 
*store_mfn);
 
-/* xd_exec */
+/* xl_exec */
 int libxl_exec(struct libxl_ctx *ctx, int stdinfd, int stdoutfd, int stderrfd,
                char *arg0, char **args);
 
diff -r d714386b668f -r 8a1d2e35edfa tools/libxl/xl.c
--- a/tools/libxl/xl.c  Fri Nov 13 15:30:24 2009 +0000
+++ b/tools/libxl/xl.c  Fri Nov 13 15:31:16 2009 +0000
@@ -40,6 +40,8 @@ static void printf_info(libxl_domain_cre
                         int num_disks,
                         libxl_device_nic *vifs,
                         int num_vifs,
+                        libxl_device_pci *pcidevs,
+                        int num_pcidevs,
                         libxl_device_model_info *dm_info)
 {
     int i;
@@ -104,6 +106,12 @@ static void printf_info(libxl_domain_cre
         printf("model %s\n", vifs[i].model);
         printf("mac %02x:%02x:%02x:%02x:%02x:%02x\n", vifs[i].mac[0], 
vifs[i].mac[1], vifs[i].mac[2], vifs[i].mac[3], vifs[i].mac[4], vifs[i].mac[5]);
         printf("smac %s\n", vifs[i].mac);
+    }
+
+    for (i = 0; i < num_pcidevs; i++) {
+        printf("\n\n\n*** pcidevs_info: %d ***\n", i);
+        printf("pci dev "PCI_BDF_VDEVFN"\n", pcidevs[i].domain, 
pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func, pcidevs[i].vdevfn);
+        printf("opts msitranslate %d power_mgmt %d\n", 
pcidevs[i].msitranslate, pcidevs[i].power_mgmt);
     }
 
     printf("\n\n\n*** device_model_info ***\n");
@@ -286,13 +294,17 @@ static void parse_config_file(const char
                               int *num_disks,
                               libxl_device_nic **vifs,
                               int *num_vifs,
+                              libxl_device_pci **pcidevs,
+                              int *num_pcidevs,
                               libxl_device_model_info *dm_info)
 {
     const char *buf;
     xen_uuid_t uuid[16];
     long l;
     struct config_t config;
-    struct config_setting_t *vbds, *nics;
+    struct config_setting_t *vbds, *nics, *pcis;
+    int pci_power_mgmt = 0;
+    int pci_msitranslate = 1;
 
     config_init (&config);
 
@@ -482,6 +494,48 @@ skip:
         }
     }
 
+    if (config_lookup_int (&config, "pci_msitranslate", &l) == CONFIG_TRUE)
+        pci_msitranslate = l;
+
+    if (config_lookup_int (&config, "pci_power_mgmt", &l) == CONFIG_TRUE)
+        pci_power_mgmt = l;
+
+    if ((pcis = config_lookup (&config, "pci")) != NULL) {
+        *num_pcidevs = 0;
+        *pcidevs = NULL;
+        while ((buf = config_setting_get_string_elem (pcis, *num_pcidevs)) != 
NULL) {
+            unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
+            char *buf2 = strdup(buf);
+            char *p;
+            *pcidevs = (libxl_device_pci *) realloc(*pcidevs, sizeof 
(libxl_device_pci) * ((*num_pcidevs) + 1));
+            memset(*pcidevs + *num_pcidevs, 0x00, sizeof(libxl_device_pci));
+            p = strtok(buf2, ",");
+            if (!p)
+                goto skip_pci;
+            if (!sscanf(p, PCI_BDF_VDEVFN, &domain, &bus, &dev, &func, 
&vdevfn)) {
+                sscanf(p, "%02x:%02x.%01x@%02x", &bus, &dev, &func, &vdevfn);
+                domain = 0;
+            }
+            libxl_device_pci_init(*pcidevs + *num_pcidevs, domain, bus, dev, 
func, vdevfn);
+            (*pcidevs)[*num_pcidevs].msitranslate = pci_msitranslate;
+            (*pcidevs)[*num_pcidevs].power_mgmt = pci_power_mgmt;
+            while ((p = strtok(NULL, ",=")) != NULL) {
+                while (*p == ' ')
+                    p++;
+                if (!strcmp(p, "msitranslate")) {
+                    p = strtok(NULL, ",=");
+                    (*pcidevs)[*num_pcidevs].msitranslate = atoi(p);
+                } else if (!strcmp(p, "power_mgmt")) {
+                    p = strtok(NULL, ",=");
+                    (*pcidevs)[*num_pcidevs].power_mgmt = atoi(p);
+                }
+            }
+            *num_pcidevs = (*num_pcidevs) + 1;
+skip_pci:
+            free(buf2);
+        }
+    }
+
     /* init dm from c and b */
     init_dm_info(dm_info, c_info, b_info);
 
@@ -527,13 +581,14 @@ static void create_domain(int debug, con
     libxl_device_model_info dm_info;
     libxl_device_disk *disks = NULL;
     libxl_device_nic *vifs = NULL;
-    int num_disks = 0, num_vifs = 0;
+    libxl_device_pci *pcidevs = NULL;
+    int num_disks = 0, num_vifs = 0, num_pcidevs = 0;
     int i;
 
     printf("Parsing config file %s\n", filename);
-    parse_config_file(filename, &info1, &info2, &disks, &num_disks, &vifs, 
&num_vifs, &dm_info);
+    parse_config_file(filename, &info1, &info2, &disks, &num_disks, &vifs, 
&num_vifs, &pcidevs, &num_pcidevs, &dm_info);
     if (debug)
-        printf_info(&info1, &info2, disks, num_disks, vifs, num_vifs, 
&dm_info);
+        printf_info(&info1, &info2, disks, num_disks, vifs, num_vifs, pcidevs, 
num_pcidevs, &dm_info);
 
     libxl_ctx_init(&ctx);
     libxl_ctx_set_log(&ctx, log_callback, NULL);
@@ -551,6 +606,8 @@ static void create_domain(int debug, con
         libxl_device_nic_add(&ctx, domid, &vifs[i]);
     }
     libxl_create_device_model(&ctx, &dm_info, vifs, num_vifs);
+    for (i = 0; i < num_pcidevs; i++)
+        libxl_device_pci_add(&ctx, domid, &pcidevs[i]);
     libxl_domain_unpause(&ctx, domid);
 
 }
@@ -560,9 +617,12 @@ static void help(char *command)
     if (!command || !strcmp(command, "help")) {
         printf("Usage xl <subcommand> [args]\n\n");
         printf("xl full list of subcommands:\n\n");
-        printf(" create                                create a domain from 
config file <filename>\n\n");
+        printf(" create                        create a domain from config 
file <filename>\n\n");
         printf(" list                          list information about all 
domains\n\n");
         printf(" destroy                       terminate a domain 
immediately\n\n");
+        printf(" pci-attach                    insert a new pass-through pci 
device\n\n");
+        printf(" pci-detach                    remove a domain's pass-through 
pci device\n\n");
+        printf(" pci-list                      list pass-through pci devices 
for a domain\n\n");
     } else if(!strcmp(command, "create")) {
         printf("Usage: xl create <ConfigFile> [options] [vars]\n\n");
         printf("Create a domain based on <ConfigFile>.\n\n");
@@ -572,11 +632,166 @@ static void help(char *command)
     } else if(!strcmp(command, "list")) {
         printf("Usage: xl list [Domain]\n\n");
         printf("List information about all/some domains.\n\n");
+    } else if(!strcmp(command, "pci-attach")) {
+        printf("Usage: xl pci-attach <Domain> <BDF> [Virtual Slot]\n\n");
+        printf("Insert a new pass-through pci device.\n\n");
+    } else if(!strcmp(command, "pci-detach")) {
+        printf("Usage: xl pci-detach <Domain> <BDF>\n\n");
+        printf("Remove a domain's pass-through pci device.\n\n");
+    } else if(!strcmp(command, "pci-list")) {
+        printf("Usage: xl pci-list <Domain>\n\n");
+        printf("List pass-through pci devices for a domain.\n\n");
     } else if(!strcmp(command, "destroy")) {
         printf("Usage: xl destroy <Domain>\n\n");
         printf("Terminate a domain immediately.\n\n");
     }
 }
+
+void pcilist(char *dom)
+{
+    struct libxl_ctx ctx;
+    uint32_t domid;
+    libxl_device_pci *pcidevs;
+    int num, i;
+
+    libxl_ctx_init(&ctx);
+    libxl_ctx_set_log(&ctx, log_callback, NULL);
+
+    if (libxl_param_to_domid(&ctx, dom, &domid) < 0) {
+        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
+        exit(2);
+    }
+    pcidevs = libxl_device_pci_list(&ctx, domid, &num);
+    if (!num)
+        return;
+    printf("VFn  domain bus  slot func\n");
+    for (i = 0; i < num; i++) {
+        printf("0x%02x 0x%04x 0x%02x 0x%02x 0x%01x\n", pcidevs[i].vdevfn, 
pcidevs[i].domain, pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func);
+    }
+}
+
+int main_pcilist(int argc, char **argv)
+{
+    int opt;
+    char *domname = NULL;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("pci-list");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help("pci-list");
+        exit(2);
+    }
+
+    domname = argv[optind];
+
+    pcilist(domname);
+    exit(0);
+}
+
+void pcidetach(char *dom, char *bdf)
+{
+    struct libxl_ctx ctx;
+    uint32_t domid;
+    libxl_device_pci pcidev;
+    unsigned int domain, bus, dev, func;
+
+    libxl_ctx_init(&ctx);
+    libxl_ctx_set_log(&ctx, log_callback, NULL);
+
+    if (libxl_param_to_domid(&ctx, dom, &domid) < 0) {
+        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
+        exit(2);
+    }
+    memset(&pcidev, 0x00, sizeof(pcidev));
+    sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func);
+    libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0);
+    libxl_device_pci_remove(&ctx, domid, &pcidev);
+}
+
+int main_pcidetach(int argc, char **argv)
+{
+    int opt;
+    char *domname = NULL, *bdf = NULL;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("pci-attach");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc - 1) {
+        help("pci-detach");
+        exit(2);
+    }
+
+    domname = argv[optind];
+    bdf = argv[optind + 1];
+
+    pcidetach(domname, bdf);
+    exit(0);
+}
+void pciattach(char *dom, char *bdf, char *vs)
+{
+    struct libxl_ctx ctx;
+    uint32_t domid;
+    libxl_device_pci pcidev;
+    unsigned int domain, bus, dev, func;
+
+    libxl_ctx_init(&ctx);
+    libxl_ctx_set_log(&ctx, log_callback, NULL);
+
+    if (libxl_param_to_domid(&ctx, dom, &domid) < 0) {
+        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
+        exit(2);
+    }
+    memset(&pcidev, 0x00, sizeof(pcidev));
+    sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func);
+    libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0);
+    libxl_device_pci_add(&ctx, domid, &pcidev);
+}
+
+int main_pciattach(int argc, char **argv)
+{
+    int opt;
+    char *domname = NULL, *bdf = NULL, *vs = NULL;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("pci-attach");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc - 1) {
+        help("pci-attach");
+        exit(2);
+    }
+
+    domname = argv[optind];
+    bdf = argv[optind + 1];
+
+    if (optind + 1 < argc)
+        vs = argv[optind + 2];
+
+    pciattach(domname, bdf, vs);
+    exit(0);
+}
+
 
 void destroy_domain(char *p)
 {
@@ -713,6 +928,12 @@ int main(int argc, char **argv)
         main_list(argc - 1, argv + 1);
     } else if (!strcmp(argv[1], "destroy")) {
         main_destroy(argc - 1, argv + 1);
+    } else if (!strcmp(argv[1], "pci-attach")) {
+        main_pciattach(argc - 1, argv + 1);
+    } else if (!strcmp(argv[1], "pci-detach")) {
+        main_pcidetach(argc - 1, argv + 1);
+    } else if (!strcmp(argv[1], "pci-list")) {
+        main_pcilist(argc - 1, argv + 1);
     } else if (!strcmp(argv[1], "help")) {
         if (argc > 2)
             help(argv[2]);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] libxenlight: implement pci passthrough, Xen patchbot-unstable <=