[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250728-luo-pci-v1-22-955b078dd653@kernel.org>
Date: Mon, 28 Jul 2025 01:24:52 -0700
From: chrisl@...nel.org
To: Bjorn Helgaas <bhelgaas@...gle.com>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
"Rafael J. Wysocki" <rafael@...nel.org>, Danilo Krummrich <dakr@...nel.org>,
Len Brown <lenb@...nel.org>
Cc: linux-kernel@...r.kernel.org, linux-pci@...r.kernel.org,
linux-acpi@...r.kernel.org, David Matlack <dmatlack@...gle.com>,
Pasha Tatashin <tatashin@...gle.com>, Jason Miu <jasonmiu@...gle.com>,
Vipin Sharma <vipinsh@...gle.com>, Saeed Mahameed <saeedm@...dia.com>,
Adithya Jayachandran <ajayachandra@...dia.com>,
Parav Pandit <parav@...dia.com>, William Tu <witu@...dia.com>,
Mike Rapoport <rppt@...nel.org>, Chris Li <chrisl@...nel.org>,
Jason Gunthorpe <jgg@...pe.ca>, Leon Romanovsky <leon@...nel.org>
Subject: [PATCH RFC 22/25] PCI/LUO: Save PCI bus and host bridge states
From: Jason Miu <jasonmiu@...gle.com>
In the LUO prepare phase, saves the PCI bus and host bridge states.
For a PCI bus, save the domain and bus numbers. Save the bridge types.
Save the upstream bus domain and bus numbers so we can verify the
relationship in the later restoration phase.
If the current bridge is a host bridge, save also the PCI bridge
resource. This is not needed by other PCI bridges as the resource is
already preserved by its associated struct pci_dev.
Tested:
- QEMU VM boot test, preserve device with pci-lu-stub
Signed-off-by: Chris Li <chrisl@...nel.org>
---
drivers/pci/liveupdate.c | 60 +++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 52 insertions(+), 8 deletions(-)
diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
index 7fda7e4d409adce6bf92ef7af1167f7bda302c7e..be22af7a2db3a9bb06d8e100603a59f11b7fa5f8 100644
--- a/drivers/pci/liveupdate.c
+++ b/drivers/pci/liveupdate.c
@@ -20,9 +20,20 @@ static LIST_HEAD(preserved_buses);
static LIST_HEAD(probe_devices);
static LIST_HEAD(probe_buses);
+enum pci_bus_ser_bridge_type {
+ PCI_BUS_SER_NULL_BRIDGE, /* virtual bus */
+ PCI_BUS_SER_PCI_HOST_BRIDGE,
+ PCI_BUS_SER_PCI_BRIDGE,
+};
+
struct pci_bus_ser {
u16 domain;
u8 number;
+ u16 parent_domain;
+ u8 parent_number;
+ enum pci_bus_ser_bridge_type bridge_type;
+ /* For a root bus, saves the host bridge PCI bridge resource */
+ struct pci_resource_ser resource[PCI_BRIDGE_RESOURCE_NUM];
};
struct pci_ser {
@@ -162,6 +173,16 @@ static int pci_get_device_path(struct pci_dev *pdev)
return (pci_domain_nr(pdev->bus) << 16) | pci_dev_id(pdev);
}
+static void save_device_resource(struct pci_resource_ser *dest,
+ struct resource *src)
+{
+ strscpy((char *)dest->name, src->name, sizeof(dest->name));
+ dest->start = src->start;
+ dest->end = src->end;
+ dest->flags = src->flags;
+ dest->desc = src->desc;
+}
+
static int pci_save_device_state(struct device *dev, struct pci_dev_ser *s)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -205,13 +226,7 @@ static int pci_save_device_state(struct device *dev, struct pci_dev_ser *s)
(strlen(pdev->resource[i].name) == 0))
continue;
- s->resource[i].start = pdev->resource[i].start;
- s->resource[i].end = pdev->resource[i].end;
- s->resource[i].flags = pdev->resource[i].flags;
- s->resource[i].desc = pdev->resource[i].desc;
-
- strscpy((char *)s->resource[i].name, pci_name(pdev),
- sizeof(s->resource[i].name));
+ save_device_resource(s->resource + i, pdev->resource + i);
}
return 0;
@@ -219,8 +234,37 @@ static int pci_save_device_state(struct device *dev, struct pci_dev_ser *s)
static void pci_save_bus_state(struct pci_bus *bus, struct pci_bus_ser *s)
{
- s->number = bus->number;
+ int i;
+
s->domain = pci_domain_nr(bus);
+ s->number = bus->number;
+ if (bus->parent) {
+ s->parent_domain = pci_domain_nr(bus->parent);
+ s->parent_number = bus->parent->number;
+ }
+
+ /* This bus is a virtual bus if no physical bridge is being referred. */
+ if (!bus->bridge) {
+ s->bridge_type = PCI_BUS_SER_NULL_BRIDGE;
+ return;
+ }
+
+ if (!pci_is_root_bus(bus)) {
+ s->bridge_type = PCI_BUS_SER_PCI_BRIDGE;
+ return;
+ }
+
+ /* This bridge is a PCI host bridge. Saves its resource. */
+ for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
+ /* This resource region is not claimed, skip. */
+ if ((bus->resource[i] == NULL) ||
+ (bus->resource[i]->name == NULL) ||
+ (strlen(bus->resource[i]->name) == 0))
+ continue;
+
+ save_device_resource(s->resource + i, bus->resource[i]);
+ }
+ s->bridge_type = PCI_BUS_SER_PCI_HOST_BRIDGE;
}
static int pci_call_prepare(struct pci_ser *pci_state,
--
2.50.1.487.gc89ff58d15-goog
Powered by blists - more mailing lists