From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D5ED53B961B for ; Fri, 10 Jul 2026 21:26:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718788; cv=none; b=Stxxu3CSD/M8fiNweK5fQg6dLXDDPAvwCN6J786XZAmysvjquabMT7IklT8SKUR5KnL9AMHqCPXpWEViafsZYd7FvpjAlih3jejsqKiVWhqaUYgu3tBBPkppj7d9AMfVPSE4lDoKU/yR0HgLvB1MLAGcbPNknwMxUK21vN311is= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718788; c=relaxed/simple; bh=yhxxTEDUxYjf8DzFRoKAY/bC6BCrZ9/scSTPlz0R2qU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=OHnAMAzoCB3fzfhgZfMvnqADDn9yNRPsVp3WdKF/zU9o5dD/CJuT72qjbSZaEpFpqSQ0zuFYu3xGWEsWnmhUk8evQkQtBeEODdnPagJchKD0/MlCFZjJDxmG2FHZHK7sXCkfMFx65VqqOfX6M3igQm+EjB+sj8of9waNHHzJSOw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=qX9LlNKm; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="qX9LlNKm" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-848415e9e8eso1920733b3a.2 for ; Fri, 10 Jul 2026 14:26:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718784; x=1784323584; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=nJNVxjvVmYROzvILHkxiv/3zu6J6S8o6lQRGVaWTNbg=; b=qX9LlNKm3NkBtToXIj5JWKTDuzVdhq6gIbTUb1n8crgFlD6/VdPStWPHB7M34qDWq7 zN96aA2L4STf6qIQPRTIMQ3pX/sSDrbU6nwkz2CawCfnBaKxueK0Ywg6ezk1kHRM2Kon /ivxbs9x12l7/+MYw55pIhFcIdxcMkwDvHCW4rZuek0BEnlQtYw9r4NAbRHuJTuC7Yb7 sewbTqaRNBR1O7m2xSbZP4+MJbMuT782dO7oFYS5j1IGMswL45PHITNeZhxZMnEVhwU+ 6laCYqqdzUEKRWDv+MfmTdksqTKXgZHD4G2pYz1K4S0KhlBWeHCkWgnZoSHZN1UubD3Q xvVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718784; x=1784323584; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=nJNVxjvVmYROzvILHkxiv/3zu6J6S8o6lQRGVaWTNbg=; b=na5+N1JmPnyofa1N9kKwX5o8QOFfYZCHOWtX7w/eE0xICKsF76Loouoj4L7EyZasVy G3Ug4znhdAYx/qp457rbLLYzjb97bs87Fx5iXIJFkV6CKLfBOX2VGVBQLUbDRlmuDXkN a0+ZeQlOD9YqSEteTP67NFjxY/faCMULGrTGIg/q2k3Qxul/kFOBLDCdB8En5NUdXzGW VKjRV+Sbqe8cgsNnRn71dOLO51eEPhmKBra4m2NyjwbjGnlLhvDtzCMCY6XK7CKMfaja SbbfR911CWVhad3cVgW7qva73lAGjrsNqYUvK6TaGb0OWG9T6RaBBCWHmdbKc9pHT0rA 83Lg== X-Forwarded-Encrypted: i=1; AHgh+RpkRFnCw35hrjpnc6VtOzxeL98QP6IW4/7/UasFVYuH+oZftaEgPTnqOnnLNpf40KMyZOEmrsJINlafyBU=@vger.kernel.org X-Gm-Message-State: AOJu0YwB3f2GZ+z7CdwbDSNH1kdU8TonoKXQ6DR6u132Z+Y0R4Q3sFLy ybKYBkwaKPP4UBpI7ZmwgHySRh4MYPiP4jzORzJbQZ8Xa9xr1oWfTpywYajUpjZ7YoYvytavGou OZnRkDkzBMPj26A== X-Received: from pfbln8.prod.google.com ([2002:a05:6a00:3cc8:b0:848:48a0:41e6]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:179b:b0:848:30fe:da34 with SMTP id d2e1a72fcca58-8488974b074mr589334b3a.45.1783718783985; Fri, 10 Jul 2026 14:26:23 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:04 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-2-dmatlack@google.com> Subject: [PATCH v7 01/12] PCI: liveupdate: Set up FLB handler for the PCI core From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Set up a File-Lifecycle-Bound (FLB) handler for the PCI core to enable it to participate in the preservation of PCI devices across Live Update. Essentially, this commit enables the PCI core to allocate a struct (struct pci_ser) and preserve it across a Live Update whenever at least one device is preserved. Preserving PCI devices across Live Update is built on top of the Live Update Orchestrator's (LUO) support for file preservation. Drivers are expected to expose a file to userspace to represent a single PCI device and support preservation of that file. This is intended primarily to support preservation of PCI devices bound to VFIO drivers. This commit enables drivers to register their liveupdate_file_handler with the PCI core so that the PCI core can do its own tracking and enforcement of which devices are preserved. pci_liveupdate_register_flb(driver_file_handler); pci_liveupdate_unregister_flb(driver_file_handler); When the first file (with a handler registered with the PCI core) is preserved, the PCI core will be notified to allocate its tracking struct (pci_ser). When the last file is unpreserved (i.e. preservation cancelled) the PCI core will be notified to free struct pci_ser. This struct is preserved across a Live Update using KHO and can be fetched by the PCI core during early boot (e.g. during device enumeration) so that it knows which devices were preserved. Note: This commit only allocates struct pci_ser and preserves it across Live Update. A subsequent commit will add an API for drivers to tell the PCI core exactly which devices are being preserved. Note: There is no reason to check for kho_is_enabled() since it can be assumed to return true. If KHO was not enabled then Live Update would not be enabled and these routines would never run. Reviewed-by: Pranjal Shrivastava Signed-off-by: David Matlack --- Documentation/core-api/liveupdate.rst | 4 + MAINTAINERS | 13 +++ drivers/pci/Kconfig | 15 +++ drivers/pci/Makefile | 1 + drivers/pci/liveupdate.c | 155 ++++++++++++++++++++++++++ include/linux/kho/abi/pci.h | 58 ++++++++++ include/linux/pci.h | 1 + include/linux/pci_liveupdate.h | 30 +++++ 8 files changed, 277 insertions(+) create mode 100644 drivers/pci/liveupdate.c create mode 100644 include/linux/kho/abi/pci.h create mode 100644 include/linux/pci_liveupdate.h diff --git a/Documentation/core-api/liveupdate.rst b/Documentation/core-api= /liveupdate.rst index 5a292d0f3706..b3c689e633c1 100644 --- a/Documentation/core-api/liveupdate.rst +++ b/Documentation/core-api/liveupdate.rst @@ -1,5 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 =20 +.. _luo: + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Live Update Orchestrator =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D @@ -18,6 +20,8 @@ LUO Preserving File Descriptors .. kernel-doc:: kernel/liveupdate/luo_file.c :doc: LUO File Descriptors =20 +.. _flb: + LUO File Lifecycle Bound Global Data =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D .. kernel-doc:: kernel/liveupdate/luo_flb.c diff --git a/MAINTAINERS b/MAINTAINERS index a3ed337e827d..9cc7b9291ace 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20824,6 +20824,19 @@ L: linux-pci@vger.kernel.org S: Supported F: Documentation/PCI/pci-error-recovery.rst =20 +PCI LIVE UPDATE +M: David Matlack +R: Pasha Tatashin +R: Mike Rapoport +R: Pratyush Yadav +L: kexec@lists.infradead.org +L: linux-pci@vger.kernel.org +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git +F: drivers/pci/liveupdate.c +F: include/linux/kho/abi/pci.h +F: include/linux/pci_liveupdate.h + PCI MSI DRIVER FOR ALTERA MSI IP L: linux-pci@vger.kernel.org S: Orphan diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 0c7408509ba2..3781e2b5f095 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -271,6 +271,21 @@ config VGA_ARB_MAX_GPUS Reserves space in the kernel to maintain resource locking for multiple GPUS. The overhead for each GPU is very small. =20 +config PCI_LIVEUPDATE + bool "PCI Live Update Support" + depends on PCI && LIVEUPDATE + help + Enable PCI core support for preserving PCI devices across Live + Update. This, in combination with support in a device's driver, + enables PCI devices to run and perform memory transactions + uninterrupted during a kexec for Live Update. + + This option should only be enabled by users who plan to use Live + Update for kernel upgrades and require preserving PCI devices during + those upgrades. + + If unsure, say N. + source "drivers/pci/hotplug/Kconfig" source "drivers/pci/controller/Kconfig" source "drivers/pci/endpoint/Kconfig" diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 41ebc3b9a518..e8d003cb6757 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_PROC_FS) +=3D proc.o obj-$(CONFIG_SYSFS) +=3D pci-sysfs.o slot.o obj-$(CONFIG_ACPI) +=3D pci-acpi.o obj-$(CONFIG_GENERIC_PCI_IOMAP) +=3D iomap.o +obj-$(CONFIG_PCI_LIVEUPDATE) +=3D liveupdate.o endif =20 obj-$(CONFIG_OF) +=3D of.o diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c new file mode 100644 index 000000000000..899758883dd5 --- /dev/null +++ b/drivers/pci/liveupdate.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2026, Google LLC. + * David Matlack + */ + +/** + * DOC: PCI Live Update + * + * The PCI subsystem participates in the Live Update process to enable dri= vers + * to preserve their PCI devices across kexec. + * + * :ref:`FLB ` Data + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * + * PCI device preservation across Live Update is built on top of the + * :ref:`LUO ` support for file preservation across kexec. Drivers are + * expected to expose a file to represent a single PCI device and support + * preservation of that file with ``ioctl(LIVEUPDATE_SESSION_PRESERVE_FD)`= `. + * This allows userspace to control the preservation of devices and ensure + * proper lifecycle management while a device is preserved. The first inte= nded + * use-case is preserving vfio-pci device files. + * + * The PCI core maintains its own state about what devices are being prese= rved + * across Live Update using FLB data in LUO. Essentially, this allows the = PCI + * core to allocate struct pci_ser when the first device (file) is preserv= ed + * and free it when the last device (file) is unpreserved. After kexec, the + * PCI core can fetch the struct pci_ser (which was constructed by the pre= vious + * kernel) from LUO at any time (e.g. during enumeration) so that it knows + * which devices were preserved. + * + * To enable the PCI core to be notified whenever a file representing a de= vice + * is preserved, drivers must register their struct liveupdate_file_handle= r with + * the PCI core by using the following APIs: + * + * * ``pci_liveupdate_register_flb(driver_file_handler)`` + * * ``pci_liveupdate_unregister_flb(driver_file_handler)`` + */ + +#define pr_fmt(fmt) "PCI: " KBUILD_BASENAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct pci_flb_outgoing - Outgoing PCI FLB object + * @ser: Pointer to the preserved struct pci_ser. + * @block_set: The KHO block set holding the outgoing devices. + * + * This structure holds the runtime state for the outgoing PCI Live Update + * state. It wraps the serialized pci_ser and the block_set used to manage + * the serialized entries. + */ +struct pci_flb_outgoing { + struct pci_ser *ser; + struct kho_block_set block_set; +}; + +static int pci_flb_preserve(struct liveupdate_flb_op_args *args) +{ + struct pci_flb_outgoing *outgoing; + struct pci_ser *ser; + + outgoing =3D kzalloc_obj(*outgoing); + if (!outgoing) + return -ENOMEM; + + ser =3D kho_alloc_preserve(sizeof(*ser)); + if (IS_ERR(ser)) { + kfree(outgoing); + return PTR_ERR(ser); + } + + ser->nr_devices =3D 0; + ser->devices =3D 0; + + outgoing->ser =3D ser; + kho_block_set_init(&outgoing->block_set, sizeof(struct pci_dev_ser)); + + args->obj =3D outgoing; + args->data =3D virt_to_phys(ser); + return 0; +} + +static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args) +{ + struct pci_flb_outgoing *outgoing =3D args->obj; + + WARN_ON(outgoing->ser->nr_devices); + kho_block_set_destroy(&outgoing->block_set); + kho_unpreserve_free(outgoing->ser); + kfree(outgoing); + pr_debug("Unpreserved struct pci_ser\n"); +} + +static int pci_flb_retrieve(struct liveupdate_flb_op_args *args) +{ + args->obj =3D phys_to_virt(args->data); + return 0; +} + +static void pci_flb_finish(struct liveupdate_flb_op_args *args) +{ + kho_restore_free(args->obj); +} + +static struct liveupdate_flb_ops pci_liveupdate_flb_ops =3D { + .preserve =3D pci_flb_preserve, + .unpreserve =3D pci_flb_unpreserve, + .retrieve =3D pci_flb_retrieve, + .finish =3D pci_flb_finish, + .owner =3D THIS_MODULE, +}; + +static struct liveupdate_flb pci_liveupdate_flb =3D { + .ops =3D &pci_liveupdate_flb_ops, + .compatible =3D PCI_LUO_FLB_COMPATIBLE, +}; + +/** + * pci_liveupdate_register_flb() - Register a file handler with the PCI co= re + * @fh: The file handler to register. + * + * Drivers should call pci_liveupdate_register_flb() to register their + * struct liveupdate_file_handler with the PCI core. This enables the PCI = core + * to allocate its outgoing struct pci_ser whenever the first device is + * preserved, and free it when the last device is unpreserved. + * + * Return: 0 on success, <0 on failure. + */ +int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh) +{ + pr_debug("Registering file handler \"%s\"\n", fh->compatible); + return liveupdate_register_flb(fh, &pci_liveupdate_flb); +} +EXPORT_SYMBOL_GPL(pci_liveupdate_register_flb); + +/** + * pci_liveupdate_unregister_flb() - Unregister a file handler with the PC= I core + * @fh: The file handler to unregister. + */ +void pci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh) +{ + pr_debug("Unregistering file handler \"%s\"\n", fh->compatible); + liveupdate_unregister_flb(fh, &pci_liveupdate_flb); +} +EXPORT_SYMBOL_GPL(pci_liveupdate_unregister_flb); diff --git a/include/linux/kho/abi/pci.h b/include/linux/kho/abi/pci.h new file mode 100644 index 000000000000..de549016807a --- /dev/null +++ b/include/linux/kho/abi/pci.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2026, Google LLC. + * David Matlack + */ + +#ifndef _LINUX_KHO_ABI_PCI_H +#define _LINUX_KHO_ABI_PCI_H + +#include +#include +#include + +/** + * DOC: PCI File-Lifecycle Bound (FLB) Live Update ABI + * + * This header defines the ABI for preserving core PCI state across kexec = using + * Live Update File-Lifecycle Bound (FLB) data. + * + * This interface is a contract. Any modification to any of the serializat= ion + * structs defined here constitutes a breaking change. Such changes require + * incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. + */ + +#define PCI_LUO_FLB_COMPATIBLE "pci-v1" + +/** + * struct pci_dev_ser - Serialized state about a single PCI device. + * + * @domain: The device's PCI domain number (segment). + * @bdf: The device's PCI bus, device, and function number. + * @refcount: Reference count used by the PCI core to keep track of whethe= r it + * is done using a device's struct pci_dev_ser. The value of the + * refcount is equal to 1 when the struct pci_dev_ser is in use= , and + * 0 otherwise. + */ +struct pci_dev_ser { + u32 domain; + u16 bdf; + u16 refcount; +} __packed; + +/** + * struct pci_ser - PCI Subsystem Live Update State + * + * This struct tracks state about all devices that are being preserved acr= oss + * a Live Update for the next kernel. + * + * @nr_devices: The number of devices that were preserved. + * @devices: Physical address of the first KHO block containing pci_dev_se= r. + */ +struct pci_ser { + u32 nr_devices; + u64 devices; +} __packed; + +#endif /* _LINUX_KHO_ABI_PCI_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index ebb5b9d76360..da58aa101e4c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -43,6 +43,7 @@ #include =20 #include +#include =20 #define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \ PCI_STATUS_SIG_SYSTEM_ERROR | \ diff --git a/include/linux/pci_liveupdate.h b/include/linux/pci_liveupdate.h new file mode 100644 index 000000000000..8ec98beefcb4 --- /dev/null +++ b/include/linux/pci_liveupdate.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PCI Live Update support (Public/Driver API) + * + * Copyright (c) 2026, Google LLC. + * David Matlack + */ +#ifndef LINUX_PCI_LIVEUPDATE_H +#define LINUX_PCI_LIVEUPDATE_H + +#include +#include + +struct pci_dev; + +#ifdef CONFIG_PCI_LIVEUPDATE +int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh); +void pci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh); +#else +static inline int pci_liveupdate_register_flb(struct liveupdate_file_handl= er *fh) +{ + return -EOPNOTSUPP; +} + +static inline void pci_liveupdate_unregister_flb(struct liveupdate_file_ha= ndler *fh) +{ +} +#endif + +#endif /* LINUX_PCI_LIVEUPDATE_H */ --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BF4F73BADB2 for ; Fri, 10 Jul 2026 21:26:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718787; cv=none; b=PwHBH20KyuQz3Rf+UX/zZ7u4Uv5GRzckAOO67gK9C0VWmLeH2wa4ZJPby8WOvPMPfwcs/Z/2sD2dcd7eTCyJWyTsztsj9scJdgzfroKgT9n+Volz2/fKF+gGCy9anXAurdmViFAS0RQ73voOQXbjVhza5AWL7azAZituJ16hiWI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718787; c=relaxed/simple; bh=Ou4RgPAmlIjduI5snDRTQ8MisPcnqtjwemoupdlPcV8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=OA9esta3+ocGN0UHkXTfRR4uI2tQYg8LDmAlD6uNpBWUiNP+H80Wd4Z0BUzoxkhFe7sQBybihKVD8SKjM5xP87Byh8mq8pxCfkt0sPfEkVyIBOIWQ1KAsYE6eIvdA76UDNs6yCBjGk1faF6S8pDiuP/nxVc/K7hiGxblvYB3Mhc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=dJuI8L/9; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="dJuI8L/9" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-c88aab7c1fcso2551770a12.3 for ; Fri, 10 Jul 2026 14:26:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718785; x=1784323585; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=ZqWNkuvdAaukVWBKpdd7ishFwM9qcIXIJrQ5YQadICw=; b=dJuI8L/9eWjhmJb/maloCpDEjmpnW25qVIx7ZF+V4sFnBtt/F7w0BATnNyTryUbGmq zmkHorML28cWl+3q4jFQj8uoZ+1WCNYk8fyDtewZeeHxDTJG75T3LYy5Vbq46//N6Jbo IQg4T+GfwwBUqqopRx4H5FoRelug5mipDPIXgtJmcrI/OHhUpfif3Hjxhm07QPIuCW0x gvWWCdwGd7P/iXisu8lCwAp+/XCs1ECUIoSB+xJ3eNqmgsu8CPndJusX7chaGHHwFw1H RwQJAcHzdqGCyMjkvNs4C2JTwcoPvQaZcgi1+KQSvJ2kyxAjd8hs5JFsFNmbayYl8gX+ 3IBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718785; x=1784323585; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=ZqWNkuvdAaukVWBKpdd7ishFwM9qcIXIJrQ5YQadICw=; b=bR671NrRyekYNAWr2GLJtlkiDaIfW5mhTkRKDQXU9NF6VbAozvFqOB/pht3Gk4fOD1 6t/0pXzFH+XzEgvep9W71Q+/zVGyUkWOv5ivXsgKZ4O+nErcIKFu4IKf8WE+neH/bnCk Um7NA51ol4qO7TozayGfDiwn4TVpSx3lwzR63/0RhgI40AGq9GU3i8ltPclIz9XEhTuS RUhR316a43Gq/E5zpnVnNklmvgnw4Wj2zjpsLueqU6LydYNnzIqMwT90A5IfTXVn5tWi hvDeo7JpM6uCziK3fWBLYY4q6h8XKtlOMzpak+RNk7a4qJTRNyQ8GaAes/MIghHMarVR IftA== X-Forwarded-Encrypted: i=1; AHgh+RoQLVjivCZPAzQAEqYp19prpRcS/bCXYcyUq09FmLJ0jjoXNnWEbHth3cgpBykq745xbrba4JmB8AxjR1E=@vger.kernel.org X-Gm-Message-State: AOJu0YzCvU189IHz2XjD6r8FvtFRpCEta0Ni5cMSEWOK765BhPtmZOOZ cT4otvcEmfpx2Sk/CCzFb7F3sEZa7yosLdzAFJPFo8yIv47tNXGPAUePZn+aq2GEHRAEeqH+6eg uH68qpea1k3+sUQ== X-Received: from pgeq9.prod.google.com ([2002:a63:bc09:0:b0:ca1:3a05:d935]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:800f:b0:845:4e6a:768e with SMTP id d2e1a72fcca58-8488974b0b9mr573992b3a.35.1783718784876; Fri, 10 Jul 2026 14:26:24 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:05 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-3-dmatlack@google.com> Subject: [PATCH v7 02/12] PCI: liveupdate: Track outgoing preserved PCI devices From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add APIs to allow drivers to notify the PCI core of which devices are being preserved across a Live Update for the next kernel, i.e. "outgoing" devices. Drivers must notify the PCI core when devices are preserved so that the PCI core can update its FLB data (struct pci_ser) and track the list of outgoing devices. pci_liveupdate_preserve() notifies the PCI core that a device must be preserved across Live Update. pci_liveupdate_unpreserve() reverses this (cancels the preservation of the device). This tracking ensures the PCI core is fully aware of which devices may need special handling during shutdown and kexec, and so that it can be handed off to the next kernel. Reviewed-by: Pranjal Shrivastava Signed-off-by: David Matlack Reviewed-by: Bjorn Helgaas =20 Reviewed-by: Pasha Tatashin --- drivers/pci/liveupdate.c | 186 +++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.h | 21 ++++ drivers/pci/probe.c | 2 + include/linux/pci.h | 3 + include/linux/pci_liveupdate.h | 21 ++++ 5 files changed, 233 insertions(+) create mode 100644 drivers/pci/liveupdate.h diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c index 899758883dd5..03075ce06ac9 100644 --- a/drivers/pci/liveupdate.c +++ b/drivers/pci/liveupdate.c @@ -36,6 +36,26 @@ * * * ``pci_liveupdate_register_flb(driver_file_handler)`` * * ``pci_liveupdate_unregister_flb(driver_file_handler)`` + * + * Device Tracking + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * + * Drivers must notify the PCI core when specific devices are preserved or + * unpreserved with the following APIs: + * + * * ``pci_liveupdate_preserve(pci_dev)`` + * * ``pci_liveupdate_unpreserve(pci_dev)`` + * + * This allows the PCI core to keep its FLB data (struct pci_ser) up to da= te + * with the list of **outgoing** preserved devices for the next kernel. + * + * Restrictions + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * + * The PCI core enforces the following restrictions on which devices can be + * preserved. These may be relaxed in the future: + * + * * The device cannot be a Virtual Function (VF). */ =20 #define pr_fmt(fmt) "PCI: " KBUILD_BASENAME ": " fmt @@ -50,6 +70,21 @@ #include #include =20 +#include "liveupdate.h" + +/** + * struct pci_liveupdate_global - Global state for PCI Live Update support + * @rwsem: Reader/writer semaphore used to protect the incoming and outgoi= ng + * FLBs, and the references to them in struct pci_dev. + */ +struct pci_liveupdate_global { + struct rw_semaphore rwsem; +}; + +static struct pci_liveupdate_global pci_liveupdate =3D { + .rwsem =3D __RWSEM_INITIALIZER(pci_liveupdate.rwsem), +}; + /** * struct pci_flb_outgoing - Outgoing PCI FLB object * @ser: Pointer to the preserved struct pci_ser. @@ -125,6 +160,157 @@ static struct liveupdate_flb pci_liveupdate_flb =3D { .compatible =3D PCI_LUO_FLB_COMPATIBLE, }; =20 +static struct pci_flb_outgoing *pci_liveupdate_flb_get_outgoing(void) +{ + struct pci_flb_outgoing *outgoing =3D NULL; + int ret; + + ret =3D liveupdate_flb_get_outgoing(&pci_liveupdate_flb, (void **)&outgoi= ng); + if (ret) + return ERR_PTR(ret); + + if (!outgoing) + return ERR_PTR(-ENOENT); + + return outgoing; +} + +static struct pci_dev_ser *pci_get_empty_or_append(struct pci_flb_outgoing= *outgoing) +{ + struct pci_dev_ser *dev_ser, *found =3D NULL; + struct kho_block_set_it it; + int err; + u32 count =3D 0; + + kho_block_set_it_init(&it, &outgoing->block_set); + while ((dev_ser =3D kho_block_set_it_read_entry(&it))) { + count++; + if (dev_ser->refcount =3D=3D 0 && !found) + found =3D dev_ser; + } + + if (found) + return found; + + err =3D kho_block_set_grow(&outgoing->block_set, count + 1); + if (err) + return ERR_PTR(err); + + if (count =3D=3D 0) + kho_block_set_it_init(&it, &outgoing->block_set); + + dev_ser =3D kho_block_set_it_reserve_entry(&it); + if (!dev_ser) + return ERR_PTR(-ENOSPC); + + return dev_ser; +} + +static void pci_liveupdate_unpreserve_device(struct pci_flb_outgoing *outg= oing, struct pci_dev *dev) +{ + struct pci_dev_ser *dev_ser =3D dev->liveupdate.outgoing; + + if (!dev_ser) { + pci_warn(dev, "Cannot unpreserve device that is not preserved\n"); + return; + } + + pci_info(dev, "Device will no longer be preserved across next Live Update= \n"); + outgoing->ser->nr_devices--; + memset(dev_ser, 0, sizeof(*dev_ser)); + dev->liveupdate.outgoing =3D NULL; +} + +static int pci_liveupdate_preserve_device(struct pci_flb_outgoing *outgoin= g, struct pci_dev *dev) +{ + struct pci_dev_ser *dev_ser; + + if (dev->liveupdate.outgoing) + return -EBUSY; + + dev_ser =3D pci_get_empty_or_append(outgoing); + if (IS_ERR(dev_ser)) + return PTR_ERR(dev_ser); + + pci_info(dev, "Device will be preserved across next Live Update\n"); + outgoing->ser->nr_devices++; + outgoing->ser->devices =3D kho_block_set_head_pa(&outgoing->block_set); + + dev_ser->domain =3D pci_domain_nr(dev->bus); + dev_ser->bdf =3D pci_dev_id(dev); + dev_ser->refcount =3D 1; + + dev->liveupdate.outgoing =3D dev_ser; + return 0; +} + +/** + * pci_liveupdate_preserve() - Preserve a PCI device across Live Update + * @dev: The PCI device to preserve. + * + * pci_liveupdate_preserve() notifies the PCI core that a PCI device shoul= d be + * preserved across the next Live Update. Drivers are expected to call + * pci_liveupdate_preserve() from their struct liveupdate_file_handler + * preserve() callback to ensure the outgoing struct pci_ser is already se= t up. + * + * Returns: 0 on success, <0 on failure. + */ +int pci_liveupdate_preserve(struct pci_dev *dev) +{ + struct pci_flb_outgoing *outgoing =3D NULL; + + if (dev->is_virtfn) + return -EINVAL; + + guard(rwsem_write)(&pci_liveupdate.rwsem); + + outgoing =3D pci_liveupdate_flb_get_outgoing(); + if (IS_ERR(outgoing)) + return PTR_ERR(outgoing); + + return pci_liveupdate_preserve_device(outgoing, dev); +} +EXPORT_SYMBOL_GPL(pci_liveupdate_preserve); + +/** + * pci_liveupdate_unpreserve() - Cancel preservation of a PCI device + * @dev: The PCI device to unpreserve. + * + * pci_liveupdate_unpreserve() notifies the PCI core that a PCI device sho= uld no + * longer be preserved across the next Live Update. Drivers are expected t= o call + * pci_liveupdate_unpreserve() from their struct liveupdate_file_handler + * unpreserve() callback to ensure the outgoing struct pci_ser is already = set + * up. + */ +void pci_liveupdate_unpreserve(struct pci_dev *dev) +{ + struct pci_flb_outgoing *outgoing =3D NULL; + + guard(rwsem_write)(&pci_liveupdate.rwsem); + + outgoing =3D pci_liveupdate_flb_get_outgoing(); + if (IS_ERR(outgoing)) { + pci_warn(dev, "Cannot unpreserve device without outgoing Live Update sta= te\n"); + return; + } + + pci_liveupdate_unpreserve_device(outgoing, dev); +} +EXPORT_SYMBOL_GPL(pci_liveupdate_unpreserve); + +void pci_liveupdate_cleanup_device(struct pci_dev *dev) +{ + /* + * It should be safe to READ_ONCE() outside of the rwsem during cleanup + * since there should no longer be any references to @dev on the system. + * + * This should never happen in practice. Drivers should block removal + * while a device is preserved. + */ + if (READ_ONCE(dev->liveupdate.outgoing)) + pci_WARN(dev, 1, "Destroying outgoing-preserved device!\n"); +} + /** * pci_liveupdate_register_flb() - Register a file handler with the PCI co= re * @fh: The file handler to register. diff --git a/drivers/pci/liveupdate.h b/drivers/pci/liveupdate.h new file mode 100644 index 000000000000..b2335581f8d0 --- /dev/null +++ b/drivers/pci/liveupdate.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PCI Live Update support (core API) + * + * Copyright (c) 2026, Google LLC. + * David Matlack + */ +#ifndef DRIVERS_PCI_LIVEUPDATE_H +#define DRIVERS_PCI_LIVEUPDATE_H + +#include + +#ifdef CONFIG_PCI_LIVEUPDATE +void pci_liveupdate_cleanup_device(struct pci_dev *dev); +#else +static inline void pci_liveupdate_cleanup_device(struct pci_dev *dev) +{ +} +#endif + +#endif /* DRIVERS_PCI_LIVEUPDATE_H */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index dd0abbc63e18..14b66acbdb15 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -24,6 +24,7 @@ #include #include #include +#include "liveupdate.h" #include "pci.h" =20 static struct resource busn_resource =3D { @@ -2485,6 +2486,7 @@ static void pci_release_dev(struct device *dev) =20 pci_dev =3D to_pci_dev(dev); pci_release_capabilities(pci_dev); + pci_liveupdate_cleanup_device(pci_dev); pci_release_of_node(pci_dev); pcibios_release_device(pci_dev); pci_bus_put(pci_dev->bus); diff --git a/include/linux/pci.h b/include/linux/pci.h index da58aa101e4c..b41dd572a2d6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -593,6 +593,9 @@ struct pci_dev { u8 tph_mode; /* TPH mode */ u8 tph_req_type; /* TPH requester type */ #endif +#ifdef CONFIG_PCI_LIVEUPDATE + struct pci_liveupdate liveupdate; +#endif }; =20 static inline struct pci_dev *pci_physfn(struct pci_dev *dev) diff --git a/include/linux/pci_liveupdate.h b/include/linux/pci_liveupdate.h index 8ec98beefcb4..cfcfbfa73af7 100644 --- a/include/linux/pci_liveupdate.h +++ b/include/linux/pci_liveupdate.h @@ -8,14 +8,26 @@ #ifndef LINUX_PCI_LIVEUPDATE_H #define LINUX_PCI_LIVEUPDATE_H =20 +#include #include #include +#include + +/** + * struct pci_liveupdate - PCI Live Update state for a struct pci_dev + * @outgoing: State preserved for the next kernel. + */ +struct pci_liveupdate { + struct pci_dev_ser *outgoing; +}; =20 struct pci_dev; =20 #ifdef CONFIG_PCI_LIVEUPDATE int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh); void pci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh); +int pci_liveupdate_preserve(struct pci_dev *dev); +void pci_liveupdate_unpreserve(struct pci_dev *dev); #else static inline int pci_liveupdate_register_flb(struct liveupdate_file_handl= er *fh) { @@ -25,6 +37,15 @@ static inline int pci_liveupdate_register_flb(struct liv= eupdate_file_handler *fh static inline void pci_liveupdate_unregister_flb(struct liveupdate_file_ha= ndler *fh) { } + +static inline int pci_liveupdate_preserve(struct pci_dev *dev) +{ + return -EOPNOTSUPP; +} + +static inline void pci_liveupdate_unpreserve(struct pci_dev *dev) +{ +} #endif =20 #endif /* LINUX_PCI_LIVEUPDATE_H */ --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 90B543B9DA6 for ; Fri, 10 Jul 2026 21:26:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718789; cv=none; b=JfO9LBB1hWXr96sNduSPFsdtMhtXNtPbBjrzqoX8/hr6b0s/R/5dzrZpae2wbLJ0ol1dHF1IdaHKmf7mx+xsvyrM/iewEH7rAtpBmgO2WVGQbI4mV/sBjZ7jl5H4wzzirChwUx5olSzoh8TijqwD1IL3Js6rEgcuQKa+DuEVTYw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718789; c=relaxed/simple; bh=wDK96R3B273CLNejo5khL7j/0MEwgmuxB/Cn16PAsUs=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=bcSg432C+C8Z8PpDq4RYgotKO/rJMo/WE2+rRyrzIntYUNkSjqCV+YnXnSeAIhha0cOUT5UD5Q2eXGt47MZ1k7gvrm8l9pa4QqgnwD3wZL6oZG7J85TNYPvoGYl4Cv2/9iV9iSrHZ0Y80g+Y2zm9iFZWwaLbplMhbjnyuvksAVg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=BPNlz5/S; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="BPNlz5/S" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-2ccd1958e8fso16273325ad.2 for ; Fri, 10 Jul 2026 14:26:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718786; x=1784323586; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=OQrpvHKyfewFed1C96fmigU0fqx5g50RgiJpnH3PBzY=; b=BPNlz5/STxqC3XkmQt/0JsRMCgppTI/OMTjbKg5dcgGLqYbovZgpNgjHB0psT4XU0y Lql3l8zGYbtsgTcddlU8tvuX4W1IIEQaaIqwhPMN36RqWX6wc4XpDpq4eaQYS9hsQi99 fTPejP7Zdebe7CJ5t3fPnbVgv0weafe6jDfiX6rlxi4yGyrk+zgtOOl4FWDaL8TXcXsz rCXau96W/waA5IaJ7pCkGF1SleDeHRK7dUH/76Cdm+W1nPGBQhw19WAtp3bxiGeGny8D P6AE3s0MDSpd2K6NmcP+u6mRoF0Suc+zkSBBxHy9WoWjThfZgFRE2e9X9NZOUX/n0SDE q0gQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718786; x=1784323586; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=OQrpvHKyfewFed1C96fmigU0fqx5g50RgiJpnH3PBzY=; b=QpNyYr2nQeg2qH8iGZ30AMFrebQPG4bxfnrGOAPCGiAH9P21hAFLgLTGWjQXmrV8yS go6dUEC8V0KIRQi6V213XzWjcKdUElEJ5tNMXSxQS9qubtkCjyJy9atcpQLRYjMJ2Q0P RSYkuzjQJpsbNhvz9cCcbfkacG36oHYECDkaJ9ohlaQFpbhq9pIpJUtDJmVjSuRgunbv aFe8UNibVsciJkIXXnOhzVdHDHROTWBpEnXcJbgiBj0wHWBsFbaeyFdCpQ1lcod+QQxN +txXAmpdk5L3immxpIRgpaXLo6nEVF7EUY2fxKOV4CCl8MZLig61wXIUlgtZsA08n7CC OfIA== X-Forwarded-Encrypted: i=1; AHgh+RqOFYzkSxJFOstLFuPjFdUWDDp1AWoKGk5gA6lctB1zr4e4F0rpX8cZkIdVhItBpGeguKW/Xiusy1W6z1U=@vger.kernel.org X-Gm-Message-State: AOJu0Yx5kOLlQ4soCFdhQRq/mmHHWr8Xb00Ycnzyok+RlmxycvSw2VfM 99TWe9266bb0BTxG8p02H/Clx/q5HYFcaFN3NRvyL51oAt1G7sq9F3DH5mHiRf/OEcjliDU+KLg D0saS4Biq5o83dw== X-Received: from plrf24.prod.google.com ([2002:a17:902:ab98:b0:2cc:622b:5b52]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:120f:b0:2c9:97a7:f540 with SMTP id d9443c01a7336-2ce9f059398mr6625505ad.38.1783718785688; Fri, 10 Jul 2026 14:26:25 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:06 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-4-dmatlack@google.com> Subject: [PATCH v7 03/12] PCI: liveupdate: Track incoming preserved PCI devices From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" During PCI enumeration, the previous kernel might have passed state about devices that were preserved across kexec. The PCI core needs to fetch this state to identify which devices are "incoming" and require special handling. Add pci_liveupdate_setup_device() which is called during device setup to fetch the serialized state (struct pci_ser) from the Live Update Orchestrator. The first time this happens, pci_flb_retrieve() will run and convert the array of pci_dev_ser structs into an xarray so that it can be looked up efficiently. If a device is found in the xarray, the PCI core stores a pointer to its state in dev->liveupdate_incoming and holds a reference to the incoming FLB until pci_liveupdate_finish() is called by the driver. This ensures proper lifecycle management for incoming preserved devices and allows the PCI core and drivers to apply specific Live Update logic to them in subsequent commits. Drivers can check if a device is an incoming preserved device (e.g. during probe) by calling pci_liveupdate_is_incoming(). CONFIG_64BIT is now required to enable CONFIG_PCI_LIVEUPDATE so that the domain and bdf can be guaranteed to fit in an unsigned long and be used as the xarray key. Reviewed-by: Pranjal Shrivastava Signed-off-by: David Matlack --- MAINTAINERS | 1 + drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 240 ++++++++++++++++++++++++++++++++- drivers/pci/liveupdate.h | 5 + drivers/pci/probe.c | 3 + include/linux/pci_liveupdate.h | 13 ++ 6 files changed, 261 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 9cc7b9291ace..08a724b860dc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20834,6 +20834,7 @@ L: linux-pci@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git F: drivers/pci/liveupdate.c +F: drivers/pci/liveupdate.h F: include/linux/kho/abi/pci.h F: include/linux/pci_liveupdate.h =20 diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 3781e2b5f095..8af20f558086 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -273,7 +273,7 @@ config VGA_ARB_MAX_GPUS =20 config PCI_LIVEUPDATE bool "PCI Live Update Support" - depends on PCI && LIVEUPDATE + depends on PCI && LIVEUPDATE && 64BIT help Enable PCI core support for preserving PCI devices across Live Update. This, in combination with support in a device's driver, diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c index 03075ce06ac9..df6a02240aa4 100644 --- a/drivers/pci/liveupdate.c +++ b/drivers/pci/liveupdate.c @@ -49,6 +49,20 @@ * This allows the PCI core to keep its FLB data (struct pci_ser) up to da= te * with the list of **outgoing** preserved devices for the next kernel. * + * After kexec, whenever a device is enumerated, the PCI core will check i= f it + * is an **incoming** preserved device (i.e. preserved by the previous ker= nel) + * by checking the incoming FLB data (struct pci_ser). + * + * Drivers must notify the PCI core when an **incoming** device is done + * participating in the incoming Live Update with the following API: + * + * * ``pci_liveupdate_finish(pci_dev)`` + * + * The PCI core does not enforce any ordering of ``pci_liveupdate_finish()= `` and + * ``pci_liveupdate_preserve()``. i.e. A PCI device can be **outgoing** + * (preserved for next kernel) and **incoming** (preserved by previous ker= nel) + * at the same time. + * * Restrictions * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D * @@ -99,6 +113,26 @@ struct pci_flb_outgoing { struct kho_block_set block_set; }; =20 +/** + * struct pci_flb_incoming - Incoming PCI FLB object + * @ser: The incoming struct pci_ser from the previous kernel. + * @xa: Xarray used to quickly lookup devices in @ser. + * @block_set: The KHO block set holding the incoming devices. + * + * This structure holds the runtime state for the incoming PCI Live Update + * state. It wraps the serialized pci_ser, the block_set used to restore + * the serialized entries, and an xarray for fast lookups. + */ +struct pci_flb_incoming { + struct pci_ser *ser; + struct xarray xa; + struct kho_block_set block_set; +}; + +static unsigned long pci_ser_xa_key(u32 domain, u16 bdf) +{ + return (unsigned long)domain << 16 | bdf; +} static int pci_flb_preserve(struct liveupdate_flb_op_args *args) { struct pci_flb_outgoing *outgoing; @@ -138,13 +172,58 @@ static void pci_flb_unpreserve(struct liveupdate_flb_= op_args *args) =20 static int pci_flb_retrieve(struct liveupdate_flb_op_args *args) { - args->obj =3D phys_to_virt(args->data); + struct pci_ser *ser =3D phys_to_virt(args->data); + struct pci_flb_incoming *incoming; + struct pci_dev_ser *dev_ser; + struct kho_block_set_it it; + int ret =3D -ENOMEM; + + incoming =3D kzalloc_obj(*incoming); + if (!incoming) + goto err_restore_free; + + incoming->ser =3D ser; + xa_init(&incoming->xa); + + kho_block_set_init(&incoming->block_set, sizeof(struct pci_dev_ser)); + ret =3D kho_block_set_restore(&incoming->block_set, ser->devices); + if (ret) + goto err_free_incoming; + + kho_block_set_it_init(&it, &incoming->block_set); + while ((dev_ser =3D kho_block_set_it_read_entry(&it))) { + unsigned long key; + + if (!dev_ser->refcount) + continue; + + key =3D pci_ser_xa_key(dev_ser->domain, dev_ser->bdf); + ret =3D xa_insert(&incoming->xa, key, dev_ser, GFP_KERNEL); + if (ret) + goto err_block_set_destroy; + } + + args->obj =3D incoming; return 0; + +err_block_set_destroy: + kho_block_set_destroy(&incoming->block_set); +err_free_incoming: + xa_destroy(&incoming->xa); + kfree(incoming); +err_restore_free: + kho_restore_free(ser); + return ret; } =20 static void pci_flb_finish(struct liveupdate_flb_op_args *args) { - kho_restore_free(args->obj); + struct pci_flb_incoming *incoming =3D args->obj; + + xa_destroy(&incoming->xa); + kho_block_set_destroy(&incoming->block_set); + kho_restore_free(incoming->ser); + kfree(incoming); } =20 static struct liveupdate_flb_ops pci_liveupdate_flb_ops =3D { @@ -298,6 +377,87 @@ void pci_liveupdate_unpreserve(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_liveupdate_unpreserve); =20 +static struct pci_flb_incoming *pci_liveupdate_flb_get_incoming(void) +{ + struct pci_flb_incoming *incoming =3D NULL; + int ret; + + ret =3D liveupdate_flb_get_incoming(&pci_liveupdate_flb, (void **)&incomi= ng); + + /* Live Update is not enabled. */ + if (ret =3D=3D -EOPNOTSUPP) + return NULL; + + /* Live Update is enabled, but there is no incoming FLB data. */ + if (ret =3D=3D -ENODATA) + return NULL; + + /* + * Live Update is enabled and there is incoming FLB data, but none of it + * matches pci_liveupdate_flb.compatible. + * + * This could mean that no PCI FLB data was passed by the previous + * kernel, but it could also mean the previous kernel used a different + * compatibility string (i.e. a different ABI). + */ + if (ret =3D=3D -ENOENT) { + pr_info_once("No incoming FLB matched %s\n", pci_liveupdate_flb.compatib= le); + return NULL; + } + + /* + * There is incoming FLB data that matches pci_liveupdate_flb.compatible + * but it cannot be retrieved. + */ + if (ret) + panic("Failed to retrieve incoming FLB data (%d)\n", ret); + + return incoming; +} + +static void pci_liveupdate_flb_put_incoming(void) +{ + liveupdate_flb_put_incoming(&pci_liveupdate_flb); +} + +void pci_liveupdate_setup_device(struct pci_dev *dev) +{ + struct pci_flb_incoming *incoming; + struct pci_dev_ser *dev_ser; + unsigned long key; + + guard(rwsem_write)(&pci_liveupdate.rwsem); + + incoming =3D pci_liveupdate_flb_get_incoming(); + if (!incoming) + return; + + key =3D pci_ser_xa_key(pci_domain_nr(dev->bus), pci_dev_id(dev)); + dev_ser =3D xa_load(&incoming->xa, key); + + /* + * This device was not preserved across Live Update, or it was preserved + * but has already been probed and gone through pci_liveupdate_finish(), + * e.g. due to removing and re-adding the device. Either way, it's not + * treated as incoming-preserved. + */ + if (!dev_ser || !dev_ser->refcount) { + pci_liveupdate_flb_put_incoming(); + return; + } + + + pci_info(dev, "Device was preserved by previous kernel across Live Update= \n"); + dev->liveupdate.incoming =3D dev_ser; + + /* + * Hold the ref on the incoming FLB until pci_liveupdate_finish() so + * that dev->liveupdate.incoming cannot get freed while the PCI core + * has a pointer to it. It's better to leak the incoming FLB than do a + * use-after-free if driver does not call pci_liveupdate_finish(). + */ +} + void pci_liveupdate_cleanup_device(struct pci_dev *dev) { /* @@ -309,7 +469,83 @@ void pci_liveupdate_cleanup_device(struct pci_dev *dev) */ if (READ_ONCE(dev->liveupdate.outgoing)) pci_WARN(dev, 1, "Destroying outgoing-preserved device!\n"); + + if (READ_ONCE(dev->liveupdate.incoming)) { + pci_WARN(dev, 1, "Destroying incoming-preserved device!\n"); + pci_liveupdate_flb_put_incoming(); + } +} + +static void pci_liveupdate_finish_device(struct pci_ser *ser, struct pci_d= ev *dev) +{ + if (!dev->liveupdate.incoming) { + pci_warn(dev, "Cannot finish preserving an unpreserved device\n"); + return; + } + + if (dev->liveupdate.incoming->refcount !=3D 1) { + pci_WARN(dev, 1, "Preserved device has a corrupted refcount!\n"); + return; + } + + /* + * Drop the refcount so this device does not get treated as an incoming + * device again, e.g. in case pci_liveupdate_setup_device() gets called + * again because the device is hot-plugged. + */ + dev->liveupdate.incoming->refcount =3D 0; + + pci_info(dev, "Device is finished participating in Live Update\n"); + dev->liveupdate.incoming =3D NULL; + ser->nr_devices--; + pci_liveupdate_flb_put_incoming(); +} + +/** + * pci_liveupdate_finish() - Finish the preservation of a PCI device + * @dev: The PCI device + * + * pci_liveupdate_finish() notifies the PCI core that a PCI device that was + * preserved across the previous Live Update has finished participating in= Live + * Update. Drivers must call pci_liveupdate_finish() from their struct + * liveupdate_file_handler finish() callback to ensure the incoming struct + * pci_ser is allocated. + */ +void pci_liveupdate_finish(struct pci_dev *dev) +{ + struct pci_flb_incoming *incoming; + + guard(rwsem_write)(&pci_liveupdate.rwsem); + + incoming =3D pci_liveupdate_flb_get_incoming(); + if (!incoming) { + pci_warn(dev, "Cannot finish preserving device without incoming FLB\n"); + return; + } + + pci_liveupdate_finish_device(incoming->ser, dev); + pci_liveupdate_flb_put_incoming(); +} +EXPORT_SYMBOL_GPL(pci_liveupdate_finish); + +/** + * pci_liveupdate_is_incoming() - Check if a device is incoming-preserved + * @dev: The PCI device to check + * + * Check if a device was preserved across Live Update by the previous kern= el, + * i.e. the device is incoming-preserved. Note that a device is only consi= dered + * incoming-preserved prior to pci_liveupdate_finish(). It is up to driver= s to + * synchronize usage of pci_liveupdate_is_incoming() with their own call to + * pci_liveupdate_finish() to avoid acting on stale data. + * + * Returns: True if the device is incoming-preserved, false otherwise. + */ +bool pci_liveupdate_is_incoming(struct pci_dev *dev) +{ + guard(rwsem_read)(&pci_liveupdate.rwsem); + return dev->liveupdate.incoming; } +EXPORT_SYMBOL_GPL(pci_liveupdate_is_incoming); =20 /** * pci_liveupdate_register_flb() - Register a file handler with the PCI co= re diff --git a/drivers/pci/liveupdate.h b/drivers/pci/liveupdate.h index b2335581f8d0..eaaa3559fd77 100644 --- a/drivers/pci/liveupdate.h +++ b/drivers/pci/liveupdate.h @@ -11,8 +11,13 @@ #include =20 #ifdef CONFIG_PCI_LIVEUPDATE +void pci_liveupdate_setup_device(struct pci_dev *dev); void pci_liveupdate_cleanup_device(struct pci_dev *dev); #else +static inline void pci_liveupdate_setup_device(struct pci_dev *dev) +{ +} + static inline void pci_liveupdate_cleanup_device(struct pci_dev *dev) { } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 14b66acbdb15..5dc9d86e3597 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2065,6 +2065,8 @@ int pci_setup_device(struct pci_dev *dev) if (pci_early_dump) early_dump_pci_device(dev); =20 + pci_liveupdate_setup_device(dev); + /* Need to have dev->class ready */ dev->cfg_size =3D pci_cfg_space_size(dev); =20 @@ -2188,6 +2190,7 @@ int pci_setup_device(struct pci_dev *dev) default: /* unknown header */ pci_err(dev, "unknown header type %02x, ignoring device\n", dev->hdr_type); + pci_liveupdate_cleanup_device(dev); pci_release_of_node(dev); return -EIO; =20 diff --git a/include/linux/pci_liveupdate.h b/include/linux/pci_liveupdate.h index cfcfbfa73af7..cfdc3d62ec02 100644 --- a/include/linux/pci_liveupdate.h +++ b/include/linux/pci_liveupdate.h @@ -16,9 +16,11 @@ /** * struct pci_liveupdate - PCI Live Update state for a struct pci_dev * @outgoing: State preserved for the next kernel. + * @incoming: State preserved by the previous kernel. */ struct pci_liveupdate { struct pci_dev_ser *outgoing; + struct pci_dev_ser *incoming; }; =20 struct pci_dev; @@ -28,6 +30,8 @@ int pci_liveupdate_register_flb(struct liveupdate_file_ha= ndler *fh); void pci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh); int pci_liveupdate_preserve(struct pci_dev *dev); void pci_liveupdate_unpreserve(struct pci_dev *dev); +void pci_liveupdate_finish(struct pci_dev *dev); +bool pci_liveupdate_is_incoming(struct pci_dev *dev); #else static inline int pci_liveupdate_register_flb(struct liveupdate_file_handl= er *fh) { @@ -46,6 +50,15 @@ static inline int pci_liveupdate_preserve(struct pci_dev= *dev) static inline void pci_liveupdate_unpreserve(struct pci_dev *dev) { } + +static inline void pci_liveupdate_finish(struct pci_dev *dev) +{ +} + +static inline bool pci_liveupdate_is_incoming(struct pci_dev *dev) +{ + return false; +} #endif =20 #endif /* LINUX_PCI_LIVEUPDATE_H */ --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4AFB93BADA7 for ; Fri, 10 Jul 2026 21:26:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718789; cv=none; b=tHFADY+HqVyJw6ddr+k2fjGceZhXqGgBb+n5lnQalECpINsmcjVBslc4Aw9VdWMkUqkVXbT3TngGW9Wmw2annExOfWaKHeX1f1JuBKqObC79gLTu3JWOOsO8CmXmI7nUAgZjkUQvDrTh51a27tueHcjmgCSxWh9tE24HL7Sp4Qw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718789; c=relaxed/simple; bh=SLWJxUiNoHAtZnCZfKjICsopCm149nKp65AomgWi7OE=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=RQM1sqtAAapj38LmnQQFaXcefoda2QAd/WSAgKmwI/NWNggTTIcyY7GKQbBfPcxs9UJrArZiKWcbvS+Aust89o8yUCK2R4zO394sbcDrqCXGxDcFxG3O+j5rNtOEoT0UnswHfGO6qKpet51Vk1guJeTFA/IENs25WmS7LKaZIPI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=RNKErh0j; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="RNKErh0j" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-c892143db7fso1298905a12.1 for ; Fri, 10 Jul 2026 14:26:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718787; x=1784323587; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=YGoZNXB/ZYxw+GyFT2bV+z2qLaGl3Mol8FyZ542tK3Y=; b=RNKErh0jJBlNC3kxoddKs1dJ57CXNnIHSoEcUQROY2oG4vButRCQlwhoA9iaFyAvrx 9iXvR37eWrJRO2YKTxB+TAfCfFonBrLYMwN3n/KQfrOfoRAIejwEPbsyJfGZTP63EF0V yAFyLxUTQwDaRG9KChpQ0YJrvVpgkHzfnXJ/YH7P3YhuVFKAvvOwfs+psrvT+pDXXcJd YdpbZznmWjvvytd0tnrsX+o9ZjyBO4VuCk+MmYnm8tBi4aRH61/AARoXJEL3gbYPjUuD inhL9I3wA+XWGJOSXuruNHITsUcX6eg8Y4rE/EeSMdGTFJuTsGvV9ClnSTiTLoggRQ3x bxOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718787; x=1784323587; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=YGoZNXB/ZYxw+GyFT2bV+z2qLaGl3Mol8FyZ542tK3Y=; b=XphjZXfrHkRQU7tcLrEjtutMumb+WmUF0e0buqiVdrGAyTtddoNwNYdXTkcwy0VJMO 0VcThFDKk1PapYTFXJUbKxe3misrvyomrjZnwOF2gJPU6FPuQ6pQ0BgK5LDip/TWvmU4 iDhMkC7qxz4M/SHV4KjRIiJ3YyYruzPzW6IdmbCuPX9hPPpS+ieqD9mf/mjnZnQdhAry 3VmdzEWzEI1lk8mjZ55kCq7+XJyg33N0Fi5xP9pPp4+IMONHF630I+x0U+HNqHVmOVUs 0GLFnZ61l1jLGUbRqDn5ZqVOC6tXp8gebvmzxGgOD32t7FYQLxR8aYFTclOlFW8C3dxe d5PA== X-Forwarded-Encrypted: i=1; AHgh+RoL0hTo0V/7MT4J95asWlwjOb5iEKRWCmYSh0rinr6M2OxFuJp+dGWVLxdBS6x9M3WI8+SvuOgBZ/xMVlQ=@vger.kernel.org X-Gm-Message-State: AOJu0YwzGHiKY5/EnQLvwrhdTfZVZqPDH3WDFZ4JzN6f755mabptSPQ+ AxzuwCSJJ8uL3y639k2yxRzmFC3HtQjUM5lbejoiKSGfgFQG9SBacn5u4hmHWjE+uvrMUDIRZwV RsE32hSUhcU8EWA== X-Received: from pghx9.prod.google.com ([2002:a63:f709:0:b0:c85:c772:c6a5]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:4304:b0:3bf:bde7:d671 with SMTP id adf61e73a8af0-3c11060a6cbmr641192637.20.1783718786556; Fri, 10 Jul 2026 14:26:26 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:07 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-5-dmatlack@google.com> Subject: [PATCH v7 04/12] PCI: liveupdate: Document driver binding responsibilities From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Document how driver binding works during a Live Update and what the PCI core expects of drivers and users. Note that this is only a description of the current division of responsibilities. These can change in the future if we decide. Reviewed-by: Pasha Tatashin Reviewed-by: Pranjal Shrivastava Reviewed-by: Samiullah Khawaja Signed-off-by: David Matlack --- drivers/pci/liveupdate.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c index df6a02240aa4..a067632e70d1 100644 --- a/drivers/pci/liveupdate.c +++ b/drivers/pci/liveupdate.c @@ -70,6 +70,22 @@ * preserved. These may be relaxed in the future: * * * The device cannot be a Virtual Function (VF). + * + * Driver Binding + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * + * In the outgoing kernel, it is the driver's responsibility to ensure tha= t it + * does not release a device between pci_liveupdate_preserve() and + * pci_liveupdate_unpreserve(). + * + * In the incoming kernel, it is the driver's responsibility to ensure tha= t it + * does not release a preserved device between probe() and + * pci_liveupdate_finish(). + * + * It is the user's responsibility to ensure that incoming preserved devic= es are + * bound to the correct driver. i.e. The PCI core does not protect against= a + * device getting preserved by driver A in the outgoing kernel and then ge= tting + * bound to driver B in the incoming kernel. This may change in the future. */ =20 #define pr_fmt(fmt) "PCI: " KBUILD_BASENAME ": " fmt --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 21B4B3BB115 for ; Fri, 10 Jul 2026 21:26:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718791; cv=none; b=hxQJcE3rJzYFHvJynj31OsQmFNQ08OjY4DBSUv7gtaL7k+RS/LrtvzxMNlNeytABBhMw/DOHIbT2yhjb9wPGyo0luDt1IcQNn7JXsHZQvfQQjC8qF/R01VCK7akpj2ZfrxI1/yiu+Fv0YgNXXHd9oUaUp0+B6R6A8Ec0IHOQw2I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718791; c=relaxed/simple; bh=l99c6rideUNoGc9UcbCSKFpumoM8k0lZ5nIWPqVf/BA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=fGlT5B5VCdiT9Q1mAj00kDApwpk8Sbjc+Gn7MTC4gcHIdmmPJ6zjKviTj2Uo5yHLz+95xbe7c7F6/7LeNv2AoOa7ziB65uFCb4iIKdyHCWyk5PYNZtveXSjy08MN0R4/gl1y3jtnDP4fpi0JA4ieX63QKLGmv8D6Zh5qhSMpWeA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=XnIjcl8G; arc=none smtp.client-ip=209.85.214.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="XnIjcl8G" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-2c354050c34so21279965ad.3 for ; Fri, 10 Jul 2026 14:26:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718787; x=1784323587; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=/hPVaDoRJAueZjNQ0NAjSyINZ2msgaXxj6lZgcfKzVg=; b=XnIjcl8GP0BeNPMuR3E+2TPaY46XpFdM9ZkZFwDBn899JoFKugXNr1DYLvHHI0fSGD OlSThidGYZJATznXk+tk2/l2PBocqDU5Xv41UqzQdW9rk6Zt8ufIME4kVJX7RN7BKU/S tHvJEU0EGbCjrM8mgu86T1Va8ftiRaFi9Y6Qh0qMTDu/txPMSIxfuOIJcGpYHaQK4ox5 xnLdMD9PZgHTN8gzb8c/xXXaWh5SgSo4ENoA9/ZYIGLOu5eLZilwERnpqDJz8+PYzmZc E9AGOk/v1AcdJ0ClVW5Mbwze0j2z5fhdhzY/rv7yjGAMW7bjbbKr63TQzNbH46xhHhX/ siYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718787; x=1784323587; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=/hPVaDoRJAueZjNQ0NAjSyINZ2msgaXxj6lZgcfKzVg=; b=mHyOiKeGQRZJc+Nj08ikmJrWiOTPiBDVT1tukPhaHZYc2unyavUQAYHbzcll5vKNqQ 48WHZfXf/jJIERvtA2X9fu7GtXyKpcWHMJx44AFksGvMUzM/fNHCMEq2ept0ZjiF0Php OmwlkyTP+dYoIZYZ0C/l9vd5aUokG/IjXwfAscE2WRWBm8HfQ34/RK12wtTFxeMqP9iJ 5cZabXoMe+3MGyyKAwVCDs2Mv8+VhmFqyBlgZB5FVbdWRusM3HsNvg3vVPKENxdFaKTe qJ+9g3pCnVxEc03kAVupdUMGbRYls+tkXljnyN/s5mQGeifnEE/chYWk2D2FOKKmIYjJ RmqQ== X-Forwarded-Encrypted: i=1; AHgh+RpMcLvzOeqvpdJNbZMVT90IRfT3LSIUAL0nn7hPbher0+ciLmjYAZOiH6XzGz3CN/fY9vyZOu1TbbyhCuc=@vger.kernel.org X-Gm-Message-State: AOJu0YxiJgDXidkh+gja3C1g1tCq8em3B6GlOYYFpDO6rNSxNzhjuZGD MuGzOp1BbOHv9OzjN8wcgZ+xPETopDDgK8I8cz36UQIIolslkIaTAdjvoXIibqDlZmTFp4X0pJl /bjsSYsisX9m0PA== X-Received: from plhu3.prod.google.com ([2002:a17:903:1243:b0:2cc:c59c:76ac]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:e94e:b0:2ca:bf68:2a54 with SMTP id d9443c01a7336-2ce9f021408mr7596855ad.22.1783718787297; Fri, 10 Jul 2026 14:26:27 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:08 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-6-dmatlack@google.com> Subject: [PATCH v7 05/12] PCI: liveupdate: Keep bus numbers constant during Live Update From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" During a Live Update, preserved devices must be allowed to continue performing memory transactions so the kernel cannot change the fabric topology, including bus numbers, since that would require disabling and flushing any memory transactions first. To keep bus numbers constant, always inherit the secondary and subordinate bus numbers assigned to bridges during scanning, instead of assigning new ones, if any PCI devices are being preserved. Note that the kernel inherits bus numbers even on bridges without any downstream endpoints that were preserved. This avoids accidentally assigning a bridge a new window that overlaps with a preserved device that is downstream of a different bridge. If a bridge is scanned with a broken topology or has no bus numbers set during a Live Update, refuse to assign it new bus numbers and refuse to enumerate devices below it until the Live Update is finished. This is a safety measure to prevent topology conflicts. Require that CONFIG_CARDBUS is not enabled to enable CONFIG_PCI_LIVEUPDATE since inheriting bus numbers on PCI-to-CardBus bridges requires additional work but is not a priority at the moment. Reviewed-by: Pranjal Shrivastava Reviewed-by: Samiullah Khawaja Signed-off-by: David Matlack Reviewed-by: Pasha Tatashin --- .../admin-guide/kernel-parameters.txt | 6 +- drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 102 ++++++++++++++++++ drivers/pci/liveupdate.h | 14 +++ drivers/pci/probe.c | 17 ++- include/linux/pci_liveupdate.h | 4 + 6 files changed, 139 insertions(+), 6 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index 4f65b2a37521..ed9eef8de64c 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -5105,7 +5105,11 @@ Kernel parameters explicitly which ones they are. assign-busses [X86] Always assign all PCI bus numbers ourselves, overriding - whatever the firmware may have done. + whatever the firmware may have done. Ignored + during a Live Update, where the kernel must + inherit the PCI topology (including bus numbers) + to avoid interrupting ongoing memory + transactions of preserved devices. usepirqmask [X86] Honor the possible IRQ mask stored in the BIOS $PIR table. This is needed on some systems with broken BIOSes, notably diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 8af20f558086..16fbd4212e0f 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -273,7 +273,7 @@ config VGA_ARB_MAX_GPUS =20 config PCI_LIVEUPDATE bool "PCI Live Update Support" - depends on PCI && LIVEUPDATE && 64BIT + depends on PCI && LIVEUPDATE && 64BIT && !CARDBUS help Enable PCI core support for preserving PCI devices across Live Update. This, in combination with support in a device's driver, diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c index a067632e70d1..b2b950d71657 100644 --- a/drivers/pci/liveupdate.c +++ b/drivers/pci/liveupdate.c @@ -86,6 +86,21 @@ * bound to the correct driver. i.e. The PCI core does not protect against= a * device getting preserved by driver A in the outgoing kernel and then ge= tting * bound to driver B in the incoming kernel. This may change in the future. + * + * BDF Stability + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * + * The PCI core guarantees that preserved devices can be identified by the= same + * bus, device, and function numbers for as long as they are preserved + * (including across kexec). To accomplish this, the PCI core always inher= its + * the secondary and subordinate bus numbers assigned to bridges during sc= anning + * if any device is preserved. This is true even on architectures that alw= ays + * assign new bus numbers during scanning. The kernel assumes the previous + * kernel established a sane bus topology across kexec. + * + * If a misconfigured or unconfigured bridge is encountered during enumera= tion + * while there are preserved devices, its secondary and subordinate bus nu= mbers + * will be cleared and devices below it will not be enumerated. */ =20 #define pr_fmt(fmt) "PCI: " KBUILD_BASENAME ": " fmt @@ -436,6 +451,93 @@ static void pci_liveupdate_flb_put_incoming(void) liveupdate_flb_put_incoming(&pci_liveupdate_flb); } =20 +/** + * pci_liveupdate_scan_bridge_begin() - Determine if a bridge should inher= it bus numbers + * @bus: The parent bus of the bridge. + * @dev: The PCI bridge device. + * @pass: The scan pass (0 for first pass, 1 for second pass). + * + * This function is called by the PCI core when it begins scanning a bridg= e. + * It determines whether the bridge should inherit the secondary and subor= dinate + * bus numbers assigned to it by the previous kernel. This is necessary to + * keep bus numbers constant for preserved devices downstream of the bridg= e. + * + * Return: True if bus numbers should be inherited, false otherwise. + */ +bool pci_liveupdate_scan_bridge_begin(struct pci_bus *bus, struct pci_dev = *dev, + int pass) +{ + struct pci_dev *parent =3D bus->self; + + /* + * On the second pass, reuse the value that was set on the first pass + * so that the passes are consistent with one another. + */ + if (pass) + return dev->liveupdate.inherit_buses; + + /* + * If the parent bridge is being forced to inherit its bus numbers + * during this scan then this bridge must as well, otherwise the PCI + * core could expand this bridge's reservation beyond its parent (which + * cannot expand). + */ + if (parent && parent->liveupdate.inherit_buses) { + dev->liveupdate.inherit_buses =3D true; + return true; + } + + /* + * Otherwise, if there are any incoming preserved devices, force the + * bus numbers to be inherited to avoid changing the bus numbers + * assigned to those devices during enumeration. + * + * To keep things simple, inherit bus numbers on all bridges if any PCI + * devices are incoming, to ensure that no bridge's reservation is + * expanded to overlap with a preserved device downstream of a different + * bridge. + */ + scoped_guard(rwsem_read, &pci_liveupdate.rwsem) { + struct pci_flb_incoming *incoming; + + incoming =3D pci_liveupdate_flb_get_incoming(); + if (!incoming) { + dev->liveupdate.inherit_buses =3D false; + return false; + } + + /* + * It is safe to sample incoming->ser->nr_devices and then + * drop the rwsem since nr_devices will only decrease. Thus the + * only "race" is that the current scan will be overly + * conservative and force bus inheritance. + */ + dev->liveupdate.inherit_buses =3D !!incoming->ser->nr_devices; + pci_liveupdate_flb_put_incoming(); + } + + return dev->liveupdate.inherit_buses; +} + +/** + * pci_liveupdate_scan_bridge_end() - Finish scanning a PCI bridge + * @dev: The PCI bridge device. + * @pass: The scan pass (0 for first pass, 1 for second pass). + * + * This function is called by the PCI core when it finishes scanning a bri= dge. + * It clears the inheritance status after the second pass so it can be + * re-evaluated on future scans. + */ +void pci_liveupdate_scan_bridge_end(struct pci_dev *dev, int pass) +{ + /* + * Clear inherit_buses after the second pass so it can be re-evaluated + * on future scans. + */ + if (pass) + dev->liveupdate.inherit_buses =3D false; +} + void pci_liveupdate_setup_device(struct pci_dev *dev) { struct pci_flb_incoming *incoming; diff --git a/drivers/pci/liveupdate.h b/drivers/pci/liveupdate.h index eaaa3559fd77..c763255a8de4 100644 --- a/drivers/pci/liveupdate.h +++ b/drivers/pci/liveupdate.h @@ -13,6 +13,9 @@ #ifdef CONFIG_PCI_LIVEUPDATE void pci_liveupdate_setup_device(struct pci_dev *dev); void pci_liveupdate_cleanup_device(struct pci_dev *dev); +bool pci_liveupdate_scan_bridge_begin(struct pci_bus *bus, struct pci_dev = *dev, + int pass); +void pci_liveupdate_scan_bridge_end(struct pci_dev *dev, int pass); #else static inline void pci_liveupdate_setup_device(struct pci_dev *dev) { @@ -21,6 +24,17 @@ static inline void pci_liveupdate_setup_device(struct pc= i_dev *dev) static inline void pci_liveupdate_cleanup_device(struct pci_dev *dev) { } + +static inline bool pci_liveupdate_scan_bridge_begin(struct pci_bus *bus, + struct pci_dev *dev, + int pass) +{ + return false; +} + +static inline void pci_liveupdate_scan_bridge_end(struct pci_dev *dev, int= pass) +{ +} #endif =20 #endif /* DRIVERS_PCI_LIVEUPDATE_H */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5dc9d86e3597..165973bc92aa 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1397,6 +1397,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus= , struct pci_dev *dev, int max, unsigned int available_buses, int pass) { + bool liveupdate, assign_new_buses =3D pcibios_assign_all_busses(); struct pci_bus *child; u32 buses; u16 bctl; @@ -1406,6 +1407,10 @@ static int pci_scan_bridge_extend(struct pci_bus *bu= s, struct pci_dev *dev, u8 fixed_sec, fixed_sub; int next_busnr; =20 + liveupdate =3D pci_liveupdate_scan_bridge_begin(bus, dev, pass); + if (liveupdate) + assign_new_buses =3D false; + /* * Make sure the bridge is powered on to be able to access config * space of devices below it. @@ -1449,8 +1454,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus= , struct pci_dev *dev, goto out; } =20 - if ((secondary || subordinate) && - !pcibios_assign_all_busses() && !broken) { + if ((secondary || subordinate) && !assign_new_buses && !broken) { unsigned int cmax, buses; =20 /* @@ -1492,8 +1496,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus= , struct pci_dev *dev, * do in the second pass. */ if (!pass) { - if (pcibios_assign_all_busses() || broken) - + if (assign_new_buses || broken) /* * Temporarily disable forwarding of the * configuration cycles on all bridges in @@ -1507,6 +1510,11 @@ static int pci_scan_bridge_extend(struct pci_bus *bu= s, struct pci_dev *dev, goto out; } =20 + if (liveupdate) { + pci_err(dev, "Cannot reconfigure bridge during Live Update, skipping\n"= ); + goto out; + } + /* Clear errors */ pci_write_config_word(dev, PCI_STATUS, 0xffff); =20 @@ -1567,6 +1575,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus= , struct pci_dev *dev, pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl); =20 pm_runtime_put(&dev->dev); + pci_liveupdate_scan_bridge_end(dev, pass); =20 return max; } diff --git a/include/linux/pci_liveupdate.h b/include/linux/pci_liveupdate.h index cfdc3d62ec02..2be98819e313 100644 --- a/include/linux/pci_liveupdate.h +++ b/include/linux/pci_liveupdate.h @@ -17,10 +17,14 @@ * struct pci_liveupdate - PCI Live Update state for a struct pci_dev * @outgoing: State preserved for the next kernel. * @incoming: State preserved by the previous kernel. + * @inherit_buses: True if the PCI core should inherit the secondary and + * subordinate bus numbers assigned to this device due to + * an ongoing Live Update. */ struct pci_liveupdate { struct pci_dev_ser *outgoing; struct pci_dev_ser *incoming; + bool inherit_buses; }; =20 struct pci_dev; --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA22F3BBFAE for ; Fri, 10 Jul 2026 21:26:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718792; cv=none; b=b4sIDXXMnd4aM1RGgaQ8f8S/ccm5ihn0UNvAhzAQaM6HcadygQbxhFaG2XtyxfiuK0G/eRz6Azj4OVZ8Z+C6rbORVD2z6kGYuUaqLHXWqz5v9iNEenW2LhSaG5JaDbjg++aORmZ27BML1vrtMvPsgSeBRiQN9RJAVCzZHutH2FE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718792; c=relaxed/simple; bh=8ha6HCuXvqr/g+nFcZIjj8vXsbPeH/dzz3F2cknWwG0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=SmMeqIIA6SEd+Adz9lfLlQUuFL0R5IlMu8ZGrfxiri4x+KNUe18SUKshJSA+EHklTluXt7Oz8GFHPhf69uRq3Nep228MqpPW3u4jPaQDW1Z6tPx6F13lIBpwf/awPObC1jpYPBHZFFsnW+WOWkQF/7jOem56+LwKZBBwvKdk8Go= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=fs+/N9/W; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="fs+/N9/W" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-8482b95574dso1428919b3a.1 for ; Fri, 10 Jul 2026 14:26:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718788; x=1784323588; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=57QfbJnRLtEgyk7xuyEyKOzrYVcCZwar9BStEh/xugM=; b=fs+/N9/Wpm8mUn70rLOJvP0k6xqlIwlUzqH5Bk1FRF3vxK4599AH+ioytasO6f6SKr 2GK8kVZhtL53lE2asmNftM2mRa3nhEf1F+lYtRnPjVK/k9cjWytqWuVrrEwCwqbG/RYH y/KERnzMleqPYRFqCQZKY8NjG+qWvC2wSfd68KSTZwrAU00CpjfwPrMouZQ54LH2czLu 2HYmrgmfcxzb2i9EF+Le8O7Xz3RWj2/vXFqCQJYasxp+lbwEIttyNIf5BtlNyuisQmAU AiXH+0Ft2FPMCb5vao3Sg1Z1OxKI42MGsVQn7Id+5wDgvMzCN0F8YUFGEMX5C75Es0xA w1Kw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718788; x=1784323588; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=57QfbJnRLtEgyk7xuyEyKOzrYVcCZwar9BStEh/xugM=; b=iM3KCf3IuBdtafGdkKrlopgLmDrt6t+4twdUiLf9y4x+88Kf7cbg+gRtA5F5Caqh7o Wempq95YUHZpCkSEOriXYwC3lamP7fVvTounMbjGrOaswXcKohpHJF6kTBUp4Nm4XF7l AGVjfRhhBAOFDwJqTuiTcuJ7pWyBk3/BBvVbLiqhyLF0q/OfLDppQLMsTEUYrOcqdMMW GFnZjONQvCDqHmmxG08JEOWD6MsBw/f1aqkecVEOggq91a+xXpX86NT6bt0+2RijgYow ZnTd6I5M3lX08vc6AE7S1sQDhUOXrfFYKbuCjMfDQKwZ/CBQhPaNSNfHYJS/R0cm938i pZjQ== X-Forwarded-Encrypted: i=1; AHgh+RpahjDFzWriyZSWaP87gDZN92GYlQ8EPi1rXCEn9YQfLO2YjBjlXg2OKtMaGjN1TSTgyGJ+lczfVHm+6JE=@vger.kernel.org X-Gm-Message-State: AOJu0Yx8MxCGGwEYUsTctRKwRJ/Z4esIYyXfuUvD7HU0jldREXd9ve40 fsb5X85k1PLV3Ayo7pI2zYXFLfECguITwWEovtsvzdALIJm+VrnVvuu/2qZRPuoZ1N/MJDAx2CH PARiRGmIrxL0mBg== X-Received: from pfbhm2.prod.google.com ([2002:a05:6a00:6702:b0:847:9cc9:a40d]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:450f:b0:848:2f71:b65b with SMTP id d2e1a72fcca58-848897d5cc1mr570948b3a.70.1783718788088; Fri, 10 Jul 2026 14:26:28 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:09 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-7-dmatlack@google.com> Subject: [PATCH v7 06/12] PCI: liveupdate: Auto-preserve upstream bridges across Live Update From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When a PCI device is preserved across a Live Update, all of its upstream bridges up to the root port must also be preserved. This enables the PCI core and any drivers bound to the bridges to manage bridges correctly across a Live Update. Notably, this will be used in subsequent commits to ensure that preserved devices can continue performing memory transactions without a disruption or change in routing. To preserve bridges, the PCI core tracks the number of downstream devices preserved under each bridge using a reference count in struct pci_dev_ser. This allows a bridge to remain preserved until all its downstream preserved devices are unpreserved or finish their participation in the Live Update. Signed-off-by: David Matlack Reviewed-by: Pasha Tatashin --- drivers/pci/liveupdate.c | 136 +++++++++++++++++++++++++++++++----- include/linux/kho/abi/pci.h | 5 +- 2 files changed, 122 insertions(+), 19 deletions(-) diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c index b2b950d71657..7f7710cb1da0 100644 --- a/drivers/pci/liveupdate.c +++ b/drivers/pci/liveupdate.c @@ -101,6 +101,18 @@ * If a misconfigured or unconfigured bridge is encountered during enumera= tion * while there are preserved devices, its secondary and subordinate bus nu= mbers * will be cleared and devices below it will not be enumerated. + * + * PCI-to-PCI Bridges + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * + * Any PCI-to-PCI bridges upstream of a preserved device are automatically + * preserved when the device is preserved. The PCI core keeps track of the + * number of downstream devices that are preserved under a bridge so that = the + * bridge is only unpreserved once all downstream devices are unpreserved. + * + * This enables the PCI core and any drivers bound to the bridge to partic= ipate + * in the Live Update so that preserved endpoints can continue issuing mem= ory + * transactions during the Live Update. */ =20 #define pr_fmt(fmt) "PCI: " KBUILD_BASENAME ": " fmt @@ -316,28 +328,52 @@ static struct pci_dev_ser *pci_get_empty_or_append(st= ruct pci_flb_outgoing *outg return dev_ser; } =20 -static void pci_liveupdate_unpreserve_device(struct pci_flb_outgoing *outg= oing, struct pci_dev *dev) +static int pci_liveupdate_unpreserve_device(struct pci_flb_outgoing *outgo= ing, struct pci_dev *dev) { struct pci_dev_ser *dev_ser =3D dev->liveupdate.outgoing; =20 if (!dev_ser) { pci_warn(dev, "Cannot unpreserve device that is not preserved\n"); - return; + return -EINVAL; + } + + if (!dev_ser->refcount) { + pci_WARN(dev, 1, "Preserved device has a 0 refcount!\n"); + return -EINVAL; } =20 + if (--dev_ser->refcount) + return 0; + pci_info(dev, "Device will no longer be preserved across next Live Update= \n"); outgoing->ser->nr_devices--; memset(dev_ser, 0, sizeof(*dev_ser)); dev->liveupdate.outgoing =3D NULL; + return 0; } =20 -static int pci_liveupdate_preserve_device(struct pci_flb_outgoing *outgoin= g, struct pci_dev *dev) +static int pci_liveupdate_preserve_device_again(struct pci_dev *dev) { - struct pci_dev_ser *dev_ser; + if (!dev->liveupdate.outgoing->refcount) { + pci_WARN(dev, 1, "Preserved device with 0 refcount!\n"); + return -EINVAL; + } =20 - if (dev->liveupdate.outgoing) + /* + * Endpoint devices should not be preserved more than once. Bridges are + * preserved once for every downstream device that is preserved. + */ + if (!dev->subordinate) return -EBUSY; =20 + dev->liveupdate.outgoing->refcount++; + return 0; +} + +static int __pci_liveupdate_preserve_device(struct pci_flb_outgoing *outgo= ing, struct pci_dev *dev) +{ + struct pci_dev_ser *dev_ser; + dev_ser =3D pci_get_empty_or_append(outgoing); if (IS_ERR(dev_ser)) return PTR_ERR(dev_ser); @@ -354,6 +390,52 @@ static int pci_liveupdate_preserve_device(struct pci_f= lb_outgoing *outgoing, str return 0; } =20 +static int pci_liveupdate_preserve_device(struct pci_flb_outgoing *outgoin= g, struct pci_dev *dev) +{ + if (dev->liveupdate.outgoing) + return pci_liveupdate_preserve_device_again(dev); + + return __pci_liveupdate_preserve_device(outgoing, dev); +} + +#define for_each_pci_dev_in_path(_d, _start, _end) \ + for ((_d) =3D (_start); (_d) !=3D (_end); (_d) =3D (_d)->bus->self) + +static void __pci_liveupdate_unpreserve_path(struct pci_flb_outgoing *outg= oing, + struct pci_dev *start, + struct pci_dev *end) +{ + struct pci_dev *dev; + + for_each_pci_dev_in_path(dev, start, end) { + if (pci_liveupdate_unpreserve_device(outgoing, dev)) + return; + } +} + +static void pci_liveupdate_unpreserve_path(struct pci_flb_outgoing *outgoi= ng, + struct pci_dev *start) +{ + __pci_liveupdate_unpreserve_path(outgoing, start, /*end=3D*/NULL); +} + +static int pci_liveupdate_preserve_path(struct pci_flb_outgoing *outgoing, + struct pci_dev *start) +{ + struct pci_dev *dev; + int ret; + + for_each_pci_dev_in_path(dev, start, NULL) { + ret =3D pci_liveupdate_preserve_device(outgoing, dev); + if (ret) { + __pci_liveupdate_unpreserve_path(outgoing, start, dev); + return ret; + } + } + + return 0; +} + /** * pci_liveupdate_preserve() - Preserve a PCI device across Live Update * @dev: The PCI device to preserve. @@ -363,6 +445,9 @@ static int pci_liveupdate_preserve_device(struct pci_fl= b_outgoing *outgoing, str * pci_liveupdate_preserve() from their struct liveupdate_file_handler * preserve() callback to ensure the outgoing struct pci_ser is already se= t up. * + * pci_liveupdate_preserve() automatically preserves all bridges upstream = of + * @dev. + * * Returns: 0 on success, <0 on failure. */ int pci_liveupdate_preserve(struct pci_dev *dev) @@ -378,7 +463,7 @@ int pci_liveupdate_preserve(struct pci_dev *dev) if (IS_ERR(outgoing)) return PTR_ERR(outgoing); =20 - return pci_liveupdate_preserve_device(outgoing, dev); + return pci_liveupdate_preserve_path(outgoing, dev); } EXPORT_SYMBOL_GPL(pci_liveupdate_preserve); =20 @@ -391,6 +476,9 @@ EXPORT_SYMBOL_GPL(pci_liveupdate_preserve); * pci_liveupdate_unpreserve() from their struct liveupdate_file_handler * unpreserve() callback to ensure the outgoing struct pci_ser is already = set * up. + * + * pci_liveupdate_unpreserve() automatically unpreserves all bridges upstr= eam of + * @dev. */ void pci_liveupdate_unpreserve(struct pci_dev *dev) { @@ -404,7 +492,7 @@ void pci_liveupdate_unpreserve(struct pci_dev *dev) return; } =20 - pci_liveupdate_unpreserve_device(outgoing, dev); + pci_liveupdate_unpreserve_path(outgoing, dev); } EXPORT_SYMBOL_GPL(pci_liveupdate_unpreserve); =20 @@ -594,29 +682,41 @@ void pci_liveupdate_cleanup_device(struct pci_dev *de= v) } } =20 -static void pci_liveupdate_finish_device(struct pci_ser *ser, struct pci_d= ev *dev) +static int pci_liveupdate_finish_device(struct pci_ser *ser, struct pci_de= v *dev) { if (!dev->liveupdate.incoming) { pci_warn(dev, "Cannot finish preserving an unpreserved device\n"); - return; + return -EINVAL; } =20 - if (dev->liveupdate.incoming->refcount !=3D 1) { - pci_WARN(dev, 1, "Preserved device has a corrupted refcount!\n"); - return; + if (!dev->liveupdate.incoming->refcount) { + pci_WARN(dev, 1, "Preserved device has a 0 refcount!\n"); + return -EINVAL; } =20 /* - * Drop the refcount so this device does not get treated as an incoming - * device again, e.g. in case pci_liveupdate_setup_device() gets called - * again because the device is hot-plugged. + * Decrement the refcount so this device does not get treated as an + * incoming device again, e.g. in case pci_liveupdate_setup_device() + * gets called again because the device is hot-plugged. */ - dev->liveupdate.incoming->refcount =3D 0; + if (--dev->liveupdate.incoming->refcount) + return 0; =20 pci_info(dev, "Device is finished participating in Live Update\n"); dev->liveupdate.incoming =3D NULL; ser->nr_devices--; pci_liveupdate_flb_put_incoming(); + return 0; +} + +static void pci_liveupdate_finish_path(struct pci_ser *ser, struct pci_dev= *start) +{ + struct pci_dev *dev; + + for_each_pci_dev_in_path(dev, start, NULL) { + if (pci_liveupdate_finish_device(ser, dev)) + return; + } } =20 /** @@ -628,6 +728,8 @@ static void pci_liveupdate_finish_device(struct pci_ser= *ser, struct pci_dev *de * Update. Drivers must call pci_liveupdate_finish() from their struct * liveupdate_file_handler finish() callback to ensure the incoming struct * pci_ser is allocated. + * + * pci_liveupdate_finish() automatically finishes all bridges upstream of = @dev. */ void pci_liveupdate_finish(struct pci_dev *dev) { @@ -641,7 +743,7 @@ void pci_liveupdate_finish(struct pci_dev *dev) return; } =20 - pci_liveupdate_finish_device(incoming->ser, dev); + pci_liveupdate_finish_path(incoming->ser, dev); pci_liveupdate_flb_put_incoming(); } EXPORT_SYMBOL_GPL(pci_liveupdate_finish); diff --git a/include/linux/kho/abi/pci.h b/include/linux/kho/abi/pci.h index de549016807a..acf1b38dff02 100644 --- a/include/linux/kho/abi/pci.h +++ b/include/linux/kho/abi/pci.h @@ -23,7 +23,7 @@ * incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */ =20 -#define PCI_LUO_FLB_COMPATIBLE "pci-v1" +#define PCI_LUO_FLB_COMPATIBLE "pci-v2" =20 /** * struct pci_dev_ser - Serialized state about a single PCI device. @@ -32,7 +32,8 @@ * @bdf: The device's PCI bus, device, and function number. * @refcount: Reference count used by the PCI core to keep track of whethe= r it * is done using a device's struct pci_dev_ser. The value of the - * refcount is equal to 1 when the struct pci_dev_ser is in use= , and + * refcount is equal to the number of preserved devices at or b= elow + * it in the PCI hierarchy when the struct pci_dev_ser is in us= e, and * 0 otherwise. */ struct pci_dev_ser { --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F09413BCD0B for ; Fri, 10 Jul 2026 21:26:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718793; cv=none; b=bGxtbe2b2hjgxyIKBV+3lw/boaJN1h+U6fq7xa+erMs84UajnN2iRWCpwXcugueBMiJQw4/Gqbk17eMuuJ+oPbXnjW26AvsBTdwzLrYSUxP1ARIvrYZuTrH43gFK4ubO4T2OXaNEqGlPy2KS9Jj+48BoEqyvYvW5VeIEmuPi98Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718793; c=relaxed/simple; bh=4mMeD/WJsmKp4i9OQVeLhrR8NDiaTpFSYRFgOS4JvXA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=evmjoSOAQYfBXpzC0FotRZm+UotJAb6OfENQTSPyT9RRp5+zY4b61KdrIcnyXRMU0VvPsif4yN9sR2by8rGCFPzokkbXFRSydwpi4BSc8CzMaJVNa7hP+phXOM+wVUgBp7P2xpAHMIgzHsup7D1DETQAK2Y/SUPKVUjSUlthdW8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=q2/JzkO+; arc=none smtp.client-ip=209.85.210.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="q2/JzkO+" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-847a00bcbd0so1757802b3a.0 for ; Fri, 10 Jul 2026 14:26:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718789; x=1784323589; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=92/0TGptvABo802k4Z/+83heETiRRWcuAF49mOH2xHs=; b=q2/JzkO+OFrnzeztMC/0T6+Ggg4VNqbt64d3Zw/N2Yfu5MbUibc00m//3WbdEomJDt BdRQN4PJKg17sO/1gZYCr3fpRUb3MaEhVW1wCQerlmCvJr/WDCvGz1Ae8ncp8RX61/Qa wDXPKvmZKd96BWYcEl1rhqOOfFAh2rmZdeT8WBAluhk8lZlIM3rD9DoRSlLz7g0uatuC J6b2EbLpmtH0NVb0Pu++O+JXTwgrgQR0Cq8yan7Z50GvVxc9jQIxcSFtyhPlLKh0jhWK Xe4tc+6yrsYY6B0nnEaRNrbASbOfHhHOgC6vy2Lw7a+kYx6C68fimBkXsBV4/Tc5H9ee fNWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718789; x=1784323589; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=92/0TGptvABo802k4Z/+83heETiRRWcuAF49mOH2xHs=; b=W0IfXI4UnbmItoQ7NyFeG7cxZhdKxJl5sF/vu5xOQ/0QiE7IZLDqs14UFs/vemdYl+ WPplacH7ibRnw8BqMqCdKDAd0/XjK3PxTFs3bLPyd2wKWUXfKG6u5jyky6b9QBpRXz16 ppSq2MrofNBzLDEJ/RiQDXJfPCMKNWJVZ1HrEsDNv26W2JWITwO4dqzDkaPiMgbYsejV rVTZ7pJXhCKBL+DH5yHIkHgI8jHjYfhkcvngJxXdGwvSdWMX+iaNb3jEXY7a4OjuzKTy mM423XyvjVZeLH58H9wQIj/gs8+q+SeAzGVXwTsEMYm+/pDIrCrCpLhCFBIb/QzKV+X0 WQsw== X-Forwarded-Encrypted: i=1; AHgh+RpQ41fbyEtd+7xxSEt4bM6f9GU0gbeu56CurmksibplUppwJnkrOxZLX12Ju6wVWK+VIivcqCPhCybDf5E=@vger.kernel.org X-Gm-Message-State: AOJu0Yz4/U6XIjQ0Xe4KE11/3kOHiXF0w4dLR4kuvKk2p45qYmE3cCHY v3Y2jm/P4REdI0zSyNSS3yopn5vU4GOibd1jeTyHZRLh5mSwNJIoR+zeBdPr7wpIxaWnXdczjAX +bMRxXJgGCNNmZA== X-Received: from pfn17.prod.google.com ([2002:a05:6a00:a211:b0:848:7bbd:284b]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:ab88:b0:848:2f84:f429 with SMTP id d2e1a72fcca58-8488976cfd4mr571193b3a.66.1783718788869; Fri, 10 Jul 2026 14:26:28 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:10 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-8-dmatlack@google.com> Subject: [PATCH v7 07/12] PCI: Refactor matching logic for pci_dev_acs_ops From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Refactor the logic to match devices to pci_dev_acs_ops by factoring out the loop and device matching into its own routine. This eliminates some duplicate code between pci_dev_specific_enable_acs() and pci_dev_specific_disable_acs_redir(), and will also be used in a subsequent commit to check if a device requires device-specific enable_acs() during a Live Update. No functional change intended. Reviewed-by: Pranjal Shrivastava Signed-off-by: David Matlack Reviewed-by: Bjorn Helgaas Reviewed-by: Pasha Tatashin --- drivers/pci/quirks.c | 51 ++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b09f27f7846f..7ac39ec2843e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -5374,9 +5374,6 @@ static void pci_quirk_enable_intel_rp_mpc_acs(struct = pci_dev *dev) */ static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev) { - if (!pci_quirk_intel_pch_acs_match(dev)) - return -ENOTTY; - if (pci_quirk_enable_intel_lpc_acs(dev)) { pci_warn(dev, "Failed to enable Intel PCH ACS quirk\n"); return 0; @@ -5396,9 +5393,6 @@ static int pci_quirk_enable_intel_spt_pch_acs(struct = pci_dev *dev) int pos; u32 cap, ctrl; =20 - if (!pci_quirk_intel_spt_pch_acs_match(dev)) - return -ENOTTY; - pos =3D dev->acs_cap; if (!pos) return -ENOTTY; @@ -5426,9 +5420,6 @@ static int pci_quirk_disable_intel_spt_pch_acs_redir(= struct pci_dev *dev) int pos; u32 cap, ctrl; =20 - if (!pci_quirk_intel_spt_pch_acs_match(dev)) - return -ENOTTY; - pos =3D dev->acs_cap; if (!pos) return -ENOTTY; @@ -5448,56 +5439,56 @@ static int pci_quirk_disable_intel_spt_pch_acs_redi= r(struct pci_dev *dev) static const struct pci_dev_acs_ops { u16 vendor; u16 device; + bool (*match)(struct pci_dev *dev); int (*enable_acs)(struct pci_dev *dev); int (*disable_acs_redir)(struct pci_dev *dev); } pci_dev_acs_ops[] =3D { { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, + .match =3D pci_quirk_intel_pch_acs_match, .enable_acs =3D pci_quirk_enable_intel_pch_acs, }, { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, + .match =3D pci_quirk_intel_spt_pch_acs_match, .enable_acs =3D pci_quirk_enable_intel_spt_pch_acs, .disable_acs_redir =3D pci_quirk_disable_intel_spt_pch_acs_redir, }, }; =20 -int pci_dev_specific_enable_acs(struct pci_dev *dev) +static const struct pci_dev_acs_ops *pci_dev_acs_ops_get(struct pci_dev *d= ev) { const struct pci_dev_acs_ops *p; - int i, ret; + int i; =20 for (i =3D 0; i < ARRAY_SIZE(pci_dev_acs_ops); i++) { p =3D &pci_dev_acs_ops[i]; if ((p->vendor =3D=3D dev->vendor || p->vendor =3D=3D (u16)PCI_ANY_ID) && (p->device =3D=3D dev->device || - p->device =3D=3D (u16)PCI_ANY_ID) && - p->enable_acs) { - ret =3D p->enable_acs(dev); - if (ret >=3D 0) - return ret; + p->device =3D=3D (u16)PCI_ANY_ID)) { + if (!p->match || p->match(dev)) + return p; } } =20 + return NULL; +} + +int pci_dev_specific_enable_acs(struct pci_dev *dev) +{ + const struct pci_dev_acs_ops *p =3D pci_dev_acs_ops_get(dev); + + if (p && p->enable_acs) + return p->enable_acs(dev); + return -ENOTTY; } =20 int pci_dev_specific_disable_acs_redir(struct pci_dev *dev) { - const struct pci_dev_acs_ops *p; - int i, ret; + const struct pci_dev_acs_ops *p =3D pci_dev_acs_ops_get(dev); =20 - for (i =3D 0; i < ARRAY_SIZE(pci_dev_acs_ops); i++) { - p =3D &pci_dev_acs_ops[i]; - if ((p->vendor =3D=3D dev->vendor || - p->vendor =3D=3D (u16)PCI_ANY_ID) && - (p->device =3D=3D dev->device || - p->device =3D=3D (u16)PCI_ANY_ID) && - p->disable_acs_redir) { - ret =3D p->disable_acs_redir(dev); - if (ret >=3D 0) - return ret; - } - } + if (p && p->disable_acs_redir) + return p->disable_acs_redir(dev); =20 return -ENOTTY; } --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CBC0F3B8BC5 for ; Fri, 10 Jul 2026 21:26:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718795; cv=none; b=SIAe0l4xCfvMcS/0oyuYP+ApWwaZrxNnhEC2txXj//L5Nr25peZWM9qzsK6Vs4lbEGPQ77EFoHWA/2Elbz5H3eN+uoSyWnCP1A2FWrJ7UBpzMrK4+jx1cSJrmDvVBDIV+lZMYE9AQES2ZWV1jJSISIIUfX0VxqFEx2sV7OX8WHo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718795; c=relaxed/simple; bh=pra37XY1BGogOvBFAEnb6quSKA6WjTBoHKuKMwccp6Y=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=MITGq0jauoHo4WGLDwSGLQHzyPCrhTXp8V2uLGHDu4MdgIJ7kweg0SQJ4xC0jUiMcL9u2/dXuLHeYRd1g+TO1i3S5+Pu1BMn8Ljjl9dFqc43wOwKNV/jMtyWD/Txuf9yrZTWo8B5o8/xFUXNXHSvssvzNnm2vicZtuMs/ooRV8g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=A8sBo6/y; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="A8sBo6/y" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-2ccb687f82eso18724045ad.3 for ; Fri, 10 Jul 2026 14:26:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718790; x=1784323590; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=vyFHddSgtH+5JtZtRXs5kryYSNhZjQ+wgfA9vuynw+w=; b=A8sBo6/yCojZ7Im+QR1tXLk8XuyEfIcbS7exSBCgEJKUcA6zYFbTdLd1OLIiUY5589 lN7ERE1czorgXnn5BeYxg+NjHy5Nq0Ci41EsSQFFOIg3dGu+UNCBlVYQn4x9IhvTcfCZ bzcphMZVSa2vBRq7Eb5e7i6os3+pQ1Kp5tBXcqnz0yOdgPpHxI/bPdOf7z8KCu/lNxas MqJXvVlh1vI30kQ8qm5Gatwrt0RUzte17VDVY9W+1hpnk+5iT/G6sPjzDjtTBJiMmNvR W2z2klLlMaNiAhI/1tbkakqyfg/o8YPdk28s5BIqK+BPzwGqeyfaAy8NoxN2pqj8w5Jk 2NNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718790; x=1784323590; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=vyFHddSgtH+5JtZtRXs5kryYSNhZjQ+wgfA9vuynw+w=; b=DUnSV27v28aBD/cDOYhOSzGs5V34s6jjafqbSFUDPUczNIT+tYKJiTQyb2pMIR4+QZ +FIVa2gTreu7FcOG+r+iXKRinr5Fhr1V0pELV3ARHx2y8qZREDN4SjPI6qVE3athlRMy MmI2nfgG2ijD2hLZtRtJk+5taHBIPf6KC4paGc+XTEJro8TrorD035BQkWqDwxlrpjkF iXHSe6nuZ4s5chAAJZbe8vH4MndVtiFZMSut2NO7HcRFJR0+TFf5k5MYBOTUKTfKgfgP g8GNHWMY7sblnlYQMPSofhbuwtATF/XbEgqho5OqpK5HZwFAY4+QQj35Lsk5wU2wFl+Q 58Ig== X-Forwarded-Encrypted: i=1; AHgh+RrlE3sGI/ehBcjbDdo4Cy9JSgC/iYQ1/6L5dydtnF/BGsCjH36FY+3evyHBWsHQi6aTYWvE08i+IEZdsXk=@vger.kernel.org X-Gm-Message-State: AOJu0Yw8WGhlo4/PmaolKWoAy0zc9JmRT40aQihpZKCSMnH4TIMCp/KM SNnXbuNguZZuuC74PfwvIbwuyiIXtAVlrcex6ur93Boqi/nm1/KCdhLP6770RVc7pgljtzzEzSn FsE0fG2RtT7LiIg== X-Received: from pldd21.prod.google.com ([2002:a17:902:c195:b0:2c8:4c1:883a]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:32ce:b0:2c9:fa31:84f9 with SMTP id d9443c01a7336-2ce9e9a6c80mr7580575ad.5.1783718789594; Fri, 10 Jul 2026 14:26:29 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:11 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-9-dmatlack@google.com> Subject: [PATCH v7 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Inherit Access Control Services (ACS) flags on all incoming preserved devices (endpoints and upstream bridges) during a Live Update. Inheriting ACS flags avoids changing routing rules while memory transactions are in flight from preserved devices. This is also strictly necessary to ensure that IOMMU group assignments do not change across a Live Update for preserved devices, as changing ACS configurations can split or merge IOMMU groups. Cache the inherited ACS controls established by the previous kernel in struct pci_dev so that ACS controls do not change after a reset (pci_restore_state() calls pci_enable_acs()). To simplify ACS inheritance, reject preserving any devices that require quirks to enable ACS as those quirks would also have to take Live Update into account. Signed-off-by: David Matlack Reviewed-by: Pasha Tatashin --- drivers/pci/liveupdate.c | 68 ++++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.h | 11 ++++++ drivers/pci/pci.c | 6 +++ drivers/pci/pci.h | 5 +++ drivers/pci/quirks.c | 7 ++++ include/linux/pci_liveupdate.h | 6 +++ 6 files changed, 103 insertions(+) diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c index 7f7710cb1da0..a95bfe5eff77 100644 --- a/drivers/pci/liveupdate.c +++ b/drivers/pci/liveupdate.c @@ -71,6 +71,9 @@ * * * The device cannot be a Virtual Function (VF). * + * * The device cannot require device-specific quirks to enable Access + * Control Services (ACS). + * * Driver Binding * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D * @@ -113,6 +116,18 @@ * This enables the PCI core and any drivers bound to the bridge to partic= ipate * in the Live Update so that preserved endpoints can continue issuing mem= ory * transactions during the Live Update. + * + * Handling Preserved Devices + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + * + * The PCI core treats preserved devices differently than non-preserved de= vices. + * This section enumerates those differences. + * + * * The PCI core inherits all ACS flags enabled on incoming preserved de= vices + * rather than assigning new ones. This ensures that TLPs are routed th= e same + * way after Live Update and ensures that IOMMU groups do not change. N= ote + * that a device will use its inherited ACS flags for the lifetime of i= ts + * struct pci_dev (i.e. even after pci_liveupdate_finish()). */ =20 #define pr_fmt(fmt) "PCI: " KBUILD_BASENAME ": " fmt @@ -128,6 +143,7 @@ #include =20 #include "liveupdate.h" +#include "pci.h" =20 /** * struct pci_liveupdate_global - Global state for PCI Live Update support @@ -374,6 +390,16 @@ static int __pci_liveupdate_preserve_device(struct pci= _flb_outgoing *outgoing, s { struct pci_dev_ser *dev_ser; =20 + /* + * Do not preserve devices that rely on device-specific ACS equivalents + * (for now) since that would complicate keeping ACS constant across + * Live Update. + */ + if (pci_need_dev_specific_enable_acs(dev)) { + pci_warn(dev, "Refusing to preserve device that relies on ACS quirks\n"); + return -EINVAL; + } + dev_ser =3D pci_get_empty_or_append(outgoing); if (IS_ERR(dev_ser)) return PTR_ERR(dev_ser); @@ -655,6 +681,7 @@ void pci_liveupdate_setup_device(struct pci_dev *dev) =20 pci_info(dev, "Device was preserved by previous kernel across Live Update= \n"); dev->liveupdate.incoming =3D dev_ser; + dev->liveupdate.was_preserved =3D true; =20 /* * Hold the ref on the incoming FLB until pci_liveupdate_finish() so @@ -748,6 +775,47 @@ void pci_liveupdate_finish(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_liveupdate_finish); =20 +void pci_liveupdate_init_acs(struct pci_dev *dev) +{ + guard(rwsem_read)(&pci_liveupdate.rwsem); + + if (!dev->acs_cap || !dev->liveupdate.incoming) + return; + + pci_read_config_word(dev, dev->acs_cap + PCI_ACS_CTRL, &dev->liveupdate.a= cs_ctrl); +} + +int pci_liveupdate_enable_acs(struct pci_dev *dev) +{ + u16 acs_ctrl =3D dev->liveupdate.acs_ctrl; + u16 acs_cap =3D dev->acs_cap; + + /* + * Use liveupdate.was_preserved instead of liveupdate.incoming since the + * device's ACS controls should not change even after the device is + * finished participating in the Live Update. + */ + if (!dev->liveupdate.was_preserved) + return -EINVAL; + + /* + * The previous kernel should not have preserved any devices that + * require device-specific quirks to enable ACS, but if such a device is + * detected (e.g. new device-specific ACS quirk in the current kernel), + * log a big warning and fall back to the normal enable ACS path. + */ + if (pci_need_dev_specific_enable_acs(dev)) { + pci_warn(dev, "Device-specific quirk required to enable ACS!\n"); + WARN_ON_ONCE(true); + return -EINVAL; + } + + if (acs_cap) + pci_write_config_word(dev, acs_cap + PCI_ACS_CTRL, acs_ctrl); + + return 0; +} + /** * pci_liveupdate_is_incoming() - Check if a device is incoming-preserved * @dev: The PCI device to check diff --git a/drivers/pci/liveupdate.h b/drivers/pci/liveupdate.h index c763255a8de4..4e8a01bcb4bb 100644 --- a/drivers/pci/liveupdate.h +++ b/drivers/pci/liveupdate.h @@ -16,6 +16,8 @@ void pci_liveupdate_cleanup_device(struct pci_dev *dev); bool pci_liveupdate_scan_bridge_begin(struct pci_bus *bus, struct pci_dev = *dev, int pass); void pci_liveupdate_scan_bridge_end(struct pci_dev *dev, int pass); +void pci_liveupdate_init_acs(struct pci_dev *dev); +int pci_liveupdate_enable_acs(struct pci_dev *dev); #else static inline void pci_liveupdate_setup_device(struct pci_dev *dev) { @@ -35,6 +37,15 @@ static inline bool pci_liveupdate_scan_bridge_begin(stru= ct pci_bus *bus, static inline void pci_liveupdate_scan_bridge_end(struct pci_dev *dev, int= pass) { } + +static inline void pci_liveupdate_init_acs(struct pci_dev *dev) +{ +} + +static inline int pci_liveupdate_enable_acs(struct pci_dev *dev) +{ + return -EINVAL; +} #endif =20 #endif /* DRIVERS_PCI_LIVEUPDATE_H */ diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 77b17b13ee61..739ecaab2e76 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -34,6 +34,8 @@ #include #include #include + +#include "liveupdate.h" #include "pci.h" =20 DEFINE_MUTEX(pci_slot_mutex); @@ -1008,6 +1010,9 @@ void pci_enable_acs(struct pci_dev *dev) bool enable_acs =3D false; int pos; =20 + if (!pci_liveupdate_enable_acs(dev)) + return; + /* If an iommu is present we start with kernel default caps */ if (pci_acs_enable) { if (pci_dev_specific_enable_acs(dev)) @@ -3689,6 +3694,7 @@ void pci_acs_init(struct pci_dev *dev) =20 pci_read_config_word(dev, pos + PCI_ACS_CAP, &dev->acs_capabilities); pci_disable_broken_acs_cap(dev); + pci_liveupdate_init_acs(dev); } =20 /** diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4469e1a77f3c..988a18b3204a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1047,6 +1047,7 @@ void pci_acs_init(struct pci_dev *dev); void pci_enable_acs(struct pci_dev *dev); #ifdef CONFIG_PCI_QUIRKS int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); +bool pci_need_dev_specific_enable_acs(struct pci_dev *dev); int pci_dev_specific_enable_acs(struct pci_dev *dev); int pci_dev_specific_disable_acs_redir(struct pci_dev *dev); void pci_disable_broken_acs_cap(struct pci_dev *pdev); @@ -1057,6 +1058,10 @@ static inline int pci_dev_specific_acs_enabled(struc= t pci_dev *dev, { return -ENOTTY; } +static inline bool pci_need_dev_specific_enable_acs(struct pci_dev *dev) +{ + return false; +} static inline int pci_dev_specific_enable_acs(struct pci_dev *dev) { return -ENOTTY; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7ac39ec2843e..99b819f38e49 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -5473,6 +5473,13 @@ static const struct pci_dev_acs_ops *pci_dev_acs_ops= _get(struct pci_dev *dev) return NULL; } =20 +bool pci_need_dev_specific_enable_acs(struct pci_dev *dev) +{ + const struct pci_dev_acs_ops *p =3D pci_dev_acs_ops_get(dev); + + return p && p->enable_acs; +} + int pci_dev_specific_enable_acs(struct pci_dev *dev) { const struct pci_dev_acs_ops *p =3D pci_dev_acs_ops_get(dev); diff --git a/include/linux/pci_liveupdate.h b/include/linux/pci_liveupdate.h index 2be98819e313..2446c6d237ca 100644 --- a/include/linux/pci_liveupdate.h +++ b/include/linux/pci_liveupdate.h @@ -17,14 +17,20 @@ * struct pci_liveupdate - PCI Live Update state for a struct pci_dev * @outgoing: State preserved for the next kernel. * @incoming: State preserved by the previous kernel. + * @acs_ctrl: ACS features established by the previous kernel. * @inherit_buses: True if the PCI core should inherit the secondary and * subordinate bus numbers assigned to this device due to * an ongoing Live Update. + * @was_preserved: True if this struct pci_dev was preserved by the previo= us + * kernel. Unlike @incoming, this field is not cleared aft= er + * the device is finished participating in Live Update. */ struct pci_liveupdate { struct pci_dev_ser *outgoing; struct pci_dev_ser *incoming; + u16 acs_ctrl; bool inherit_buses; + bool was_preserved; }; =20 struct pci_dev; --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ACC343BB12D for ; Fri, 10 Jul 2026 21:26:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718795; cv=none; b=GwsaNlTd/4RBUWo7FDmIinYSrKyIKqTIrZa6Cg2sW1VXVsM2EW6fxGCHOggfIQraMsB7eX+nkppcTFqOMTQq4exHnDsyQlJeDxpdXGjYV1nwdu7hBg3xL2I8M7wn9jH9kKppms1Avef6Shfl6+ASkaaUJLtObU9MjGu7TlX6948= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718795; c=relaxed/simple; bh=TT1r+Sc1kpyFY8Swon5dHUVCA+faxMR/hxQ7WWn8eM0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=L17XfmVkmRG+miHfvX/jt1Qld79miv4iQeSrtFz4DABU8htDg0s4WyBi3Ch4boR2alccsQ8qfE4gy82dU1JL5bH2a0cQfi8cxLzjGEdNzcw6/OsJGz1OOR07FRoem5Wtv2kM/AvtNICcecSxt275b8mBQH1JzZyVIhNh5Eiopqc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=D1XJ9O9O; arc=none smtp.client-ip=209.85.214.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="D1XJ9O9O" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-2cc8bde6318so23249435ad.3 for ; Fri, 10 Jul 2026 14:26:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718790; x=1784323590; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=8nXcm3EXUYcPcGCSx60NMKl0mL3TQCPUFy3rNzpS5dk=; b=D1XJ9O9OEC20wqBYNiQIVSPAgaZFIDRYzU8eLTZYt4tbc3rZ/SpIo5gncvHvx9TKKh kzjyFVctr7oDheGq0V7IW2zithjKEpX+5kQ4Q9hhQbDnmOied9etLymycxS0U00TiX/h Sqj8B8W9/8C57a2XSHbm/N63iqNUnkU9+n98cD95KFggApaRaz5q5XfIvuyLzOSAZyBr 0t3+PgUx3hRwON1Eq0HCTtHzsjM4K0dtu7vzwtnZ/SGvxyPWlbhRmzhhOZnQq01enr5k bRV+Q5oKyVXoMdPAjQqfbyX6GGXk2hgvvgTRVoW1uI4oYH7KqXX8U2KIj4ceSXKMHYGq 3MXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718790; x=1784323590; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=8nXcm3EXUYcPcGCSx60NMKl0mL3TQCPUFy3rNzpS5dk=; b=rSYNjccDnAg8+FCNIpsNjCOJgRQ+8Smv7jDl9rQjdyMY35nn9EQ7Z4OMhtks49mEEr JLfpo3O+QezKWHU/bZbyaHScGfQUFtGmMvTm5LIs8XCpciL4tt+aOsTBgsCwIfyvb/l6 +3xF+P3P5np5uCZkfOqmY19EbjdBUN7zvNoz68vphyLziGsNwElWOLN1bzbnw4JREaPN Kbd3w8Opw07gr3ORcAud/2/hps6heZqSqunN0mEHAw1xT7auv+bVtJsC0RzdEe1pCK01 4xBfjHis61QC0GTEe5RFTtUYiFfvtR2Tf7YQSzZXFxPpeYEZOu8IhoLrD76F1ANDXhyD Rxcw== X-Forwarded-Encrypted: i=1; AHgh+Rq9absc6ZSYYDkutVmmuBGB3eSFx7T/LaSylqxCef9HGnWRnbvnmfs5przr6vY6oDlVgfqdqPH4YxptgQM=@vger.kernel.org X-Gm-Message-State: AOJu0Yzsb1K/rS/ATcCcQezovFbe9MYRfUaKom5SMGbj3tcn3v3wB+Px 1lBGjr2j0Ra02FM3/uyaYUtYYjXKCoPuZLjTCgvzZfGCOU+ESJYqFyTlwyepQz5Y/VB8MOg7CLa FQM7KyQcuF2GgOg== X-Received: from plal14.prod.google.com ([2002:a17:903:4e:b0:2cc:da2c:8084]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:1c8:b0:2ca:ed41:d33d with SMTP id d9443c01a7336-2ce9f294803mr7037355ad.45.1783718790387; Fri, 10 Jul 2026 14:26:30 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:12 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-10-dmatlack@google.com> Subject: [PATCH v7 09/12] PCI: liveupdate: Inherit ARI Forwarding Enable on preserved bridges From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Inherit the ARI Forwarding Enable on preserved bridges and update pci_dev->ari_enabled accordingly during a Live Update. This ensures that the preserved devices on the bridge's secondary bus can be identified with the same expanded 8-bit function number after a Live Update. Signed-off-by: David Matlack --- drivers/pci/liveupdate.c | 18 ++++++++++++++++++ drivers/pci/liveupdate.h | 6 ++++++ drivers/pci/pci.c | 8 +++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c index a95bfe5eff77..74a11e520f0d 100644 --- a/drivers/pci/liveupdate.c +++ b/drivers/pci/liveupdate.c @@ -128,6 +128,10 @@ * way after Live Update and ensures that IOMMU groups do not change. N= ote * that a device will use its inherited ACS flags for the lifetime of i= ts * struct pci_dev (i.e. even after pci_liveupdate_finish()). + * + * * The PCI core inherits ARI Forwarding Enable on all bridges with down= stream + * preserved devices to ensure that all preserved devices on the bridge= 's + * secondary bus are addressable after the Live Update. */ =20 #define pr_fmt(fmt) "PCI: " KBUILD_BASENAME ": " fmt @@ -816,6 +820,20 @@ int pci_liveupdate_enable_acs(struct pci_dev *dev) return 0; } =20 +int pci_liveupdate_configure_ari(struct pci_dev *dev) +{ + u16 val; + + guard(rwsem_read)(&pci_liveupdate.rwsem); + + if (!dev->liveupdate.incoming) + return -EINVAL; + + pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &val); + dev->ari_enabled =3D !!(val & PCI_EXP_DEVCTL2_ARI); + return 0; +} + /** * pci_liveupdate_is_incoming() - Check if a device is incoming-preserved * @dev: The PCI device to check diff --git a/drivers/pci/liveupdate.h b/drivers/pci/liveupdate.h index 4e8a01bcb4bb..6f21ec50927b 100644 --- a/drivers/pci/liveupdate.h +++ b/drivers/pci/liveupdate.h @@ -18,6 +18,7 @@ bool pci_liveupdate_scan_bridge_begin(struct pci_bus *bus= , struct pci_dev *dev, void pci_liveupdate_scan_bridge_end(struct pci_dev *dev, int pass); void pci_liveupdate_init_acs(struct pci_dev *dev); int pci_liveupdate_enable_acs(struct pci_dev *dev); +int pci_liveupdate_configure_ari(struct pci_dev *dev); #else static inline void pci_liveupdate_setup_device(struct pci_dev *dev) { @@ -46,6 +47,11 @@ static inline int pci_liveupdate_enable_acs(struct pci_d= ev *dev) { return -EINVAL; } + +static inline int pci_liveupdate_configure_ari(struct pci_dev *dev) +{ + return -EINVAL; +} #endif =20 #endif /* DRIVERS_PCI_LIVEUPDATE_H */ diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 739ecaab2e76..e0c133b66a35 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3528,7 +3528,7 @@ void pci_configure_ari(struct pci_dev *dev) u32 cap; struct pci_dev *bridge; =20 - if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn) + if (!pci_is_pcie(dev) || dev->devfn) return; =20 bridge =3D dev->bus->self; @@ -3539,6 +3539,12 @@ void pci_configure_ari(struct pci_dev *dev) if (!(cap & PCI_EXP_DEVCAP2_ARI)) return; =20 + if (!pci_liveupdate_configure_ari(bridge)) + return; + + if (pcie_ari_disabled) + return; + if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) { pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ARI); --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3ADFE3BFACF for ; Fri, 10 Jul 2026 21:26:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718797; cv=none; b=mCxTdXfSqnn3jpJYBATiS0iz344MXJ/GzpSNKz/AeHYfZMgOx5GpI0woYaz2eQKjwsdOyUAHPOcYQ//efI9b/Y3iQFdcqWKA3hUfEOdJvgvkMF60Xf44OMd3c0VjS+3akwEW5MOi9EpJd5wa3PxiFLtc5HIOfS3Wa0z+4AMrVNc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718797; c=relaxed/simple; bh=hBpyAX1ANil//5hIqEWoMbY4GyRjYVO8UOaUzZ3AIBE=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=F/JWGfKKQ4c2qY3p/i4VfJjGKycVm0K05/Cqp9SdCwaGNK2VRBU5L8kLvA/67Q3BSIQ9OWewSLm/G49/eXW6mgpT7RXRaukxCPjdG7yTU5L/hwy/ytXMtLu6WFT9XkH/9yFt7yppPnJ8SCwMcyCpuybBVGl/WarAmY8k48bpIBM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=HEIN/LiG; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="HEIN/LiG" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-8487ed7f7beso742706b3a.0 for ; Fri, 10 Jul 2026 14:26:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718791; x=1784323591; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=Vh0w4YZ9EkCKSJvWXCxWBgNBQIG8ERULbiy01R/Xx2Q=; b=HEIN/LiGTO/ZqWzPQ4sPvjCX1KMrMXJR7nLySDNp7uxlzuY1b1ttY3t6A8+xHfksfm RiqYJ1C4pvAiS2sTL2QyP8M3MhCr57Svt04ongjl4UWaBjZIf8hb74LWbutMSAwdDk9x TPMeSpy0jXHuFbzxEG9O0cFRoZBCRwzjmFuA496mLCIVMfZglG442phWFHvmB7Gw7Sw6 ZmMyRgkEUFR3dom1nPPT0IBN3jGdP3+5XQmdcxJG97jau5cNW2eiFBGHkjcusJcHySfj lqiH1tPWGB0imnbtJsOh2M2diStgILk0pgbeWkV+Dcwfq27FefHK3zb+tUKr/nD952yY gN/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718791; x=1784323591; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Vh0w4YZ9EkCKSJvWXCxWBgNBQIG8ERULbiy01R/Xx2Q=; b=O0+pvvdnje31KIhLAuaU+bKnnzgt3djArCr6oW2ntglcLqmnQnPbjQ0ZLdSsCDGhN1 qnsB6jdE8PuGvtJ17iCn7Rma8wVbTLeiJnSNdr6BWGO2N4u5TJnB9i5QeFCKk9TNxmE/ LrRhOhvdYQpM8WBJ8xBq4eDWWj/Xo130mJGut6KI0Rp1qzFqaFew/BoAmFqqbRl+SRDl ptIIMqr9YWVUKyvwioyPEpzkiy4qj8F4wIzYoNzmbIDJ8UED/n5ZneSdHfNWex76WuBw 9FnVd+eFFgWGtPWQw0atszYdlh4+GF3Dzca6pCad4blyO2kdRIkTu0to3T51ndUUSeTp /Epw== X-Forwarded-Encrypted: i=1; AHgh+RpXM4/Svcc8B9xyxUf1gOUs0d8o1i9nMyLyBp+YDrQd8m+IEKY6K/tFDI0TCg60OKj1KFkBK5DH2uYRHeQ=@vger.kernel.org X-Gm-Message-State: AOJu0YzaopSDXpBr7tLop+Fz4Fz80bOZuUffh62GS+Bc6yFsMBFrUarJ CCdnKEKX1MiVQQViytizlrjHTSb0qmnvly4x571gm+/cRDelvTYpK9StMkjc0unYDDZRaXdMXVx 93Zu7TOzE/tc24A== X-Received: from pfbfe24.prod.google.com ([2002:a05:6a00:2f18:b0:848:401c:994]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:14c3:b0:847:9c06:2bef with SMTP id d2e1a72fcca58-8488971669emr605929b3a.29.1783718791168; Fri, 10 Jul 2026 14:26:31 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:13 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-11-dmatlack@google.com> Subject: [PATCH v7 10/12] PCI: liveupdate: Freeze preservation status during shutdown From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Freeze a device's outgoing preservation status (preserved or not preserved) during shutdown. This enables the PCI core and drivers to safely make decisions based on the device's preservation status during shutdown. Note that pci_liveupdate_freeze() is triggered by the PCI core rather than from drivers participating in Live Update so that all devices can have their status frozen (i.e. prevent non-preserved devices from getting preserved late). Reviewed-by: Pranjal Shrivastava Signed-off-by: David Matlack Reviewed-by: Pasha Tatashin --- drivers/pci/liveupdate.c | 16 ++++++++++++++++ drivers/pci/liveupdate.h | 5 +++++ drivers/pci/pci-driver.c | 2 ++ include/linux/pci_liveupdate.h | 3 +++ 4 files changed, 26 insertions(+) diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c index 74a11e520f0d..64052892ea84 100644 --- a/drivers/pci/liveupdate.c +++ b/drivers/pci/liveupdate.c @@ -352,6 +352,11 @@ static int pci_liveupdate_unpreserve_device(struct pci= _flb_outgoing *outgoing, s { struct pci_dev_ser *dev_ser =3D dev->liveupdate.outgoing; =20 + if (dev->liveupdate.frozen) { + pci_warn(dev, "Cannot unpreserve device after it is frozen!\n"); + return -EINVAL; + } + if (!dev_ser) { pci_warn(dev, "Cannot unpreserve device that is not preserved\n"); return -EINVAL; @@ -422,6 +427,11 @@ static int __pci_liveupdate_preserve_device(struct pci= _flb_outgoing *outgoing, s =20 static int pci_liveupdate_preserve_device(struct pci_flb_outgoing *outgoin= g, struct pci_dev *dev) { + if (dev->liveupdate.frozen) { + pci_warn(dev, "Cannot preserve device after it is frozen!\n"); + return -EINVAL; + } + if (dev->liveupdate.outgoing) return pci_liveupdate_preserve_device_again(dev); =20 @@ -713,6 +723,12 @@ void pci_liveupdate_cleanup_device(struct pci_dev *dev) } } =20 +void pci_liveupdate_freeze(struct pci_dev *dev) +{ + guard(rwsem_write)(&pci_liveupdate.rwsem); + dev->liveupdate.frozen =3D 1; +} + static int pci_liveupdate_finish_device(struct pci_ser *ser, struct pci_de= v *dev) { if (!dev->liveupdate.incoming) { diff --git a/drivers/pci/liveupdate.h b/drivers/pci/liveupdate.h index 6f21ec50927b..bcb0bc73d684 100644 --- a/drivers/pci/liveupdate.h +++ b/drivers/pci/liveupdate.h @@ -13,6 +13,7 @@ #ifdef CONFIG_PCI_LIVEUPDATE void pci_liveupdate_setup_device(struct pci_dev *dev); void pci_liveupdate_cleanup_device(struct pci_dev *dev); +void pci_liveupdate_freeze(struct pci_dev *dev); bool pci_liveupdate_scan_bridge_begin(struct pci_bus *bus, struct pci_dev = *dev, int pass); void pci_liveupdate_scan_bridge_end(struct pci_dev *dev, int pass); @@ -28,6 +29,10 @@ static inline void pci_liveupdate_cleanup_device(struct = pci_dev *dev) { } =20 +static inline void pci_liveupdate_freeze(struct pci_dev *dev) +{ +} + static inline bool pci_liveupdate_scan_bridge_begin(struct pci_bus *bus, struct pci_dev *dev, int pass) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index f36778e62ac1..51616e4327d3 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -21,6 +21,7 @@ #include #include #include +#include "liveupdate.h" #include "pci.h" #include "pcie/portdrv.h" =20 @@ -536,6 +537,7 @@ static void pci_device_shutdown(struct device *dev) struct pci_dev *pci_dev =3D to_pci_dev(dev); struct pci_driver *drv =3D pci_dev->driver; =20 + pci_liveupdate_freeze(pci_dev); pm_runtime_resume(dev); =20 if (drv && drv->shutdown) diff --git a/include/linux/pci_liveupdate.h b/include/linux/pci_liveupdate.h index 2446c6d237ca..150993405754 100644 --- a/include/linux/pci_liveupdate.h +++ b/include/linux/pci_liveupdate.h @@ -24,6 +24,8 @@ * @was_preserved: True if this struct pci_dev was preserved by the previo= us * kernel. Unlike @incoming, this field is not cleared aft= er * the device is finished participating in Live Update. + * @frozen: True if the outgoing preservation status of this device is fro= zen + * and thus cannot be changed. */ struct pci_liveupdate { struct pci_dev_ser *outgoing; @@ -31,6 +33,7 @@ struct pci_liveupdate { u16 acs_ctrl; bool inherit_buses; bool was_preserved; + bool frozen; }; =20 struct pci_dev; --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3A2DC3BFACE for ; Fri, 10 Jul 2026 21:26:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718798; cv=none; b=AGNWKsRyKrKWWZOOv/qF0tuB9+Cw0ng6sMSFd53VBjm8e5Y6RzELQU78VqKT292Q/+KVtVC7iWU3mXkEDVdqfNmE9FEIfm21zCk7Eb7y6caBpapEGelffILdTIXJxqjL33gs2Bpc9yTfUxEQz391v7iXzr8cVKnhtlBJfXkF4xE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718798; c=relaxed/simple; bh=4e+6sLDNIk2wfvCbSyulceEmFWyfLO94oPNauemCv6c=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=YTWvwh39J8HvEiiPY2Z6COlXb7PHtaBcsrogrVqV6EWEK61T2aq22dP+c9zqKrrHbA5/cp/8wPhVMiz7lj6yQXFjJwyUQ8KNdeUJDaMwTJqyrltKR5NCAMRPwu4qZAIiRi0C6m8qMLh6d1w7WZLQgEIEQGKYREqjK45XbYQrr5U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=dzuPULIx; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="dzuPULIx" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-8484b57b98bso2195109b3a.0 for ; Fri, 10 Jul 2026 14:26:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718792; x=1784323592; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=kC0I5yGr+D5g0K5ia+KYUwEESYLYNJwODX2HQMDkX0U=; b=dzuPULIxfnJDuQZCsxrlyrQ9HiV7atBeekHS28RTW64/kaQ1OSnP7oDmGdd0TYb+Eh +DY2DWZ+Fd3RYkz9Q+1I7USghsI8WXlis0Juh2odYIla8IbteyTl6bLMLUGMW25zu2KZ i+YxFFNVDUseUU9/j9y3JawZHwk6xAu/Nx6E2Jry+ubKZ6l5U1ey5a+bRZ4m8yf+8lUC KUoVZv+hveOtD13wcOgQSBnF1pwxLxfxZrkISmORk05Siy0NcBAJqK76+Immo0g7k2y0 u9MGEjQ/4vRbmDCncZ4Q3f8i7T41NC+Nbc+C13mYVJQ0tt4klUUatc4q0X8czgbHZN2a YwHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718792; x=1784323592; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=kC0I5yGr+D5g0K5ia+KYUwEESYLYNJwODX2HQMDkX0U=; b=Uop0LzYs5r/haHG/wAuKzjRVbbSWbAupm9Kr/mtp63eavVMh4oxS59V3n8+UIeDt6Q jIErc1cDlEMlsImrzsmLN0Vp33c7o6tuysGHf6pWP4kbXe5Uj2+Hm4zrIgHWRe7Zbjia trRJPFCOk1RFXqbp4p+uG62Mk6eX4SY9J0AEstVJgfqDcacMa01CjKQ3DUolEFhRSKTX tw99VEKV2NewImQsxatzT60NxqZaZSjGwbrLVefOy10PGqdQWP7nU4L+DUDIa+8mzeHv tVu27FVNKf8uzm/jSnZbNIgU6iCsMO8Xhhnl5cBCJy3BizNE5SWNM99NmY0KRhL+KK2v t1Mw== X-Forwarded-Encrypted: i=1; AHgh+RrAp9xoEb9bik7t4sn3gz+/p9gv/p5/1wQ1vraoPli4xuV3FRQHpptI50uhhlRYMDt+UMkUVia9C6p7pSg=@vger.kernel.org X-Gm-Message-State: AOJu0YysbDLCUtN1nFFPbd4PnXaCPYOpOyZw/xaRWxxNmEIjXWu9ASb+ zz62bdKYZBeyYuQw3YGvZNFjRUIcj/t+cQqOTJrYp+Z/Cw7iJuM18ycQxfhmswvyeh0HhpxU4al qG2HKiOByVOMBcQ== X-Received: from pfcs28.prod.google.com ([2002:a05:6a00:6fdc:b0:847:8189:3c6c]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:14ce:b0:848:2f73:8ff6 with SMTP id d2e1a72fcca58-84889770231mr613896b3a.63.1783718791956; Fri, 10 Jul 2026 14:26:31 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:14 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-12-dmatlack@google.com> Subject: [PATCH v7 11/12] PCI: liveupdate: Do not disable bus mastering on preserved devices during kexec From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Do not disable bus mastering on outgoing preserved devices during pci_device_shutdown() for kexec. Preserved devices must be allowed to perform memory transactions during a Live Update to ensure continuous operation. Clearing the bus mastering bit would prevent these devices from issuing any memory requests while the new kernel boots. Because bridges upstream of preserved endpoint devices are also automatically preserved, this change also avoids clearing bus mastering on them. This is critical because clearing bus mastering on an upstream bridge prevents the bridge from forwarding memory requests upstream (i.e. it would prevent the endpoint device from accessing system RAM and doing peer-to-peer transactions with devices not downstream of the bridge). Reviewed-by: Pranjal Shrivastava Signed-off-by: David Matlack Reviewed-by: Pasha Tatashin --- drivers/pci/liveupdate.c | 11 +++++++++++ drivers/pci/liveupdate.h | 6 ++++++ drivers/pci/pci-driver.c | 7 +++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c index 64052892ea84..5935e88de073 100644 --- a/drivers/pci/liveupdate.c +++ b/drivers/pci/liveupdate.c @@ -132,6 +132,10 @@ * * The PCI core inherits ARI Forwarding Enable on all bridges with down= stream * preserved devices to ensure that all preserved devices on the bridge= 's * secondary bus are addressable after the Live Update. + * + * * The PCI core does not disable bus mastering on outgoing preserved de= vices + * during kexec. This allows preserved devices to issue memory transact= ions + * throughout the Live Update. */ =20 #define pr_fmt(fmt) "PCI: " KBUILD_BASENAME ": " fmt @@ -850,6 +854,13 @@ int pci_liveupdate_configure_ari(struct pci_dev *dev) return 0; } =20 +bool pci_liveupdate_is_outgoing(struct pci_dev *dev) +{ + guard(rwsem_read)(&pci_liveupdate.rwsem); + pci_WARN_ONCE(dev, !dev->liveupdate.frozen, "Preservation status is unsta= ble!\n"); + return dev->liveupdate.outgoing; +} + /** * pci_liveupdate_is_incoming() - Check if a device is incoming-preserved * @dev: The PCI device to check diff --git a/drivers/pci/liveupdate.h b/drivers/pci/liveupdate.h index bcb0bc73d684..b266406aaac8 100644 --- a/drivers/pci/liveupdate.h +++ b/drivers/pci/liveupdate.h @@ -20,6 +20,7 @@ void pci_liveupdate_scan_bridge_end(struct pci_dev *dev, = int pass); void pci_liveupdate_init_acs(struct pci_dev *dev); int pci_liveupdate_enable_acs(struct pci_dev *dev); int pci_liveupdate_configure_ari(struct pci_dev *dev); +bool pci_liveupdate_is_outgoing(struct pci_dev *dev); #else static inline void pci_liveupdate_setup_device(struct pci_dev *dev) { @@ -57,6 +58,11 @@ static inline int pci_liveupdate_configure_ari(struct pc= i_dev *dev) { return -EINVAL; } + +static inline bool pci_liveupdate_is_outgoing(struct pci_dev *dev) +{ + return false; +} #endif =20 #endif /* DRIVERS_PCI_LIVEUPDATE_H */ diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 51616e4327d3..47cb3dcaa927 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -546,11 +546,14 @@ static void pci_device_shutdown(struct device *dev) /* * If this is a kexec reboot, turn off Bus Master bit on the * device to tell it to not continue to do DMA. Don't touch - * devices in D3cold or unknown states. + * devices being preserved for Live Update or in D3cold or + * unknown states. + * * If it is not a kexec reboot, firmware will hit the PCI * devices with big hammer and stop their DMA any way. */ - if (kexec_in_progress && (pci_dev->current_state <=3D PCI_D3hot)) + if (kexec_in_progress && !pci_liveupdate_is_outgoing(pci_dev) && + pci_dev->current_state <=3D PCI_D3hot) pci_clear_master(pci_dev); } =20 --=20 2.55.0.795.g602f6c329a-goog From nobody Sun Jul 26 00:19:31 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 964E03BFE5D for ; Fri, 10 Jul 2026 21:26:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718800; cv=none; b=qZURs2mlbMuDhHNNLtVOwqXDwPDISvp/cGbAs+UCjSv+JghmqhbJjHfZkxwqPZdcu1+mbz1qRVGT20hJFuNhBuQCpW6kEisa6zu3e69dfkxSWCxMXx6II5bAXO8CRQhbQaAhTqeoNlLHydDDyoKdHaUcjNzzt44MQ60UVRVdGXw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783718800; c=relaxed/simple; bh=O8Lb2kC0q9pWayCFgpEouBe9yAioEPmBnRCX4jxSNVA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=gTcPxdvoRgQ218lstFTxHfxa/ZLFlBt2AkwmWrSc4QWlNNB7qEB+xaSiDtegPjWCx95LfV+Nf+mXul/i5i1NXa3qXftMJ0aRnamLbIMnbkovlVETYGE8ju+nly3dKAx8SB6tEOUgeRlAfNgGFoaNG/PecAuyZ0lnKat2JtREe5Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Fnwq6lS7; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--dmatlack.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Fnwq6lS7" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-c9d5a5b63c5so1966595a12.1 for ; Fri, 10 Jul 2026 14:26:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1783718793; x=1784323593; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=INpd5qJ/nDERayrqFlF9TRfffxREvDfF4kxC1qPOhOg=; b=Fnwq6lS7hGezE5YWw6zSaWiof/5afukYRFBAKiTmN82y/BW+oIMgjmGg9Iq8C17Ke9 2/CTRFGC8+5Dv8LiLfDLNqklICP96qktelLoda/+9s+tjBM09Da+74xVu3zMi4y6TCMb phamCJCbY4o0Rau2APSQB00RTif2EhXBQV46UMDTPdjhMIAgKQ6Fq+7yR2uAzQBSLovz 0dm7BPSWlKNOttMBTjeRmuwYHgXdEh87IKVgz3xOGy8RTbPqErmFij7ZEHkn5TqNB2iY rYg9gPVdRBGneV/2Snc/zYNZ/4n4Z1iF9gZQYQDtBySviscXBFCJZlknXl/fjyOT25fh AAhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783718793; x=1784323593; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=INpd5qJ/nDERayrqFlF9TRfffxREvDfF4kxC1qPOhOg=; b=JIp7P+sXt1GuI2trcbzABviJ8yY5PTdyZebTfdw3BH8jBTqa41NA+j5Y7lplQLqIMq LNSr1kAcw69BrCdjfa3XTR3NSxrtVpq/2WUvcDg6TUQr9fbMF/NOR2EhSrGzemJlKLKC lozTgr+TJbkcYCicFILkdbvb1NuLQNvkmhlxuGWgcd06oLuuPhlnb35ygDrOOiQ5/2IB 8hjQnO/1COMg+0Bg9P7JaZtIrbX+dul7E3FKJ20ouujkOVVcTk46el3wOdKNmanMYCc5 d4te9M/8McekBpSKH/5N0l+NMf9gXTX0hi0pt/LeHdgDcOpHGoQtpBEwJvgo8M1HwP2d 705w== X-Forwarded-Encrypted: i=1; AHgh+Rrf9/FUVF+lfdx7MuPt+9HeN6RkiHqaL5FsnmuiS53tjBiTa2xoVwXPF2Loj5inYQTQalil3ZQoqZ5f268=@vger.kernel.org X-Gm-Message-State: AOJu0YxjDiTX/pFtFSK5ySijjJMfe646FQRo3bjcfVWTODYCpDn/lfC8 rcHFwz20/kk2UrJJEXPWXw+UeiCQwLpoDlJ1EFSlBqabeBP7ZHDskJHgXnhdfw45DUuhPtkrDG+ fHJlqcH7V0qOY1A== X-Received: from pgnh4.prod.google.com ([2002:a63:3844:0:b0:c99:aff5:7085]) (user=dmatlack job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:e293:b0:3c0:9c18:d5a2 with SMTP id adf61e73a8af0-3c110f61b7emr693546637.63.1783718792786; Fri, 10 Jul 2026 14:26:32 -0700 (PDT) Date: Fri, 10 Jul 2026 21:26:15 +0000 In-Reply-To: <20260710212616.1351130-1-dmatlack@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260710212616.1351130-1-dmatlack@google.com> X-Mailer: git-send-email 2.55.0.795.g602f6c329a-goog Message-ID: <20260710212616.1351130-13-dmatlack@google.com> Subject: [PATCH v7 12/12] Documentation: PCI: Add documentation for Live Update From: David Matlack To: kexec@lists.infradead.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-pci@vger.kernel.org Cc: Adithya Jayachandran , Alexander Graf , Alex Williamson , Bjorn Helgaas , Chris Li , David Matlack , David Rientjes , Jacob Pan , Jason Gunthorpe , Jonathan Corbet , Josh Hilke , Leon Romanovsky , Lukas Wunner , Mike Rapoport , Parav Pandit , Pasha Tatashin , Pranjal Shrivastava , Pratyush Yadav , Saeed Mahameed , Samiullah Khawaja , Shuah Khan , Vipin Sharma , William Tu , Yi Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add documentation files for the PCI subsystem's participation in Live Update. These documentation files are generated from the kernel-doc comments in the PCI Live Update source code. They describe the File-Lifecycle Bound (FLB) API, the device tracking API, and the specific policies applied to preserved devices (such as bus number inheritance and bus mastering preservation). Reviewed-by: Pranjal Shrivastava Signed-off-by: David Matlack --- Documentation/PCI/index.rst | 1 + Documentation/PCI/liveupdate.rst | 29 +++++++++++++++++++++++++++ Documentation/core-api/liveupdate.rst | 1 + MAINTAINERS | 1 + 4 files changed, 32 insertions(+) create mode 100644 Documentation/PCI/liveupdate.rst diff --git a/Documentation/PCI/index.rst b/Documentation/PCI/index.rst index 5d720d2a415e..23fb737ac969 100644 --- a/Documentation/PCI/index.rst +++ b/Documentation/PCI/index.rst @@ -20,3 +20,4 @@ PCI Bus Subsystem controller/index boot-interrupts tph + liveupdate diff --git a/Documentation/PCI/liveupdate.rst b/Documentation/PCI/liveupdat= e.rst new file mode 100644 index 000000000000..eba55f8a92ae --- /dev/null +++ b/Documentation/PCI/liveupdate.rst @@ -0,0 +1,29 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D +PCI Support for Live Update +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +.. kernel-doc:: drivers/pci/liveupdate.c + :doc: PCI Live Update + +Driver API +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. kernel-doc:: drivers/pci/liveupdate.c + :export: + +Live Update ABI +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. kernel-doc:: include/linux/kho/abi/pci.h + :doc: PCI File-Lifecycle Bound (FLB) Live Update ABI + +.. kernel-doc:: include/linux/kho/abi/pci.h + :internal: + +See Also +=3D=3D=3D=3D=3D=3D=3D=3D + + * :doc:`/core-api/liveupdate` + * :doc:`/core-api/kho/index` diff --git a/Documentation/core-api/liveupdate.rst b/Documentation/core-api= /liveupdate.rst index b3c689e633c1..2bce2644eba2 100644 --- a/Documentation/core-api/liveupdate.rst +++ b/Documentation/core-api/liveupdate.rst @@ -74,3 +74,4 @@ See Also =20 - :doc:`Live Update uAPI ` - :doc:`/core-api/kho/index` +- :doc:`PCI ` diff --git a/MAINTAINERS b/MAINTAINERS index 08a724b860dc..347c435ca404 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20833,6 +20833,7 @@ L: kexec@lists.infradead.org L: linux-pci@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git +F: Documentation/PCI/liveupdate.rst F: drivers/pci/liveupdate.c F: drivers/pci/liveupdate.h F: include/linux/kho/abi/pci.h --=20 2.55.0.795.g602f6c329a-goog