# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1192782663 -3600
# Node ID bc4afcd4c612afcee7f2fa2fc0ca400c26758876
# Parent 3ad0080ad9b56a8eb19433c61f6e3c5644fb6f2e
vt-d: Detect and report failure to assign a pass-thru PCI device.
Signed-off-by: Weidong Han <weidong.han@xxxxxxxxx>
---
tools/ioemu/hw/pass-through.c | 93 ++++++++++++++++----------------
tools/python/xen/lowlevel/xc/xc.c | 88 ++++++++++++++++++++++++++++++
tools/python/xen/xend/XendDomainInfo.py | 14 ++++
3 files changed, 149 insertions(+), 46 deletions(-)
diff -r 3ad0080ad9b5 -r bc4afcd4c612 tools/ioemu/hw/pass-through.c
--- a/tools/ioemu/hw/pass-through.c Fri Oct 19 09:28:21 2007 +0100
+++ b/tools/ioemu/hw/pass-through.c Fri Oct 19 09:31:03 2007 +0100
@@ -28,40 +28,52 @@
#include "pci/pci.h"
extern FILE *logfile;
-char *token;
-
-int pci_devs(const char *direct_pci)
-{
- int count = 0;
- const char *c;
-
- /* skip first "[" character */
- c = direct_pci + 1;
- while ((c = strchr(c, '[')) != NULL) {
- c++;
- count++;
- }
- return (count);
-}
-
-int next_token(char *direct_pci)
-{
- if (token == NULL)
- token = strtok(direct_pci, ",");
- else
- token = strtok(NULL, ",");
+
+static int token_value(char *token)
+{
token = strchr(token, 'x');
token = token + 1;
+
return ((int) strtol(token, NULL, 16));
}
-void next_bdf(char *direct_pci, int *seg,
- int *bus, int *dev, int *func)
-{
- *seg = next_token(direct_pci);
- *bus = next_token(direct_pci);
- *dev = next_token(direct_pci);
- *func = next_token(direct_pci);
+static int first_bdf(char *pci_str, char **last,
+ int *seg, int *bus, int *dev, int *func)
+{
+ char *token;
+
+ token = strtok_r(pci_str, ",", last);
+ if ( !token )
+ return 0;
+
+ *seg = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *bus = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *dev = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *func = token_value(token);
+
+ return 1;
+}
+
+static int next_bdf(char **last, int *seg, int *bus, int *dev, int *func)
+{
+ char *token;
+
+ token = strtok_r(NULL, ",", last);
+ if ( !token )
+ return 0;
+
+ *seg = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *bus = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *dev = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *func = token_value(token);
+
+ return 1;
}
uint8_t find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
@@ -333,7 +345,6 @@ struct pt_dev * register_real_device(PCI
int rc, i;
struct pt_dev *assigned_device = NULL;
struct pci_dev *pci_dev;
- struct pci_config_cf8 machine_bdf;
uint8_t e_device, e_intx;
PT_LOG("Assigning real physical device %02x:%02x.%x ...\n",
@@ -367,15 +378,6 @@ struct pt_dev * register_real_device(PCI
/* Issue PCIe FLR */
pdev_flr(pci_dev);
-
- /* Tell XEN vmm to change iommu settings */
- machine_bdf.reg = 0;
- machine_bdf.bus = r_bus;
- machine_bdf.dev = r_dev;
- machine_bdf.func = r_func;
- rc = xc_assign_device(xc_handle, domid, machine_bdf.value);
- if ( rc < 0 )
- PT_LOG("Error: xc_domain_assign_device error %d\n", rc);
/* Initialize virtualized PCI configuration (Extended 256 Bytes) */
for ( i = 0; i < PCI_CONFIG_SIZE; i++ )
@@ -417,11 +419,11 @@ struct pt_dev * register_real_device(PCI
int pt_init(PCIBus *e_bus, char *direct_pci)
{
- int i;
int seg, b, d, f;
struct pt_dev *pt_dev;
struct pci_access *pci_access;
- int dev_count = pci_devs(direct_pci);
+ int get_bdf;
+ char *last = NULL;
/* Initialize libpci */
pci_access = pci_alloc();
@@ -434,11 +436,10 @@ int pt_init(PCIBus *e_bus, char *direct_
pci_scan_bus(pci_access);
/* Assign given devices to guest */
- for ( i = 0; i < dev_count; i++ )
- {
- /* Get next device bdf (bus, device, function) */
- next_bdf(direct_pci, &seg, &b, &d, &f);
-
+ for ( get_bdf = first_bdf(direct_pci, &last, &seg, &b, &d, &f);
+ get_bdf;
+ get_bdf = next_bdf(&last, &seg, &b, &d, &f) )
+ {
/* Register real device with the emulated bus */
pt_dev = register_real_device(e_bus, "DIRECT PCI", PT_VIRT_DEVFN_AUTO,
b, d, f, PT_MACHINE_IRQ_AUTO, pci_access);
diff -r 3ad0080ad9b5 -r bc4afcd4c612 tools/python/xen/lowlevel/xc/xc.c
--- a/tools/python/xen/lowlevel/xc/xc.c Fri Oct 19 09:28:21 2007 +0100
+++ b/tools/python/xen/lowlevel/xc/xc.c Fri Oct 19 09:31:03 2007 +0100
@@ -529,6 +529,86 @@ static PyObject *pyxc_set_hvm_param(XcOb
return zero;
}
+static int token_value(char *token)
+{
+ token = strchr(token, 'x');
+ token = token + 1;
+
+ return ((int) strtol(token, NULL, 16));
+}
+
+static int first_bdf(char *pci_str, char **last,
+ int *seg, int *bus, int *dev, int *func)
+{
+ char *token;
+
+ token = strtok_r(pci_str, ",", last);
+ if ( !token )
+ return 0;
+
+ *seg = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *bus = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *dev = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *func = token_value(token);
+
+ return 1;
+}
+
+static int next_bdf(char **last, int *seg, int *bus, int *dev, int *func)
+{
+ char *token;
+
+ token = strtok_r(NULL, ",", last);
+ if ( !token )
+ return 0;
+
+ *seg = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *bus = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *dev = token_value(token);
+ token = strtok_r(NULL, ",", last);
+ *func = token_value(token);
+
+ return 1;
+}
+
+static PyObject *pyxc_assign_device(XcObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ uint32_t dom;
+ char *pci_str;
+ uint32_t bdf = 0;
+ int seg, bus, dev, func;
+ int get_bdf;
+ char *last = NULL;
+
+ static char *kwd_list[] = { "domid", "pci", NULL };
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|s", kwd_list,
+ &dom, &pci_str) )
+ return NULL;
+
+ for ( get_bdf = first_bdf(pci_str, &last, &seg, &bus, &dev, &func);
+ get_bdf;
+ get_bdf = next_bdf(&last, &seg, &bus, &dev, &func) )
+ {
+ bdf |= (bus & 0xff) << 16;
+ bdf |= (dev & 0x1f) << 11;
+ bdf |= (func & 0x7) << 8;
+
+ if ( xc_assign_device(self->xc_handle, dom, bdf) != 0 )
+ break;
+
+ bdf = 0;
+ }
+
+ return Py_BuildValue("i", bdf);
+}
+
#ifdef __ia64__
static PyObject *pyxc_nvram_init(XcObject *self,
PyObject *args)
@@ -1349,6 +1429,14 @@ static PyMethodDef pyxc_methods[] = {
" value [long]: Value of param.\n"
"Returns: [int] 0 on success.\n" },
+ { "assign_device",
+ (PyCFunction)pyxc_assign_device,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "assign device with VT-d.\n"
+ " dom [int]: Identifier of domain to build into.\n"
+ " pci_str [str]: PCI devices.\n"
+ "Returns: [int] 0 on success, or device bdf that can't be assigned.\n"
},
+
{ "sched_id_get",
(PyCFunction)pyxc_sched_id_get,
METH_NOARGS, "\n"
diff -r 3ad0080ad9b5 -r bc4afcd4c612 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py Fri Oct 19 09:28:21 2007 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py Fri Oct 19 09:31:03 2007 +0100
@@ -1586,6 +1586,20 @@ class XendDomainInfo:
# Set maximum number of vcpus in domain
xc.domain_max_vcpus(self.domid, int(self.info['VCPUs_max']))
+ # Assign devices with VT-d
+ pci_str = str(self.info["platform"].get("pci"))
+ if hvm and pci_str:
+ bdf = xc.assign_device(self.domid, pci_str)
+ if bdf != 0:
+ bus = (bdf >> 16) & 0xff
+ devfn = (bdf >> 8) & 0xff
+ dev = (devfn >> 3) & 0x1f
+ func = devfn & 0x7
+ raise VmError("Fail to assign device(%x:%x.%x): maybe VT-d is "
+ "not enabled, or the device is not exist, or it "
+ "has already been assigned to other domain"
+ % (bus, dev, func))
+
# register the domain in the list
from xen.xend import XendDomain
XendDomain.instance().add_domain(self)
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|