debuggers.hg

diff tools/libxl/libxl.c @ 20482:8a1d2e35edfa

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@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Nov 13 15:31:16 2009 +0000 (2009-11-13)
parents 50d33023051d
children 014579af0350
line diff
     1.1 --- a/tools/libxl/libxl.c	Fri Nov 13 15:30:24 2009 +0000
     1.2 +++ b/tools/libxl/libxl.c	Fri Nov 13 15:31:16 2009 +0000
     1.3 @@ -156,6 +156,7 @@ retry_transaction:
     1.4  
     1.5      xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
     1.6      xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", vm_path), info->name, strlen(info->name));
     1.7 +    xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/image/ostype", vm_path), "hvm", strlen("hvm"));
     1.8  
     1.9      libxl_xs_writev(ctx, t, dom_path, info->xsdata);
    1.10      libxl_xs_writev(ctx, t, libxl_sprintf(ctx, "%s/platform", dom_path), info->platformdata);
    1.11 @@ -368,6 +369,8 @@ int libxl_domain_destroy(struct libxl_ct
    1.12          XL_LOG(ctx, XL_LOG_ERROR, "failed ot get uuid for %d\n", domid);
    1.13          return -1;
    1.14      }
    1.15 +    if (libxl_device_pci_shutdown(ctx, domid) < 0)
    1.16 +        XL_LOG(ctx, XL_LOG_ERROR, "pci shutdown failed for domid %d\n", domid);
    1.17      xs_write(ctx->xsh, XBT_NULL,
    1.18               libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid),
    1.19               "shutdown", strlen("shutdown"));
    1.20 @@ -375,7 +378,6 @@ int libxl_domain_destroy(struct libxl_ct
    1.21          XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_pause failed for %d\n", domid);
    1.22          return -1;
    1.23      }
    1.24 -    /* do_FLR */
    1.25      if (xc_domain_destroy(ctx->xch, domid) < 0) {
    1.26          XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_destroy failed for %d\n", domid);
    1.27          return -1;
    1.28 @@ -746,17 +748,417 @@ int libxl_device_vfb_hard_shutdown(struc
    1.29  }
    1.30  
    1.31  /******************************************************************************/
    1.32 -int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid)
    1.33 +
    1.34 +int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
    1.35 +                          unsigned int bus, unsigned int dev,
    1.36 +                          unsigned int func, unsigned int vdevfn)
    1.37 +{
    1.38 +    pcidev->domain = domain;
    1.39 +    pcidev->bus = bus;
    1.40 +    pcidev->dev = dev;
    1.41 +    pcidev->func = func;
    1.42 +    pcidev->vdevfn = vdevfn;
    1.43 +    return 0;
    1.44 +}
    1.45 +
    1.46 +static int libxl_create_pci_backend(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev, int num)
    1.47 +{
    1.48 +    flexarray_t *front;
    1.49 +    flexarray_t *back;
    1.50 +    unsigned int boffset = 0;
    1.51 +    unsigned int foffset = 0;
    1.52 +    libxl_device device;
    1.53 +    int i;
    1.54 +
    1.55 +    front = flexarray_make(16, 1);
    1.56 +    if (!front)
    1.57 +        return ERROR_NOMEM;
    1.58 +    back = flexarray_make(16, 1);
    1.59 +    if (!back)
    1.60 +        return ERROR_NOMEM;
    1.61 +
    1.62 +    XL_LOG(ctx, XL_LOG_DEBUG, "Creating pci backend\n");
    1.63 +
    1.64 +    /* add pci device */
    1.65 +    device.backend_devid = 0;
    1.66 +    device.backend_domid = 0;
    1.67 +    device.backend_kind = DEVICE_PCI;
    1.68 +    device.devid = 0;
    1.69 +    device.domid = domid;
    1.70 +    device.kind = DEVICE_PCI;
    1.71 +
    1.72 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
    1.73 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", domid));
    1.74 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
    1.75 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
    1.76 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
    1.77 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
    1.78 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "domain"));
    1.79 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", libxl_domid_to_name(ctx, domid)));
    1.80 +    for (i = 0; i < num; i++) {
    1.81 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", i));
    1.82 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
    1.83 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", i));
    1.84 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
    1.85 +        if (pcidev->vdevfn) {
    1.86 +            flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", i));
    1.87 +            flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
    1.88 +        }
    1.89 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", i));
    1.90 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
    1.91 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", i));
    1.92 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
    1.93 +    }
    1.94 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs"));
    1.95 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num));
    1.96 +
    1.97 +    flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
    1.98 +    flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 0));
    1.99 +    flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
   1.100 +    flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
   1.101 +
   1.102 +    libxl_device_generic_add(ctx, &device,
   1.103 +                             libxl_xs_kvs_of_flexarray(ctx, back, boffset),
   1.104 +                             libxl_xs_kvs_of_flexarray(ctx, front, foffset));
   1.105 +
   1.106 +    flexarray_free(back);
   1.107 +    flexarray_free(front);
   1.108 +    return 0;
   1.109 +}
   1.110 +
   1.111 +static int libxl_device_pci_add_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
   1.112  {
   1.113 -    return ERROR_NI;
   1.114 +    flexarray_t *back;
   1.115 +    char *num_devs, *be_path;
   1.116 +    int num = 0;
   1.117 +    unsigned int boffset = 0;
   1.118 +    xs_transaction_t t;
   1.119 +
   1.120 +    be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
   1.121 +    num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
   1.122 +    if (!num_devs)
   1.123 +        return libxl_create_pci_backend(ctx, domid, pcidev, 1);
   1.124 +
   1.125 +    if (!is_hvm(ctx, domid)) {
   1.126 +        if (libxl_wait_for_backend(ctx, be_path, "4") < 0)
   1.127 +            return -1;
   1.128 +    }
   1.129 +
   1.130 +    back = flexarray_make(16, 1);
   1.131 +    if (!back)
   1.132 +        return ERROR_NOMEM;
   1.133 +
   1.134 +    XL_LOG(ctx, XL_LOG_DEBUG, "Adding new pci device to xenstore\n");
   1.135 +    num = atoi(num_devs);
   1.136 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", num));
   1.137 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
   1.138 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", num));
   1.139 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
   1.140 +    if (pcidev->vdevfn) {
   1.141 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", num));
   1.142 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
   1.143 +    }
   1.144 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", num));
   1.145 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
   1.146 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", num));
   1.147 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
   1.148 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs"));
   1.149 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num + 1));
   1.150 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
   1.151 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 7));
   1.152 +
   1.153 +retry_transaction:
   1.154 +    t = xs_transaction_start(ctx->xsh);
   1.155 +    libxl_xs_writev(ctx, t, be_path,
   1.156 +                    libxl_xs_kvs_of_flexarray(ctx, back, boffset));
   1.157 +    if (!xs_transaction_end(ctx->xsh, t, 0))
   1.158 +        if (errno == EAGAIN)
   1.159 +            goto retry_transaction;
   1.160 +
   1.161 +    flexarray_free(back);
   1.162 +    return 0;
   1.163 +}
   1.164 +
   1.165 +static int libxl_device_pci_remove_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
   1.166 +{
   1.167 +    char *be_path, *num_devs_path, *num_devs, *xsdev;
   1.168 +    int num, i;
   1.169 +    xs_transaction_t t;
   1.170 +    unsigned int domain = 0, bus = 0, dev = 0, func = 0;
   1.171 +
   1.172 +    be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
   1.173 +    num_devs_path = libxl_sprintf(ctx, "%s/num_devs", be_path);
   1.174 +    num_devs = libxl_xs_read(ctx, XBT_NULL, num_devs_path);
   1.175 +    if (!num_devs)
   1.176 +        return -1;
   1.177 +    num = atoi(num_devs);
   1.178 +    if (num == 1) {
   1.179 +        libxl_device_destroy(ctx, be_path, 1);
   1.180 +        xs_rm(ctx->xsh, XBT_NULL, be_path);
   1.181 +        return 0;
   1.182 +    }
   1.183 +
   1.184 +    if (!is_hvm(ctx, domid)) {
   1.185 +        if (libxl_wait_for_backend(ctx, be_path, "4") < 0) {
   1.186 +            XL_LOG(ctx, XL_LOG_DEBUG, "pci backend at %s is not ready\n");
   1.187 +            return -1;
   1.188 +        }
   1.189 +    }
   1.190 +
   1.191 +    for (i = 0; i < num; i++) {
   1.192 +        xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
   1.193 +        sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
   1.194 +        if (domain == pcidev->domain && bus == pcidev->bus &&
   1.195 +            pcidev->dev == dev && pcidev->func == func) {
   1.196 +            break;
   1.197 +        }
   1.198 +    }
   1.199 +    if (i == num) {
   1.200 +        XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find the device on xenstore\n");
   1.201 +        return -1;
   1.202 +    }
   1.203 +
   1.204 +retry_transaction:
   1.205 +    t = xs_transaction_start(ctx->xsh);
   1.206 +    libxl_xs_write(ctx, t, num_devs_path, "%d", num - 1);
   1.207 +    xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, i), "6", strlen("6"));
   1.208 +    xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state", be_path), "7", strlen("7"));
   1.209 +    if (!xs_transaction_end(ctx->xsh, t, 0))
   1.210 +        if (errno == EAGAIN)
   1.211 +            goto retry_transaction;
   1.212 +    return 0;
   1.213  }
   1.214  
   1.215 -int libxl_device_pci_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
   1.216 +int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
   1.217  {
   1.218 -    return ERROR_NI;
   1.219 +    char path[50];
   1.220 +    char *state, *vdevfn;
   1.221 +    int rc, hvm;
   1.222 +
   1.223 +    /* TODO: check if the device can be assigned */
   1.224 +
   1.225 +    libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
   1.226 +
   1.227 +    hvm = is_hvm(ctx, domid);
   1.228 +    if (hvm) {
   1.229 +        if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
   1.230 +            return -1;
   1.231 +        }
   1.232 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
   1.233 +        state = libxl_xs_read(ctx, XBT_NULL, path);
   1.234 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
   1.235 +        if (pcidev->vdevfn)
   1.236 +            libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF_VDEVFN, pcidev->domain,
   1.237 +                           pcidev->bus, pcidev->dev, pcidev->func, pcidev->vdevfn);
   1.238 +        else
   1.239 +            libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
   1.240 +                           pcidev->bus, pcidev->dev, pcidev->func);
   1.241 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/command", domid);
   1.242 +        xs_write(ctx->xsh, XBT_NULL, path, "pci-ins", strlen("pci-ins"));
   1.243 +        if (libxl_wait_for_device_model(ctx, domid, "pci-inserted") < 0)
   1.244 +            XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n");
   1.245 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
   1.246 +        vdevfn = libxl_xs_read(ctx, XBT_NULL, path);
   1.247 +        sscanf(vdevfn + 2, "%x", &pcidev->vdevfn);
   1.248 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
   1.249 +        xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
   1.250 +    } else {
   1.251 +        char *sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain,
   1.252 +                                         pcidev->bus, pcidev->dev, pcidev->func);
   1.253 +        FILE *f = fopen(sysfs_path, "r");
   1.254 +        unsigned int start = 0, end = 0, flags = 0, size = 0;
   1.255 +        int irq = 0;
   1.256 +        int i;
   1.257 +
   1.258 +        if (f == NULL) {
   1.259 +            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
   1.260 +            return -1;
   1.261 +        }
   1.262 +        for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
   1.263 +            fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
   1.264 +            size = end - start + 1;
   1.265 +            if (start) {
   1.266 +                if (flags & PCI_BAR_IO) {
   1.267 +                    rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 1);
   1.268 +                    if (rc < 0)
   1.269 +                        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_ioport_permission error 0x%x/0x%x:  %d\n", start, size, rc);
   1.270 +                } else {
   1.271 +                    rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
   1.272 +                                                    (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 1);
   1.273 +                    if (rc < 0)
   1.274 +                        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_iomem_permission error 0x%x/0x%x:  %d\n", start, size, rc);
   1.275 +                }
   1.276 +            }
   1.277 +        }
   1.278 +        fclose(f);
   1.279 +        sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", pcidev->domain,
   1.280 +                                   pcidev->bus, pcidev->dev, pcidev->func);
   1.281 +        f = fopen(sysfs_path, "r");
   1.282 +        if (f == NULL) {
   1.283 +            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
   1.284 +            goto out;
   1.285 +        }
   1.286 +        fscanf(f, "%u", &irq);
   1.287 +        if (irq) {
   1.288 +            rc = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq);
   1.289 +            if (rc < 0) {
   1.290 +                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: %d\n", irq, rc);
   1.291 +            }
   1.292 +            rc = xc_domain_irq_permission(ctx->xch, domid, irq, 1);
   1.293 +            if (rc < 0) {
   1.294 +                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission irq=%d: %d\n", irq, rc);
   1.295 +            }
   1.296 +        }
   1.297 +        fclose(f);
   1.298 +    }
   1.299 +out:
   1.300 +    if ((rc = xc_assign_device(ctx->xch, domid, pcidev->value)) < 0)
   1.301 +        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_assign_device error %d\n", rc);
   1.302 +
   1.303 +    libxl_device_pci_add_xenstore(ctx, domid, pcidev);
   1.304 +    return 0;
   1.305  }
   1.306  
   1.307 -int libxl_device_pci_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
   1.308 +int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
   1.309  {
   1.310 -    return ERROR_NI;
   1.311 +    char path[50];
   1.312 +    char *state;
   1.313 +    int hvm, rc;
   1.314 +
   1.315 +    /* TODO: check if the device can be detached */
   1.316 +
   1.317 +    hvm = is_hvm(ctx, domid);
   1.318 +    if (hvm) {
   1.319 +        if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
   1.320 +            return -1;
   1.321 +        }
   1.322 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
   1.323 +        state = libxl_xs_read(ctx, XBT_NULL, path);
   1.324 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
   1.325 +        libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
   1.326 +                       pcidev->bus, pcidev->dev, pcidev->func);
   1.327 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/command", domid);
   1.328 +        xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem"));
   1.329 +        if (libxl_wait_for_device_model(ctx, domid, "pci-removed") < 0) {
   1.330 +            XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n");
   1.331 +            return -1;
   1.332 +        }
   1.333 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
   1.334 +        xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
   1.335 +    } else {
   1.336 +        char *sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain,
   1.337 +                                         pcidev->bus, pcidev->dev, pcidev->func);
   1.338 +        FILE *f = fopen(sysfs_path, "r");
   1.339 +        unsigned int start = 0, end = 0, flags = 0, size = 0;
   1.340 +        int irq = 0;
   1.341 +        int i;
   1.342 +
   1.343 +        if (f == NULL) {
   1.344 +            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
   1.345 +            goto skip1;
   1.346 +        }
   1.347 +        for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
   1.348 +            fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
   1.349 +            size = end - start + 1;
   1.350 +            if (start) {
   1.351 +                if (flags & PCI_BAR_IO) {
   1.352 +                    rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 0);
   1.353 +                    if (rc < 0)
   1.354 +                        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_ioport_permission error 0x%x/0x%x:  %d\n", start, size, rc);
   1.355 +                } else {
   1.356 +                    rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
   1.357 +                                                    (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 0);
   1.358 +                    if (rc < 0)
   1.359 +                        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_iomem_permission error 0x%x/0x%x:  %d\n", start, size, rc);
   1.360 +                }
   1.361 +            }
   1.362 +        }
   1.363 +        fclose(f);
   1.364 +skip1:
   1.365 +        sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", pcidev->domain,
   1.366 +                                   pcidev->bus, pcidev->dev, pcidev->func);
   1.367 +        f = fopen(sysfs_path, "r");
   1.368 +        if (f == NULL) {
   1.369 +            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
   1.370 +            goto out;
   1.371 +        }
   1.372 +        fscanf(f, "%u", &irq);
   1.373 +        if (irq) {
   1.374 +            rc = xc_physdev_unmap_pirq(ctx->xch, domid, irq);
   1.375 +            if (rc < 0) {
   1.376 +                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: %d\n", irq, rc);
   1.377 +            }
   1.378 +            rc = xc_domain_irq_permission(ctx->xch, domid, irq, 0);
   1.379 +            if (rc < 0) {
   1.380 +                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission irq=%d: %d\n", irq, rc);
   1.381 +            }
   1.382 +        }
   1.383 +        fclose(f);
   1.384 +    }
   1.385 +out:
   1.386 +    libxl_device_pci_remove_xenstore(ctx, domid, pcidev);
   1.387 +
   1.388 +    libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
   1.389 +
   1.390 +    if ((rc = xc_deassign_device(ctx->xch, domid, pcidev->value)) < 0)
   1.391 +        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_deassign_device error %d\n", rc);
   1.392 +    return 0;
   1.393  }
   1.394 +
   1.395 +libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t domid, int *num)
   1.396 +{
   1.397 +    char *be_path, *num_devs, *xsdev, *xsvdevfn, *xsopts;
   1.398 +    int n, i;
   1.399 +    unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
   1.400 +    libxl_device_pci *pcidevs;
   1.401 +
   1.402 +    be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
   1.403 +    num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
   1.404 +    if (!num_devs) {
   1.405 +        *num = 0;
   1.406 +        return NULL;
   1.407 +    }
   1.408 +    n = atoi(num_devs);
   1.409 +    pcidevs = (libxl_device_pci *) libxl_calloc(ctx, n, sizeof(libxl_device_pci));
   1.410 +    *num = n;
   1.411 +
   1.412 +    for (i = 0; i < n; i++) {
   1.413 +        xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
   1.414 +        sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
   1.415 +        xsvdevfn = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, i));
   1.416 +        if (xsvdevfn)
   1.417 +            vdevfn = strtol(xsvdevfn, (char **) NULL, 16);
   1.418 +        libxl_device_pci_init(pcidevs + i, domain, bus, dev, func, vdevfn);
   1.419 +        xsopts = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/opts-%d", be_path, i));
   1.420 +        if (xsopts) {
   1.421 +            char *saveptr;
   1.422 +            char *p = strtok_r(xsopts, ",=", &saveptr);
   1.423 +            do {
   1.424 +                while (*p == ' ')
   1.425 +                    p++;
   1.426 +                if (!strcmp(p, "msitranslate")) {
   1.427 +                    p = strtok_r(NULL, ",=", &saveptr);
   1.428 +                    pcidevs[i].msitranslate = atoi(p);
   1.429 +                } else if (!strcmp(p, "power_mgmt")) {
   1.430 +                    p = strtok_r(NULL, ",=", &saveptr);
   1.431 +                    pcidevs[i].power_mgmt = atoi(p);
   1.432 +                }
   1.433 +            } while ((p = strtok_r(NULL, ",=", &saveptr)) != NULL);
   1.434 +        }
   1.435 +    }
   1.436 +    return pcidevs;
   1.437 +}
   1.438 +
   1.439 +int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid)
   1.440 +{
   1.441 +    libxl_device_pci *pcidevs;
   1.442 +    int num, i;
   1.443 +
   1.444 +    pcidevs = libxl_device_pci_list(ctx, domid, &num);
   1.445 +    for (i = 0; i < num; i++) {
   1.446 +        if (libxl_device_pci_remove(ctx, domid, pcidevs + i) < 0)
   1.447 +            return -1;
   1.448 +    }
   1.449 +    return 0;
   1.450 +}
   1.451 +