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>
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)