From nobody Mon Feb 9 17:57:33 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) client-ip=216.205.24.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=canonical.com Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by mx.zohomail.com with SMTPS id 1632320688771147.96654553405438; Wed, 22 Sep 2021 07:24:48 -0700 (PDT) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-197-YKJfhM5mNSa5lf-VNcuydQ-1; Wed, 22 Sep 2021 10:24:42 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 20E90839A00; Wed, 22 Sep 2021 14:24:37 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 87123652A6; Wed, 22 Sep 2021 14:24:36 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 4D46F1806D01; Wed, 22 Sep 2021 14:24:36 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 18MEODps028643 for ; Wed, 22 Sep 2021 10:24:13 -0400 Received: by smtp.corp.redhat.com (Postfix) id 3D8CE2077FD1; Wed, 22 Sep 2021 14:24:13 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast06.extmail.prod.ext.rdu2.redhat.com [10.11.55.22]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2B73A207A523 for ; Wed, 22 Sep 2021 14:24:02 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [205.139.110.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id CB13118A01C7 for ; Wed, 22 Sep 2021 14:24:02 +0000 (UTC) Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-604-ySM5XslPOcubaxUDns6_Ng-1; Wed, 22 Sep 2021 10:24:00 -0400 Received: from mail-lf1-f71.google.com (mail-lf1-f71.google.com [209.85.167.71]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 9E8A4402DE for ; Wed, 22 Sep 2021 14:23:59 +0000 (UTC) Received: by mail-lf1-f71.google.com with SMTP id g9-20020a0565123b8900b003f33a027130so2943720lfv.18 for ; Wed, 22 Sep 2021 07:23:59 -0700 (PDT) Received: from ws.. ([5.8.16.162]) by smtp.gmail.com with ESMTPSA id e3sm273868ljo.2.2021.09.22.07.23.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 Sep 2021 07:23:58 -0700 (PDT) X-MC-Unique: YKJfhM5mNSa5lf-VNcuydQ-1 X-MC-Unique: ySM5XslPOcubaxUDns6_Ng-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=T77B2b6TkJQ/AjFKJCA7VWGNBfsY7p8BZA6SVhVkN5w=; b=eXnX0eqLclRikMZg1SGug8qK7SaO/LY+/DgBlQgi5MY9UTH7qBex6z32iwXkanaCSc 2frayZDX41tzZtgmI8WFLv4WZjvwXZ0GyY5XYdWD7WJNoUkcojOpiStZhrOLJIVyHy49 S3z8yrd8+hwvzMP46fO84qe9yF3VKTdXu0c7F5o1w1OXKjzVgqyBINFcttQY15cKIME8 CoSHuF5Hm+oIKIEtHH/lZgTg/y4VCxKXM2svPVI2TmhRAGVSSRpLq8M8qbifbNuelBTW H9rdOkcBmpF52QQNvlkZqTWReeu5GD9gPON+Bi92WUbsF9OapxNFB4/cbxxd4pEZcnZe C7/Q== X-Gm-Message-State: AOAM533OR1iE7MU0dLIru10B8Qh2SOs4npoD+3LNTvqtw5eBAsb4z319 k9iJ0Afz0gR0YK08FIzzHeYKmbz0d4O+RID3CwMZG9LrrgbGWsxOBekQSI6D9ol+rMtXom8Vc3B fmP29klZMB6/MorX0yi+i+IxKmmn/k1jg3w== X-Received: by 2002:a2e:a785:: with SMTP id c5mr35156850ljf.434.1632320638901; Wed, 22 Sep 2021 07:23:58 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyW+hfACwuanngs9TksCqx4fhcbJHS3KdkYE82mRwU7O9QEpvafZa2JBS7nqkcPRDg5BvEzAQ== X-Received: by 2002:a2e:a785:: with SMTP id c5mr35156807ljf.434.1632320638386; Wed, 22 Sep 2021 07:23:58 -0700 (PDT) From: Dmitrii Shcherbakov To: dmitrii.shcherbakov@canonical.com, libvir-list@redhat.com Subject: [libvirt PATCH v4 3/4] Add PCI VPD Capability Support Date: Wed, 22 Sep 2021 17:23:52 +0300 Message-Id: <20210922142353.957080-4-dmitrii.shcherbakov@canonical.com> In-Reply-To: <20210922142353.957080-1-dmitrii.shcherbakov@canonical.com> References: <20210922142353.957080-1-dmitrii.shcherbakov@canonical.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 18MEODps028643 X-loop: libvir-list@redhat.com Cc: pkrempa@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1632320689232100001 Content-Type: text/plain; charset="utf-8" * XML serialization and deserialization of PCI VPD resources; * PCI VPD capability flags added and used in relevant places; * XML to XML tests for the added capability. --- docs/schemas/nodedev.rng | 40 +++ include/libvirt/libvirt-nodedev.h | 1 + src/conf/node_device_conf.c | 271 ++++++++++++++++++ src/conf/node_device_conf.h | 6 +- src/conf/virnodedeviceobj.c | 7 +- src/node_device/node_device_driver.c | 2 + src/node_device/node_device_udev.c | 2 + .../pci_0000_42_00_0_vpd.xml | 33 +++ .../pci_0000_42_00_0_vpd.xml | 1 + tests/nodedevxml2xmltest.c | 1 + tools/virsh-nodedev.c | 3 + 11 files changed, 365 insertions(+), 2 deletions(-) create mode 100644 tests/nodedevschemadata/pci_0000_42_00_0_vpd.xml create mode 120000 tests/nodedevxml2xmlout/pci_0000_42_00_0_vpd.xml diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng index e089e66858..fbbee4d0c6 100644 --- a/docs/schemas/nodedev.rng +++ b/docs/schemas/nodedev.rng @@ -223,6 +223,10 @@ =20 + + + + @@ -770,6 +774,42 @@ =20 + + + + vpd + + + + + + + string + + + + + + + + vpd-r + vpd-w + + + + + + + + + + + + + + + + diff --git a/include/libvirt/libvirt-nodedev.h b/include/libvirt/libvirt-no= dedev.h index e492634217..245365b07f 100644 --- a/include/libvirt/libvirt-nodedev.h +++ b/include/libvirt/libvirt-nodedev.h @@ -84,6 +84,7 @@ typedef enum { VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_CARD =3D 1 << 18, /* s390 A= P Card device */ VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_QUEUE =3D 1 << 19, /* s390 A= P Queue */ VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX =3D 1 << 20, /* s390 A= P Matrix */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD =3D 1 << 21, /* Device= with VPD */ =20 /* filter the devices by active state */ VIR_CONNECT_LIST_NODE_DEVICES_INACTIVE =3D 1 << 30, /* Inacti= ve devices */ diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 9bbff97ffd..7d9f74f45b 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -36,6 +36,7 @@ #include "virrandom.h" #include "virlog.h" #include "virfcp.h" +#include "virpcivpd.h" =20 #define VIR_FROM_THIS VIR_FROM_NODEDEV =20 @@ -70,6 +71,7 @@ VIR_ENUM_IMPL(virNodeDevCap, "ap_card", "ap_queue", "ap_matrix", + "vpd", ); =20 VIR_ENUM_IMPL(virNodeDevNetCap, @@ -240,6 +242,90 @@ virNodeDeviceCapMdevTypesFormat(virBuffer *buf, } } =20 +static void +virNodeDeviceCapVPDStringResourceFormat(virBuffer *buf, virPCIVPDResource = *res) +{ + virBufferAdjustIndent(buf, 2); + virBufferEscapeString(buf, "%s", virPCIVPDStringResourceGetValue((virP= CIVPDStringResource *)res)); + virBufferAdjustIndent(buf, -2); +} + +static gboolean +virNodeDeviceCapVPDWriteTextField(gpointer key, gpointer val, gpointer use= rData) +{ + const gchar *k =3D (const gchar*)key, *v =3D (const gchar*)val; + virBuffer *buf =3D userData; + virPCIVPDResourceFieldValueFormat format =3D VIR_PCI_VPD_RESOURCE_FIEL= D_VALUE_FORMAT_LAST; + + format =3D virPCIVPDResourceGetFieldValueFormat(k); + + if (format =3D=3D VIR_PCI_VPD_RESOURCE_FIELD_VALUE_FORMAT_TEXT) { + virBufferEscapeString(buf, "", k); + virBufferEscapeString(buf, "%s", v); + virBufferEscapeString(buf, "\n", k); + } + return false; +} + +static void +virNodeDeviceCapVPDKeywordResourceFormat(virBuffer *buf, virPCIVPDResource= *res) +{ + virPCIVPDKeywordResource *keywordRes =3D NULL; + g_autofree GHashTableIter *iter =3D NULL; + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + keywordRes =3D (virPCIVPDKeywordResource*)res; + + virPCIVPDKeywordResourceForEach(keywordRes, virNodeDeviceCapVPDWriteTe= xtField, buf); + virBufferAdjustIndent(buf, -2); +} + +static void +virNodeDeviceCapVPDResourceFormat(virBuffer *buf, virPCIVPDResource *res) +{ + GEnumValue *resRype =3D NULL; + void (*resFormatFunc)(virBuffer *buf, virPCIVPDResource *res); + + if (G_TYPE_CHECK_INSTANCE_TYPE(res, VIR_TYPE_PCI_VPD_STRING_RESOURCE))= { + resFormatFunc =3D virNodeDeviceCapVPDStringResourceFormat; + } else if (G_TYPE_CHECK_INSTANCE_TYPE(res, VIR_TYPE_PCI_VPD_KEYWORD_RE= SOURCE)) { + resFormatFunc =3D virNodeDeviceCapVPDKeywordResourceFormat; + } else { + /* Unexpected resource type. This should not happen unless the PCI= (e) specs + * change and new resource types are introduced into util.virpcivp= d. Either way, + * we can only return the control back to the caller here. + */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unexpected VPD resource type encountered during = formatting")); + return; + } + virBufferAdjustIndent(buf, 2); + + resRype =3D virPCIVPDResourceGetResourceType(res); + virBufferEscapeString(buf, "", resRype->value_ni= ck); + /* Format the resource in a type-specific way. */ + resFormatFunc(buf, res); + virBufferAddLit(buf, "\n"); + + virBufferAdjustIndent(buf, -2); +} + +static void +virNodeDeviceCapVPDFormat(virBuffer *buf, GList *vpdResources) +{ + if (!g_list_length(vpdResources)) { + return; + } + + virBufferAddLit(buf, "\n"); + while (vpdResources) { + GList *next =3D vpdResources->next; + virNodeDeviceCapVPDResourceFormat(buf, vpdResources->data); + vpdResources =3D next; + } + virBufferAddLit(buf, "\n"); +} =20 static void virNodeDeviceCapPCIDefFormat(virBuffer *buf, @@ -315,6 +401,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_resources); + } if (data->pci_dev.nIommuGroupDevices) { virBufferAsprintf(buf, "\n", data->pci_dev.iommuGroupNumber); @@ -673,6 +762,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 +949,132 @@ virNodeDevCapMdevTypesParseXML(xmlXPathContextPtr ctx= t, return ret; } =20 +static GTree * +virNodeDeviceCapVPDParseXMLKeywordResource(xmlXPathContextPtr ctxt) +{ + int nfields =3D -1; + g_autofree gchar* fieldValue =3D NULL; + g_autofree gchar* fieldKeyword =3D NULL; + g_autoptr(GTree) resourceFields =3D NULL; + g_autofree xmlNodePtr *nodes =3D NULL; + xmlNodePtr orignode =3D NULL; + size_t i =3D 0; + + resourceFields =3D g_tree_new_full( + (GCompareDataFunc)g_strcmp0, NULL, g_free, g_free); + + if ((nfields =3D virXPathNodeSet("./field[@keyword]", ctxt, &nodes)) <= 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("no VPD elements with a keyword specified found"= )); + ctxt->node =3D orignode; + return NULL; + } + + orignode =3D ctxt->node; + for (i =3D 0; i < nfields; i++) { + ctxt->node =3D nodes[i]; + if (!(fieldKeyword =3D virXPathString("string(./@keyword[1])", ctx= t))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("VPD resource field keyword parsing has failed")); + continue; + } + if (!(fieldValue =3D virXPathString("string(./text())", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("VPD resource field keyword parsing has failed")); + continue; + } + g_tree_insert(resourceFields, g_steal_pointer(&fieldKeyword), + g_steal_pointer(&fieldValue)); + } + ctxt->node =3D orignode; + return g_steal_pointer(&resourceFields); +} + +static int +virNodeDeviceCapVPDParseXML(xmlXPathContextPtr ctxt, GList **vpdResources) +{ + xmlNodePtr orignode =3D NULL; + g_autofree gchar* resText =3D NULL; + g_autofree GTree *resourceFields =3D NULL; + g_autofree xmlNodePtr *nodes =3D NULL; + int nresources =3D -1; + g_autofree gchar* resTypeStr =3D NULL; + virPCIVPDResourceType type =3D VIR_PCI_VPD_RESOURCE_TYPE_LAST; + GEnumClass *class; + size_t i =3D 0; + + if ((nresources =3D virXPathNodeSet("./resource[@type]", ctxt, &nodes)= ) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("no VPD elements with a type specified found"= )); + return -1; + } + + orignode =3D ctxt->node; + for (i =3D 0; i < nresources; i++) { + ctxt->node =3D nodes[i]; + if (!(resTypeStr =3D virXPathString("string(./@type[1])", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("VPD resource type parsing has failed")); + ctxt->node =3D orignode; + return -1; + } + + class =3D g_type_class_ref(VIR_TYPE_PCI_VPD_RESOURCE_TYPE); + type =3D g_enum_get_value_by_nick(class, resTypeStr)->value; + g_type_class_unref(class); + if (!type) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Unexpected VPD resource type encountered")); + /* Skip resources with unknown types. */ + continue; + } + + /* Create in-memory representations of resources based on their ty= pe. If a resource is not + * valid, report an error and skip to parsing another resource. + */ + switch (type) { + case VIR_PCI_VPD_RESOURCE_TYPE_STRING: + if (!(resText =3D virXPathString("string(./text())", ctxt)= )) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Could not read a string resource text")); + continue; + } + *vpdResources =3D g_list_append(*vpdResources, virPCIVPDSt= ringResourceNew( + g_steal_pointer(&resText))); + break; + case VIR_PCI_VPD_RESOURCE_TYPE_VPD_R: + if (!(resourceFields =3D virNodeDeviceCapVPDParseXMLKeywor= dResource(ctxt))) { + virReportError(VIR_ERR_XML_ERROR, + _("Could not parse %s VPD resource fields"), r= esTypeStr); + continue; + } + *vpdResources =3D g_list_append(*vpdResources, + virPCIVPDKeywordResourceNew(g_steal_pointer(&resou= rceFields), true)); + break; + case VIR_PCI_VPD_RESOURCE_TYPE_VPD_W: + if (!(resourceFields =3D virNodeDeviceCapVPDParseXMLKeywor= dResource(ctxt))) { + virReportError(VIR_ERR_XML_ERROR, + _("Could not parse %s VPD resource fields"), r= esTypeStr); + continue; + } + *vpdResources =3D g_list_append(*vpdResources, + virPCIVPDKeywordResourceNew(g_steal_pointer(&resou= rceFields), false)); + break; + case VIR_PCI_VPD_RESOURCE_TYPE_LAST: + default: + /* If the VPD module is aware of a resource type and it ha= s been serialized into + * XML while the parser does not then this is a bug. + */ + virReportError(VIR_ERR_XML_ERROR, + _("The XML parser has encountered an unsupported r= esource type %s"), + resTypeStr); + ctxt->node =3D orignode; + return -1; + } + } + ctxt->node =3D orignode; + return 0; +} =20 static int virNodeDevAPMatrixCapabilityParseXML(xmlXPathContextPtr ctxt, @@ -1718,6 +1934,11 @@ virNodeDevPCICapabilityParseXML(xmlXPathContextPtr c= txt, &pci_dev->nmdev_types) < 0) return -1; pci_dev->flags |=3D VIR_NODE_DEV_CAP_FLAG_PCI_MDEV; + } else if (STREQ(type, "vpd")) { + if (virNodeDeviceCapVPDParseXML(ctxt, &pci_dev->vpd_resources) < 0= ) { + return -1; + } + pci_dev->flags |=3D VIR_NODE_DEV_CAP_FLAG_PCI_VPD; } else { int hdrType =3D virPCIHeaderTypeFromString(type); =20 @@ -2024,6 +2245,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 +2509,8 @@ virNodeDevCapsDefFree(virNodeDevCapsDef *caps) for (i =3D 0; i < data->pci_dev.nmdev_types; i++) virMediatedDeviceTypeFree(data->pci_dev.mdev_types[i]); g_free(data->pci_dev.mdev_types); + g_list_free_full(g_steal_pointer(&data->pci_dev.vpd_resources), + g_object_unref); break; case VIR_NODE_DEV_CAP_USB_DEV: g_free(data->usb_dev.product_name); @@ -2352,6 +2576,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 +2643,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 +2715,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++; + } } =20 if (caps->data.type =3D=3D VIR_NODE_DEV_CAP_CSS_DEV) { @@ -2749,6 +2979,44 @@ virNodeDeviceGetMdevTypesCaps(const char *sysfspath, } =20 =20 +/** + * 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 =3D NULL; + virPCIDeviceAddress devAddr; + g_autolist(virPCIVPDResource) resourceList =3D NULL; + + devAddr.domain =3D devCapPCIDev->domain; + devAddr.bus =3D devCapPCIDev->bus; + devAddr.slot =3D devCapPCIDev->slot; + devAddr.function =3D devCapPCIDev->function; + + if (!(pciDev =3D virPCIDeviceNew(&devAddr))) + return -1; + + if (virPCIDeviceHasVPD(pciDev)) { + /* VPD is optional in PCI(e) specs. If it is there, attempt to add= it. */ + if ((resourceList =3D virPCIDeviceGetVPDResources(pciDev))) { + devCapPCIDev->flags |=3D VIR_NODE_DEV_CAP_FLAG_PCI_VPD; + devCapPCIDev->vpd_resources =3D g_steal_pointer(&resourceList); + } else { + g_list_free_full(devCapPCIDev->vpd_resources, g_object_unref); + } + } + 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 +3039,9 @@ virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, if (pci_dev->nmdev_types > 0) pci_dev->flags |=3D VIR_NODE_DEV_CAP_FLAG_PCI_MDEV; =20 + if (virNodeDeviceGetPCIVPDDynamicCap(pci_dev) < 0) + return -1; + return 0; } =20 diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 5a4d9c7a55..32e59fa52a 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -69,6 +69,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 */ =20 VIR_NODE_DEV_CAP_LAST } virNodeDevCapType; @@ -103,6 +104,7 @@ typedef enum { VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION =3D (1 << 1), VIR_NODE_DEV_CAP_FLAG_PCIE =3D (1 << 2), VIR_NODE_DEV_CAP_FLAG_PCI_MDEV =3D (1 << 3), + VIR_NODE_DEV_CAP_FLAG_PCI_VPD =3D (1 << 4), } virNodeDevPCICapFlags; =20 typedef enum { @@ -181,6 +183,7 @@ struct _virNodeDevCapPCIDev { int hdrType; /* enum virPCIHeaderType or -1 */ virMediatedDeviceType **mdev_types; size_t nmdev_types; + GList *vpd_resources; }; =20 typedef struct _virNodeDevCapUSBDev virNodeDevCapUSBDev; @@ -418,7 +421,8 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNodeDevCapsDef, virNod= eDevCapsDefFree); 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) =20 #define VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_ACTIVE \ VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE | \ diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index 9a9841576a..165ec1f1dd 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -701,6 +701,9 @@ virNodeDeviceObjHasCap(const virNodeDeviceObj *obj, if (type =3D=3D VIR_NODE_DEV_CAP_MDEV_TYPES && (cap->data.pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV)) return true; + if (type =3D=3D VIR_NODE_DEV_CAP_VPD && + (cap->data.pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_VPD)) + return true; break; =20 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; } =20 diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_de= vice_driver.c index 3bc6eb1c11..d19ed7d948 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -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; } diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_devi= ce_udev.c index 71f0bef827..7c3bb762b3 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -42,6 +42,7 @@ #include "virnetdev.h" #include "virmdev.h" #include "virutil.h" +#include "virpcivpd.h" =20 #include "configmake.h" =20 @@ -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: diff --git a/tests/nodedevschemadata/pci_0000_42_00_0_vpd.xml b/tests/noded= evschemadata/pci_0000_42_00_0_vpd.xml new file mode 100644 index 0000000000..831b6feb24 --- /dev/null +++ b/tests/nodedevschemadata/pci_0000_42_00_0_vpd.xml @@ -0,0 +1,33 @@ + + pci_0000_42_00_0 + + 0x020000 + 0 + 66 + 0 + 0 + MT42822 BlueField-2 integrated ConnectX-6 Dx ne= twork controller + Mellanox Technologies + + + BlueField-2 DPU 25GbE Dual-Port SFP56, Cry= pto Enabled, 16GB on-board DDR, 1GbE OOB management, Tall Bracket + + B1 + MBF2H332A-AEEOT + MT2113X00000 + PCIeGen4 x8 + MBF2H332A-AEEOT + 3c53d07eec484d8aab34dabd24fe575aa + MLX:MN=3DMLNX:CSKU=3DV2:UUID=3DV3:PCI=3DV0:M= ODL=3DBF2H332A + + + +
+ + + + + + + + diff --git a/tests/nodedevxml2xmlout/pci_0000_42_00_0_vpd.xml b/tests/noded= evxml2xmlout/pci_0000_42_00_0_vpd.xml new file mode 120000 index 0000000000..a0b5372ca0 --- /dev/null +++ b/tests/nodedevxml2xmlout/pci_0000_42_00_0_vpd.xml @@ -0,0 +1 @@ +../nodedevschemadata/pci_0000_42_00_0_vpd.xml \ No newline at end of file diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c index 9e32e7d553..557347fb07 100644 --- a/tests/nodedevxml2xmltest.c +++ b/tests/nodedevxml2xmltest.c @@ -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"); diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index f1b4eb94bf..e2f299d809 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -480,6 +480,9 @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G= _GNUC_UNUSED) case VIR_NODE_DEV_CAP_MDEV: flags |=3D VIR_CONNECT_LIST_NODE_DEVICES_CAP_MDEV; break; + case VIR_NODE_DEV_CAP_VPD: + flags |=3D VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD; + break; case VIR_NODE_DEV_CAP_CCW_DEV: flags |=3D VIR_CONNECT_LIST_NODE_DEVICES_CAP_CCW_DEV; break; --=20 2.30.2