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; }