From nobody Mon Feb 9 16:19:16 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 1634718682684265.07471151929144; Wed, 20 Oct 2021 01:31:22 -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-199-74wAlCmPORGcg2g7F6W0kw-1; Wed, 20 Oct 2021 04:31:20 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B752D1B18BC3; Wed, 20 Oct 2021 08:31:14 +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 7A8B66A8E5; Wed, 20 Oct 2021 08:31:14 +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 B314B1801241; Wed, 20 Oct 2021 08:31:13 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 19K8Uijx029851 for ; Wed, 20 Oct 2021 04:30:45 -0400 Received: by smtp.corp.redhat.com (Postfix) id D96112166B2F; Wed, 20 Oct 2021 08:30:44 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast03.extmail.prod.ext.rdu2.redhat.com [10.11.55.19]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D32862166B2D for ; Wed, 20 Oct 2021 08:30:42 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-2.mimecast.com [207.211.31.81]) (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 1D238811E91 for ; Wed, 20 Oct 2021 08:30:42 +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-381-YcYI853mNESLtaL0supcKg-1; Wed, 20 Oct 2021 04:30:40 -0400 Received: from mail-lj1-f198.google.com (mail-lj1-f198.google.com [209.85.208.198]) (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 8399D402E8 for ; Wed, 20 Oct 2021 08:30:38 +0000 (UTC) Received: by mail-lj1-f198.google.com with SMTP id z9-20020a2e3509000000b00210f31ea0e3so1507023ljz.16 for ; Wed, 20 Oct 2021 01:30:38 -0700 (PDT) Received: from ws.lan.d-node.is ([95.165.29.203]) by smtp.gmail.com with ESMTPSA id z5sm136753lfr.96.2021.10.20.01.30.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 Oct 2021 01:30:37 -0700 (PDT) X-MC-Unique: 74wAlCmPORGcg2g7F6W0kw-1 X-MC-Unique: YcYI853mNESLtaL0supcKg-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=1y8nsyDu1fBh4v5bu68clTwGT/x+sE1SvKk4mXXOA2o=; b=4YNipgn3uQ81e6bcmiQIpvo2wN7IBTHaVTAX8xXn+B2kaFV1LfwBN2Wg3hX1r+NAh6 Un+Lz6P5fbBpFbos7m6FqVmFZOmsgN8+Lp+z1acSPthYOSX90yW8qlxqmnXQPIfoRsuF EwazvlR6RSipgZ9pfT6GeEqlLph3N1Qj0IaFT9QuRlu6L1yFVALNcXnCfZT+yHSAjTQl MfiFO+HXFrY6TxU/M/OyogKlsJTlukZ7UVN9fF/OqXQR0WqELZtgiNXG7i7ssgLzpbMB /Rkthjn5lxVtBa2h0KaNOTL6auQk18koohdbA5L2n8rr6yt9N0nEG/JM1y/ViGY0jVbz UV3w== X-Gm-Message-State: AOAM532vI7SSXSE/sRUVeMmVyjiLi7akzr4MBguCBlo0vcESbitcYMvW K+PaNqbfoEN2HHDaJI/CjyIljdecIXLNJXCM1siJYXYdHL24l9n1GSfRg33otjzUJI3juy+qblU 6YhU418Jm+zpZIlk0hIy9SEiOAROBv8JdCQ== X-Received: by 2002:ac2:538a:: with SMTP id g10mr11054140lfh.90.1634718637809; Wed, 20 Oct 2021 01:30:37 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxzdKyCYX3CMlhA9gFAB/sJ2RXM+PKbiH9PJHjjRKq+/a6cAswPtVF5cvJyIOfDzuEw+rAUtw== X-Received: by 2002:ac2:538a:: with SMTP id g10mr11054117lfh.90.1634718637449; Wed, 20 Oct 2021 01:30:37 -0700 (PDT) From: Dmitrii Shcherbakov To: dmitrii.shcherbakov@canonical.com, libvir-list@redhat.com Subject: [libvirt PATCH v7 3/5] Add PCI VPD Capability Support Date: Wed, 20 Oct 2021 11:30:33 +0300 Message-Id: <20211020083035.737231-4-dmitrii.shcherbakov@canonical.com> In-Reply-To: <20211020083035.737231-1-dmitrii.shcherbakov@canonical.com> References: <20211020083035.737231-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.6 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 19K8Uijx029851 X-loop: libvir-list@redhat.com Cc: laine@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.15 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: 1634718683664100001 Content-Type: text/plain; charset="utf-8" * 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. Signed-off-by: Dmitrii Shcherbakov --- docs/schemas/nodedev.rng | 96 ++++++ include/libvirt/libvirt-nodedev.h | 1 + src/conf/node_device_conf.c | 309 ++++++++++++++++++ src/conf/node_device_conf.h | 7 +- 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 | 42 +++ .../pci_0000_42_00_0_vpd.xml | 1 + tests/nodedevxml2xmltest.c | 1 + tools/virsh-nodedev.c | 3 + 11 files changed, 469 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..e4733f0804 100644 --- a/docs/schemas/nodedev.rng +++ b/docs/schemas/nodedev.rng @@ -223,6 +223,10 @@ =20 + + + + @@ -770,6 +774,80 @@ =20 + + + + vpd + + + + + + + + readonly + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + readwrite + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -782,4 +860,22 @@ =20 + + + [0-9a-zA-F -_,.:;=3D]{0,255} + + + + + + [0-9A-Z]{1} + + + + + + [0-9B-Z]{1} + + + 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 1f39e2cbfd..9a24041022 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,80 @@ virNodeDeviceCapMdevTypesFormat(virBuffer *buf, } } =20 +static void +virNodeDeviceCapVPDFormatCustomVendorField(virPCIVPDResourceCustom *field,= virBuffer *buf) +{ + if (field =3D=3D NULL || field->value =3D=3D NULL) { + return; + } + virBufferAsprintf(buf, "%s\n= ", field->idx, + field->value); +} + +static void +virNodeDeviceCapVPDFormatCustomSystemField(virPCIVPDResourceCustom *field,= virBuffer *buf) +{ + if (field =3D=3D NULL || field->value =3D=3D NULL) { + return; + } + virBufferAsprintf(buf, "%s\n= ", field->idx, + field->value); +} + +static inline void +virNodeDeviceCapVPDFormatRegularField(virBuffer *buf, const char *keyword,= const char *value) +{ + if (keyword =3D=3D NULL || value =3D=3D NULL) { + return; + } + virBufferAsprintf(buf, "<%s>%s\n", keyword, value, keyword); +} + +static void +virNodeDeviceCapVPDFormat(virBuffer *buf, virPCIVPDResource *res) +{ + if (res =3D=3D NULL) { + return; + } + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + if (res->name !=3D NULL) { + virBufferEscapeString(buf, "%s\n", res->name); + } + + if (res->ro !=3D NULL) { + virBufferEscapeString(buf, "\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->r= o->serial_number); + g_ptr_array_foreach(res->ro->vendor_specific, + (GFunc)virNodeDeviceCapVPDFormatCustomVendorFi= eld, buf); + virBufferAdjustIndent(buf, -2); + + virBufferAddLit(buf, "\n"); + } + + if (res->rw !=3D NULL) { + virBufferEscapeString(buf, "\n", "readwrite"= ); + + virBufferAdjustIndent(buf, 2); + virNodeDeviceCapVPDFormatRegularField(buf, "asset_tag", res->rw->a= sset_tag); + g_ptr_array_foreach(res->rw->vendor_specific, + (GFunc)virNodeDeviceCapVPDFormatCustomVendorFi= eld, buf); + g_ptr_array_foreach(res->rw->system_specific, + (GFunc)virNodeDeviceCapVPDFormatCustomSystemFi= eld, buf); + virBufferAdjustIndent(buf, -2); + + virBufferAddLit(buf, "\n"); + } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); +} =20 static void virNodeDeviceCapPCIDefFormat(virBuffer *buf, @@ -315,6 +391,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, "\n", data->pci_dev.iommuGroupNumber); @@ -673,6 +752,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 +939,181 @@ virNodeDevCapMdevTypesParseXML(xmlXPathContextPtr ctx= t, return ret; } =20 +static int +virNodeDeviceCapVPDParseCustomFields(xmlXPathContextPtr ctxt, virPCIVPDRes= ource *res, bool readOnly) +{ + int nfields =3D -1; + g_autofree char *index =3D NULL, *value =3D NULL, *keyword =3D NULL; + g_autofree xmlNodePtr *nodes =3D NULL; + xmlNodePtr orignode =3D NULL; + size_t i =3D 0; + + orignode =3D ctxt->node; + if ((nfields =3D virXPathNodeSet("./vendor_field[@index]", ctxt, &node= s)) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to evaluate elements")); + ctxt->node =3D orignode; + return -1; + } + for (i =3D 0; i < nfields; i++) { + ctxt->node =3D nodes[i]; + if (!(index =3D virXPathStringLimit("string(./@index[1])", 2, ctxt= ))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _(" evaluation has failed")); + continue; + } + if (!(value =3D virXPathString("string(./text())", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _(" value evaluation has failed")); + continue; + } + keyword =3D 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 =3D orignode; + + if (!readOnly) { + if ((nfields =3D virXPathNodeSet("./system_field[@index]", ctxt, &= nodes)) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("failed to evaluate elements")); + ctxt->node =3D orignode; + return -1; + } + for (i =3D 0; i < nfields; i++) { + ctxt->node =3D nodes[i]; + if (!(index =3D virXPathStringLimit("string(./@index[1])", 2, = ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _(" evaluation has failed")); + continue; + } + if (!(value =3D virXPathString("string(./text())", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _(" value evaluation has failed")); + continue; + } + keyword =3D 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 =3D orignode; + } + + return 0; +} + +static int +virNodeDeviceCapVPDParseReadOnlyFields(xmlXPathContextPtr ctxt, virPCIVPDR= esource *res) +{ + const char *keywords[] =3D {"change_level", "manufacture_id", + "serial_number", "part_number", NULL}; + g_autofree char *expression =3D NULL; + g_autofree char *result =3D NULL; + size_t i =3D 0; + + if (res =3D=3D NULL) { + return -1; + } + res->ro =3D virPCIVPDResourceRONew(); + + while (keywords[i]) { + expression =3D g_strdup_printf("string(./%s)", keywords[i]); + result =3D 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, virPCIVPD= Resource *res) +{ + g_autofree char *assetTag =3D virXPathString("string(./asset_tag)", ct= xt); + res->rw =3D virPCIVPDResourceRWNew(); + virPCIVPDResourceUpdateKeyword(res, false, "asset_tag", assetTag); + if (virNodeDeviceCapVPDParseCustomFields(ctxt, res, false) < 0) { + return -1; + } + return 0; +} + +static int +virNodeDeviceCapVPDParseXML(xmlXPathContextPtr ctxt, virPCIVPDResource **r= es) +{ + xmlNodePtr orignode =3D NULL; + g_autofree xmlNodePtr *nodes =3D NULL; + int nfields =3D -1; + g_autofree char *access =3D NULL; + size_t i =3D 0; + g_autoptr(virPCIVPDResource) newres =3D g_new0(virPCIVPDResource, 1); + + if (res =3D=3D NULL) { + return -1; + } + + orignode =3D ctxt->node; + + if (!(newres->name =3D virXPathString("string(./name)", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Could not read a device name from the element")); + ctxt->node =3D orignode; + return -1; + } + + if ((nfields =3D virXPathNodeSet("./fields[@access]", ctxt, &nodes)) <= 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("no VPD elements with an access type attribute = found")); + ctxt->node =3D orignode; + return -1; + } + + for (i =3D 0; i < nfields; i++) { + ctxt->node =3D nodes[i]; + if (!(access =3D virXPathString("string(./@access[1])", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("VPD fields access type parsing has failed")); + ctxt->node =3D orignode; + return -1; + } + + if (STREQ(access, "readonly")) { + if (virNodeDeviceCapVPDParseReadOnlyFields(ctxt, newres) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Could not parse %s VPD resource fields"), acces= s); + return -1; + } + } else if (STREQ(access, "readwrite")) { + if (virNodeDeviceCapVPDParseReadWriteFields(ctxt, newres) < 0)= { + virReportError(VIR_ERR_XML_ERROR, + _("Could not parse %s VPD resource fields"), acces= s); + return -1; + } + } else { + virReportError(VIR_ERR_XML_ERROR, _("Unsupported VPD field acc= ess type specified %s"), + access); + return -1; + } + g_free(g_steal_pointer(&access)); + } + ctxt->node =3D orignode; + + /* Replace the existing VPD representation if there is one already. */ + if (*res !=3D NULL) { + virPCIVPDResourceFree(*res); + } + *res =3D g_steal_pointer(&newres); + return 0; +} =20 static int virNodeDevAPMatrixCapabilityParseXML(xmlXPathContextPtr ctxt, @@ -1718,6 +1973,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) < 0) { + return -1; + } + pci_dev->flags |=3D VIR_NODE_DEV_CAP_FLAG_PCI_VPD; } else { int hdrType =3D virPCIHeaderTypeFromString(type); =20 @@ -2024,6 +2284,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 +2548,7 @@ 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); + 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 +2614,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 +2681,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 +2753,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 +3017,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_autoptr(virPCIVPDResource) res =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 ((res =3D virPCIDeviceGetVPD(pciDev))) { + devCapPCIDev->flags |=3D VIR_NODE_DEV_CAP_FLAG_PCI_VPD; + devCapPCIDev->vpd =3D 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 +3077,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..e4d1f67d53 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -24,6 +24,7 @@ =20 #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 */ =20 VIR_NODE_DEV_CAP_LAST } virNodeDevCapType; @@ -103,6 +105,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 +184,7 @@ struct _virNodeDevCapPCIDev { int hdrType; /* enum virPCIHeaderType or -1 */ virMediatedDeviceType **mdev_types; size_t nmdev_types; + virPCIVPDResource *vpd; }; =20 typedef struct _virNodeDevCapUSBDev virNodeDevCapUSBDev; @@ -418,7 +422,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..8b56e4f6b4 --- /dev/null +++ b/tests/nodedevschemadata/pci_0000_42_00_0_vpd.xml @@ -0,0 +1,42 @@ + + 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, Crypto Enabled, 16GB on= -board DDR, 1GbE OOB management, Tall Bracket + + B1 + foobar + MBF2H332A-AEEOT + MT2113X00000 + PCIeGen4 x8 + MBF2H332A-AEEOT + 3c53d07eec484d8aab34dabd24fe575aa + MLX:MN=3DMLNX:CSKU=3DV2:UUID=3DV3:PCI=3D= V0:MODL=3DBF2H332A + + + fooasset + vendorfield0 + vendorfield2 + vendorfieldA + systemfieldB + systemfield0 + + + +
+ + + + + + + + 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 c989a77ad2..1ad8db7a3f 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -472,6 +472,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.32.0