mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
iommu: Handle sibling device assignment correctly
Domctl interface is extended to allow libxc retrieve device group information from hypervisor. Vendor-specific iommu_ops is also extended by adding a new operation "get_device_group_id()", which is currently a null pointer but could be implemented later for vt-d. Error will be raised from tools side when user trying to assign PCI device with a sibling device being driven by dom0. User will keep being prompted until he has hidden the entire device group (at least, the sibling devices driven by dom0) in dom0 kernel parameter. Hopefully this framework could be flexible enough to support both amd iommu and vt-d. The following 2 cases are not covered by this patch, but should be easy to handle. * Checking for hot-plug devices (maybe we can delay calling ImageHandler.signalDeviceModel() until all checks are done?) * Checking for splitted device group between different passthru domains Signed-off-by: Wei Wang <wei.wang2@amd.com>
This commit is contained in:
1 parent
32c028cd83
commit
491c0ade25
10 files changed
+246
No files matched your search
@@ -646,6 +646,68 @@ static PyObject *pyxc_deassign_device(XcObject *self,
|
||||
return Py_BuildValue("i", bdf);
|
||||
}
|
||||
|
||||
static PyObject *pyxc_get_device_group(XcObject *self,
|
||||
PyObject *args)
|
||||
{
|
||||
domid_t domid;
|
||||
uint32_t bdf = 0;
|
||||
uint32_t max_sdevs, num_sdevs;
|
||||
int seg, bus, dev, func, rc, i;
|
||||
PyObject *Pystr;
|
||||
char *group_str;
|
||||
char dev_str[9];
|
||||
uint32_t *sdev_array;
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "iiiii", &domid, &seg, &bus, &dev, &func) )
|
||||
return NULL;
|
||||
|
||||
/* Maximum allowed siblings device number per group */
|
||||
max_sdevs = 1024;
|
||||
|
||||
if ( (sdev_array = malloc(max_sdevs * sizeof(*sdev_array))) == NULL )
|
||||
return PyErr_NoMemory();
|
||||
memset(sdev_array, 0, max_sdevs * sizeof(*sdev_array));
|
||||
|
||||
bdf |= (bus & 0xff) << 16;
|
||||
bdf |= (dev & 0x1f) << 11;
|
||||
bdf |= (func & 0x7) << 8;
|
||||
|
||||
rc = xc_get_device_group(self->xc_handle,
|
||||
domid, bdf, max_sdevs, &num_sdevs, sdev_array);
|
||||
|
||||
if ( rc < 0 )
|
||||
{
|
||||
free(sdev_array);
|
||||
return pyxc_error_to_exception();
|
||||
}
|
||||
|
||||
if ( !num_sdevs )
|
||||
{
|
||||
free(sdev_array);
|
||||
return Py_BuildValue("s", "");
|
||||
}
|
||||
|
||||
if ( (group_str = malloc(num_sdevs * sizeof(dev_str))) == NULL )
|
||||
return PyErr_NoMemory();
|
||||
memset(group_str, '\0', num_sdevs * sizeof(dev_str));
|
||||
|
||||
for ( i = 0; i < num_sdevs; i++ )
|
||||
{
|
||||
bus = (sdev_array[i] >> 16) & 0xff;
|
||||
dev = (sdev_array[i] >> 11) & 0x1f;
|
||||
func = (sdev_array[i] >> 8) & 0x7;
|
||||
sprintf(dev_str, "%02x:%02x.%x,", bus, dev, func);
|
||||
strcat(group_str, dev_str);
|
||||
}
|
||||
|
||||
Pystr = Py_BuildValue("s", group_str);
|
||||
|
||||
free(sdev_array);
|
||||
free(group_str);
|
||||
|
||||
return Pystr;
|
||||
}
|
||||
|
||||
#ifdef __ia64__
|
||||
static PyObject *pyxc_nvram_init(XcObject *self,
|
||||
PyObject *args)
|
||||
@@ -1584,6 +1646,17 @@ static PyMethodDef pyxc_methods[] = {
|
||||
" value [long]: Value of param.\n"
|
||||
"Returns: [int] 0 on success.\n" },
|
||||
|
||||
{ "get_device_group",
|
||||
(PyCFunction)pyxc_get_device_group,
|
||||
METH_VARARGS, "\n"
|
||||
"get sibling devices infomation.\n"
|
||||
" dom [int]: Domain to assign device to.\n"
|
||||
" seg [int]: PCI segment.\n"
|
||||
" bus [int]: PCI bus.\n"
|
||||
" dev [int]: PCI dev.\n"
|
||||
" func [int]: PCI func.\n"
|
||||
"Returns: [string]: Sibling devices \n" },
|
||||
|
||||
{ "test_assign_device",
|
||||
(PyCFunction)pyxc_test_assign_device,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
|
||||
@@ -226,6 +226,39 @@ class PciController(DevController):
|
||||
|
||||
return sxpr
|
||||
|
||||
def CheckSiblingDevices(self, domid, dev):
|
||||
""" Check if all sibling devices of dev are owned by pciback
|
||||
"""
|
||||
if not self.vm.info.is_hvm():
|
||||
return
|
||||
|
||||
group_str = xc.get_device_group(domid, dev.domain, dev.bus, dev.slot, dev.func)
|
||||
if group_str == "":
|
||||
return
|
||||
|
||||
#group string format xx:xx.x,xx:xx.x,
|
||||
devstr_len = group_str.find(',')
|
||||
for i in range(0, len(group_str), devstr_len + 1):
|
||||
(bus, slotfunc) = group_str[i:i + devstr_len].split(':')
|
||||
(slot, func) = slotfunc.split('.')
|
||||
b = parse_hex(bus)
|
||||
d = parse_hex(slot)
|
||||
f = parse_hex(func)
|
||||
try:
|
||||
sdev = PciDevice(dev.domain, b, d, f)
|
||||
except Exception, e:
|
||||
#no dom0 drivers bound to sdev
|
||||
continue
|
||||
|
||||
if sdev.driver!='pciback':
|
||||
raise VmError(("pci: PCI Backend does not own\n "+ \
|
||||
"sibling device %s of device %s\n"+ \
|
||||
"See the pciback.hide kernel "+ \
|
||||
"command-line parameter or\n"+ \
|
||||
"bind your slot/device to the PCI backend using sysfs" \
|
||||
)%(sdev.name, dev.name))
|
||||
return
|
||||
|
||||
def setupOneDevice(self, domain, bus, slot, func):
|
||||
""" Attach I/O resources for device to frontend domain
|
||||
"""
|
||||
@@ -245,6 +278,8 @@ class PciController(DevController):
|
||||
"bind your slot/device to the PCI backend using sysfs" \
|
||||
)%(dev.name))
|
||||
|
||||
self.CheckSiblingDevices(fe_domid, dev)
|
||||
|
||||
PCIQuirk(dev.vendor, dev.device, dev.subvendor, dev.subdevice, domain,
|
||||
bus, slot, func)
|
||||
|
||||
|
||||