kexec.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: Zhu Yanjun <yanjun.zhu@linux.dev>
To: David Matlack <dmatlack@google.com>,
	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 <ajayachandra@nvidia.com>,
	Alexander Graf <graf@amazon.com>,
	Alex Williamson <alex@shazbot.org>,
	Bjorn Helgaas <bhelgaas@google.com>, Chris Li <chrisl@kernel.org>,
	David Rientjes <rientjes@google.com>,
	Jacob Pan <jacob.pan@linux.microsoft.com>,
	Jason Gunthorpe <jgg@nvidia.com>,
	Jonathan Corbet <corbet@lwn.net>, Josh Hilke <jrhilke@google.com>,
	Leon Romanovsky <leonro@nvidia.com>,
	Lukas Wunner <lukas@wunner.de>, Mike Rapoport <rppt@kernel.org>,
	Parav Pandit <parav@nvidia.com>,
	Pasha Tatashin <pasha.tatashin@soleen.com>,
	Pranjal Shrivastava <praan@google.com>,
	Pratyush Yadav <pratyush@kernel.org>,
	Saeed Mahameed <saeedm@nvidia.com>,
	Samiullah Khawaja <skhawaja@google.com>,
	Shuah Khan <skhan@linuxfoundation.org>,
	Vipin Sharma <vipinsh@google.com>, William Tu <witu@nvidia.com>,
	Yi Liu <yi.l.liu@intel.com>,
	"yanjun.zhu@linux.dev" <yanjun.zhu@linux.dev>
Subject: Re: [PATCH v8 02/12] PCI: liveupdate: Track outgoing preserved PCI devices
Date: Tue, 15 Sep 2026 20:10:04 -0700	[thread overview]
Message-ID: <9211b2b6-9fca-4ef7-a141-84636d56e67e@linux.dev> (raw)
In-Reply-To: <20260728221007.2098560-3-dmatlack@google.com>

在 2026/7/28 15:09, David Matlack 写道:
> 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).

Hi David,

I have a question about the pci_liveupdate_preserve() and 
pci_liveupdate_unpreserve() APIs.

Is it supported to call these APIs multiple times for the same PCI 
device? For example, a driver could do:

pci_liveupdate_preserve(pdev) -- > pci_liveupdate_unpreserve(pdev) -- > 
perform some operations -- > pci_liveupdate_preserve(pdev) again, before 
the actual Live Update starts.

 From the implementation, it looks like an unpreserved pci_dev_ser entry 
can be reused, so I wanted to confirm whether this preserve -- > 
unpreserve -- > preserve sequence is an intended and supported usage.

Thanks!

Yanjun.Zhu

