diff options
| author | Mark Brown <broonie@kernel.org> | 2026-11-13 16:32:37 +0000 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-11-13 16:32:37 +0000 |
| commit | 568b89e7f74b81d116f962d4f242638bcc2feb96 (patch) | |
| tree | 480e87297a8329086a5fd8704d5ca49bf98a17cc /include/linux | |
| parent | ad05ff8b816ecff892506ef1b42934bfc559c669 (diff) | |
| parent | a0dc8eddbfdb6dd9c5c2b70eb66ab49cb1978425 (diff) | |
| download | linux-next-568b89e7f74b81d116f962d4f242638bcc2feb96.tar.gz linux-next-568b89e7f74b81d116f962d4f242638bcc2feb96.zip | |
Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/kho/abi/pci.h | 96 | ||||
| -rw-r--r-- | include/linux/liveupdate.h | 22 | ||||
| -rw-r--r-- | include/linux/pci.h | 7 | ||||
| -rw-r--r-- | include/linux/pci_liveupdate.h | 72 |
4 files changed, 197 insertions, 0 deletions
diff --git a/include/linux/kho/abi/pci.h b/include/linux/kho/abi/pci.h new file mode 100644 index 000000000000..c2e3a5949f73 --- /dev/null +++ b/include/linux/kho/abi/pci.h @@ -0,0 +1,96 @@ +/* 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/stddef.h> +#include <linux/types.h> + +/** + * DOC: PCI File-Lifecycle Bound (FLB) Live Update ABI + * + * The PCI core preserves its state across kexec as Live Update + * File-Lifecycle Bound (FLB) data, identified by the compatible string + * ``"pci"`` and laid out as described by the structs below. + * + * This layout is a contract between kernels. Rather than being versioned, it + * is extended according to the following rules: + * + * * Existing fields must never be moved, resized, removed, or have their + * meaning changed. New fields may only be appended to the end of a struct. + * + * * A bit set in ``pci_ser.required_flags`` marks a feature that the next + * kernel must understand to safely take over the preserved devices. The + * next kernel panics if it finds a bit it does not know how to handle. + * + * * A bit set in ``pci_ser.optional_flags`` marks a feature that the next + * kernel can safely ignore if it does not understand it. + * + * * Fields appended to struct pci_ser must be accompanied by a flag that + * indicates they are present, since the size of struct pci_ser is not + * recorded. + * + * * The size of each struct pci_dev_ser is recorded in + * ``pci_ser.dev_ser_size`` and is never smaller than + * ``PCI_DEV_SER_MIN_SIZE``. The next kernel ignores any fields beyond the + * ones it knows about, and must handle entries that are smaller than its + * own struct pci_dev_ser. + */ + +#define PCI_LUO_FLB_COMPATIBLE "pci" + +/** + * 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 + * reference count 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; + +/* + * The size of struct pci_dev_ser when this ABI was introduced. Since fields + * can only be appended, every struct pci_dev_ser is at least this large. + */ +#define PCI_DEV_SER_MIN_SIZE offsetofend(struct pci_dev_ser, refcount) + +/** + * 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. + * + * @required_flags: Features that the next kernel must support to take over + * the preserved devices. No flags are currently defined. + * @optional_flags: Features that the next kernel may ignore if it does not + * support them. No flags are currently defined. + * @dev_ser_size: The size in bytes of each struct pci_dev_ser in @devices. + * @nr_devices: The number of devices that were preserved. + * @devices: Physical address of the first KHO block containing pci_dev_ser. + */ +struct pci_ser { + u64 required_flags; + u64 optional_flags; + u32 dev_ser_size; + 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/pci.h b/include/linux/pci.h index aa3765a20a96..6482549a8417 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) @@ -836,6 +840,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 */ |
