mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-05 04:25:19 +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
|
<dd>Vendor details from the device ROM, including an
|
||||||
attribute <code>id</code> with the hexadecimal vendor
|
attribute <code>id</code> with the hexadecimal vendor
|
||||||
id, and an optional text name of that vendor.</dd>
|
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>
|
</dl>
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>usb_device</code></dt>
|
<dt><code>usb_device</code></dt>
|
||||||
@ -232,7 +262,38 @@
|
|||||||
<address>00:27:13:6a:fe:00</address>
|
<address>00:27:13:6a:fe:00</address>
|
||||||
<capability type='80203'/>
|
<capability type='80203'/>
|
||||||
</capability>
|
</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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -144,6 +144,17 @@
|
|||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
|
||||||
|
<optional>
|
||||||
|
<element name='iommuGroup'>
|
||||||
|
<attribute name='number'>
|
||||||
|
<ref name='unsignedInt'/>
|
||||||
|
</attribute>
|
||||||
|
<oneOrMore>
|
||||||
|
<ref name='address'/>
|
||||||
|
</oneOrMore>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
|
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
<define name='capusbdev'>
|
<define name='capusbdev'>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* node_device_conf.c: config handling for node devices
|
* 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 Virtual Iron Software, Inc.
|
||||||
* Copyright (C) 2008 David F. Lively
|
* Copyright (C) 2008 David F. Lively
|
||||||
*
|
*
|
||||||
@ -31,6 +32,7 @@
|
|||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
#include "virstring.h"
|
#include "virstring.h"
|
||||||
#include "node_device_conf.h"
|
#include "node_device_conf.h"
|
||||||
|
#include "device_conf.h"
|
||||||
#include "virxml.h"
|
#include "virxml.h"
|
||||||
#include "virbuffer.h"
|
#include "virbuffer.h"
|
||||||
#include "viruuid.h"
|
#include "viruuid.h"
|
||||||
@ -330,6 +332,20 @@ char *virNodeDeviceDefFormat(const virNodeDeviceDefPtr def)
|
|||||||
}
|
}
|
||||||
virBufferAddLit(&buf, " </capability>\n");
|
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;
|
break;
|
||||||
case VIR_NODE_DEV_CAP_USB_DEV:
|
case VIR_NODE_DEV_CAP_USB_DEV:
|
||||||
virBufferAsprintf(&buf, " <bus>%d</bus>\n", data->usb_dev.bus);
|
virBufferAsprintf(&buf, " <bus>%d</bus>\n", data->usb_dev.bus);
|
||||||
@ -965,13 +981,72 @@ out:
|
|||||||
return ret;
|
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
|
static int
|
||||||
virNodeDevCapPciDevParseXML(xmlXPathContextPtr ctxt,
|
virNodeDevCapPciDevParseXML(xmlXPathContextPtr ctxt,
|
||||||
virNodeDeviceDefPtr def,
|
virNodeDeviceDefPtr def,
|
||||||
xmlNodePtr node,
|
xmlNodePtr node,
|
||||||
union _virNodeDevCapData *data)
|
union _virNodeDevCapData *data)
|
||||||
{
|
{
|
||||||
xmlNodePtr orignode;
|
xmlNodePtr orignode, iommuGroupNode;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
orignode = ctxt->node;
|
orignode = ctxt->node;
|
||||||
@ -1016,6 +1091,12 @@ virNodeDevCapPciDevParseXML(xmlXPathContextPtr ctxt,
|
|||||||
data->pci_dev.vendor_name = virXPathString("string(./vendor[1])", ctxt);
|
data->pci_dev.vendor_name = virXPathString("string(./vendor[1])", ctxt);
|
||||||
data->pci_dev.product_name = virXPathString("string(./product[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;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
ctxt->node = orignode;
|
ctxt->node = orignode;
|
||||||
@ -1385,6 +1466,9 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
|
|||||||
for (i = 0; i < data->pci_dev.num_virtual_functions; i++) {
|
for (i = 0; i < data->pci_dev.num_virtual_functions; i++) {
|
||||||
VIR_FREE(data->pci_dev.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;
|
break;
|
||||||
case VIR_NODE_DEV_CAP_USB_DEV:
|
case VIR_NODE_DEV_CAP_USB_DEV:
|
||||||
VIR_FREE(data->usb_dev.product_name);
|
VIR_FREE(data->usb_dev.product_name);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* node_device_conf.h: config handling for node devices
|
* 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 Virtual Iron Software, Inc.
|
||||||
* Copyright (C) 2008 David F. Lively
|
* Copyright (C) 2008 David F. Lively
|
||||||
*
|
*
|
||||||
@ -112,6 +112,9 @@ struct _virNodeDevCapsDef {
|
|||||||
virPCIDeviceAddressPtr *virtual_functions;
|
virPCIDeviceAddressPtr *virtual_functions;
|
||||||
unsigned int num_virtual_functions;
|
unsigned int num_virtual_functions;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
virPCIDeviceAddressPtr *iommuGroupDevices;
|
||||||
|
size_t nIommuGroupDevices;
|
||||||
|
unsigned int iommuGroupNumber;
|
||||||
} pci_dev;
|
} pci_dev;
|
||||||
struct {
|
struct {
|
||||||
unsigned int bus;
|
unsigned int bus;
|
||||||
|
@ -421,7 +421,8 @@ static int udevProcessPCI(struct udev_device *device,
|
|||||||
{
|
{
|
||||||
const char *syspath = NULL;
|
const char *syspath = NULL;
|
||||||
union _virNodeDevCapData *data = &def->caps->data;
|
union _virNodeDevCapData *data = &def->caps->data;
|
||||||
int ret = -1;
|
virPCIDeviceAddress addr;
|
||||||
|
int tmpGroup, ret = -1;
|
||||||
char *p;
|
char *p;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -501,6 +502,23 @@ static int udevProcessPCI(struct udev_device *device,
|
|||||||
else if (!rc && (data->pci_dev.num_virtual_functions > 0))
|
else if (!rc && (data->pci_dev.num_virtual_functions > 0))
|
||||||
data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
|
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;
|
ret = 0;
|
||||||
|
|
||||||
out:
|
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_13_02_b9_f9_d3");
|
||||||
DO_TEST("net_00_15_58_2f_e9_55");
|
DO_TEST("net_00_15_58_2f_e9_55");
|
||||||
DO_TEST("pci_1002_71c4");
|
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_0");
|
||||||
DO_TEST("pci_8086_27c5_scsi_host_scsi_device_lun0");
|
DO_TEST("pci_8086_27c5_scsi_host_scsi_device_lun0");
|
||||||
DO_TEST("pci_8086_27c5_scsi_host_scsi_host");
|
DO_TEST("pci_8086_27c5_scsi_host_scsi_host");
|
||||||
|
Loading…
Reference in New Issue
Block a user