> 
> This tracking ensures the PCI core is fully aware of which devices may
> need special handling during shutdown and kexec, and so the list of
> preserved devices can be handed off to the next kernel.
> 
> For now, the API only supports preserving non-VF devices on a root bus
> (not behind an PCI-to-PCI bridges).
> 
> Reviewed-by: Pranjal Shrivastava <praan@google.com>
> Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> Reviewed-by: Bjorn Helgaas <bhelgaas@google.com>
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
>   drivers/pci/liveupdate.c       | 210 +++++++++++++++++++++++++++++++++
>   drivers/pci/liveupdate.h       |  21 ++++
>   drivers/pci/probe.c            |   2 +
>   include/linux/pci.h            |   3 +
>   include/linux/pci_liveupdate.h |  21 ++++
>   5 files changed, 257 insertions(+)
>   create mode 100644 drivers/pci/liveupdate.h
> 
> diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
> index fffb41a66ca7..b003b7069cdb 100644
> --- a/drivers/pci/liveupdate.c
> +++ b/drivers/pci/liveupdate.c
> @@ -36,6 +36,27 @@
>    *
>    *  * ``pci_liveupdate_register_flb(driver_file_handler)``
>    *  * ``pci_liveupdate_unregister_flb(driver_file_handler)``
> + *
> + * Device Tracking
> + * ===============
> + *
> + * 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 date
> + * with the list of **outgoing** preserved devices for the next kernel.
> + *
> + * Restrictions
> + * ============
> + *
> + * 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).
> + *  * The device cannot be behind a PCI-to-PCI bridge.
>    */
>   
>   #define pr_fmt(fmt) "PCI: liveupdate: " fmt
> @@ -50,6 +71,21 @@
>   #include <linux/pci.h>
>   #include <linux/slab.h>
>   
> +#include "liveupdate.h"
> +
> +/**
> + * struct pci_liveupdate_global - Global state for PCI Live Update support
> + * @rwsem: Reader/writer semaphore used to protect the incoming and outgoing
> + *         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 = {
> +	.rwsem = __RWSEM_INITIALIZER(pci_liveupdate.rwsem),
> +};
> +
>   /**
>    * struct pci_flb_outgoing - Outgoing PCI FLB object
>    * @ser: Pointer to the preserved struct pci_ser.
> @@ -128,6 +164,180 @@ static struct liveupdate_flb pci_liveupdate_flb = {
>   	.compatible = PCI_LUO_FLB_COMPATIBLE,
>   };
>   
> +static void pci_liveupdate_flb_put_outgoing(void)
> +{
> +	liveupdate_flb_put_outgoing(&pci_liveupdate_flb);
> +}
> +
> +static struct pci_flb_outgoing *pci_liveupdate_flb_get_outgoing(void)
> +{
> +	struct pci_flb_outgoing *outgoing = NULL;
> +	int ret;
> +
> +	ret = liveupdate_flb_get_outgoing(&pci_liveupdate_flb, (void **)&outgoing);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	if (!outgoing)
> +		return ERR_PTR(-ENOENT);
> +
> +	return outgoing;
> +}
> +
> +static struct pci_dev_ser *pci_flb_alloc_dev_ser(struct pci_flb_outgoing *outgoing)
> +{
> +	struct pci_dev_ser *dev_ser;
> +	struct kho_block_set_it it;
> +	u64 count = 0;
> +	int err;
> +
> +	kho_block_set_it_init(&it, &outgoing->block_set);
> +
> +	/* Try to find an existing, previously unpreserved, entry. */
> +	while ((dev_ser = kho_block_set_it_read_entry(&it))) {
> +		if (!dev_ser->refcount)
> +			return dev_ser;
> +
> +		count++;
> +	}
> +
> +	/* Otherwise grow the block set and reserve a new entry. */
> +	err = kho_block_set_grow(&outgoing->block_set, count + 1);
> +	if (err)
> +		return ERR_PTR(err);
> +
> +	if (!count)
> +		kho_block_set_it_init(&it, &outgoing->block_set);
> +
> +	/* This should always succeed since kho_block_set_grow() succeeded. */
> +	dev_ser = kho_block_set_it_reserve_entry(&it);
> +	if (WARN_ON_ONCE(!dev_ser))
> +		return ERR_PTR(-ENOSPC);
> +
> +	return dev_ser;
> +}
> +
> +static void pci_liveupdate_unpreserve_device(struct pci_flb_outgoing *outgoing,
> +					     struct pci_dev *dev)
> +{
> +	struct pci_dev_ser *dev_ser = 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 = NULL;
> +}
> +
> +static int pci_liveupdate_preserve_device(struct pci_flb_outgoing *outgoing,
> +					  struct pci_dev *dev)
> +{
> +	struct pci_dev_ser *dev_ser;
> +
> +	if (dev->is_virtfn) {
> +		pci_warn(dev, "Cannot preserve Virtual Functions\n");
> +		return -EINVAL;
> +	}
> +
> +	if (dev->liveupdate.outgoing) {
> +		pci_warn(dev, "Device is already preserved\n");
> +		return -EBUSY;
> +	}
> +
> +	if (!pci_is_root_bus(dev->bus)) {
> +		pci_warn(dev, "Cannot preserve devices behind bridges\n");
> +		return -EINVAL;
> +	}
> +
> +	dev_ser = pci_flb_alloc_dev_ser(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 = kho_block_set_head_pa(&outgoing->block_set);
> +
> +	dev_ser->domain = pci_domain_nr(dev->bus);
> +	dev_ser->bdf = pci_dev_id(dev);
> +	dev_ser->refcount = 1;
> +
> +	dev->liveupdate.outgoing = 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 should 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 set up.
> + *
> + * Returns: 0 on success, <0 on failure.
> + */
> +int pci_liveupdate_preserve(struct pci_dev *dev)
> +{
> +	struct pci_flb_outgoing *outgoing = NULL;
> +	int ret;
> +
> +	guard(rwsem_write)(&pci_liveupdate.rwsem);
> +
> +	outgoing = pci_liveupdate_flb_get_outgoing();
> +	if (IS_ERR(outgoing))
> +		return PTR_ERR(outgoing);
> +
> +	ret = pci_liveupdate_preserve_device(outgoing, dev);
> +
> +	pci_liveupdate_flb_put_outgoing();
> +	return ret;
> +}
> +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 should no
> + * longer be preserved across the next Live Update. Drivers are expected to 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 = NULL;
> +
> +	guard(rwsem_write)(&pci_liveupdate.rwsem);
> +
> +	outgoing = pci_liveupdate_flb_get_outgoing();
> +	if (IS_ERR(outgoing)) {
> +		pci_warn(dev, "Cannot unpreserve device without outgoing Live Update state\n");
> +		return;
> +	}
> +
> +	pci_liveupdate_unpreserve_device(outgoing, dev);
> +	pci_liveupdate_flb_put_outgoing();
> +}
> +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 core
>    * @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 <dmatlack@google.com>
> + */
> +#ifndef DRIVERS_PCI_LIVEUPDATE_H
> +#define DRIVERS_PCI_LIVEUPDATE_H
> +
> +#include <linux/pci.h>
> +
> +#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 <linux/pm_runtime.h>
>   #include <linux/bitfield.h>
>   #include <trace/events/pci.h>
> +#include "liveupdate.h"
>   #include "pci.h"
>   
>   static struct resource busn_resource = {
> @@ -2485,6 +2486,7 @@ static void pci_release_dev(struct device *dev)
>   
>   	pci_dev = 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
>   };
>   
>   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..894052ad6961 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
>   
> +#include <linux/kho/abi/pci.h>
>   #include <linux/liveupdate.h>
> +#include <linux/spinlock_types.h>
>   #include <linux/types.h>
>   
> +/**
> + * 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;
> +};
> +
>   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);
> +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_handler *fh)
>   {
> @@ -25,6 +37,15 @@ static inline int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh
>   static inline void pci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh)
>   {
>   }
> +
> +static inline int pci_liveupdate_preserve(struct pci_dev *dev)
> +{
> +	return -EOPNOTSUPP;
> +}
> +
> +static inline void pci_liveupdate_unpreserve(struct pci_dev *dev)
> +{
> +}
>   #endif
>   
>   #endif /* LINUX_PCI_LIVEUPDATE_H */



  parent reply	other threads:[~2026-09-16  3:10 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-28 22:09 [PATCH v8 00/12] PCI: liveupdate: PCI core support for Live Update David Matlack
2026-07-28 22:09 ` [PATCH v8 01/12] PCI: liveupdate: Set up FLB handler for the PCI core David Matlack
2026-08-17 21:12   ` Samiullah Khawaja
2026-09-10 23:48   ` Bjorn Helgaas
2026-09-11 16:44     ` David Matlack
2026-07-28 22:09 ` [PATCH v8 02/12] PCI: liveupdate: Track outgoing preserved PCI devices David Matlack
2026-08-24 20:14   ` Samiullah Khawaja
2026-08-27 21:47   ` Bjorn Helgaas
2026-09-16  3:10   ` Zhu Yanjun [this message]
2026-09-16 14:58     ` David Matlack
2026-07-28 22:09 ` [PATCH v8 03/12] PCI: liveupdate: Track incoming " David Matlack
2026-08-24 20:13   ` Samiullah Khawaja
2026-09-10 23:49   ` Bjorn Helgaas
2026-09-11 16:45     ` David Matlack
2026-09-16  3:31   ` Zhu Yanjun
2026-09-16 17:28     ` David Matlack
2026-09-16 18:25       ` Pratyush Yadav
2026-09-16 18:31         ` David Matlack
2026-07-28 22:09 ` [PATCH v8 04/12] PCI: liveupdate: Document driver binding responsibilities David Matlack
2026-09-10 23:50   ` Bjorn Helgaas
2026-07-28 22:09 ` [PATCH v8 05/12] PCI: liveupdate: Preserve bus numbers during Live Update David Matlack
2026-09-10 23:51   ` Bjorn Helgaas
2026-09-11 18:30     ` David Matlack
2026-09-12 17:31       ` David Matlack
2026-07-28 22:10 ` [PATCH v8 06/12] PCI: liveupdate: Auto-preserve upstream bridges across " David Matlack
2026-08-24 13:41   ` Pranjal Shrivastava
2026-09-10 23:51   ` Bjorn Helgaas
2026-09-11 17:00     ` David Matlack
2026-07-28 22:10 ` [PATCH v8 07/12] PCI: Refactor matching logic for pci_dev_acs_ops David Matlack
2026-07-28 22:10 ` [PATCH v8 08/12] PCI: liveupdate: Adopt ACS controls in incoming preserved devices David Matlack
2026-08-24 13:42   ` Pranjal Shrivastava
2026-09-10 23:51   ` Bjorn Helgaas
2026-09-11 18:31     ` David Matlack
2026-09-14 16:45       ` David Matlack
2026-07-28 22:10 ` [PATCH v8 09/12] PCI: liveupdate: Adopt ARI Forwarding Enable on preserved bridges David Matlack
2026-08-24 13:43   ` Pranjal Shrivastava
2026-07-28 22:10 ` [PATCH v8 10/12] PCI: liveupdate: Freeze preservation status during shutdown David Matlack
2026-08-24 20:07   ` Samiullah Khawaja
2026-07-28 22:10 ` [PATCH v8 11/12] PCI: liveupdate: Do not disable bus mastering on preserved devices during kexec David Matlack
2026-08-24 20:02   ` Samiullah Khawaja
2026-07-28 22:10 ` [PATCH v8 12/12] Documentation: PCI: Add documentation for Live Update David Matlack
2026-08-24 20:01   ` Samiullah Khawaja
2026-08-18 17:01 ` [PATCH v8 00/12] PCI: liveupdate: PCI core support " David Matlack
2026-09-10 21:37 ` Pasha Tatashin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9211b2b6-9fca-4ef7-a141-84636d56e67e@linux.dev \
    --to=yanjun.zhu@linux.dev \
    --cc=ajayachandra@nvidia.com \
    --cc=alex@shazbot.org \
    --cc=bhelgaas@google.com \
    --cc=chrisl@kernel.org \
    --cc=corbet@lwn.net \
    --cc=dmatlack@google.com \
    --cc=graf@amazon.com \
    --cc=jacob.pan@linux.microsoft.com \
    --cc=jgg@nvidia.com \
    --cc=jrhilke@google.com \
    --cc=kexec@lists.infradead.org \
    --cc=leonro@nvidia.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=parav@nvidia.com \
    --cc=pasha.tatashin@soleen.com \
    --cc=praan@google.com \
    --cc=pratyush@kernel.org \
    --cc=rientjes@google.com \
    --cc=rppt@kernel.org \
    --cc=saeedm@nvidia.com \
    --cc=skhan@linuxfoundation.org \
    --cc=skhawaja@google.com \
    --cc=vipinsh@google.com \
    --cc=witu@nvidia.com \
    --cc=yi.l.liu@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).