From nobody Tue Feb 10 17:08:05 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 1632771114595909.7035336680375; Mon, 27 Sep 2021 12:31:54 -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-113-DRALJZUsNhiMJoY5JE4CXg-1; Mon, 27 Sep 2021 15:31:42 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 9CF748145E6; Mon, 27 Sep 2021 19:31:31 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 7774C5F91D; Mon, 27 Sep 2021 19:31:31 +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 3DAE44EA38; Mon, 27 Sep 2021 19:31:31 +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 18RJVAaD014453 for ; Mon, 27 Sep 2021 15:31:10 -0400 Received: by smtp.corp.redhat.com (Postfix) id DF6F0202F31E; Mon, 27 Sep 2021 19:31:09 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast04.extmail.prod.ext.rdu2.redhat.com [10.11.55.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D4825202F31F for ; Mon, 27 Sep 2021 19:31: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 DF8C3106655D for ; Mon, 27 Sep 2021 19:31:01 +0000 (UTC) Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-470-zMBsNK7IMri0S1t8nTEgbA-1; Mon, 27 Sep 2021 15:30:59 -0400 Received: from mail-lf1-f70.google.com (mail-lf1-f70.google.com [209.85.167.70]) (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-1.canonical.com (Postfix) with ESMTPS id 45CA240784 for ; Mon, 27 Sep 2021 19:30:58 +0000 (UTC) Received: by mail-lf1-f70.google.com with SMTP id q4-20020ac25284000000b003fcebb305a6so3267387lfm.15 for ; Mon, 27 Sep 2021 12:30:58 -0700 (PDT) Received: from ws.lan.d-node.is ([95.165.29.203]) by smtp.gmail.com with ESMTPSA id a8sm1688090lfr.256.2021.09.27.12.30.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Sep 2021 12:30:56 -0700 (PDT) X-MC-Unique: DRALJZUsNhiMJoY5JE4CXg-1 X-MC-Unique: zMBsNK7IMri0S1t8nTEgbA-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:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=xuU21URt/qzTR6CZ+ZChvvcRKvSX7S8/2AVK4Ek2rZw=; b=wfkoNRwjx054OwhIaTZq0adj8gIwgjib4u4Z4HxJsd0KOOslg8wnMlaOcxxGK7t5Un ULIzV4D5F+scOsNzkBQyj1SyWf7wZRV/w92JFrIyEEVxnrozWO1+H8aCrP4e4TMhQYMS iqg/vY5X+CAXPQdjmk5daYgMX1qsdWIMSCPslmGVWzdI+7G9fjLvntjQZ6zog2re1kwT rO01guHlXEFZMxSvPShn7wpyC/brLnOIKG0WaVw11CYEdx1JtmR441xe49u+LMZc0zP6 yIsOMOjwAoqbsum95+38bE1JUXZF6xKz0oMFDDSjLBSAnfyo0VORoPc7s/u71+X1+Q5X Npeg== X-Gm-Message-State: AOAM533FXoj2HXddrVPa3jKO+Znpej6C7MXR8TCUkMRphYkWaRm24AQ8 UCM9uNZBJFm7VFB46BAOHYTjubTHg2QgD13r4hlnVsXxZoHy8BXn3ZTvVQD0CCk2Gh8lzEYcRqi u/y9079KINYpl+YDjt4q9SFadMwlwCLUQ2w== X-Received: by 2002:a05:6512:1087:: with SMTP id j7mr1535582lfg.414.1632771057205; Mon, 27 Sep 2021 12:30:57 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz1lYxzhjz9ulKOX8C+I3Wz89s11c1c+cc3kbyDG0rmGMJxIlb+5eSCkalvj7KkH4EQRUle/A== X-Received: by 2002:a05:6512:1087:: with SMTP id j7mr1535561lfg.414.1632771056865; Mon, 27 Sep 2021 12:30:56 -0700 (PDT) From: Dmitrii Shcherbakov To: libvir-list@redhat.com, dmitrii.shcherbakov@canonical.com Subject: [libvirt PATCH v5 5/7] Add PCI VPD Capability Support Date: Mon, 27 Sep 2021 22:30:51 +0300 Message-Id: <20210927193053.109029-6-dmitrii.shcherbakov@canonical.com> In-Reply-To: <20210927193053.109029-1-dmitrii.shcherbakov@canonical.com> References: <20210927193053.109029-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 18RJVAaD014453 X-loop: libvir-list@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.14 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: 1632771115613100001 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. Signed-off-by: Dmitrii Shcherbakov --- 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 f72359121f..63725587fc 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -476,6 +476,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