From nobody Fri May 15 10:53:06 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) client-ip=38.145.34.151; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1776977620; cv=none; d=zohomail.com; s=zohoarc; b=fF841DW14mav3pwl6eRErC8I6G2rcYk89XhGGRbLWKL5i4kgjNFjtvZRUCTgDxZaJcFccNvdFTqHniHCV019+4Zes+RNxfeHaasqu51dTUmm/kYAEgtOOkCXSd+hnmSv3TGQ4IKJ+j5oQoBpAuQ0qGTQD+ewv8SFfO1fAzZgGlA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1776977620; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:Subject:Subject:To:To:Message-Id; bh=TbaG6nIHdvFuGocQnL0x2/PpTjL82ibIRbtzYx5vcgA=; b=Bv1k5jDYGLl49LbGbgmdPTvw+7Gx+hDNvZJp221End9omJo/58BlaStOCuqpQZXW5jh7htwyG4+Wn2tVB8hppbeK68wkxebuO6my3+sjHuz9QLVLLl7Ab2sD4gjMCn0Bkwueq5E9vdYgS55SSp6Krzh6oTO/12rQj3IuRpytMnE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [38.145.34.151]) by mx.zohomail.com with SMTPS id 1776977620013787.9652152508426; Thu, 23 Apr 2026 13:53:40 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 0D29E4197C; Thu, 23 Apr 2026 16:53:39 -0400 (EDT) Received: from [172.19.199.9] (unknown [10.16.107.18]) by lists.libvirt.org (Postfix) with ESMTP id 6C11541ADC; Thu, 23 Apr 2026 16:52:23 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 515E93F281; Thu, 23 Apr 2026 16:52:17 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id BC4A6417F9 for ; Thu, 23 Apr 2026 16:52:15 -0400 (EDT) Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-362-DMMy98HqN7yiHDczV2iwFQ-1; Thu, 23 Apr 2026 16:52:13 -0400 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (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 mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5BB43197732A; Thu, 23 Apr 2026 20:52:08 +0000 (UTC) Received: from vhost3.router.laine.org (unknown [10.22.80.243]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 92875196B8F6; Thu, 23 Apr 2026 20:52:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL,RCVD_IN_SBL_CSS,SPF_HELO_PASS autolearn=no autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1776977535; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=TbaG6nIHdvFuGocQnL0x2/PpTjL82ibIRbtzYx5vcgA=; b=UXm/BQx9/+iA5GJPoyFTLoOj4phGfE+XxlJHe8n1b56YXh7jj0GwUbAH3ZQTHwIVaF7FnZ cBWVVxIH3cDnfbltRgo04MfB4rN60yfyANZ8wGATLAoGGRJhU7wQTYeLOVcWIMT1r4lBGe k1Hqs/WFU1Mt3PoGlTNdjhhlA8QexnM= X-MC-Unique: DMMy98HqN7yiHDczV2iwFQ-1 X-Mimecast-MFC-AGG-ID: DMMy98HqN7yiHDczV2iwFQ_1776977533 To: devel@lists.libvirt.org Subject: [PATCH] util: Allow for PCI root buses not numbered "0" Date: Thu, 23 Apr 2026 16:43:05 -0400 Message-ID: <20260423205206.22437-1-laine@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: djt2Snt4900BGI5bMOSMlKXqoB7zXoQaFq6lW19WLVU_1776977533 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID-Hash: LEUXIPSQC33NWTLS266RX7YFXNNRSVFP X-Message-ID-Hash: LEUXIPSQC33NWTLS266RX7YFXNNRSVFP X-MailFrom: laine@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: ehanoc X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Laine Stump via Devel Reply-To: Laine Stump X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1776977623996154100 From: ehanoc via Devel virPCIDeviceReset() and virPCIDeviceIsBehindSwitchLackingACS() both used a hardcoded check for bus !=3D 0 to determine if a device is attached directly to a "root bus". This breaks on systems with more than one root bus, where at least one of the buses is necessarily not 0! (for example Intel Arrow Lake based systems where the CPU's root complex is bus 0x00 and the PCH root complex is bus 0x80). Update both functions to use virPCIDeviceIsOnRootBus(), which detects root bus attachment via the canonicalized sysfs device link in /sys/devices/*, making it work correctly for all root buses, not just those numbered 0. Discussion of the issue here: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/NE62= XCNHTWTFN4SFNTTSLI2W6BGGM64W/ Resolves: https://github.com/QubesOS/qubes-issues/issues/10393 Signed-off-by: Bruno Martins Signed-off-by: Laine Stump Reviewed-by: Laine Stump Reviewed-by: Daniel P. Berrang=C3=A9 Reviewed-by: Bruno Martins Tested-by: Bruno Martins --- Changes from V1: * Editorial changes to comments in code and commit log message * log an error when virPCIDeviceIsOnRootBus() fails * use g_path_get_basename() rather than strrchr(blah, '/') * rename a couple variables I haven't been able to test these changes because I only have QEMU/KVM, and it doesn't call any of this code. Please test and add your Reviewed-by (of my changes) and Tested-by: and I'll push it. src/util/virpci.c | 106 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 6 deletions(-) diff --git a/src/util/virpci.c b/src/util/virpci.c index d43fa1ef54..642717d23c 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -1080,6 +1080,87 @@ virPCIDeviceInit(virPCIDevice *dev, int cfgfd) return 0; } =20 +/* + * Check if a PCI device is directly attached to a root bus (no parent bri= dge). + * + * A PCIe topology can have multiple root buses (a "root" bus is any + * PCI bus that doesn't have yet another higher level PCI bus as its + * parent), so by definition we can't detect a root bus by just + * looking for bus 0. Instead, we can detect if a bus is attached to a + * root bus by examining the *canonical* path of the device's + * directory in sysfs: a device is connected directly to a root bus if + * its canonicalized sysfs path is a direct child of a + * /sys/devices/pciXXXX:YY directory. For example, this device: + * + * /sys/bus/pci/devices/0000:00:14.0 (path in "flat" sysfs pci name= space) + * /sys/devices/pci0000:80/0000:80:14.0). (canonicalized version of abov= e) + + * is connnected to a root bus. Conversely, if the given device's + * canonial path has yet another PCI device as its parent in the + * sys/device's hierarchy, then it *isn't* attached to a root bus, + * e.g.: + * + * /sys/bus/pci/devices/0000:04:00.1 (link in "flat" na= mespace) + * /sys/devices/pci0000:00/0000:00:1c.4/0000:04:00.0 (canonicalized) + * + * Returns 1 if the given device is directly attached to a root bus, + * 0 if not, -1 on error. + */ +static int +virPCIDeviceIsOnRootBus(virPCIDevice *dev) +{ + unsigned int domain, bus; + g_autofree char *devPath =3D NULL; + g_autofree char *canonicalPath =3D NULL; + g_autofree char *parentPath =3D NULL; + g_autofree char *parentName =3D NULL; + + /* Get the sysfs symlink path for this device */ + devPath =3D g_strdup_printf(PCI_SYSFS "devices/%s", dev->name); + + /* Resolve the symlink to get the real path in /sys/devices/... */ + if (virFileResolveLink(devPath, &canonicalPath) < 0) { + virReportSystemError(errno, _("failed to resolve links in PCI devi= ce %1$s sysfs path '%2$s'"), + dev->name, devPath); + return -1; + } + + /* get just the final component of the parent directory */ + parentPath =3D g_path_get_dirname(canonicalPath); + parentName =3D g_path_get_basename(parentPath); + + /* + * Detect root bus by parsing the parent directory name with sscanf. + * + * PCI root buses in /sys/devices follow the naming convention: + * pci: + * + * : number (0000-ffff, hex) + * : number within the domain (00-ff, hex) + * + * This format is defined in: + * https://www.kernel.org/doc/html/latest/PCI/sysfs-pci.html + * + * Examples from Intel Arrow Lake systems: + * - pci0000:00 (CPU root bus) + * - pci0000:80 (PCH root bus) + * + * We aren't concerned with the actual values parsed by sscanf, + * only whether or not the parse was successful - if soo, then we + * return 1 indicating this device is attached to a root bus, + * otherwise 0. + */ + if (sscanf(parentName, "pci%x:%x", &domain, &bus) =3D=3D 2) { + VIR_DEBUG("%s %s: device is on root bus (parent=3D%s)", + dev->id, dev->name, parentName); + return 1; + } + + VIR_DEBUG("%s %s: device is not on root bus (parent=3D%s)", + dev->id, dev->name, parentName); + return 0; +} + int virPCIDeviceReset(virPCIDevice *dev, virPCIDeviceList *activeDevs, @@ -1145,9 +1226,18 @@ virPCIDeviceReset(virPCIDevice *dev, if (dev->has_pm_reset) ret =3D virPCIDeviceTryPowerManagementReset(dev, fd); =20 - /* Bus reset is not an option with the root bus */ - if (ret < 0 && dev->address.bus !=3D 0) - ret =3D virPCIDeviceTrySecondaryBusReset(dev, fd, inactiveDevs); + /* If power management reset isn't available (or if it failed), + * and the bus we're attached to isn't a root bus, try a secondary + * bus reset. (This is not an option if we are attached directly + * to a root bus). + */ + if (ret < 0) { + int onRootBus =3D virPCIDeviceIsOnRootBus(dev); + if (onRootBus < 0) + goto cleanup; + if (!onRootBus) + ret =3D virPCIDeviceTrySecondaryBusReset(dev, fd, inactiveDevs= ); + } =20 if (ret < 0) { virErrorPtr err =3D virGetLastError(); @@ -2531,15 +2621,19 @@ static int virPCIDeviceIsBehindSwitchLackingACS(virPCIDevice *dev) { g_autoptr(virPCIDevice) parent =3D NULL; + int onRootBus; =20 if (virPCIDeviceGetParent(dev, &parent) < 0) return -1; if (!parent) { - /* if we have no parent, and this is the root bus, ACS doesn't come - * into play since devices on the root bus can't P2P without going + /* if we have no parent, and this is a root bus, ACS doesn't come + * into play since devices on root buses can't P2P without going * through the root IOMMU. */ - if (dev->address.bus =3D=3D 0) { + onRootBus =3D virPCIDeviceIsOnRootBus(dev); + if (onRootBus < 0) + return -1; + if (onRootBus) { return 0; } else { virReportError(VIR_ERR_INTERNAL_ERROR, --=20 2.53.0