ia64/xen-unstable

changeset 16159:bc4afcd4c612

vt-d: Detect and report failure to assign a pass-thru PCI device.
Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir@xensource.com>
date Fri Oct 19 09:31:03 2007 +0100 (2007-10-19)
parents 3ad0080ad9b5
children e733e6b73d56
files tools/ioemu/hw/pass-through.c tools/python/xen/lowlevel/xc/xc.c tools/python/xen/xend/XendDomainInfo.py
line diff
     1.1 --- a/tools/ioemu/hw/pass-through.c	Fri Oct 19 09:28:21 2007 +0100
     1.2 +++ b/tools/ioemu/hw/pass-through.c	Fri Oct 19 09:31:03 2007 +0100
     1.3 @@ -28,40 +28,52 @@
     1.4  #include "pci/pci.h"
     1.5  
     1.6  extern FILE *logfile;
     1.7 -char *token;
     1.8  
     1.9 -int pci_devs(const char *direct_pci)
    1.10 +static int token_value(char *token)
    1.11  {
    1.12 -    int count = 0;
    1.13 -    const char *c;
    1.14 -
    1.15 -    /* skip first "[" character */
    1.16 -    c = direct_pci + 1;
    1.17 -    while ((c = strchr(c, '[')) != NULL) {
    1.18 -        c++;
    1.19 -        count++;
    1.20 -    }
    1.21 -    return (count);
    1.22 -}
    1.23 -
    1.24 -int next_token(char *direct_pci)
    1.25 -{
    1.26 -    if (token == NULL)
    1.27 -        token = strtok(direct_pci, ",");
    1.28 -    else 
    1.29 -        token = strtok(NULL, ",");
    1.30      token = strchr(token, 'x');
    1.31      token = token + 1;
    1.32 +
    1.33      return ((int) strtol(token, NULL, 16));
    1.34  }
    1.35  
    1.36 -void next_bdf(char *direct_pci, int *seg,
    1.37 -              int *bus, int *dev, int *func)
    1.38 +static int first_bdf(char *pci_str, char **last,
    1.39 +                     int *seg, int *bus, int *dev, int *func)
    1.40  {
    1.41 -    *seg  = next_token(direct_pci);
    1.42 -    *bus  = next_token(direct_pci);
    1.43 -    *dev  = next_token(direct_pci);
    1.44 -    *func = next_token(direct_pci);
    1.45 +    char *token;
    1.46 +
    1.47 +    token = strtok_r(pci_str, ",", last);
    1.48 +    if ( !token )
    1.49 +        return 0;
    1.50 +
    1.51 +    *seg  = token_value(token);
    1.52 +    token = strtok_r(NULL, ",", last);
    1.53 +    *bus  = token_value(token);
    1.54 +    token = strtok_r(NULL, ",", last);
    1.55 +    *dev  = token_value(token);
    1.56 +    token = strtok_r(NULL, ",", last);
    1.57 +    *func  = token_value(token);
    1.58 +
    1.59 +    return 1;
    1.60 +}
    1.61 +
    1.62 +static int next_bdf(char **last, int *seg, int *bus, int *dev, int *func)
    1.63 +{
    1.64 +    char *token;
    1.65 +
    1.66 +    token = strtok_r(NULL, ",", last);
    1.67 +    if ( !token )
    1.68 +        return 0;
    1.69 +
    1.70 +    *seg  = token_value(token);
    1.71 +    token = strtok_r(NULL, ",", last);
    1.72 +    *bus  = token_value(token);
    1.73 +    token = strtok_r(NULL, ",", last);
    1.74 +    *dev  = token_value(token);
    1.75 +    token = strtok_r(NULL, ",", last);
    1.76 +    *func  = token_value(token);
    1.77 +
    1.78 +    return 1;
    1.79  }
    1.80  
    1.81  uint8_t find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
    1.82 @@ -333,7 +345,6 @@ struct pt_dev * register_real_device(PCI
    1.83      int rc, i;
    1.84      struct pt_dev *assigned_device = NULL;
    1.85      struct pci_dev *pci_dev;
    1.86 -    struct pci_config_cf8 machine_bdf;
    1.87      uint8_t e_device, e_intx;
    1.88  
    1.89      PT_LOG("Assigning real physical device %02x:%02x.%x ...\n",
    1.90 @@ -368,15 +379,6 @@ struct pt_dev * register_real_device(PCI
    1.91      /* Issue PCIe FLR */
    1.92      pdev_flr(pci_dev);
    1.93  
    1.94 -    /* Tell XEN vmm to change iommu settings */
    1.95 -    machine_bdf.reg = 0;
    1.96 -    machine_bdf.bus = r_bus;
    1.97 -    machine_bdf.dev = r_dev;
    1.98 -    machine_bdf.func = r_func;
    1.99 -    rc = xc_assign_device(xc_handle, domid, machine_bdf.value);
   1.100 -    if ( rc < 0 )
   1.101 -        PT_LOG("Error: xc_domain_assign_device error %d\n", rc);
   1.102 -
   1.103      /* Initialize virtualized PCI configuration (Extended 256 Bytes) */
   1.104      for ( i = 0; i < PCI_CONFIG_SIZE; i++ )
   1.105          assigned_device->dev.config[i] = pci_read_byte(pci_dev, i);
   1.106 @@ -417,11 +419,11 @@ struct pt_dev * register_real_device(PCI
   1.107  
   1.108  int pt_init(PCIBus *e_bus, char *direct_pci)
   1.109  {
   1.110 -    int i;
   1.111      int seg, b, d, f;
   1.112      struct pt_dev *pt_dev;
   1.113      struct pci_access *pci_access;
   1.114 -    int dev_count = pci_devs(direct_pci);
   1.115 +    int get_bdf;
   1.116 +    char *last = NULL;
   1.117  
   1.118      /* Initialize libpci */
   1.119      pci_access = pci_alloc();
   1.120 @@ -434,11 +436,10 @@ int pt_init(PCIBus *e_bus, char *direct_
   1.121      pci_scan_bus(pci_access);
   1.122  
   1.123      /* Assign given devices to guest */
   1.124 -    for ( i = 0; i < dev_count; i++ )
   1.125 +    for ( get_bdf = first_bdf(direct_pci, &last, &seg, &b, &d, &f);
   1.126 +          get_bdf;
   1.127 +          get_bdf = next_bdf(&last, &seg, &b, &d, &f) )
   1.128      {
   1.129 -        /* Get next device bdf (bus, device, function) */
   1.130 -        next_bdf(direct_pci, &seg, &b, &d, &f);
   1.131 -
   1.132          /* Register real device with the emulated bus */
   1.133          pt_dev = register_real_device(e_bus, "DIRECT PCI", PT_VIRT_DEVFN_AUTO,
   1.134              b, d, f, PT_MACHINE_IRQ_AUTO, pci_access);
     2.1 --- a/tools/python/xen/lowlevel/xc/xc.c	Fri Oct 19 09:28:21 2007 +0100
     2.2 +++ b/tools/python/xen/lowlevel/xc/xc.c	Fri Oct 19 09:31:03 2007 +0100
     2.3 @@ -529,6 +529,86 @@ static PyObject *pyxc_set_hvm_param(XcOb
     2.4      return zero;
     2.5  }
     2.6  
     2.7 +static int token_value(char *token)
     2.8 +{
     2.9 +    token = strchr(token, 'x');
    2.10 +    token = token + 1;
    2.11 +
    2.12 +    return ((int) strtol(token, NULL, 16));
    2.13 +}
    2.14 +
    2.15 +static int first_bdf(char *pci_str, char **last,
    2.16 +                     int *seg, int *bus, int *dev, int *func)
    2.17 +{
    2.18 +    char *token;
    2.19 +
    2.20 +    token = strtok_r(pci_str, ",", last);
    2.21 +    if ( !token )
    2.22 +        return 0;
    2.23 +
    2.24 +    *seg  = token_value(token);
    2.25 +    token = strtok_r(NULL, ",", last);
    2.26 +    *bus  = token_value(token);
    2.27 +    token = strtok_r(NULL, ",", last);
    2.28 +    *dev  = token_value(token);
    2.29 +    token = strtok_r(NULL, ",", last);
    2.30 +    *func  = token_value(token);
    2.31 +
    2.32 +    return 1;
    2.33 +}
    2.34 +
    2.35 +static int next_bdf(char **last, int *seg, int *bus, int *dev, int *func)
    2.36 +{
    2.37 +    char *token;
    2.38 +
    2.39 +    token = strtok_r(NULL, ",", last);
    2.40 +    if ( !token )
    2.41 +        return 0;
    2.42 +
    2.43 +    *seg  = token_value(token);
    2.44 +    token = strtok_r(NULL, ",", last);
    2.45 +    *bus  = token_value(token);
    2.46 +    token = strtok_r(NULL, ",", last);
    2.47 +    *dev  = token_value(token);
    2.48 +    token = strtok_r(NULL, ",", last);
    2.49 +    *func  = token_value(token);
    2.50 +
    2.51 +    return 1;
    2.52 +}
    2.53 +
    2.54 +static PyObject *pyxc_assign_device(XcObject *self,
    2.55 +                                    PyObject *args,
    2.56 +                                    PyObject *kwds)
    2.57 +{
    2.58 +    uint32_t dom;
    2.59 +    char *pci_str;
    2.60 +    uint32_t bdf = 0;
    2.61 +    int seg, bus, dev, func;
    2.62 +    int get_bdf;
    2.63 +    char *last = NULL;
    2.64 +
    2.65 +    static char *kwd_list[] = { "domid", "pci", NULL };
    2.66 +    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|s", kwd_list,
    2.67 +                                      &dom, &pci_str) )
    2.68 +        return NULL;
    2.69 +
    2.70 +    for ( get_bdf = first_bdf(pci_str, &last, &seg, &bus, &dev, &func);
    2.71 +          get_bdf;
    2.72 +          get_bdf = next_bdf(&last, &seg, &bus, &dev, &func) )
    2.73 +    {
    2.74 +        bdf |= (bus & 0xff) << 16;
    2.75 +        bdf |= (dev & 0x1f) << 11;
    2.76 +        bdf |= (func & 0x7) << 8;
    2.77 +
    2.78 +        if ( xc_assign_device(self->xc_handle, dom, bdf) != 0 )
    2.79 +            break;
    2.80 +
    2.81 +        bdf = 0;
    2.82 +    }
    2.83 +
    2.84 +    return Py_BuildValue("i", bdf);
    2.85 +}
    2.86 +
    2.87  #ifdef __ia64__
    2.88  static PyObject *pyxc_nvram_init(XcObject *self,
    2.89                                   PyObject *args)
    2.90 @@ -1349,6 +1429,14 @@ static PyMethodDef pyxc_methods[] = {
    2.91        " value   [long]:     Value of param.\n"
    2.92        "Returns: [int] 0 on success.\n" },
    2.93  
    2.94 +     { "assign_device",
    2.95 +       (PyCFunction)pyxc_assign_device,
    2.96 +       METH_VARARGS | METH_KEYWORDS, "\n"
    2.97 +       "assign device with VT-d.\n"
    2.98 +       " dom     [int]:      Identifier of domain to build into.\n"
    2.99 +       " pci_str [str]:      PCI devices.\n"
   2.100 +       "Returns: [int] 0 on success, or device bdf that can't be assigned.\n" },
   2.101 +  
   2.102      { "sched_id_get",
   2.103        (PyCFunction)pyxc_sched_id_get,
   2.104        METH_NOARGS, "\n"
     3.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Fri Oct 19 09:28:21 2007 +0100
     3.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Fri Oct 19 09:31:03 2007 +0100
     3.3 @@ -1586,6 +1586,20 @@ class XendDomainInfo:
     3.4          # Set maximum number of vcpus in domain
     3.5          xc.domain_max_vcpus(self.domid, int(self.info['VCPUs_max']))
     3.6  
     3.7 +        # Assign devices with VT-d
     3.8 +        pci_str = str(self.info["platform"].get("pci"))
     3.9 +        if hvm and pci_str:
    3.10 +            bdf = xc.assign_device(self.domid, pci_str)
    3.11 +            if bdf != 0:
    3.12 +                bus = (bdf >> 16) & 0xff
    3.13 +                devfn = (bdf >> 8) & 0xff
    3.14 +                dev = (devfn >> 3) & 0x1f
    3.15 +                func = devfn & 0x7
    3.16 +                raise VmError("Fail to assign device(%x:%x.%x): maybe VT-d is "
    3.17 +                              "not enabled, or the device is not exist, or it "
    3.18 +                              "has already been assigned to other domain"
    3.19 +                              % (bus, dev, func))
    3.20 +
    3.21          # register the domain in the list 
    3.22          from xen.xend import XendDomain
    3.23          XendDomain.instance().add_domain(self)