mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
Add PCI VPD Capability Support
* XML serialization and deserialization of PCI VPD; * PCI VPD capability flags added and used in relevant places; * XML to XML tests for the added capability. Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Dmitrii Shcherbakov <dmitrii.shcherbakov@canonical.com>
This commit is contained in:
parent
38003e7551
commit
3954378d06
@ -223,6 +223,10 @@
|
||||
<ref name="mdev_types"/>
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<ref name="vpd"/>
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<element name="iommuGroup">
|
||||
<attribute name="number">
|
||||
@ -770,6 +774,80 @@
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="vpd">
|
||||
<element name="capability">
|
||||
<attribute name="type">
|
||||
<value>vpd</value>
|
||||
</attribute>
|
||||
<element name="name">
|
||||
<ref name="vpdFieldValueFormat"/>
|
||||
</element>
|
||||
<optional>
|
||||
<element name="fields">
|
||||
<attribute name="access">
|
||||
<value>readonly</value>
|
||||
</attribute>
|
||||
<optional>
|
||||
<element name="change_level">
|
||||
<ref name="vpdFieldValueFormat"/>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="manufacture_id">
|
||||
<ref name="vpdFieldValueFormat"/>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="part_number">
|
||||
<ref name="vpdFieldValueFormat"/>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="serial_number">
|
||||
<ref name="vpdFieldValueFormat"/>
|
||||
</element>
|
||||
</optional>
|
||||
<zeroOrMore>
|
||||
<element name="vendor_field">
|
||||
<attribute name="index">
|
||||
<ref name="vendorVPDFieldIndex"/>
|
||||
</attribute>
|
||||
<ref name="vpdFieldValueFormat"/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="fields">
|
||||
<attribute name="access">
|
||||
<value>readwrite</value>
|
||||
</attribute>
|
||||
<optional>
|
||||
<element name="asset_tag">
|
||||
<ref name="vpdFieldValueFormat"/>
|
||||
</element>
|
||||
</optional>
|
||||
<zeroOrMore>
|
||||
<element name="vendor_field">
|
||||
<attribute name="index">
|
||||
<ref name="vendorVPDFieldIndex"/>
|
||||
</attribute>
|
||||
<ref name="vpdFieldValueFormat"/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
<zeroOrMore>
|
||||
<element name="system_field">
|
||||
<attribute name="index">
|
||||
<ref name="systemVPDFieldIndex"/>
|
||||
</attribute>
|
||||
<ref name="vpdFieldValueFormat"/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="apDomainRange">
|
||||
<choice>
|
||||
<data type="string">
|
||||
@ -782,4 +860,22 @@
|
||||
</choice>
|
||||
</define>
|
||||
|
||||
<define name="vpdFieldValueFormat">
|
||||
<data type="string">
|
||||
<param name="pattern">[0-9a-zA-F -_,.:;=]{0,255}</param>
|
||||
</data>
|
||||
</define>
|
||||
|
||||
<define name="vendorVPDFieldIndex">
|
||||
<data type="string">
|
||||
<param name="pattern">[0-9A-Z]{1}</param>
|
||||
</data>
|
||||
</define>
|
||||
|
||||
<define name="systemVPDFieldIndex">
|
||||
<data type="string">
|
||||
<param name="pattern">[0-9B-Z]{1}</param>
|
||||
</data>
|
||||
</define>
|
||||
|
||||
</grammar>
|
||||
|
@ -84,6 +84,7 @@ typedef enum {
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_CARD = 1 << 18, /* s390 AP Card device */
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_QUEUE = 1 << 19, /* s390 AP Queue */
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX = 1 << 20, /* s390 AP Matrix */
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD = 1 << 21, /* Device with VPD */
|
||||
|
||||
/* filter the devices by active state */
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_INACTIVE = 1 << 30, /* Inactive devices */
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "virrandom.h"
|
||||
#include "virlog.h"
|
||||
#include "virfcp.h"
|
||||
#include "virpcivpd.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_NODEDEV
|
||||
|
||||
@ -70,6 +71,7 @@ VIR_ENUM_IMPL(virNodeDevCap,
|
||||
"ap_card",
|
||||
"ap_queue",
|
||||
"ap_matrix",
|
||||
"vpd",
|
||||
);
|
||||
|
||||
VIR_ENUM_IMPL(virNodeDevNetCap,
|
||||
@ -240,6 +242,77 @@ virNodeDeviceCapMdevTypesFormat(virBuffer *buf,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
virNodeDeviceCapVPDFormatCustomVendorField(virPCIVPDResourceCustom *field, virBuffer *buf)
|
||||
{
|
||||
if (field == NULL || field->value == NULL)
|
||||
return;
|
||||
|
||||
virBufferAsprintf(buf, "<vendor_field index='%c'>%s</vendor_field>\n", field->idx,
|
||||
field->value);
|
||||
}
|
||||
|
||||
static void
|
||||
virNodeDeviceCapVPDFormatCustomSystemField(virPCIVPDResourceCustom *field, virBuffer *buf)
|
||||
{
|
||||
if (field == NULL || field->value == NULL)
|
||||
return;
|
||||
|
||||
virBufferAsprintf(buf, "<system_field index='%c'>%s</system_field>\n", field->idx,
|
||||
field->value);
|
||||
}
|
||||
|
||||
static inline void
|
||||
virNodeDeviceCapVPDFormatRegularField(virBuffer *buf, const char *keyword, const char *value)
|
||||
{
|
||||
if (keyword == NULL || value == NULL)
|
||||
return;
|
||||
|
||||
virBufferAsprintf(buf, "<%s>%s</%s>\n", keyword, value, keyword);
|
||||
}
|
||||
|
||||
static void
|
||||
virNodeDeviceCapVPDFormat(virBuffer *buf, virPCIVPDResource *res)
|
||||
{
|
||||
if (res == NULL)
|
||||
return;
|
||||
|
||||
virBufferAddLit(buf, "<capability type='vpd'>\n");
|
||||
virBufferAdjustIndent(buf, 2);
|
||||
virBufferEscapeString(buf, "<name>%s</name>\n", res->name);
|
||||
|
||||
if (res->ro != NULL) {
|
||||
virBufferEscapeString(buf, "<fields access='%s'>\n", "readonly");
|
||||
|
||||
virBufferAdjustIndent(buf, 2);
|
||||
virNodeDeviceCapVPDFormatRegularField(buf, "change_level", res->ro->change_level);
|
||||
virNodeDeviceCapVPDFormatRegularField(buf, "manufacture_id", res->ro->manufacture_id);
|
||||
virNodeDeviceCapVPDFormatRegularField(buf, "part_number", res->ro->part_number);
|
||||
virNodeDeviceCapVPDFormatRegularField(buf, "serial_number", res->ro->serial_number);
|
||||
g_ptr_array_foreach(res->ro->vendor_specific,
|
||||
(GFunc)virNodeDeviceCapVPDFormatCustomVendorField, buf);
|
||||
virBufferAdjustIndent(buf, -2);
|
||||
|
||||
virBufferAddLit(buf, "</fields>\n");
|
||||
}
|
||||
|
||||
if (res->rw != NULL) {
|
||||
virBufferEscapeString(buf, "<fields access='%s'>\n", "readwrite");
|
||||
|
||||
virBufferAdjustIndent(buf, 2);
|
||||
virNodeDeviceCapVPDFormatRegularField(buf, "asset_tag", res->rw->asset_tag);
|
||||
g_ptr_array_foreach(res->rw->vendor_specific,
|
||||
(GFunc)virNodeDeviceCapVPDFormatCustomVendorField, buf);
|
||||
g_ptr_array_foreach(res->rw->system_specific,
|
||||
(GFunc)virNodeDeviceCapVPDFormatCustomSystemField, buf);
|
||||
virBufferAdjustIndent(buf, -2);
|
||||
|
||||
virBufferAddLit(buf, "</fields>\n");
|
||||
}
|
||||
|
||||
virBufferAdjustIndent(buf, -2);
|
||||
virBufferAddLit(buf, "</capability>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
virNodeDeviceCapPCIDefFormat(virBuffer *buf,
|
||||
@ -315,6 +388,9 @@ virNodeDeviceCapPCIDefFormat(virBuffer *buf,
|
||||
data->pci_dev.mdev_types,
|
||||
data->pci_dev.nmdev_types);
|
||||
}
|
||||
if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_VPD) {
|
||||
virNodeDeviceCapVPDFormat(buf, data->pci_dev.vpd);
|
||||
}
|
||||
if (data->pci_dev.nIommuGroupDevices) {
|
||||
virBufferAsprintf(buf, "<iommuGroup number='%d'>\n",
|
||||
data->pci_dev.iommuGroupNumber);
|
||||
@ -673,6 +749,7 @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def)
|
||||
case VIR_NODE_DEV_CAP_MDEV_TYPES:
|
||||
case VIR_NODE_DEV_CAP_FC_HOST:
|
||||
case VIR_NODE_DEV_CAP_VPORTS:
|
||||
case VIR_NODE_DEV_CAP_VPD:
|
||||
case VIR_NODE_DEV_CAP_LAST:
|
||||
break;
|
||||
}
|
||||
@ -859,6 +936,180 @@ virNodeDevCapMdevTypesParseXML(xmlXPathContextPtr ctxt,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
virNodeDeviceCapVPDParseCustomFields(xmlXPathContextPtr ctxt, virPCIVPDResource *res, bool readOnly)
|
||||
{
|
||||
int nfields = -1;
|
||||
g_autofree char *index = NULL, *value = NULL, *keyword = NULL;
|
||||
g_autofree xmlNodePtr *nodes = NULL;
|
||||
xmlNodePtr orignode = NULL;
|
||||
size_t i = 0;
|
||||
|
||||
orignode = ctxt->node;
|
||||
if ((nfields = virXPathNodeSet("./vendor_field[@index]", ctxt, &nodes)) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("failed to evaluate <vendor_field> elements"));
|
||||
ctxt->node = orignode;
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < nfields; i++) {
|
||||
ctxt->node = nodes[i];
|
||||
if (!(index = virXPathStringLimit("string(./@index[1])", 2, ctxt))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("<vendor_field> evaluation has failed"));
|
||||
continue;
|
||||
}
|
||||
if (!(value = virXPathString("string(./text())", ctxt))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("<vendor_field> value evaluation has failed"));
|
||||
continue;
|
||||
}
|
||||
keyword = g_strdup_printf("V%c", index[0]);
|
||||
virPCIVPDResourceUpdateKeyword(res, readOnly, keyword, value);
|
||||
g_free(g_steal_pointer(&index));
|
||||
g_free(g_steal_pointer(&keyword));
|
||||
g_free(g_steal_pointer(&value));
|
||||
}
|
||||
g_free(g_steal_pointer(&nodes));
|
||||
ctxt->node = orignode;
|
||||
|
||||
if (!readOnly) {
|
||||
if ((nfields = virXPathNodeSet("./system_field[@index]", ctxt, &nodes)) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("failed to evaluate <system_field> elements"));
|
||||
ctxt->node = orignode;
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < nfields; i++) {
|
||||
ctxt->node = nodes[i];
|
||||
if (!(index = virXPathStringLimit("string(./@index[1])", 2, ctxt))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("<system_field> evaluation has failed"));
|
||||
continue;
|
||||
}
|
||||
if (!(value = virXPathString("string(./text())", ctxt))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("<system_field> value evaluation has failed"));
|
||||
continue;
|
||||
}
|
||||
keyword = g_strdup_printf("Y%c", index[0]);
|
||||
virPCIVPDResourceUpdateKeyword(res, readOnly, keyword, value);
|
||||
g_free(g_steal_pointer(&index));
|
||||
g_free(g_steal_pointer(&keyword));
|
||||
g_free(g_steal_pointer(&value));
|
||||
}
|
||||
ctxt->node = orignode;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virNodeDeviceCapVPDParseReadOnlyFields(xmlXPathContextPtr ctxt, virPCIVPDResource *res)
|
||||
{
|
||||
const char *keywords[] = {"change_level", "manufacture_id",
|
||||
"serial_number", "part_number", NULL};
|
||||
g_autofree char *expression = NULL;
|
||||
g_autofree char *result = NULL;
|
||||
size_t i = 0;
|
||||
|
||||
if (res == NULL)
|
||||
return -1;
|
||||
|
||||
res->ro = virPCIVPDResourceRONew();
|
||||
|
||||
while (keywords[i]) {
|
||||
expression = g_strdup_printf("string(./%s)", keywords[i]);
|
||||
result = virXPathString(expression, ctxt);
|
||||
virPCIVPDResourceUpdateKeyword(res, true, keywords[i], result);
|
||||
g_free(g_steal_pointer(&expression));
|
||||
g_free(g_steal_pointer(&result));
|
||||
++i;
|
||||
}
|
||||
if (virNodeDeviceCapVPDParseCustomFields(ctxt, res, true) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virNodeDeviceCapVPDParseReadWriteFields(xmlXPathContextPtr ctxt, virPCIVPDResource *res)
|
||||
{
|
||||
g_autofree char *assetTag = virXPathString("string(./asset_tag)", ctxt);
|
||||
res->rw = virPCIVPDResourceRWNew();
|
||||
virPCIVPDResourceUpdateKeyword(res, false, "asset_tag", assetTag);
|
||||
if (virNodeDeviceCapVPDParseCustomFields(ctxt, res, false) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virNodeDeviceCapVPDParseXML(xmlXPathContextPtr ctxt, virPCIVPDResource **res)
|
||||
{
|
||||
xmlNodePtr orignode = NULL;
|
||||
g_autofree xmlNodePtr *nodes = NULL;
|
||||
int nfields = -1;
|
||||
g_autofree char *access = NULL;
|
||||
size_t i = 0;
|
||||
g_autoptr(virPCIVPDResource) newres = g_new0(virPCIVPDResource, 1);
|
||||
|
||||
if (res == NULL)
|
||||
return -1;
|
||||
|
||||
orignode = ctxt->node;
|
||||
|
||||
if (!(newres->name = virXPathString("string(./name)", ctxt))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("Could not read a device name from the <name> element"));
|
||||
ctxt->node = orignode;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((nfields = virXPathNodeSet("./fields[@access]", ctxt, &nodes)) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("no VPD <fields> elements with an access type attribute found"));
|
||||
ctxt->node = orignode;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < nfields; i++) {
|
||||
ctxt->node = nodes[i];
|
||||
if (!(access = virXPathString("string(./@access[1])", ctxt))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("VPD fields access type parsing has failed"));
|
||||
ctxt->node = orignode;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (STREQ(access, "readonly")) {
|
||||
if (virNodeDeviceCapVPDParseReadOnlyFields(ctxt, newres) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("Could not parse %s VPD resource fields"), access);
|
||||
return -1;
|
||||
}
|
||||
} else if (STREQ(access, "readwrite")) {
|
||||
if (virNodeDeviceCapVPDParseReadWriteFields(ctxt, newres) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("Could not parse %s VPD resource fields"), access);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
virReportError(VIR_ERR_XML_ERROR, _("Unsupported VPD field access type specified %s"),
|
||||
access);
|
||||
return -1;
|
||||
}
|
||||
g_free(g_steal_pointer(&access));
|
||||
}
|
||||
ctxt->node = orignode;
|
||||
|
||||
/* Replace the existing VPD representation if there is one already. */
|
||||
if (*res != NULL)
|
||||
virPCIVPDResourceFree(*res);
|
||||
|
||||
*res = g_steal_pointer(&newres);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virNodeDevAPMatrixCapabilityParseXML(xmlXPathContextPtr ctxt,
|
||||
@ -1718,6 +1969,10 @@ virNodeDevPCICapabilityParseXML(xmlXPathContextPtr ctxt,
|
||||
&pci_dev->nmdev_types) < 0)
|
||||
return -1;
|
||||
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_MDEV;
|
||||
} else if (STREQ(type, "vpd")) {
|
||||
if (virNodeDeviceCapVPDParseXML(ctxt, &pci_dev->vpd) < 0)
|
||||
return -1;
|
||||
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VPD;
|
||||
} else {
|
||||
int hdrType = virPCIHeaderTypeFromString(type);
|
||||
|
||||
@ -2024,6 +2279,7 @@ virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
|
||||
case VIR_NODE_DEV_CAP_VPORTS:
|
||||
case VIR_NODE_DEV_CAP_SCSI_GENERIC:
|
||||
case VIR_NODE_DEV_CAP_VDPA:
|
||||
case VIR_NODE_DEV_CAP_VPD:
|
||||
case VIR_NODE_DEV_CAP_LAST:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unknown capability type '%d' for '%s'"),
|
||||
@ -2287,6 +2543,7 @@ virNodeDevCapsDefFree(virNodeDevCapsDef *caps)
|
||||
for (i = 0; i < data->pci_dev.nmdev_types; i++)
|
||||
virMediatedDeviceTypeFree(data->pci_dev.mdev_types[i]);
|
||||
g_free(data->pci_dev.mdev_types);
|
||||
virPCIVPDResourceFree(g_steal_pointer(&data->pci_dev.vpd));
|
||||
break;
|
||||
case VIR_NODE_DEV_CAP_USB_DEV:
|
||||
g_free(data->usb_dev.product_name);
|
||||
@ -2352,6 +2609,7 @@ virNodeDevCapsDefFree(virNodeDevCapsDef *caps)
|
||||
case VIR_NODE_DEV_CAP_VDPA:
|
||||
case VIR_NODE_DEV_CAP_AP_CARD:
|
||||
case VIR_NODE_DEV_CAP_AP_QUEUE:
|
||||
case VIR_NODE_DEV_CAP_VPD:
|
||||
case VIR_NODE_DEV_CAP_LAST:
|
||||
/* This case is here to shutup the compiler */
|
||||
break;
|
||||
@ -2418,6 +2676,7 @@ virNodeDeviceUpdateCaps(virNodeDeviceDef *def)
|
||||
case VIR_NODE_DEV_CAP_VDPA:
|
||||
case VIR_NODE_DEV_CAP_AP_CARD:
|
||||
case VIR_NODE_DEV_CAP_AP_QUEUE:
|
||||
case VIR_NODE_DEV_CAP_VPD:
|
||||
case VIR_NODE_DEV_CAP_LAST:
|
||||
break;
|
||||
}
|
||||
@ -2489,6 +2748,10 @@ virNodeDeviceCapsListExport(virNodeDeviceDef *def,
|
||||
MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_MDEV_TYPES);
|
||||
ncaps++;
|
||||
}
|
||||
if (flags & VIR_NODE_DEV_CAP_FLAG_PCI_VPD) {
|
||||
MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_VPD);
|
||||
ncaps++;
|
||||
}
|
||||
}
|
||||
|
||||
if (caps->data.type == VIR_NODE_DEV_CAP_CSS_DEV) {
|
||||
@ -2749,6 +3012,44 @@ virNodeDeviceGetMdevTypesCaps(const char *sysfspath,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* virNodeDeviceGetPCIVPDDynamicCap:
|
||||
* @devCapPCIDev: a virNodeDevCapPCIDev for which to add VPD resources.
|
||||
*
|
||||
* While VPD has a read-only portion, there may be a read-write portion per
|
||||
* the specs which may change dynamically.
|
||||
*
|
||||
* Returns: 0 if the operation was successful (even if VPD is not present for
|
||||
* that device since it is optional in the specs, -1 otherwise.
|
||||
*/
|
||||
static int
|
||||
virNodeDeviceGetPCIVPDDynamicCap(virNodeDevCapPCIDev *devCapPCIDev)
|
||||
{
|
||||
g_autoptr(virPCIDevice) pciDev = NULL;
|
||||
virPCIDeviceAddress devAddr;
|
||||
g_autoptr(virPCIVPDResource) res = NULL;
|
||||
|
||||
devAddr.domain = devCapPCIDev->domain;
|
||||
devAddr.bus = devCapPCIDev->bus;
|
||||
devAddr.slot = devCapPCIDev->slot;
|
||||
devAddr.function = devCapPCIDev->function;
|
||||
|
||||
if (!(pciDev = virPCIDeviceNew(&devAddr)))
|
||||
return -1;
|
||||
|
||||
if (virPCIDeviceHasVPD(pciDev)) {
|
||||
/* VPD is optional in PCI(e) specs. If it is there, attempt to add it. */
|
||||
if ((res = virPCIDeviceGetVPD(pciDev))) {
|
||||
devCapPCIDev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VPD;
|
||||
devCapPCIDev->vpd = g_steal_pointer(&res);
|
||||
} else {
|
||||
virPCIVPDResourceFree(g_steal_pointer(&devCapPCIDev->vpd));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* virNodeDeviceGetPCIDynamicCaps() get info that is stored in sysfs
|
||||
* about devices related to this device, i.e. things that can change
|
||||
* without this device itself changing. These must be refreshed
|
||||
@ -2771,6 +3072,9 @@ virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath,
|
||||
if (pci_dev->nmdev_types > 0)
|
||||
pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_MDEV;
|
||||
|
||||
if (virNodeDeviceGetPCIVPDDynamicCap(pci_dev) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "internal.h"
|
||||
#include "virbitmap.h"
|
||||
#include "virpcivpd.h"
|
||||
#include "virscsihost.h"
|
||||
#include "virpci.h"
|
||||
#include "virvhba.h"
|
||||
@ -69,6 +70,7 @@ typedef enum {
|
||||
VIR_NODE_DEV_CAP_AP_CARD, /* s390 AP Card device */
|
||||
VIR_NODE_DEV_CAP_AP_QUEUE, /* s390 AP Queue */
|
||||
VIR_NODE_DEV_CAP_AP_MATRIX, /* s390 AP Matrix device */
|
||||
VIR_NODE_DEV_CAP_VPD, /* Device provides VPD */
|
||||
|
||||
VIR_NODE_DEV_CAP_LAST
|
||||
} virNodeDevCapType;
|
||||
@ -103,6 +105,7 @@ typedef enum {
|
||||
VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION = (1 << 1),
|
||||
VIR_NODE_DEV_CAP_FLAG_PCIE = (1 << 2),
|
||||
VIR_NODE_DEV_CAP_FLAG_PCI_MDEV = (1 << 3),
|
||||
VIR_NODE_DEV_CAP_FLAG_PCI_VPD = (1 << 4),
|
||||
} virNodeDevPCICapFlags;
|
||||
|
||||
typedef enum {
|
||||
@ -181,6 +184,7 @@ struct _virNodeDevCapPCIDev {
|
||||
int hdrType; /* enum virPCIHeaderType or -1 */
|
||||
virMediatedDeviceType **mdev_types;
|
||||
size_t nmdev_types;
|
||||
virPCIVPDResource *vpd;
|
||||
};
|
||||
|
||||
typedef struct _virNodeDevCapUSBDev virNodeDevCapUSBDev;
|
||||
@ -418,7 +422,8 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNodeDevCapsDef, virNodeDevCapsDefFree);
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_CAP_VDPA | \
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_CARD | \
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_QUEUE | \
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX)
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX | \
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD)
|
||||
|
||||
#define VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_ACTIVE \
|
||||
VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE | \
|
||||
|
@ -701,6 +701,9 @@ virNodeDeviceObjHasCap(const virNodeDeviceObj *obj,
|
||||
if (type == VIR_NODE_DEV_CAP_MDEV_TYPES &&
|
||||
(cap->data.pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV))
|
||||
return true;
|
||||
if (type == VIR_NODE_DEV_CAP_VPD &&
|
||||
(cap->data.pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_VPD))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case VIR_NODE_DEV_CAP_SCSI_HOST:
|
||||
@ -742,6 +745,7 @@ virNodeDeviceObjHasCap(const virNodeDeviceObj *obj,
|
||||
case VIR_NODE_DEV_CAP_VDPA:
|
||||
case VIR_NODE_DEV_CAP_AP_CARD:
|
||||
case VIR_NODE_DEV_CAP_AP_QUEUE:
|
||||
case VIR_NODE_DEV_CAP_VPD:
|
||||
case VIR_NODE_DEV_CAP_LAST:
|
||||
break;
|
||||
}
|
||||
@ -899,7 +903,8 @@ virNodeDeviceObjMatch(virNodeDeviceObj *obj,
|
||||
MATCH_CAP(VDPA) ||
|
||||
MATCH_CAP(AP_CARD) ||
|
||||
MATCH_CAP(AP_QUEUE) ||
|
||||
MATCH_CAP(AP_MATRIX)))
|
||||
MATCH_CAP(AP_MATRIX) ||
|
||||
MATCH_CAP(VPD)))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -708,6 +708,7 @@ nodeDeviceObjFormatAddress(virNodeDeviceObj *obj)
|
||||
case VIR_NODE_DEV_CAP_VDPA:
|
||||
case VIR_NODE_DEV_CAP_AP_CARD:
|
||||
case VIR_NODE_DEV_CAP_AP_QUEUE:
|
||||
case VIR_NODE_DEV_CAP_VPD:
|
||||
case VIR_NODE_DEV_CAP_LAST:
|
||||
break;
|
||||
}
|
||||
@ -1983,6 +1984,7 @@ int nodeDeviceDefValidate(virNodeDeviceDef *def,
|
||||
case VIR_NODE_DEV_CAP_AP_CARD:
|
||||
case VIR_NODE_DEV_CAP_AP_QUEUE:
|
||||
case VIR_NODE_DEV_CAP_AP_MATRIX:
|
||||
case VIR_NODE_DEV_CAP_VPD:
|
||||
case VIR_NODE_DEV_CAP_LAST:
|
||||
break;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "virnetdev.h"
|
||||
#include "virmdev.h"
|
||||
#include "virutil.h"
|
||||
#include "virpcivpd.h"
|
||||
|
||||
#include "configmake.h"
|
||||
|
||||
@ -1397,6 +1398,7 @@ udevGetDeviceDetails(struct udev_device *device,
|
||||
case VIR_NODE_DEV_CAP_AP_MATRIX:
|
||||
return udevProcessAPMatrix(device, def);
|
||||
case VIR_NODE_DEV_CAP_MDEV_TYPES:
|
||||
case VIR_NODE_DEV_CAP_VPD:
|
||||
case VIR_NODE_DEV_CAP_SYSTEM:
|
||||
case VIR_NODE_DEV_CAP_FC_HOST:
|
||||
case VIR_NODE_DEV_CAP_VPORTS:
|
||||
|
42
tests/nodedevschemadata/pci_0000_42_00_0_vpd.xml
Normal file
42
tests/nodedevschemadata/pci_0000_42_00_0_vpd.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<device>
|
||||
<name>pci_0000_42_00_0</name>
|
||||
<capability type='pci'>
|
||||
<class>0x020000</class>
|
||||
<domain>0</domain>
|
||||
<bus>66</bus>
|
||||
<slot>0</slot>
|
||||
<function>0</function>
|
||||
<product id='0xa2d6'>MT42822 BlueField-2 integrated ConnectX-6 Dx network controller</product>
|
||||
<vendor id='0x15b3'>Mellanox Technologies</vendor>
|
||||
<capability type='virt_functions' maxCount='16'/>
|
||||
<capability type='vpd'>
|
||||
<name>BlueField-2 DPU 25GbE Dual-Port SFP56, Crypto Enabled, 16GB on-board DDR, 1GbE OOB management, Tall Bracket</name>
|
||||
<fields access='readonly'>
|
||||
<change_level>B1</change_level>
|
||||
<manufacture_id>foobar</manufacture_id>
|
||||
<part_number>MBF2H332A-AEEOT</part_number>
|
||||
<serial_number>MT2113X00000</serial_number>
|
||||
<vendor_field index='0'>PCIeGen4 x8</vendor_field>
|
||||
<vendor_field index='2'>MBF2H332A-AEEOT</vendor_field>
|
||||
<vendor_field index='3'>3c53d07eec484d8aab34dabd24fe575aa</vendor_field>
|
||||
<vendor_field index='A'>MLX:MN=MLNX:CSKU=V2:UUID=V3:PCI=V0:MODL=BF2H332A</vendor_field>
|
||||
</fields>
|
||||
<fields access='readwrite'>
|
||||
<asset_tag>fooasset</asset_tag>
|
||||
<vendor_field index='0'>vendorfield0</vendor_field>
|
||||
<vendor_field index='2'>vendorfield2</vendor_field>
|
||||
<vendor_field index='A'>vendorfieldA</vendor_field>
|
||||
<system_field index='B'>systemfieldB</system_field>
|
||||
<system_field index='0'>systemfield0</system_field>
|
||||
</fields>
|
||||
</capability>
|
||||
<iommuGroup number='65'>
|
||||
<address domain='0x0000' bus='0x42' slot='0x00' function='0x0'/>
|
||||
</iommuGroup>
|
||||
<numa node='0'/>
|
||||
<pci-express>
|
||||
<link validity='cap' port='0' speed='16' width='8'/>
|
||||
<link validity='sta' speed='8' width='8'/>
|
||||
</pci-express>
|
||||
</capability>
|
||||
</device>
|
1
tests/nodedevxml2xmlout/pci_0000_42_00_0_vpd.xml
Symbolic link
1
tests/nodedevxml2xmlout/pci_0000_42_00_0_vpd.xml
Symbolic link
@ -0,0 +1 @@
|
||||
../nodedevschemadata/pci_0000_42_00_0_vpd.xml
|
@ -121,6 +121,7 @@ mymain(void)
|
||||
DO_TEST("pci_0000_02_10_7_sriov_pf_vfs_all_header_type");
|
||||
DO_TEST("drm_renderD129");
|
||||
DO_TEST("pci_0000_02_10_7_mdev_types");
|
||||
DO_TEST("pci_0000_42_00_0_vpd");
|
||||
DO_TEST("mdev_3627463d_b7f0_4fea_b468_f1da537d301b");
|
||||
DO_TEST("ccw_0_0_ffff");
|
||||
DO_TEST("css_0_0_ffff");
|
||||
|
@ -472,6 +472,9 @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
|
||||
case VIR_NODE_DEV_CAP_MDEV:
|
||||
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_MDEV;
|
||||
break;
|
||||
case VIR_NODE_DEV_CAP_VPD:
|
||||
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD;
|
||||
break;
|
||||
case VIR_NODE_DEV_CAP_CCW_DEV:
|
||||
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_CCW_DEV;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user