summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-10-14 14:38:50 +0100
committerMark Brown <broonie@kernel.org>2026-10-14 14:38:50 +0100
commita68f9e7d84af02fed8ec3f8b474a51d97c15419c (patch)
treebc8e81d79aaf3f1ff7ddba9952b629930eeeaf68 /include/linux
parentd249c3952d9febf010457f77f02b3c06766e6975 (diff)
parente1fe7daedae7a4a23aca6dbd58e1746750b632dc (diff)
downloadlinux-next-a68f9e7d84af02fed8ec3f8b474a51d97c15419c.tar.gz
linux-next-a68f9e7d84af02fed8ec3f8b474a51d97c15419c.zip
Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git
# Conflicts: # mm/memblock.c # mm/mm_init.c
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/kexec.h2
-rw-r--r--include/linux/kexec_handover.h16
-rw-r--r--include/linux/kho/abi/pci.h66
-rw-r--r--include/linux/liveupdate.h22
-rw-r--r--include/linux/memblock.h30
-rw-r--r--include/linux/pci.h7
-rw-r--r--include/linux/pci_liveupdate.h72
7 files changed, 191 insertions, 24 deletions
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index e5f1cfc11fef..f970ca2c8ce9 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -403,7 +403,7 @@ struct kimage {
#endif
struct {
- struct kexec_segment *scratch;
+ struct kexec_segment *bootmem;
phys_addr_t fdt;
} kho;
diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h
index 46de86dc343e..ef2b188c8ed0 100644
--- a/include/linux/kexec_handover.h
+++ b/include/linux/kexec_handover.h
@@ -36,15 +36,15 @@ int kho_retrieve_subtree(const char *name, phys_addr_t *phys, size_t *size);
void kho_memory_init(void);
void kho_memory_init_early(void);
-void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys,
- u64 scratch_len);
+void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t bootmem_phys,
+ u64 bootmem_len);
-bool kho_scratch_overlap(phys_addr_t phys, size_t size);
+bool kho_bootmem_overlap(phys_addr_t phys, size_t size);
-static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
+static inline enum migratetype kho_bootmem_migratetype(unsigned long pfn,
enum migratetype mt)
{
- if (kho_scratch_overlap(PFN_PHYS(pfn), pageblock_nr_pages << PAGE_SHIFT))
+ if (kho_bootmem_overlap(PFN_PHYS(pfn), pageblock_nr_pages << PAGE_SHIFT))
return MIGRATE_CMA;
return mt;
}
@@ -123,16 +123,16 @@ static inline void kho_memory_init(void) { }
static inline void kho_memory_init_early(void) { }
static inline void kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
- phys_addr_t scratch_phys, u64 scratch_len)
+ phys_addr_t bootmem_phys, u64 bootmem_len)
{
}
-static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)
+static inline bool kho_bootmem_overlap(phys_addr_t phys, size_t size)
{
return false;
}
-static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
+static inline enum migratetype kho_bootmem_migratetype(unsigned long pfn,
enum migratetype mt)
{
return mt;
diff --git a/include/linux/kho/abi/pci.h b/include/linux/kho/abi/pci.h
new file mode 100644
index 000000000000..9485ed73c351
--- /dev/null
+++ b/include/linux/kho/abi/pci.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2026, Google LLC.
+ * David Matlack <dmatlack@google.com>
+ */
+
+#ifndef _LINUX_KHO_ABI_PCI_H
+#define _LINUX_KHO_ABI_PCI_H
+
+#include <linux/bug.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+/**
+ * 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 serialization
+ * structs defined here constitutes a breaking change. Such changes require
+ * incrementing the version number in the PCI_LUO_FLB_VERSION number.
+ */
+
+#define PCI_LUO_FLB_COMPATIBLE "pci"
+#define PCI_LUO_FLB_VERSION 2
+
+/**
+ * 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 whether it
+ * is done using a device's struct pci_dev_ser. The value of the
+ * refcount is equal to the number of preserved devices at or below
+ * it in the PCI hierarchy 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 across
+ * a Live Update for the next kernel. It contains only state owned by the PCI
+ * core; the state a driver needs to resume its device is preserved separately
+ * by that driver.
+ *
+ * @version: The version of the "pci" FLB struct. This field must never be
+ * deleted, moved, or resized, as the kernel depends on always being
+ * able to check the struct pci_ser version number.
+ * @nr_devices: The number of devices that were preserved.
+ * @devices: Physical address of the first KHO block containing pci_dev_ser.
+ */
+struct pci_ser {
+ u32 version;
+ u32 nr_devices;
+ u64 devices;
+} __packed;
+
+#endif /* _LINUX_KHO_ABI_PCI_H */
diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
index 63ea5417de84..6051abc0612c 100644
--- a/include/linux/liveupdate.h
+++ b/include/linux/liveupdate.h
@@ -25,6 +25,7 @@ struct file;
/**
* struct liveupdate_file_op_args - Arguments for file operation callbacks.
* @handler: The file handler being called.
+ * @session: The session this file belongs to.
* @retrieve_status: The retrieve status for the 'can_finish / finish'
* operation. A value of 0 means the retrieve has not been
* attempted, a positive value means the retrieve was
@@ -45,6 +46,7 @@ struct file;
*/
struct liveupdate_file_op_args {
struct liveupdate_file_handler *handler;
+ struct liveupdate_session *session;
int retrieve_status;
struct file *file;
u64 serialized_data;
@@ -247,6 +249,14 @@ void liveupdate_flb_put_incoming(struct liveupdate_flb *flb);
int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp);
void liveupdate_flb_put_outgoing(struct liveupdate_flb *flb);
+/* kernel can internally retrieve files */
+int liveupdate_get_file_incoming(struct liveupdate_session *s, u64 token,
+ struct file **filep);
+
+/* Get a token for an outgoing file, or -ENOENT if file is not preserved */
+int liveupdate_get_token_outgoing(struct liveupdate_session *s,
+ struct file *file, u64 *tokenp);
+
#else /* CONFIG_LIVEUPDATE */
static inline bool liveupdate_enabled(void)
@@ -299,5 +309,17 @@ static inline void liveupdate_flb_put_outgoing(struct liveupdate_flb *flb)
{
}
+static inline int liveupdate_get_file_incoming(struct liveupdate_session *s,
+ u64 token, struct file **filep)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int liveupdate_get_token_outgoing(struct liveupdate_session *s,
+ struct file *file, u64 *tokenp)
+{
+ return -EOPNOTSUPP;
+}
+
#endif /* CONFIG_LIVEUPDATE */
#endif /* _LINUX_LIVEUPDATE_H */
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 01a2dea5aa11..40e6e0aa2f8d 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -46,11 +46,11 @@ extern unsigned long long max_possible_pfn;
* @MEMBLOCK_RSRV_KERN: memory region that is reserved for kernel use,
* either explictitly with memblock_reserve_kern() or via memblock
* allocation APIs. All memblock allocations set this flag.
- * @MEMBLOCK_KHO_SCRATCH: memory region that kexec can pass to the next
- * kernel in handover mode. During early boot, we do not know about all
- * memory reservations yet, so we get scratch memory from the previous
- * kernel that we know is good to use. It is the only memory that
- * allocations may happen from in this phase.
+ * @MEMBLOCK_KHO_NOPRSRV: memory region with no preservation from kexec
+ * handover. During early boot, we do not know about all memory preservations
+ * yet, so we get memory with no preservations from the previous kernel that we
+ * know is good to use. It is the only memory that allocations may happen from
+ * in this phase.
* @MEMBLOCK_RSRV_HUGETLB: memory is reserved for hugetlb pages
*/
enum memblock_flags {
@@ -61,7 +61,7 @@ enum memblock_flags {
MEMBLOCK_DRIVER_MANAGED = 0x8, /* always detected via a driver */
MEMBLOCK_RSRV_NOINIT = 0x10, /* don't initialize struct pages */
MEMBLOCK_RSRV_KERN = 0x20, /* memory reserved for kernel use */
- MEMBLOCK_KHO_SCRATCH = 0x40, /* scratch memory for kexec handover */
+ MEMBLOCK_KHO_NOPRSRV = 0x40, /* memory with no KHO preservations */
MEMBLOCK_RSRV_HUGETLB = 0x80, /* memory reserved for hugetlb pages */
};
@@ -158,8 +158,8 @@ int memblock_mark_nomap(phys_addr_t base, phys_addr_t size);
int memblock_clear_nomap(phys_addr_t base, phys_addr_t size);
int memblock_reserved_mark_noinit(phys_addr_t base, phys_addr_t size);
int memblock_reserved_mark_kern(phys_addr_t base, phys_addr_t size);
-int memblock_mark_kho_scratch(phys_addr_t base, phys_addr_t size);
-int memblock_clear_kho_scratch(phys_addr_t base, phys_addr_t size);
+int memblock_mark_kho_noprsrv(phys_addr_t base, phys_addr_t size);
+int memblock_clear_kho_noprsrv(phys_addr_t base, phys_addr_t size);
void memblock_free(void *ptr, size_t size);
@@ -300,9 +300,9 @@ static inline bool memblock_is_driver_managed(struct memblock_region *m)
return m->flags & MEMBLOCK_DRIVER_MANAGED;
}
-static inline bool memblock_is_kho_scratch(struct memblock_region *m)
+static inline bool memblock_is_kho_noprsrv(struct memblock_region *m)
{
- return m->flags & MEMBLOCK_KHO_SCRATCH;
+ return m->flags & MEMBLOCK_KHO_NOPRSRV;
}
int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
@@ -610,12 +610,12 @@ static inline void early_memtest(phys_addr_t start, phys_addr_t end) { }
static inline void memtest_report_meminfo(struct seq_file *m) { }
#endif
-#ifdef CONFIG_MEMBLOCK_KHO_SCRATCH
-void memblock_set_kho_scratch_only(void);
-void memblock_clear_kho_scratch_only(void);
+#ifdef CONFIG_KEXEC_HANDOVER
+void memblock_set_kho_noprsrv_only(void);
+void memblock_clear_kho_noprsrv_only(void);
#else
-static inline void memblock_set_kho_scratch_only(void) { }
-static inline void memblock_clear_kho_scratch_only(void) { }
+static inline void memblock_set_kho_noprsrv_only(void) { }
+static inline void memblock_clear_kho_noprsrv_only(void) { }
#endif
#endif /* _LINUX_MEMBLOCK_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 500cfc7b9aea..adb2a3da5f96 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -43,6 +43,7 @@
#include <uapi/linux/pci.h>
#include <linux/pci_ids.h>
+#include <linux/pci_liveupdate.h>
#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
PCI_STATUS_SIG_SYSTEM_ERROR | \
@@ -599,6 +600,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)
@@ -833,6 +837,9 @@ static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev)
return dev->bus->self;
}
+#define for_each_pci_dev_in_path(dev) \
+ for (; dev; dev = pci_upstream_bridge(dev))
+
#ifdef CONFIG_PCI_MSI
static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev)
{
diff --git a/include/linux/pci_liveupdate.h b/include/linux/pci_liveupdate.h
new file mode 100644
index 000000000000..bb79348769b7
--- /dev/null
+++ b/include/linux/pci_liveupdate.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PCI Live Update support (Public/Driver API)
+ *
+ * Copyright (c) 2026, Google LLC.
+ * David Matlack <dmatlack@google.com>
+ */
+#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.
+ * @incoming: State preserved by the previous kernel.
+ * @was_incoming: True if this struct pci_dev was incoming-preserved when it was
+ * set up, i.e. it was matched to state preserved by the previous
+ * kernel. Unlike @incoming, this is never cleared, so it stays
+ * true after the device finishes participating in Live Update.
+ * @frozen: True if the outgoing preservation status of this device is frozen
+ * and thus cannot be changed.
+ */
+struct pci_liveupdate {
+ struct pci_dev_ser *outgoing;
+ struct pci_dev_ser *incoming;
+ bool was_incoming;
+ bool frozen;
+};
+
+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);
+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_handler *fh)
+{
+ return -EOPNOTSUPP;
+}
+
+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)
+{
+}
+
+static inline void pci_liveupdate_finish(struct pci_dev *dev)
+{
+}
+
+static inline bool pci_liveupdate_is_incoming(struct pci_dev *dev)
+{
+ return false;
+}
+#endif
+
+#endif /* LINUX_PCI_LIVEUPDATE_H */