diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in
index 6c12227b89..e7b11400cb 100644
--- a/docs/formatnode.html.in
+++ b/docs/formatnode.html.in
@@ -97,27 +97,38 @@
This optional element can occur multiple times. If it
exists, it has a mandatory type
attribute
- which will be set to
- either physical_function
- or virtual_functions
. If the type
- is physical_function
, there will be a
- single address
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 virtual_functions
, then this
- device is an SRIOV PF, and the capability element will
- have a list of address
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 maxCount
- 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 since
- 1.3.0 ; in this case, even if there are
- currently no active VFs the virtual_functions
- capabililty will still be shown.
+ which will be set to:
+
+ physical_function
+
+ That means there will be a single address
+ 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)).
+
+ virtual_function
+
+ In this case this device is an SRIOV PF, and the capability
+ element will have a list of address
+ 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 maxCount
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 since 1.3.0 ; in this case,
+ even if there are currently no active VFs the
+ virtual_functions capabililty will still be shown.
+
+ pci-bridge
or cardbus-bridge
+
+ 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.
+ Since 1.3.3
+
+
numa
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
index 744dccdf5f..949811cacb 100644
--- a/docs/schemas/nodedev.rng
+++ b/docs/schemas/nodedev.rng
@@ -168,6 +168,17 @@
+
+
+
+
+ pci-bridge
+ cardbus-bridge
+
+
+
+
+
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 0c9c348e37..611045c679 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -402,6 +402,12 @@ char *virNodeDeviceDefFormat(const virNodeDeviceDef *def)
if (data->pci_dev.numa_node >= 0)
virBufferAsprintf(&buf, " \n",
data->pci_dev.numa_node);
+
+ if (data->pci_dev.hdrType) {
+ virBufferAsprintf(&buf, " \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;
@@ -1272,6 +1278,7 @@ virNodeDevCapPCIDevParseXML(xmlXPathContextPtr ctxt,
xmlNodePtr orignode, iommuGroupNode, pciExpress;
int ret = -1;
virPCIEDeviceInfoPtr pci_express = NULL;
+ char *tmp = NULL;
orignode = ctxt->node;
ctxt->node = node;
@@ -1329,6 +1336,18 @@ virNodeDevCapPCIDevParseXML(xmlXPathContextPtr ctxt,
_("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;
@@ -1343,6 +1362,7 @@ virNodeDevCapPCIDevParseXML(xmlXPathContextPtr ctxt,
ret = 0;
out:
+ VIR_FREE(tmp);
virPCIEDeviceInfoFree(pci_express);
ctxt->node = orignode;
return ret;
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index d0071867cc..be6dd5eb4e 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -119,6 +119,7 @@ typedef struct _virNodeDevCapData {
unsigned int iommuGroupNumber;
int numa_node;
virPCIEDeviceInfoPtr pci_express;
+ int hdrType; /* enum virPCIHeaderType or -1 */
} pci_dev;
struct {
unsigned int bus;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 640c6b3138..ff803f996a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2010,11 +2010,14 @@ virPCIDeviceSetUsedBy;
virPCIDeviceUnbind;
virPCIDeviceWaitForCleanup;
virPCIEDeviceInfoFree;
+virPCIGetHeaderType;
virPCIGetNetName;
virPCIGetPhysicalFunction;
virPCIGetVirtualFunctionIndex;
virPCIGetVirtualFunctionInfo;
virPCIGetVirtualFunctions;
+virPCIHeaderTypeFromString;
+virPCIHeaderTypeToString;
virPCIIsVirtualFunction;
virPCIStubDriverTypeFromString;
virPCIStubDriverTypeToString;
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index aaee0e503d..6bff5bac73 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -506,6 +506,9 @@ static int udevProcessPCI(struct udev_device *device,
/* 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;
diff --git a/src/util/virpci.c b/src/util/virpci.c
index 1854318dd1..f7921f86d6 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -62,6 +62,12 @@ VIR_ENUM_IMPL(virPCIStubDriver, VIR_PCI_STUB_DRIVER_LAST,
"vfio-pci", /* VFIO */
);
+VIR_ENUM_IMPL(virPCIHeader, VIR_PCI_HEADER_LAST,
+ "endpoint",
+ "pci-bridge",
+ "cardbus-bridge",
+);
+
struct _virPCIDevice {
virPCIDeviceAddress address;
@@ -2883,6 +2889,33 @@ virPCIDeviceGetLinkCapSta(virPCIDevicePtr dev,
}
+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)
{
diff --git a/src/util/virpci.h b/src/util/virpci.h
index 55329c8a03..82f45ec417 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -62,6 +62,16 @@ typedef enum {
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 {
@@ -223,6 +233,8 @@ int virPCIDeviceGetLinkCapSta(virPCIDevicePtr dev,
unsigned int *sta_speed,
unsigned int *sta_width);
+int virPCIGetHeaderType(virPCIDevicePtr dev, int *hdrType);
+
void virPCIEDeviceInfoFree(virPCIEDeviceInfoPtr dev);
#endif /* __VIR_PCI_H__ */
diff --git a/tests/nodedevschemadata/pci_0000_00_02_0_header_type.xml b/tests/nodedevschemadata/pci_0000_00_02_0_header_type.xml
new file mode 100644
index 0000000000..5150fd1e8b
--- /dev/null
+++ b/tests/nodedevschemadata/pci_0000_00_02_0_header_type.xml
@@ -0,0 +1,15 @@
+
+ pci_0000_00_02_0
+ computer
+
+ 0
+ 0
+ 2
+ 0
+ 4th Gen Core Processor Integrated Graphics Controller
+ Intel Corporation
+
+
+
+
+
diff --git a/tests/nodedevschemadata/pci_0000_00_1c_0_header_type.xml b/tests/nodedevschemadata/pci_0000_00_1c_0_header_type.xml
new file mode 100644
index 0000000000..dea5f05237
--- /dev/null
+++ b/tests/nodedevschemadata/pci_0000_00_1c_0_header_type.xml
@@ -0,0 +1,20 @@
+
+ pci_0000_00_1c_0
+ computer
+
+ 0
+ 0
+ 28
+ 0
+ 8 Series/C220 Series Chipset Family PCI Express Root Port #1
+ Intel Corporation
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
index 0089b5dadf..f519bce634 100644
--- a/tests/nodedevxml2xmltest.c
+++ b/tests/nodedevxml2xmltest.c
@@ -91,6 +91,8 @@ mymain(void)
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;
}