<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. If the host system supports
- reporting it (via the "sriov_maxvfs" file in the
- device's sysfs directory) the capability element will
- also have an attribute named <code>maxCount</code>
- which is the maximum number of SRIOV VFs supported by
- this device, which could be higher than the number of
- VFs that are curently active <span class="since">since
- 1.3.0</span>; in this case, even if there are
- currently no active VFs the virtual_functions
- capabililty will still be shown.
+ which will be set to:
+ <dl>
+ <dt><code>physical_function</code></dt>
+ <dd>
+ That means 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)).
+ </dd>
+ <dt><code>virtual_function</code></dt>
+ <dd>
+ In this case 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. If the host system
+ supports reporting it (via the "sriov_maxvfs" file in the
+ device's sysfs directory) the capability element will also
+ have an attribute named <code>maxCount</code> which is the
+ maximum number of SRIOV VFs supported by this device, which
+ could be higher than the number of VFs that are curently
+ active <span class="since">since 1.3.0</span>; in this case,
+ even if there are currently no active VFs the
+ virtual_functions capabililty will still be shown.
+ </dd>
+ <dt><code>pci-bridge</code> or <code>cardbus-bridge</code></dt>
+ <dd>
+ This shows merely that the lower 7 bits of PCI header type
+ have either value of 1 or 2 respectively. Usually this
+ means such device cannot be used for PCI passthrough.
+ <span class="since">Since 1.3.3</span>
+ </dd>
+ </dl>
</dd>
<dt><code>numa</code></dt>
<dd>
</element>
</optional>
+ <optional>
+ <element name='capability'>
+ <attribute name='type'>
+ <choice>
+ <value>pci-bridge</value>
+ <value>cardbus-bridge</value>
+ </choice>
+ </attribute>
+ </element>
+ </optional>
+
<optional>
<element name='pci-express'>
<zeroOrMore>
if (data->pci_dev.numa_node >= 0)
virBufferAsprintf(&buf, "<numa node='%d'/>\n",
data->pci_dev.numa_node);
+
+ if (data->pci_dev.hdrType) {
+ virBufferAsprintf(&buf, "<capability type='%s'/>\n",
+ virPCIHeaderTypeToString(data->pci_dev.hdrType));
+ }
+
if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCIE)
virPCIEDeviceInfoFormat(&buf, data->pci_dev.pci_express);
break;
xmlNodePtr orignode, iommuGroupNode, pciExpress;
int ret = -1;
virPCIEDeviceInfoPtr pci_express = NULL;
+ char *tmp = NULL;
orignode = ctxt->node;
ctxt->node = node;
_("invalid NUMA node ID supplied for '%s'")) < 0)
goto out;
+ if ((tmp = virXPathString("string(./capability[1]/@type)", ctxt))) {
+ int hdrType = virPCIHeaderTypeFromString(tmp);
+
+ if (hdrType <= 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown PCI header type '%s'"), tmp);
+ goto out;
+ }
+
+ data->pci_dev.hdrType = hdrType;
+ }
+
if ((pciExpress = virXPathNode("./pci-express[1]", ctxt))) {
if (VIR_ALLOC(pci_express) < 0)
goto out;
ret = 0;
out:
+ VIR_FREE(tmp);
virPCIEDeviceInfoFree(pci_express);
ctxt->node = orignode;
return ret;
unsigned int iommuGroupNumber;
int numa_node;
virPCIEDeviceInfoPtr pci_express;
+ int hdrType; /* enum virPCIHeaderType or -1 */
} pci_dev;
struct {
unsigned int bus;
virPCIDeviceUnbind;
virPCIDeviceWaitForCleanup;
virPCIEDeviceInfoFree;
+virPCIGetHeaderType;
virPCIGetNetName;
virPCIGetPhysicalFunction;
virPCIGetVirtualFunctionIndex;
virPCIGetVirtualFunctionInfo;
virPCIGetVirtualFunctions;
+virPCIHeaderTypeFromString;
+virPCIHeaderTypeToString;
virPCIIsVirtualFunction;
virPCIStubDriverTypeFromString;
virPCIStubDriverTypeToString;
/* We need to be root to read PCI device configs */
if (priv->privileged) {
+ if (virPCIGetHeaderType(pciDev, &data->pci_dev.hdrType) < 0)
+ goto out;
+
if (virPCIDeviceIsPCIExpress(pciDev) > 0) {
if (VIR_ALLOC(pci_express) < 0)
goto out;
"vfio-pci", /* VFIO */
);
+VIR_ENUM_IMPL(virPCIHeader, VIR_PCI_HEADER_LAST,
+ "endpoint",
+ "pci-bridge",
+ "cardbus-bridge",
+);
+
struct _virPCIDevice {
virPCIDeviceAddress address;
}
+int virPCIGetHeaderType(virPCIDevicePtr dev, int *hdrType)
+{
+ int fd;
+ uint8_t type;
+
+ *hdrType = -1;
+
+ if ((fd = virPCIDeviceConfigOpen(dev, true)) < 0)
+ return -1;
+
+ type = virPCIDeviceRead8(dev, fd, PCI_HEADER_TYPE);
+
+ virPCIDeviceConfigClose(dev, fd);
+
+ type &= PCI_HEADER_TYPE_MASK;
+ if (type >= VIR_PCI_HEADER_LAST) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown PCI header type '%d'"), type);
+ return -1;
+ }
+
+ *hdrType = type;
+
+ return 0;
+}
+
+
void
virPCIEDeviceInfoFree(virPCIEDeviceInfoPtr dev)
{
VIR_ENUM_DECL(virPCIELinkSpeed)
+typedef enum {
+ VIR_PCI_HEADER_ENDPOINT = 0,
+ VIR_PCI_HEADER_PCI_BRIDGE,
+ VIR_PCI_HEADER_CARDBUS_BRIDGE,
+
+ VIR_PCI_HEADER_LAST
+} virPCIHeaderType;
+
+VIR_ENUM_DECL(virPCIHeader)
+
typedef struct _virPCIELink virPCIELink;
typedef virPCIELink *virPCIELinkPtr;
struct _virPCIELink {
unsigned int *sta_speed,
unsigned int *sta_width);
+int virPCIGetHeaderType(virPCIDevicePtr dev, int *hdrType);
+
void virPCIEDeviceInfoFree(virPCIEDeviceInfoPtr dev);
#endif /* __VIR_PCI_H__ */
--- /dev/null
+<device>
+ <name>pci_0000_00_02_0</name>
+ <parent>computer</parent>
+ <capability type='pci'>
+ <domain>0</domain>
+ <bus>0</bus>
+ <slot>2</slot>
+ <function>0</function>
+ <product id='0x0416'>4th Gen Core Processor Integrated Graphics Controller</product>
+ <vendor id='0x8086'>Intel Corporation</vendor>
+ <iommuGroup number='1'>
+ <address domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </iommuGroup>
+ </capability>
+</device>
--- /dev/null
+<device>
+ <name>pci_0000_00_1c_0</name>
+ <parent>computer</parent>
+ <capability type='pci'>
+ <domain>0</domain>
+ <bus>0</bus>
+ <slot>28</slot>
+ <function>0</function>
+ <product id='0x8c10'>8 Series/C220 Series Chipset Family PCI Express Root Port #1</product>
+ <vendor id='0x8086'>Intel Corporation</vendor>
+ <iommuGroup number='8'>
+ <address domain='0x0000' bus='0x00' slot='0x1c' function='0x0'/>
+ </iommuGroup>
+ <capability type='pci-bridge'/>
+ <pci-express>
+ <link validity='cap' port='1' speed='5' width='1'/>
+ <link validity='sta' speed='2.5' width='1'/>
+ </pci-express>
+ </capability>
+</device>
DO_TEST("usb_device_1d6b_1_0000_00_1d_0");
DO_TEST("pci_8086_4238_pcie_wireless");
DO_TEST("pci_8086_0c0c_snd_hda_intel");
+ DO_TEST("pci_0000_00_02_0_header_type");
+ DO_TEST("pci_0000_00_1c_0_header_type");
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}