mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 03:25:20 +00:00
nodedev: add iommuGroup to node device object
This includes adding it to the nodedev parser and formatter, docs, and test. An example of the new iommuGroup element that is a part of the output from "virsh nodedev-dumpxml" (virNodeDeviceGetXMLDesc()): <device> <name>pci_0000_02_00_1</name> <capability type='pci'> ... <iommuGroup number='12'> <address domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> <address domain='0x0000' bus='0x02' slot='0x00' function='0x1'/> </iommuGroup> </capability> </device>
This commit is contained in:
parent
72c029d883
commit
8807b28559
@ -80,6 +80,36 @@
|
||||
<dd>Vendor details from the device ROM, including an
|
||||
attribute <code>id</code> with the hexadecimal vendor
|
||||
id, and an optional text name of that vendor.</dd>
|
||||
<dt><code>iommuGroup</code></dt>
|
||||
<dd>
|
||||
This optional element describes the "IOMMU group" this
|
||||
device belongs to. If the element exists, it has a
|
||||
mandatory <code>number</code> attribute which tells
|
||||
the group number used for management of the group (all
|
||||
devices in group "n" will be found in
|
||||
"/sys/kernel/iommu_groups/n"). It will also have a
|
||||
list of <code>address</code> subelements, each
|
||||
containing the PCI address of a device in the same
|
||||
group. The toplevel device will itself be included in
|
||||
this list.
|
||||
</dd>
|
||||
<dt><code>capability</code></dt>
|
||||
<dd>
|
||||
This optional element can occur multiple times. If it
|
||||
exists, it has a mandatory <code>type</code> attribute
|
||||
which will be set to
|
||||
either <code>physical_function</code>
|
||||
or <code>virtual_functions</code>. If the type
|
||||
is <code>physical_function</code>, there will be a
|
||||
single <code>address</code> subelement which contains
|
||||
the PCI address of the SRIOV Physical Function (PF)
|
||||
that is the parent of this device (and this device is,
|
||||
by implication, an SRIOV Virtual Function (VF)). If
|
||||
the type is <code>virtual_functions</code>, then this
|
||||
device is an SRIOV PF, and the capability element will
|
||||
have a list of <code>address</code> subelements, one
|
||||
for each VF on this PF.
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt><code>usb_device</code></dt>
|
||||
@ -232,7 +262,38 @@
|
||||
<address>00:27:13:6a:fe:00</address>
|
||||
<capability type='80203'/>
|
||||
</capability>
|
||||
</device></pre>
|
||||
</device>
|
||||
|
||||
<device>
|
||||
<name>pci_0000_02_00_0</name>
|
||||
<path>/sys/devices/pci0000:00/0000:00:04.0/0000:02:00.0</path>
|
||||
<parent>pci_0000_00_04_0</parent>
|
||||
<driver>
|
||||
<name>igb</name>
|
||||
</driver>
|
||||
<capability type='pci'>
|
||||
<domain>0</domain>
|
||||
<bus>2</bus>
|
||||
<slot>0</slot>
|
||||
<function>0</function>
|
||||
<product id='0x10c9'>82576 Gigabit Network Connection</product>
|
||||
<vendor id='0x8086'>Intel Corporation</vendor>
|
||||
<capability type='virt_functions'>
|
||||
<address domain='0x0000' bus='0x02' slot='0x10' function='0x0'/>
|
||||
<address domain='0x0000' bus='0x02' slot='0x10' function='0x2'/>
|
||||
<address domain='0x0000' bus='0x02' slot='0x10' function='0x4'/>
|
||||
<address domain='0x0000' bus='0x02' slot='0x10' function='0x6'/>
|
||||
<address domain='0x0000' bus='0x02' slot='0x11' function='0x0'/>
|
||||
<address domain='0x0000' bus='0x02' slot='0x11' function='0x2'/>
|
||||
<address domain='0x0000' bus='0x02' slot='0x11' function='0x4'/>
|
||||
</capability>
|
||||
<iommuGroup number='12'>
|
||||
<address domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
|
||||
<address domain='0x0000' bus='0x02' slot='0x00' function='0x1'/>
|
||||
</iommuGroup>
|
||||
</capability>
|
||||
</device>
|
||||
</pre>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -144,6 +144,17 @@
|
||||
</element>
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<element name='iommuGroup'>
|
||||
<attribute name='number'>
|
||||
<ref name='unsignedInt'/>
|
||||
</attribute>
|
||||
<oneOrMore>
|
||||
<ref name='address'/>
|
||||
</oneOrMore>
|
||||
</element>
|
||||
</optional>
|
||||
|
||||
</define>
|
||||
|
||||
<define name='capusbdev'>
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* node_device_conf.c: config handling for node devices
|
||||
*
|
||||
* Copyright (C) 2009-2013 Red Hat, Inc.
|
||||
* Copyright (C) 2008 Virtual Iron Software, Inc.
|
||||
* Copyright (C) 2008 David F. Lively
|
||||
*
|
||||
@ -31,6 +32,7 @@
|
||||
#include "viralloc.h"
|
||||
#include "virstring.h"
|
||||
#include "node_device_conf.h"
|
||||
#include "device_conf.h"
|
||||
#include "virxml.h"
|
||||
#include "virbuffer.h"
|
||||
#include "viruuid.h"
|
||||
@ -330,6 +332,20 @@ char *virNodeDeviceDefFormat(const virNodeDeviceDefPtr def)
|
||||
}
|
||||
virBufferAddLit(&buf, " </capability>\n");
|
||||
}
|
||||
if (data->pci_dev.nIommuGroupDevices) {
|
||||
virBufferAsprintf(&buf, " <iommuGroup number='%d'>\n",
|
||||
data->pci_dev.iommuGroupNumber);
|
||||
for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++) {
|
||||
virBufferAsprintf(&buf,
|
||||
" <address domain='0x%.4x' bus='0x%.2x' "
|
||||
"slot='0x%.2x' function='0x%.1x'/>\n",
|
||||
data->pci_dev.iommuGroupDevices[i]->domain,
|
||||
data->pci_dev.iommuGroupDevices[i]->bus,
|
||||
data->pci_dev.iommuGroupDevices[i]->slot,
|
||||
data->pci_dev.iommuGroupDevices[i]->function);
|
||||
}
|
||||
virBufferAddLit(&buf, " </iommuGroup>\n");
|
||||
}
|
||||
break;
|
||||
case VIR_NODE_DEV_CAP_USB_DEV:
|
||||
virBufferAsprintf(&buf, " <bus>%d</bus>\n", data->usb_dev.bus);
|
||||
@ -965,13 +981,72 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
virNodeDevCapPciDevIommuGroupParseXML(xmlXPathContextPtr ctxt,
|
||||
xmlNodePtr iommuGroupNode,
|
||||
union _virNodeDevCapData *data)
|
||||
{
|
||||
xmlNodePtr origNode = ctxt->node;
|
||||
xmlNodePtr *addrNodes = NULL;
|
||||
char *numberStr = NULL;
|
||||
int nAddrNodes, ii, ret = -1;
|
||||
virPCIDeviceAddressPtr pciAddr = NULL;
|
||||
|
||||
ctxt->node = iommuGroupNode;
|
||||
|
||||
numberStr = virXMLPropString(iommuGroupNode, "number");
|
||||
if (!numberStr) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
"%s", _("missing iommuGroup number attribute"));
|
||||
goto cleanup;
|
||||
}
|
||||
if (virStrToLong_ui(numberStr, NULL, 10,
|
||||
&data->pci_dev.iommuGroupNumber) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("invalid iommuGroup number attribute '%s'"),
|
||||
numberStr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((nAddrNodes = virXPathNodeSet("./address", ctxt, &addrNodes)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
for (ii = 0; ii < nAddrNodes; ii++) {
|
||||
virDevicePCIAddress addr = { 0, 0, 0, 0, 0 };
|
||||
if (virDevicePCIAddressParseXML(addrNodes[ii], &addr) < 0)
|
||||
goto cleanup;
|
||||
if (VIR_ALLOC(pciAddr) < 0) {
|
||||
virReportOOMError();
|
||||
goto cleanup;
|
||||
}
|
||||
pciAddr->domain = addr.domain;
|
||||
pciAddr->bus = addr.bus;
|
||||
pciAddr->slot = addr.slot;
|
||||
pciAddr->function = addr.function;
|
||||
if (VIR_APPEND_ELEMENT(data->pci_dev.iommuGroupDevices,
|
||||
data->pci_dev.nIommuGroupDevices,
|
||||
pciAddr) < 0) {
|
||||
virReportOOMError();
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
ctxt->node = origNode;
|
||||
VIR_FREE(addrNodes);
|
||||
VIR_FREE(pciAddr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virNodeDevCapPciDevParseXML(xmlXPathContextPtr ctxt,
|
||||
virNodeDeviceDefPtr def,
|
||||
xmlNodePtr node,
|
||||
union _virNodeDevCapData *data)
|
||||
{
|
||||
xmlNodePtr orignode;
|
||||
xmlNodePtr orignode, iommuGroupNode;
|
||||
int ret = -1;
|
||||
|
||||
orignode = ctxt->node;
|
||||
@ -1016,6 +1091,12 @@ virNodeDevCapPciDevParseXML(xmlXPathContextPtr ctxt,
|
||||
data->pci_dev.vendor_name = virXPathString("string(./vendor[1])", ctxt);
|
||||
data->pci_dev.product_name = virXPathString("string(./product[1])", ctxt);
|
||||
|
||||
if ((iommuGroupNode = virXPathNode("./iommuGroup[1]", ctxt))) {
|
||||
if (virNodeDevCapPciDevIommuGroupParseXML(ctxt, iommuGroupNode,
|
||||
data) < 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
ctxt->node = orignode;
|
||||
@ -1385,6 +1466,9 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
|
||||
for (i = 0; i < data->pci_dev.num_virtual_functions; i++) {
|
||||
VIR_FREE(data->pci_dev.virtual_functions[i]);
|
||||
}
|
||||
for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++) {
|
||||
VIR_FREE(data->pci_dev.iommuGroupDevices[i]);
|
||||
}
|
||||
break;
|
||||
case VIR_NODE_DEV_CAP_USB_DEV:
|
||||
VIR_FREE(data->usb_dev.product_name);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* node_device_conf.h: config handling for node devices
|
||||
*
|
||||
* Copyright (C) 2010-2011 Red Hat, Inc.
|
||||
* Copyright (C) 2009-2013 Red Hat, Inc.
|
||||
* Copyright (C) 2008 Virtual Iron Software, Inc.
|
||||
* Copyright (C) 2008 David F. Lively
|
||||
*
|
||||
@ -112,6 +112,9 @@ struct _virNodeDevCapsDef {
|
||||
virPCIDeviceAddressPtr *virtual_functions;
|
||||
unsigned int num_virtual_functions;
|
||||
unsigned int flags;
|
||||
virPCIDeviceAddressPtr *iommuGroupDevices;
|
||||
size_t nIommuGroupDevices;
|
||||
unsigned int iommuGroupNumber;
|
||||
} pci_dev;
|
||||
struct {
|
||||
unsigned int bus;
|
||||
|
@ -421,7 +421,8 @@ static int udevProcessPCI(struct udev_device *device,
|
||||
{
|
||||
const char *syspath = NULL;
|
||||
union _virNodeDevCapData *data = &def->caps->data;
|
||||
int ret = -1;
|
||||
virPCIDeviceAddress addr;
|
||||
int tmpGroup, ret = -1;
|
||||
char *p;
|
||||
int rc;
|
||||
|
||||
@ -501,6 +502,23 @@ static int udevProcessPCI(struct udev_device *device,
|
||||
else if (!rc && (data->pci_dev.num_virtual_functions > 0))
|
||||
data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
|
||||
|
||||
/* iommu group */
|
||||
addr.domain = data->pci_dev.domain;
|
||||
addr.bus = data->pci_dev.bus;
|
||||
addr.slot = data->pci_dev.slot;
|
||||
addr.function = data->pci_dev.function;
|
||||
tmpGroup = virPCIDeviceAddressGetIOMMUGroupNum(&addr);
|
||||
if (tmpGroup == -1) {
|
||||
/* error was already reported */
|
||||
goto out;
|
||||
/* -2 return means there is no iommu_group data */
|
||||
} else if (tmpGroup >= 0) {
|
||||
if (virPCIDeviceAddressGetIOMMUGroupAddresses(&addr, &data->pci_dev.iommuGroupDevices,
|
||||
&data->pci_dev.nIommuGroupDevices) < 0)
|
||||
goto out;
|
||||
data->pci_dev.iommuGroupNumber = tmpGroup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
|
16
tests/nodedevschemadata/pci_8086_10c9_sriov_pf.xml
Normal file
16
tests/nodedevschemadata/pci_8086_10c9_sriov_pf.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<device>
|
||||
<name>pci_0000_02_00_0</name>
|
||||
<parent>pci_0000_00_04_0</parent>
|
||||
<capability type='pci'>
|
||||
<domain>0</domain>
|
||||
<bus>2</bus>
|
||||
<slot>0</slot>
|
||||
<function>0</function>
|
||||
<product id='0x10c9'>82576 Gigabit Network Connection</product>
|
||||
<vendor id='0x8086'>Intel Corporation</vendor>
|
||||
<iommuGroup number='12'>
|
||||
<address domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
|
||||
<address domain='0x0000' bus='0x02' slot='0x00' function='0x1'/>
|
||||
</iommuGroup>
|
||||
</capability>
|
||||
</device>
|
@ -78,6 +78,7 @@ mymain(void)
|
||||
DO_TEST("net_00_13_02_b9_f9_d3");
|
||||
DO_TEST("net_00_15_58_2f_e9_55");
|
||||
DO_TEST("pci_1002_71c4");
|
||||
DO_TEST("pci_8086_10c9_sriov_pf");
|
||||
DO_TEST("pci_8086_27c5_scsi_host_0");
|
||||
DO_TEST("pci_8086_27c5_scsi_host_scsi_device_lun0");
|
||||
DO_TEST("pci_8086_27c5_scsi_host_scsi_host");
|
||||
|
Loading…
Reference in New Issue
Block a user