--- /dev/null
+From bfdf815f1f6afd08fb56ac84af61e6389c0b455a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 11:58:33 -0500
+Subject: iio: adc: spear: Initialize completion before requesting IRQ
+
+From: Maxwell Doose <m32285159@gmail.com>
+
+[ Upstream commit 3ee2128b6f0eb0be7b6cb8f6e0f1f113a65201a0 ]
+
+In the report from Jaeyoung Chung:
+
+"spear_adc_probe() in drivers/iio/adc/spear_adc.c registers its
+interrupt handler with devm_request_irq() before it initializes
+st->completion with init_completion(). If an interrupt arrives after
+devm_request_irq() and before init_completion(), the handler calls
+complete() on an uninitialized completion, causing a kernel panic.
+
+The probe path, in spear_adc_probe():
+
+ iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); /* st kzalloc-zeroed */
+ ...
+ retval = devm_request_irq(&pdev->dev, irq, spear_adc_isr, 0,
+ LPC32XXAD_NAME, st); /* register handler */
+ ...
+ init_completion(&st->completion); /* initialize completion */
+
+spear_adc_isr() calls complete():
+
+ complete(&st->completion);
+
+If the device raises an interrupt before init_completion() runs,
+complete() acquires the uninitialized wait.lock and walks the zeroed
+task_list in swake_up_locked(). The zeroed task_list makes list_empty()
+return false, so swake_up_locked() dereferences a NULL list entry,
+triggering a KASAN wild-memory-access."
+
+Fix the chance of a spurious IRQ causing an uninitialized pointer
+dereference by moving init_completion() above devm_request_irq().
+
+Fixes: b586e5d9eee0 ("staging:iio:adc:spear rename device specific state structure to _state")
+Reported-by: Sangyun Kim <sangyun.kim@snu.ac.kr>
+Reported-by: Kyungwook Boo <bookyungwook@gmail.com>
+Reported-by: Jaeyoung Chung <jjy600901@snu.ac.kr>
+Closes: https://lore.kernel.org/linux-iio/20260610115700.774689-1-jjy600901@snu.ac.kr/
+Signed-off-by: Maxwell Doose <m32285159@gmail.com>
+Reviewed-by: Vladimir Zapolskiy <vz@kernel.org>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <jic23@kernel.org>
+Signed-off-by: Maxwell Doose <m32285159@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/adc/spear_adc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c
+index 4d4aff88aa6ceb..12e0811a47b71a 100644
+--- a/drivers/iio/adc/spear_adc.c
++++ b/drivers/iio/adc/spear_adc.c
+@@ -274,6 +274,8 @@ static int spear_adc_probe(struct platform_device *pdev)
+ st = iio_priv(indio_dev);
+ st->np = np;
+
++ init_completion(&st->completion);
++
+ /*
+ * SPEAr600 has a different register layout than other SPEAr SoC's
+ * (e.g. SPEAr3xx). Let's provide two register base addresses
+@@ -334,8 +336,6 @@ static int spear_adc_probe(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, indio_dev);
+
+- init_completion(&st->completion);
+-
+ indio_dev->name = SPEAR_ADC_MOD_NAME;
+ indio_dev->info = &spear_adc_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+--
+2.53.0
+
--- /dev/null
+From d030a71ea48cf8fee36476ebf9d736e14688c58f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 18:16:13 +0300
+Subject: iio: temperature: ltc2983: Fix n_wires default bypassing rotation
+ check
+
+From: Liviu Stan <liviu.stan@analog.com>
+
+[ Upstream commit 434c150752675f44dc52c384a7fa22e5176bc35a ]
+
+When adi,number-of-wires is absent, n_wires is left at 0. The binding
+documents a default of 2 wires, matching the hardware default. However
+the current-rotate validation checks n_wires == 2 || n_wires == 3, so
+with n_wires = 0 the guard is bypassed and adi,current-rotate is accepted
+for a 2-wire RTD.
+
+Initialize n_wires = 2 to match the binding default and ensure the
+rotation check fires correctly when the property is absent.
+
+Fixes: f110f3188e56 ("iio: temperature: Add support for LTC2983")
+Signed-off-by: Liviu Stan <liviu.stan@analog.com>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <jic23@kernel.org>
+Signed-off-by: Liviu Stan <liviu.stan@analog.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/temperature/ltc2983.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
+index ecc8b2e129b896..c6748cfc5d5ce2 100644
+--- a/drivers/iio/temperature/ltc2983.c
++++ b/drivers/iio/temperature/ltc2983.c
+@@ -697,7 +697,7 @@ static struct ltc2983_sensor *ltc2983_rtd_new(const struct device_node *child,
+ int ret = 0;
+ struct device *dev = &st->spi->dev;
+ struct device_node *phandle;
+- u32 excitation_current = 0, n_wires = 0;
++ u32 excitation_current = 0, n_wires = 2;
+
+ rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL);
+ if (!rtd)
+--
+2.53.0
+
usb-typec-tcpm-validate-svid-index-in-svdm_consume_modes.patch
usb-typec-ucsi-invert-displayport-role-assignment.patch
usb-typec-ucsi-pass-full-dp-config-payload-in-set_new_cam-for-dp-alt-mode.patch
+iio-adc-spear-initialize-completion-before-requestin.patch
+iio-temperature-ltc2983-fix-n_wires-default-bypassin.patch
--- /dev/null
+From b27b20bfecbb8408550e81b8d0101460a0bf1fce Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 18:26:10 +0300
+Subject: iio: temperature: ltc2983: Fix n_wires default bypassing rotation
+ check
+
+From: Liviu Stan <liviu.stan@analog.com>
+
+[ Upstream commit 434c150752675f44dc52c384a7fa22e5176bc35a ]
+
+When adi,number-of-wires is absent, n_wires is left at 0. The binding
+documents a default of 2 wires, matching the hardware default. However
+the current-rotate validation checks n_wires == 2 || n_wires == 3, so
+with n_wires = 0 the guard is bypassed and adi,current-rotate is accepted
+for a 2-wire RTD.
+
+Initialize n_wires = 2 to match the binding default and ensure the
+rotation check fires correctly when the property is absent.
+
+Fixes: f110f3188e56 ("iio: temperature: Add support for LTC2983")
+Signed-off-by: Liviu Stan <liviu.stan@analog.com>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <jic23@kernel.org>
+Signed-off-by: Liviu Stan <liviu.stan@analog.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/temperature/ltc2983.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
+index ecc8b2e129b896..c6748cfc5d5ce2 100644
+--- a/drivers/iio/temperature/ltc2983.c
++++ b/drivers/iio/temperature/ltc2983.c
+@@ -697,7 +697,7 @@ static struct ltc2983_sensor *ltc2983_rtd_new(const struct device_node *child,
+ int ret = 0;
+ struct device *dev = &st->spi->dev;
+ struct device_node *phandle;
+- u32 excitation_current = 0, n_wires = 0;
++ u32 excitation_current = 0, n_wires = 2;
+
+ rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL);
+ if (!rtd)
+--
+2.53.0
+
usb-typec-tcpm-validate-svid-index-in-svdm_consume_modes.patch
usb-typec-ucsi-invert-displayport-role-assignment.patch
usb-typec-ucsi-pass-full-dp-config-payload-in-set_new_cam-for-dp-alt-mode.patch
+iio-temperature-ltc2983-fix-n_wires-default-bypassin.patch
--- /dev/null
+From 37936041684be30c92a2527b891c949bee970f0d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 23:33:29 -0500
+Subject: efivarfs: expose used and total size
+
+From: Anisse Astier <an.astier@criteo.com>
+
+[ Upstream commit d86ff3333cb1d5f42d8898fb5fdb304e143c0237 ]
+
+When writing EFI variables, one might get errors with no other message
+on why it fails. Being able to see how much is used by EFI variables
+helps analyzing such issues.
+
+Since this is not a conventional filesystem, block size is intentionally
+set to 1 instead of PAGE_SIZE.
+
+x86 quirks of reserved size are taken into account; so that available
+and free size can be different, further helping debugging space issues.
+
+With this patch, one can see the remaining space in EFI variable storage
+via efivarfs, like this:
+
+ $ df -h /sys/firmware/efi/efivars/
+ Filesystem Size Used Avail Use% Mounted on
+ efivarfs 176K 106K 66K 62% /sys/firmware/efi/efivars
+
+Signed-off-by: Anisse Astier <an.astier@criteo.com>
+[ardb: - rename efi_reserved_space() to efivar_reserved_space()
+ - whitespace/coding style tweaks]
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Adjusted for headers in linux-6.1.y
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/platform/efi/quirks.c | 8 +++++++
+ drivers/firmware/efi/efi.c | 1 +
+ drivers/firmware/efi/vars.c | 12 +++++++++++
+ fs/efivarfs/super.c | 39 +++++++++++++++++++++++++++++++++-
+ include/linux/efi.h | 11 ++++++++++
+ 5 files changed, 70 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
+index b0d0376940ba8b..a29efaf6fe411e 100644
+--- a/arch/x86/platform/efi/quirks.c
++++ b/arch/x86/platform/efi/quirks.c
+@@ -114,6 +114,14 @@ void efi_delete_dummy_variable(void)
+ EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL);
+ }
+
++u64 efivar_reserved_space(void)
++{
++ if (efi_no_storage_paranoia)
++ return 0;
++ return EFI_MIN_RESERVE;
++}
++EXPORT_SYMBOL_GPL(efivar_reserved_space);
++
+ /*
+ * In the nonblocking case we do not attempt to perform garbage
+ * collection if we do not have enough free space. Rather, we do the
+diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
+index 9786dfff9f840f..83b63dd2de9be3 100644
+--- a/drivers/firmware/efi/efi.c
++++ b/drivers/firmware/efi/efi.c
+@@ -211,6 +211,7 @@ static int generic_ops_register(void)
+ generic_ops.get_variable = efi.get_variable;
+ generic_ops.get_next_variable = efi.get_next_variable;
+ generic_ops.query_variable_store = efi_query_variable_store;
++ generic_ops.query_variable_info = efi.query_variable_info;
+
+ if (efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE)) {
+ generic_ops.set_variable = efi.set_variable;
+diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
+index 4ca256bcd69715..d22160e7c7851b 100644
+--- a/drivers/firmware/efi/vars.c
++++ b/drivers/firmware/efi/vars.c
+@@ -250,3 +250,15 @@ efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
+ return status;
+ }
+ EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR);
++
++efi_status_t efivar_query_variable_info(u32 attr,
++ u64 *storage_space,
++ u64 *remaining_space,
++ u64 *max_variable_size)
++{
++ if (!__efivars->ops->query_variable_info)
++ return EFI_UNSUPPORTED;
++ return __efivars->ops->query_variable_info(attr, storage_space,
++ remaining_space, max_variable_size);
++}
++EXPORT_SYMBOL_NS_GPL(efivar_query_variable_info, EFIVAR);
+diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
+index 9025430cf2ad35..3fbced52fc6bb8 100644
+--- a/fs/efivarfs/super.c
++++ b/fs/efivarfs/super.c
+@@ -14,6 +14,7 @@
+ #include <linux/slab.h>
+ #include <linux/magic.h>
+ #include <linux/printk.h>
++#include <linux/statfs.h>
+
+ #include "internal.h"
+
+@@ -24,8 +25,44 @@ static void efivarfs_evict_inode(struct inode *inode)
+ clear_inode(inode);
+ }
+
++static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ const u32 attr = EFI_VARIABLE_NON_VOLATILE |
++ EFI_VARIABLE_BOOTSERVICE_ACCESS |
++ EFI_VARIABLE_RUNTIME_ACCESS;
++ u64 storage_space, remaining_space, max_variable_size;
++ efi_status_t status;
++
++ status = efivar_query_variable_info(attr, &storage_space, &remaining_space,
++ &max_variable_size);
++ if (status != EFI_SUCCESS)
++ return efi_status_to_err(status);
++
++ /*
++ * This is not a normal filesystem, so no point in pretending it has a block
++ * size; we declare f_bsize to 1, so that we can then report the exact value
++ * sent by EFI QueryVariableInfo in f_blocks and f_bfree
++ */
++ buf->f_bsize = 1;
++ buf->f_namelen = NAME_MAX;
++ buf->f_blocks = storage_space;
++ buf->f_bfree = remaining_space;
++ buf->f_type = dentry->d_sb->s_magic;
++
++ /*
++ * In f_bavail we declare the free space that the kernel will allow writing
++ * when the storage_paranoia x86 quirk is active. To use more, users
++ * should boot the kernel with efi_no_storage_paranoia.
++ */
++ if (remaining_space > efivar_reserved_space())
++ buf->f_bavail = remaining_space - efivar_reserved_space();
++ else
++ buf->f_bavail = 0;
++
++ return 0;
++}
+ static const struct super_operations efivarfs_ops = {
+- .statfs = simple_statfs,
++ .statfs = efivarfs_statfs,
+ .drop_inode = generic_delete_inode,
+ .evict_inode = efivarfs_evict_inode,
+ };
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 1d73c77051c09b..5868c4b2933261 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -1039,6 +1039,7 @@ struct efivar_operations {
+ efi_set_variable_t *set_variable;
+ efi_set_variable_t *set_variable_nonblocking;
+ efi_query_variable_store_t *query_variable_store;
++ efi_query_variable_info_t *query_variable_info;
+ };
+
+ struct efivars {
+@@ -1047,6 +1048,12 @@ struct efivars {
+ const struct efivar_operations *ops;
+ };
+
++#ifdef CONFIG_X86
++u64 __attribute_const__ efivar_reserved_space(void);
++#else
++static inline u64 efivar_reserved_space(void) { return 0; }
++#endif
++
+ /*
+ * The maximum size of VariableName + Data = 1024
+ * Therefore, it's reasonable to save that much
+@@ -1081,6 +1088,10 @@ efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
+ efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
+ u32 attr, unsigned long data_size, void *data);
+
++efi_status_t efivar_query_variable_info(u32 attr, u64 *storage_space,
++ u64 *remaining_space,
++ u64 *max_variable_size);
++
+ #if IS_ENABLED(CONFIG_EFI_CAPSULE_LOADER)
+ extern bool efi_capsule_pending(int *reset_type);
+
+--
+2.53.0
+
--- /dev/null
+From 2da59d960269acedf14bd7729a5ac4e558624517 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 10 Sep 2023 06:54:45 +0200
+Subject: efivarfs: fix statfs() on efivarfs
+
+From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+
+[ Upstream commit 79b83606abc778aa3cbee535b362ce905d0b9448 ]
+
+Some firmware (notably U-Boot) provides GetVariable() and
+GetNextVariableName() but not QueryVariableInfo().
+
+With commit d86ff3333cb1 ("efivarfs: expose used and total size") the
+statfs syscall was broken for such firmware.
+
+If QueryVariableInfo() does not exist or returns EFI_UNSUPPORTED, just
+report the file system size as 0 as statfs_simple() previously did.
+
+Fixes: d86ff3333cb1 ("efivarfs: expose used and total size")
+Link: https://lore.kernel.org/all/20230910045445.41632-1-heinrich.schuchardt@canonical.com/
+Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+[ardb: log warning on QueryVariableInfo() failure]
+Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/efivarfs/super.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
+index 3fbced52fc6bb8..53d19ecc4385fa 100644
+--- a/fs/efivarfs/super.c
++++ b/fs/efivarfs/super.c
+@@ -33,10 +33,16 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+ u64 storage_space, remaining_space, max_variable_size;
+ efi_status_t status;
+
+- status = efivar_query_variable_info(attr, &storage_space, &remaining_space,
+- &max_variable_size);
+- if (status != EFI_SUCCESS)
+- return efi_status_to_err(status);
++ /* Some UEFI firmware does not implement QueryVariableInfo() */
++ storage_space = remaining_space = 0;
++ if (efi_rt_services_supported(EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO)) {
++ status = efivar_query_variable_info(attr, &storage_space,
++ &remaining_space,
++ &max_variable_size);
++ if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED)
++ pr_warn_ratelimited("query_variable_info() failed: 0x%lx\n",
++ status);
++ }
+
+ /*
+ * This is not a normal filesystem, so no point in pretending it has a block
+--
+2.53.0
+
--- /dev/null
+From f944be57e55f19a7e4b7329f2f9c9ddef780128a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 18:34:41 +0300
+Subject: iio: temperature: ltc2983: Fix n_wires default bypassing rotation
+ check
+
+From: Liviu Stan <liviu.stan@analog.com>
+
+[ Upstream commit 434c150752675f44dc52c384a7fa22e5176bc35a ]
+
+When adi,number-of-wires is absent, n_wires is left at 0. The binding
+documents a default of 2 wires, matching the hardware default. However
+the current-rotate validation checks n_wires == 2 || n_wires == 3, so
+with n_wires = 0 the guard is bypassed and adi,current-rotate is accepted
+for a 2-wire RTD.
+
+Initialize n_wires = 2 to match the binding default and ensure the
+rotation check fires correctly when the property is absent.
+
+Fixes: f110f3188e56 ("iio: temperature: Add support for LTC2983")
+Signed-off-by: Liviu Stan <liviu.stan@analog.com>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <jic23@kernel.org>
+Signed-off-by: Liviu Stan <liviu.stan@analog.com>
+
+[ Liviu Stan: resolve conflict - keep fwnode_handle *ref declaration
+ which was removed upstream by a later refactor not in 6.1.y ]
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/temperature/ltc2983.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
+index 8d18823be40f41..9d3fb988cd061a 100644
+--- a/drivers/iio/temperature/ltc2983.c
++++ b/drivers/iio/temperature/ltc2983.c
+@@ -706,7 +706,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
+ int ret = 0;
+ struct device *dev = &st->spi->dev;
+ struct fwnode_handle *ref;
+- u32 excitation_current = 0, n_wires = 0;
++ u32 excitation_current = 0, n_wires = 2;
+
+ rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL);
+ if (!rtd)
+--
+2.53.0
+
usb-typec-ucsi-pass-full-dp-config-payload-in-set_new_cam-for-dp-alt-mode.patch
usb-typec-ucsi-ccg-fix-use-after-free-of-ucsi-on-remove.patch
usb-typec-ucsi-cancel-pending-work-on-system-suspend.patch
+iio-temperature-ltc2983-fix-n_wires-default-bypassin.patch
+efivarfs-expose-used-and-total-size.patch
+efivarfs-fix-statfs-on-efivarfs.patch
--- /dev/null
+From 67f5da61ba39b5a5dac82a49d4623ac759a7a2f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 23:25:49 +0100
+Subject: PCI: Always lift 2.5GT/s restriction in PCIe failed link retraining
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 72780f7964684939d7d2f69c348876213b184484 upstream.
+
+Discard Vendor:Device ID matching in the PCIe failed link retraining quirk
+and ignore the link status for the removal of the 2.5GT/s speed clamp,
+whether applied by the quirk itself or the firmware earlier on. Revert to
+the original target link speed if this final link retraining has failed.
+
+This is so that link training noise in hot-plug scenarios does not make a
+link remain clamped to the 2.5GT/s speed where an event race has led the
+quirk to apply the speed clamp for one device, only to leave it in place
+for a subsequent device to be plugged in.
+
+Refer to the Link Capabilities register directly for the maximum link speed
+determination so as to streamline backporting.
+
+Fixes: a89c82249c37 ("PCI: Work around PCIe link training failures")
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Tested-by: Alok Tiwari <alok.a.tiwari@oracle.com>
+Cc: stable@vger.kernel.org # v6.5+
+Link: https://patch.msgid.link/alpine.DEB.2.21.2512080331530.49654@angie.orcam.me.uk
+[ Update for missing PCIe link speed helpers for 6.12.y. ]
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 51 +++++++++++++++++---------------------------
+ 1 file changed, 20 insertions(+), 31 deletions(-)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 3d05ea35c536f5..9b2acf388f8ad7 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -68,11 +68,10 @@
+ * Restrict the speed to 2.5GT/s then with the Target Link Speed field,
+ * request a retrain and check the result.
+ *
+- * If this turns out successful and we know by the Vendor:Device ID it is
+- * safe to do so, then lift the restriction, letting the devices negotiate
+- * a higher speed. Also check for a similar 2.5GT/s speed restriction the
+- * firmware may have already arranged and lift it with ports that already
+- * report their data link being up.
++ * If this turns out successful, or where a 2.5GT/s speed restriction has
++ * been previously arranged by the firmware and the port reports its link
++ * already being up, lift the restriction, in a hope it is safe to do so,
++ * letting the devices negotiate a higher speed.
+ *
+ * Otherwise revert the speed to the original setting and request a retrain
+ * again to remove any residual state, ignoring the result as it's supposed
+@@ -83,12 +82,9 @@
+ */
+ int pcie_failed_link_retrain(struct pci_dev *dev)
+ {
+- static const struct pci_device_id ids[] = {
+- { PCI_VDEVICE(ASMEDIA, 0x2824) }, /* ASMedia ASM2824 */
+- {}
+- };
+- u16 lnksta, lnkctl2;
++ u16 lnksta, lnkctl2, oldlnkctl2;
+ int ret = -ENOTTY;
++ u32 lnkcap;
+
+ if (!pci_is_pcie(dev) || !pcie_downstream_port(dev) ||
+ !pcie_cap_has_lnkctl2(dev) || !dev->link_active_reporting)
+@@ -96,10 +92,9 @@ int pcie_failed_link_retrain(struct pci_dev *dev)
+
+ pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2);
+ pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
++ oldlnkctl2 = lnkctl2;
+ if ((lnksta & (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_DLLLA)) ==
+ PCI_EXP_LNKSTA_LBMS) {
+- u16 oldlnkctl2 = lnkctl2;
+-
+ pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n");
+
+ lnkctl2 &= ~PCI_EXP_LNKCTL2_TLS;
+@@ -107,35 +102,29 @@ int pcie_failed_link_retrain(struct pci_dev *dev)
+ pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, lnkctl2);
+
+ ret = pcie_retrain_link(dev, false);
+- if (ret) {
+- pci_info(dev, "retraining failed\n");
+- pcie_capability_write_word(dev, PCI_EXP_LNKCTL2,
+- oldlnkctl2);
+- pcie_retrain_link(dev, true);
+- return ret;
+- }
+-
+- pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
++ if (ret)
++ goto err;
+ }
+
+- if ((lnksta & PCI_EXP_LNKSTA_DLLLA) &&
+- (lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT &&
+- pci_match_id(ids, dev)) {
+- u32 lnkcap;
+-
++ pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
++ if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT &&
++ (lnkcap & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
+ pci_info(dev, "removing 2.5GT/s downstream link speed restriction\n");
+- pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+ lnkctl2 &= ~PCI_EXP_LNKCTL2_TLS;
+ lnkctl2 |= lnkcap & PCI_EXP_LNKCAP_SLS;
+ pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, lnkctl2);
+
+ ret = pcie_retrain_link(dev, false);
+- if (ret) {
+- pci_info(dev, "retraining failed\n");
+- return ret;
+- }
++ if (ret)
++ goto err;
+ }
+
++ return ret;
++err:
++ pci_info(dev, "retraining failed\n");
++ pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, oldlnkctl2);
++
++ pcie_retrain_link(dev, true);
+ return ret;
+ }
+
+--
+2.53.0
+
usb-typec-ucsi-ccg-fix-use-after-free-of-ucsi-on-remove.patch
usb-typec-ucsi-cancel-pending-work-on-system-suspend.patch
usb-gadget-f_fs-fix-dma-fence-leak.patch
+x86-fs-resctrl-prevent-out-of-bounds-access-while-of.patch
+pci-always-lift-2.5gt-s-restriction-in-pcie-failed-l.patch
--- /dev/null
+From 6d17092213afa16c6188165aa5619c2a69e9f530 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 21:12:36 -0700
+Subject: x86,fs/resctrl: Prevent out-of-bounds access while offlining CPU when
+ SNC enabled
+
+From: Reinette Chatre <reinette.chatre@intel.com>
+
+commit fc16126cc11d9f507130bf84ab137ee0938c900e upstream.
+
+The architecture updates the cpu_mask in a domain's header to track which
+online CPUs are associated with the domain. When this mask becomes empty
+the architecture initiates offline of the domain that includes calling
+on resctrl fs to offline the domain. If it is a monitoring domain in
+which LLC occupancy is tracked resctrl fs forces the limbo handler to
+clear all busy RMID state associated with the domain.
+
+The limbo handler always reads the current event value associated with a
+busy RMID irrespective of it being checked as part of regular "is it still
+busy" check or whether it will be forced released anyway. When reading an
+RMID on a system with SNC enabled the "logical RMID" is converted to the
+"physical RMID" and this conversion requires the NUMA node ID of the
+resctrl monitoring domain that is in turn determined by querying the NUMA
+node ID of any CPU belonging to the monitoring domain.
+
+When the monitoring domain is going offline its cpu_mask is empty causing
+the NUMA node ID query via cpu_to_node() to be done with "nr_cpu_ids" as
+argument resulting in an out-of-bounds access.
+
+Refactor the limbo handler to skip reading the RMID when the RMID will
+just be forced to no longer be dirty in the domain anyway. Add a safety
+check to the architecture's RMID reader to protect against this scenario.
+
+Fixes: e13db55b5a0d ("x86/resctrl: Introduce snc_nodes_per_l3_cache")
+Closes: https://sashiko.dev/#/patchset/cover.1780456704.git.reinette.chatre%40intel.com?part=9
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Cc: <stable@kernel.org>
+Link: https://patch.msgid.link/16137433df42f85013b2f7a53626795cbd6637b9.1781029125.git.reinette.chatre@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/resctrl/monitor.c | 47 +++++++++++++++++----------
+ 1 file changed, 29 insertions(+), 18 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
+index c117fba4f8da92..b4dcfe6d0831ac 100644
+--- a/arch/x86/kernel/cpu/resctrl/monitor.c
++++ b/arch/x86/kernel/cpu/resctrl/monitor.c
+@@ -338,14 +338,20 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d,
+ u64 *val, void *ignored)
+ {
+ struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d);
+- int cpu = cpumask_any(&d->hdr.cpu_mask);
+ struct arch_mbm_state *am;
+ u64 msr_val;
+ u32 prmid;
++ int cpu;
+ int ret;
+
+ resctrl_arch_rmid_read_context_check();
+
++ if (cpumask_empty(&d->hdr.cpu_mask)) {
++ pr_warn_once("Domain %d has no CPUs\n", d->hdr.id);
++ return -EINVAL;
++ }
++
++ cpu = cpumask_any(&d->hdr.cpu_mask);
+ prmid = logical_rmid_to_physical_rmid(cpu, rmid);
+ ret = __rmid_read_phys(prmid, eventid, &msr_val);
+
+@@ -382,9 +388,9 @@ void __check_limbo(struct rdt_mon_domain *d, bool force_free)
+ struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
+ u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+ struct rmid_entry *entry;
++ bool rmid_dirty = true;
+ u32 idx, cur_idx = 1;
+ void *arch_mon_ctx;
+- bool rmid_dirty;
+ u64 val = 0;
+
+ arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, QOS_L3_OCCUP_EVENT_ID);
+@@ -406,22 +412,27 @@ void __check_limbo(struct rdt_mon_domain *d, bool force_free)
+ break;
+
+ entry = __rmid_entry(idx);
+- if (resctrl_arch_rmid_read(r, d, entry->closid, entry->rmid,
+- QOS_L3_OCCUP_EVENT_ID, &val,
+- arch_mon_ctx)) {
+- rmid_dirty = true;
+- } else {
+- rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
+-
+- /*
+- * x86's CLOSID and RMID are independent numbers, so the entry's
+- * CLOSID is an empty CLOSID (X86_RESCTRL_EMPTY_CLOSID). On Arm the
+- * RMID (PMG) extends the CLOSID (PARTID) space with bits that aren't
+- * used to select the configuration. It is thus necessary to track both
+- * CLOSID and RMID because there may be dependencies between them
+- * on some architectures.
+- */
+- trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid, d->hdr.id, val);
++ if (!force_free) {
++ if (resctrl_arch_rmid_read(r, d, entry->closid,
++ entry->rmid, QOS_L3_OCCUP_EVENT_ID,
++ &val, arch_mon_ctx)) {
++ rmid_dirty = true;
++ } else {
++ rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
++
++ /*
++ * x86's CLOSID and RMID are independent numbers,
++ * so the entry's CLOSID is an empty CLOSID
++ * (X86_RESCTRL_EMPTY_CLOSID). On Arm the RMID
++ * (PMG) extends the CLOSID (PARTID) space with
++ * bits that aren't used to select the configuration.
++ * It is thus necessary to track both CLOSID and
++ * RMID because there may be dependencies between
++ * them on some architectures.
++ */
++ trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid,
++ d->hdr.id, val);
++ }
+ }
+
+ if (force_free || !rmid_dirty) {
+--
+2.53.0
+
--- /dev/null
+From 682abc7bee5723cea5d781b6645259dbf973f82c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 18:12:53 -0700
+Subject: bpf: Prefer dirty packs for eBPF allocations
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit b72e29e0f7ee329d89f86db8700c8ea99b4a370a upstream.
+
+The pack allocator only flushes predictors when reusing a dirty pack for
+cBPF, eBPF allocations never trigger a flush. Currently, eBPF picks the
+first free pack, which could be a clean pack. As an optimization, leaving
+a clean pack for cBPF can avoid flushes.
+
+Prefer dirty packs for eBPF and keep clean packs free for cBPF. This
+mirrors the existing cBPF preference for clean packs: each program kind
+prefers the pack that avoids an extra flush, and falls back to the other
+kind only when no preferred pack has room. eBPF reuse of a dirty pack is
+harmless since eBPF being privileged does not flush.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/core.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index e0ffdd985eb5d7..b102704f89bc77 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -970,10 +970,10 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool
+ goto found_free_area;
+ /*
+ * cBPF reuse of a dirty pack triggers a flush, so prefer a
+- * clean pack for cBPF. eBPF never flushes, so pick the first
+- * free pack, dirty or clean.
++ * clean pack for cBPF. eBPF never flushes, so steer it to a
++ * dirty pack and keep clean packs free for cBPF.
+ */
+- if (!was_classic || !pack->arch_flush_needed)
++ if (was_classic ^ pack->arch_flush_needed)
+ goto found_free_area;
+ if (!fallback_pack) {
+ fallback_pack = pack;
+--
+2.53.0
+
--- /dev/null
+From 07ecae528d2d2edf01835b1535bd227285872dfb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 18:12:38 -0700
+Subject: bpf: Prefer packs that won't trigger an IBPB flush on allocation
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit a9b1f19a6a673ba06820898d0f1ad02883ea1639 upstream.
+
+Currently BPF pack allocator picks the chunks from the first available
+pack. While this is okay, it naturally leads to more frequent flushes
+when there are multiple packs in the system that weren't used since the
+last flush.
+
+As an optimization prefer allocating the new programs from packs that
+are unused since last flush. When all packs are dirty, allocation forces
+a flush and marks all packs clean.
+
+Below are some future optimizations ideas:
+
+ 1. Currently, the "dirty" tracking is only done at the pack-level.
+ Flush frequency can further be reduced with chunk-level tracking.
+ This requires a new bitmap per-pack to track the dirty state.
+ 2. IBPB flush is done on all CPUs, even if only a single CPU ran the
+ BPF program. On a system with hundreds of CPUs this could be a
+ major bottleneck forcing hundreds of IPIs to deliver the flush.
+ The solution is to track the CPUs where a BPF program ran, and
+ issue IBPB only on those CPUs.
+ 3. Avoid IBPB when flush is already done at other sources (e.g.
+ context switch).
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/core.c | 27 ++++++++++++++++++++++++---
+ 1 file changed, 24 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 49ca543a41115a..e0ffdd985eb5d7 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -930,8 +930,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins
+ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic)
+ {
+ unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size);
+- struct bpf_prog_pack *pack;
+- unsigned long pos;
++ struct bpf_prog_pack *pack, *fallback_pack = NULL;
++ unsigned long pos, fallback_pos = 0;
+ void *ptr = NULL;
+
+ mutex_lock(&pack_mutex);
+@@ -963,8 +963,29 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool
+ list_for_each_entry(pack, &pack_list, list) {
+ pos = bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0,
+ nbits, 0);
+- if (pos < BPF_PROG_CHUNK_COUNT)
++ if (pos >= BPF_PROG_CHUNK_COUNT)
++ continue;
++ /* Flush not enabled, use any pack */
++ if (!static_branch_unlikely(&bpf_pred_flush_enabled))
+ goto found_free_area;
++ /*
++ * cBPF reuse of a dirty pack triggers a flush, so prefer a
++ * clean pack for cBPF. eBPF never flushes, so pick the first
++ * free pack, dirty or clean.
++ */
++ if (!was_classic || !pack->arch_flush_needed)
++ goto found_free_area;
++ if (!fallback_pack) {
++ fallback_pack = pack;
++ fallback_pos = pos;
++ }
++ }
++
++ /* No preferred pack found */
++ if (fallback_pack) {
++ pack = fallback_pack;
++ pos = fallback_pos;
++ goto found_free_area;
+ }
+
+ pack = alloc_new_pack(bpf_fill_ill_insns);
+--
+2.53.0
+
--- /dev/null
+From d73e19d7bddfdf4bc77edb2596952637f02308c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 18:12:07 -0700
+Subject: bpf: Restrict JIT predictor flush to cBPF
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit 0bb99f2cfaae6822d734d69722de30af823efdf3 upstream.
+
+Currently predictor flush on memory reuse is done for all BPF JIT
+allocations, but only cBPF programs can be loaded by an unprivileged user.
+eBPF is privileged by default, and flushing predictors for all CPUs on
+every eBPF reuse penalizes the common case for no security benefit.
+
+eBPF allocations can be frequent on busy systems, only flush predictors
+for cBPF programs. Trampoline and dispatcher allocations also skip the
+flush as they are eBPF-only.
+
+ [pawan: backport had various conflicts in arches bpf_int_jit_compile().
+ loongarch bpf_int_jit_compile() doesn't use pack allocator,
+ dropped was_classic hunk. ]
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/net/bpf_jit_comp.c | 4 ++--
+ arch/loongarch/net/bpf_jit.c | 2 +-
+ arch/powerpc/net/bpf_jit_comp.c | 4 ++--
+ arch/riscv/net/bpf_jit_comp64.c | 2 +-
+ arch/riscv/net/bpf_jit_core.c | 3 ++-
+ arch/x86/net/bpf_jit_comp.c | 5 +++--
+ include/linux/filter.h | 5 +++--
+ kernel/bpf/core.c | 13 ++++++++-----
+ kernel/bpf/dispatcher.c | 2 +-
+ 9 files changed, 23 insertions(+), 17 deletions(-)
+
+diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
+index 873c1b784a872d..c563bae8fce1c2 100644
+--- a/arch/arm64/net/bpf_jit_comp.c
++++ b/arch/arm64/net/bpf_jit_comp.c
+@@ -2117,7 +2117,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+ image_size = extable_offset + extable_size;
+ ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr,
+ sizeof(u64), &header, &image_ptr,
+- jit_fill_hole);
++ jit_fill_hole, was_classic);
+ if (!ro_header) {
+ prog = orig_prog;
+ goto out_off;
+@@ -2754,7 +2754,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
+
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+- return bpf_prog_pack_alloc(size, jit_fill_hole);
++ return bpf_prog_pack_alloc(size, jit_fill_hole, false);
+ }
+
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
+index e9d666508ae28f..a000620ca99da7 100644
+--- a/arch/loongarch/net/bpf_jit.c
++++ b/arch/loongarch/net/bpf_jit.c
+@@ -1474,7 +1474,7 @@ static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_links *tl,
+
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+- return bpf_prog_pack_alloc(size, jit_fill_hole);
++ return bpf_prog_pack_alloc(size, jit_fill_hole, false);
+ }
+
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
+index 189ef7b72081d2..cedab25aa3a823 100644
+--- a/arch/powerpc/net/bpf_jit_comp.c
++++ b/arch/powerpc/net/bpf_jit_comp.c
+@@ -246,7 +246,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
+ alloclen = proglen + FUNCTION_DESCR_SIZE + fixup_len + extable_len;
+
+ fhdr = bpf_jit_binary_pack_alloc(alloclen, &fimage, 4, &hdr, &image,
+- bpf_jit_fill_ill_insns);
++ bpf_jit_fill_ill_insns, bpf_prog_was_classic(fp));
+ if (!fhdr) {
+ fp = org_fp;
+ goto out_addrs;
+@@ -468,7 +468,7 @@ bool bpf_jit_supports_insn(struct bpf_insn *insn, bool in_arena)
+
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+- return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns);
++ return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns, false);
+ }
+
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
+index 45cbc7c6fe490c..9e9e6dcfc48254 100644
+--- a/arch/riscv/net/bpf_jit_comp64.c
++++ b/arch/riscv/net/bpf_jit_comp64.c
+@@ -1268,7 +1268,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
+
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+- return bpf_prog_pack_alloc(size, bpf_fill_ill_insns);
++ return bpf_prog_pack_alloc(size, bpf_fill_ill_insns, false);
+ }
+
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
+index 191bf0e66c8243..e4ab5bb9c9f646 100644
+--- a/arch/riscv/net/bpf_jit_core.c
++++ b/arch/riscv/net/bpf_jit_core.c
+@@ -125,7 +125,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+ bpf_jit_binary_pack_alloc(prog_size + extable_size,
+ &jit_data->ro_image, sizeof(u32),
+ &jit_data->header, &jit_data->image,
+- bpf_fill_ill_insns);
++ bpf_fill_ill_insns,
++ bpf_prog_was_classic(prog));
+ if (!jit_data->ro_header) {
+ prog = orig_prog;
+ goto out_offset;
+diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
+index 788671a32d8ee0..c3798cab3b7db0 100644
+--- a/arch/x86/net/bpf_jit_comp.c
++++ b/arch/x86/net/bpf_jit_comp.c
+@@ -3447,7 +3447,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
+
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+- return bpf_prog_pack_alloc(size, jit_fill_hole);
++ return bpf_prog_pack_alloc(size, jit_fill_hole, false);
+ }
+
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+@@ -3780,7 +3780,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+ /* allocate module memory for x86 insns and extable */
+ header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
+ &image, align, &rw_header, &rw_image,
+- jit_fill_hole);
++ jit_fill_hole,
++ bpf_prog_was_classic(prog));
+ if (!header) {
+ prog = orig_prog;
+ goto out_addrs;
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index 3c4dd718beced8..2469fd2e401578 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -1290,7 +1290,7 @@ void bpf_jit_free(struct bpf_prog *fp);
+ struct bpf_binary_header *
+ bpf_jit_binary_pack_hdr(const struct bpf_prog *fp);
+
+-void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns);
++void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic);
+ void bpf_prog_pack_free(void *ptr, u32 size);
+
+ static inline bool bpf_prog_kallsyms_verify_off(const struct bpf_prog *fp)
+@@ -1304,7 +1304,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **ro_image,
+ unsigned int alignment,
+ struct bpf_binary_header **rw_hdr,
+ u8 **rw_image,
+- bpf_jit_fill_hole_t bpf_fill_ill_insns);
++ bpf_jit_fill_hole_t bpf_fill_ill_insns,
++ bool was_classic);
+ int bpf_jit_binary_pack_finalize(struct bpf_binary_header *ro_header,
+ struct bpf_binary_header *rw_header);
+ void bpf_jit_binary_pack_free(struct bpf_binary_header *ro_header,
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index a043fccb917e86..338a806e25c045 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -924,7 +924,7 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins
+ return NULL;
+ }
+
+-void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
++void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic)
+ {
+ unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size);
+ struct bpf_prog_pack *pack;
+@@ -939,7 +939,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+ * safe because cBPF programs (the unprivileged attack surface)
+ * are bounded well below a pack size.
+ */
+- if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ if (was_classic && static_branch_unlikely(&bpf_pred_flush_enabled))
+ pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n");
+ size = round_up(size, PAGE_SIZE);
+ ptr = bpf_jit_alloc_exec(size);
+@@ -971,7 +971,9 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+ pos = 0;
+
+ found_free_area:
+- static_call_cond(bpf_arch_pred_flush)();
++ /* Flush only for cBPF as it may contain a crafted gadget */
++ if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic)
++ static_call_cond(bpf_arch_pred_flush)();
+ bitmap_set(pack->bitmap, pos, nbits);
+ ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT);
+
+@@ -1131,7 +1133,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr,
+ unsigned int alignment,
+ struct bpf_binary_header **rw_header,
+ u8 **rw_image,
+- bpf_jit_fill_hole_t bpf_fill_ill_insns)
++ bpf_jit_fill_hole_t bpf_fill_ill_insns,
++ bool was_classic)
+ {
+ struct bpf_binary_header *ro_header;
+ u32 size, hole, start;
+@@ -1144,7 +1147,7 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr,
+
+ if (bpf_jit_charge_modmem(size))
+ return NULL;
+- ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns);
++ ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns, was_classic);
+ if (!ro_header) {
+ bpf_jit_uncharge_modmem(size);
+ return NULL;
+diff --git a/kernel/bpf/dispatcher.c b/kernel/bpf/dispatcher.c
+index b77db7413f8c70..ea2d60dc1feeb7 100644
+--- a/kernel/bpf/dispatcher.c
++++ b/kernel/bpf/dispatcher.c
+@@ -145,7 +145,7 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from,
+
+ mutex_lock(&d->mutex);
+ if (!d->image) {
+- d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero);
++ d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero, false);
+ if (!d->image)
+ goto out;
+ d->rw_image = bpf_jit_alloc_exec(PAGE_SIZE);
+--
+2.53.0
+
--- /dev/null
+From 17fa250049b03cbe5bff7f5fadb7622fb3d3c790 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 18:12:23 -0700
+Subject: bpf: Skip redundant IBPB in pack allocator
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit a23c1c5396a91680703360d1ee28a44657c503c4 upstream.
+
+bpf_prog_pack_alloc() issues IBPB on all CPUs on every cBPF allocation,
+even when reusing chunks from an existing pack where no new memory was
+touched since the last IBPB.
+
+Since IBPB on all CPUs is heavy, Dave Hansen suggested to track allocation
+since last IBPB, and only issue IBPB at reuse for the chunks that have not
+seen an IBPB since they were last freed.
+
+Track per-pack whether an IBPB is needed via arch_flush_needed. Set it when
+allocating a chunk, reset on IBPB flush. On reuse, conditionally issue the
+flush. Since IBPB invalidates all BTB entries, clear the flag on all packs
+after flushing.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/core.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 338a806e25c045..49ca543a41115a 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -857,6 +857,7 @@ int bpf_jit_add_poke_descriptor(struct bpf_prog *prog,
+ struct bpf_prog_pack {
+ struct list_head list;
+ void *ptr;
++ bool arch_flush_needed;
+ unsigned long bitmap[];
+ };
+
+@@ -910,6 +911,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins
+ bpf_fill_ill_insns(pack->ptr, BPF_PROG_PACK_SIZE);
+ bitmap_zero(pack->bitmap, BPF_PROG_PACK_SIZE / BPF_PROG_CHUNK_SIZE);
+
++ if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ pack->arch_flush_needed = true;
+ set_vm_flush_reset_perms(pack->ptr);
+ err = set_memory_rox((unsigned long)pack->ptr,
+ BPF_PROG_PACK_SIZE / PAGE_SIZE);
+@@ -972,8 +975,15 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool
+
+ found_free_area:
+ /* Flush only for cBPF as it may contain a crafted gadget */
+- if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic)
++ if (static_branch_unlikely(&bpf_pred_flush_enabled) &&
++ pack->arch_flush_needed &&
++ was_classic) {
++ struct bpf_prog_pack *p;
++
+ static_call_cond(bpf_arch_pred_flush)();
++ list_for_each_entry(p, &pack_list, list)
++ p->arch_flush_needed = false;
++ }
+ bitmap_set(pack->bitmap, pos, nbits);
+ ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT);
+
+@@ -1011,6 +1021,9 @@ void bpf_prog_pack_free(void *ptr, u32 size)
+ "bpf_prog_pack bug: missing bpf_arch_text_invalidate?\n");
+
+ bitmap_clear(pack->bitmap, pos, nbits);
++
++ if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ pack->arch_flush_needed = true;
+ if (bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0,
+ BPF_PROG_CHUNK_COUNT, 0) == 0) {
+ list_del(&pack->list);
+--
+2.53.0
+
--- /dev/null
+From f8258f4ab04d2a59f347a2412743bf79669faef9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 18:11:37 -0700
+Subject: bpf: Support for hardening against JIT spraying
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit 96cce16e26dd02a8678f1e87f88a4b5cdb63b995 upstream.
+
+The BPF JIT allocator packs many small programs into larger executable
+allocations and reuses space within those allocations as programs are
+loaded and freed. When fresh code is written into space that a previous
+program occupied, an indirect jump into the new program can reuse a branch
+prediction left behind by the old one.
+
+Flush the indirect branch predictors before reusing JIT memory so that
+indirect jumps into a newly written program don't reuse predictions from an
+old program that occupied the same space.
+
+Introduce bpf_arch_pred_flush_enabled static key and bpf_arch_pred_flush
+static call for flushing the branch predictors on JIT memory reuse.
+Architectures that need a flush, can update it to a predictor flush
+function. By default, its a NOP and does not emit any CALL.
+
+Allocations larger than a pack are not covered by this flush. That is safe
+because cBPF programs (the unprivileged attack surface) are bounded well
+below a pack size. Issue a warning if this assumption is ever violated
+while the flush is active.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/filter.h | 10 ++++++++++
+ kernel/bpf/core.c | 19 +++++++++++++++++++
+ 2 files changed, 29 insertions(+)
+
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index cf7a0bce1bb6d8..3c4dd718beced8 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -22,6 +22,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/sockptr.h>
+ #include <crypto/sha1.h>
++#include <linux/static_call.h>
+ #include <linux/u64_stats_sync.h>
+
+ #include <net/sch_generic.h>
+@@ -1266,6 +1267,15 @@ extern long bpf_jit_limit_max;
+
+ typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);
+
++/*
++ * Flush the indirect branch predictors before reusing JIT memory, so that
++ * indirect jumps into a newly written program don't reuse predictions left
++ * behind by an old program that occupied the same space.
++ */
++void bpf_arch_pred_flush(void);
++DECLARE_STATIC_CALL(bpf_arch_pred_flush, bpf_arch_pred_flush);
++DECLARE_STATIC_KEY_FALSE(bpf_pred_flush_enabled);
++
+ void bpf_jit_fill_hole_with_zero(void *area, unsigned int size);
+
+ struct bpf_binary_header *
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 931a4ddd8530ce..a043fccb917e86 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -21,6 +21,7 @@
+ #include <crypto/sha1.h>
+ #include <linux/filter.h>
+ #include <linux/skbuff.h>
++#include <linux/static_call.h>
+ #include <linux/vmalloc.h>
+ #include <linux/prandom.h>
+ #include <linux/bpf.h>
+@@ -864,6 +865,15 @@ void bpf_jit_fill_hole_with_zero(void *area, unsigned int size)
+ memset(area, 0, size);
+ }
+
++DEFINE_STATIC_CALL_NULL(bpf_arch_pred_flush, bpf_arch_pred_flush);
++
++/*
++ * Enabled once bpf_arch_pred_flush points at a real flush routine. Lets the
++ * pack allocator test "is a predictor flush wired up at all" with a cheap
++ * static branch instead of repeatedly querying the static call target.
++ */
++DEFINE_STATIC_KEY_FALSE(bpf_pred_flush_enabled);
++
+ #define BPF_PROG_SIZE_TO_NBITS(size) (round_up(size, BPF_PROG_CHUNK_SIZE) / BPF_PROG_CHUNK_SIZE)
+
+ static DEFINE_MUTEX(pack_mutex);
+@@ -923,6 +933,14 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+
+ mutex_lock(&pack_mutex);
+ if (size > BPF_PROG_PACK_SIZE) {
++ /*
++ * Allocations larger than a pack get their own pages, and
++ * predictors are not flushed for such allocation. This is only
++ * safe because cBPF programs (the unprivileged attack surface)
++ * are bounded well below a pack size.
++ */
++ if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n");
+ size = round_up(size, PAGE_SIZE);
+ ptr = bpf_jit_alloc_exec(size);
+ if (ptr) {
+@@ -953,6 +971,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+ pos = 0;
+
+ found_free_area:
++ static_call_cond(bpf_arch_pred_flush)();
+ bitmap_set(pack->bitmap, pos, nbits);
+ ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT);
+
+--
+2.53.0
+
--- /dev/null
+From 4703c3acf6204021d4625799da6b8f78c6fae7ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jul 2026 10:09:22 +0800
+Subject: mm: shmem: fix potential livelock issue for shmem direct swapin
+
+From: Baolin Wang <baolin.wang@linux.alibaba.com>
+
+When skipping swapcache for synchronous IO swap devices, swapcache_prepare()
+is used to prevent parallel swapin from proceeding with the swap cache flag.
+However, on PREEMPT kernels this can lead to a livelock, as reported by Chao[1]:
+
+Thread A starts direct swapin of a shmem folio and calls swapcache_prepare()
+to set SWAP_HAS_CACHE. It may then be preempted inside workingset_refault().
+Meanwhile, a higher priority thread B also attempts direct swapin of the same
+shmem swap entry. Since swapcache_prepare() already marks the entry, thread B
+repeatedly gets -EEXIST and busy-loops waiting for thread A to finish. But as
+thread B runs at higher priority, thread A cannot preempt it, resulting in
+starvation and a livelock.
+
+Fix it by yielding the CPU with schedule_timeout_uninterruptible(1) when
+swapcache_prepare() fails, following the same approach used in commit
+029c4628b2eb ("mm: swap: get rid of livelock in swapin readahead") and
+commit 13ddaf26be32 ("mm/swap: fix race when skipping swapcache").
+
+However, commit 01626a1823 ("mm: avoid unconditional one-tick sleep when
+swapcache_prepare fails") found that the unconditional one-tick sleep can
+cause UI stuttering on latency-sensitive Android devices. So we can follow
+the same approach by adding a waitqueue to wake up tasks when needed,
+instead of always sleeping for a full tick.
+
+Note that mainline does not have this potential issue, which has already been
+resolved by Kairui's swap refactoring work[2].
+
+[1] https://lore.kernel.org/all/700a2cbf90a2484f979aac858f08f5d4@xiaomi.com/
+[2] https://lore.kernel.org/all/20260517-swap-table-p4-v5-0-88ae43e064c7@tencent.com/
+Fixes: 1dd44c0af4fa ("mm: shmem: skip swapcache for swapin of synchronous swap device")
+Reported-by: Ma Chao <machao26@xiaomi.com>
+Closes: https://lore.kernel.org/all/700a2cbf90a2484f979aac858f08f5d4@xiaomi.com/
+Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/shmem.c | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/mm/shmem.c b/mm/shmem.c
+index 94c5b0d78ac31e..3c329b794ae4df 100644
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -2005,11 +2005,14 @@ static struct folio *shmem_alloc_and_add_folio(struct vm_fault *vmf,
+ return ERR_PTR(error);
+ }
+
++static DECLARE_WAIT_QUEUE_HEAD(shmem_swapcache_wq);
++
+ static struct folio *shmem_swap_alloc_folio(struct inode *inode,
+ struct vm_area_struct *vma, pgoff_t index,
+ swp_entry_t entry, int order, gfp_t gfp)
+ {
+ struct shmem_inode_info *info = SHMEM_I(inode);
++ DECLARE_WAITQUEUE(wait, current);
+ int nr_pages = 1 << order;
+ struct folio *new;
+ gfp_t alloc_gfp;
+@@ -2066,6 +2069,10 @@ static struct folio *shmem_swap_alloc_folio(struct inode *inode,
+ if (swapcache_prepare(entry, nr_pages)) {
+ folio_put(new);
+ new = ERR_PTR(-EEXIST);
++ /* Relax a bit to prevent rapid repeated page faults */
++ add_wait_queue(&shmem_swapcache_wq, &wait);
++ schedule_timeout_uninterruptible(1);
++ remove_wait_queue(&shmem_swapcache_wq, &wait);
+ /* Try smaller folio to avoid cache conflict */
+ goto fallback;
+ }
+@@ -2423,6 +2430,8 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
+ if (skip_swapcache) {
+ folio->swap.val = 0;
+ swapcache_clear(si, swap, nr_pages);
++ if (waitqueue_active(&shmem_swapcache_wq))
++ wake_up(&shmem_swapcache_wq);
+ } else {
+ swap_cache_del_folio(folio);
+ }
+@@ -2442,8 +2451,11 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
+ if (folio)
+ folio_unlock(folio);
+ failed_nolock:
+- if (skip_swapcache)
++ if (skip_swapcache) {
+ swapcache_clear(si, folio->swap, folio_nr_pages(folio));
++ if (waitqueue_active(&shmem_swapcache_wq))
++ wake_up(&shmem_swapcache_wq);
++ }
+ if (folio)
+ folio_put(folio);
+ put_swap_device(si);
+--
+2.53.0
+
--- /dev/null
+From b834619c38e13ccf912fe057c0127e3a7da0faf4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jul 2026 06:45:54 +0000
+Subject: rust_binder: fix BINDER_GET_EXTENDED_ERROR
+
+From: Alice Ryhl <aliceryhl@google.com>
+
+[ Upstream commit 77bfebf110773f5a0d6b5ff8110896adb2c9c335 ]
+
+This code currently copies the ExtendedError struct to the stack,
+modifies the copy, and then doesn't modify the original. Thus, fix it.
+
+Furthermore, errors when replying must be delivered directly to the
+remote thread, so update deliver_reply() to take an extended error
+argument.
+
+Cc: stable <stable@kernel.org>
+Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver")
+Signed-off-by: Alice Ryhl <aliceryhl@google.com>
+Acked-by: Carlos Llamas <cmllamas@google.com>
+Link: https://patch.msgid.link/20260605-set-extended-error-v3-1-d60b69a75f97@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Alice Ryhl <aliceryhl@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/android/binder/error.rs | 13 +++---
+ drivers/android/binder/thread.rs | 65 +++++++++++++++++++--------
+ drivers/android/binder/transaction.rs | 15 +++----
+ 3 files changed, 58 insertions(+), 35 deletions(-)
+
+diff --git a/drivers/android/binder/error.rs b/drivers/android/binder/error.rs
+index c6a834071f8cef..fd9e9d9e5658b1 100644
+--- a/drivers/android/binder/error.rs
++++ b/drivers/android/binder/error.rs
+@@ -72,20 +72,17 @@ impl core::fmt::Debug for BinderError {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ match self.reply {
+ BR_FAILED_REPLY => match self.source.as_ref() {
+- Some(source) => f
+- .debug_struct("BR_FAILED_REPLY")
+- .field("source", source)
+- .finish(),
++ Some(source) => source.fmt(f),
+ None => f.pad("BR_FAILED_REPLY"),
+ },
+ BR_DEAD_REPLY => f.pad("BR_DEAD_REPLY"),
+ BR_FROZEN_REPLY => f.pad("BR_FROZEN_REPLY"),
+ BR_TRANSACTION_PENDING_FROZEN => f.pad("BR_TRANSACTION_PENDING_FROZEN"),
+ BR_TRANSACTION_COMPLETE => f.pad("BR_TRANSACTION_COMPLETE"),
+- _ => f
+- .debug_struct("BinderError")
+- .field("reply", &self.reply)
+- .finish(),
++ _ => match self.source.as_ref() {
++ Some(source) => source.fmt(f),
++ None => self.reply.fmt(f),
++ },
+ }
+ }
+ }
+diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs
+index 93aa98c2a173a0..ad8bdf762ddc6f 100644
+--- a/drivers/android/binder/thread.rs
++++ b/drivers/android/binder/thread.rs
+@@ -498,9 +498,16 @@ impl Thread {
+ Ok(())
+ }
+
++ pub(crate) fn clear_extended_error(&self, debug_id: usize) {
++ self.inner.lock().extended_error = ExtendedError::new(debug_id as u32, BR_OK, 0);
++ }
++
+ pub(crate) fn get_extended_error(&self, data: UserSlice) -> Result {
+ let mut writer = data.writer();
+- let ee = self.inner.lock().extended_error;
++ let mut inner = self.inner.lock();
++ let ee = inner.extended_error;
++ inner.extended_error = ExtendedError::new(0, BR_OK, 0);
++ drop(inner);
+ writer.write(&ee)?;
+ Ok(())
+ }
+@@ -1105,7 +1112,10 @@ impl Thread {
+ inner.pop_transaction_to_reply(thread.as_ref())
+ } {
+ let reply = Err(BR_DEAD_REPLY);
+- if !transaction.from.deliver_single_reply(reply, &transaction) {
++ if !transaction
++ .from
++ .deliver_single_reply(reply, &transaction, None)
++ {
+ break;
+ }
+
+@@ -1117,8 +1127,9 @@ impl Thread {
+ &self,
+ reply: Result<DLArc<Transaction>, u32>,
+ transaction: &DArc<Transaction>,
++ extended_error: Option<ExtendedError>,
+ ) {
+- if self.deliver_single_reply(reply, transaction) {
++ if self.deliver_single_reply(reply, transaction, extended_error) {
+ transaction.from.unwind_transaction_stack();
+ }
+ }
+@@ -1132,6 +1143,7 @@ impl Thread {
+ &self,
+ reply: Result<DLArc<Transaction>, u32>,
+ transaction: &DArc<Transaction>,
++ extended_error: Option<ExtendedError>,
+ ) -> bool {
+ if let Ok(transaction) = &reply {
+ transaction.set_outstanding(&mut self.process.inner.lock());
+@@ -1147,6 +1159,12 @@ impl Thread {
+ return true;
+ }
+
++ if let Some(ee) = extended_error {
++ if inner.extended_error.command == BR_OK {
++ inner.extended_error = ee;
++ }
++ }
++
+ match reply {
+ Ok(work) => {
+ inner.push_work(work);
+@@ -1217,6 +1235,9 @@ impl Thread {
+ info.buffers_size = td.buffers_size as usize;
+ // SAFETY: Above `read` call initializes all bytes, so this union read is ok.
+ info.target_handle = unsafe { td.transaction_data.target.handle };
++
++ info.debug_id = super::next_debug_id();
++
+ Ok(())
+ }
+
+@@ -1225,6 +1246,8 @@ impl Thread {
+ let mut info = TransactionInfo::zeroed();
+ self.read_transaction_info(cmd, reader, &mut info)?;
+
++ self.clear_extended_error(info.debug_id);
++
+ let ret = if info.is_reply {
+ self.reply_inner(&mut info)
+ } else if info.is_oneway() {
+@@ -1234,23 +1257,21 @@ impl Thread {
+ };
+
+ if let Err(err) = ret {
+- if err.reply != BR_TRANSACTION_COMPLETE {
+- info.reply = err.reply;
+- }
+-
+ self.push_return_work(err.reply);
+- if let Some(source) = &err.source {
+- info.errno = source.to_errno();
++ if err.reply != BR_TRANSACTION_COMPLETE {
+ info.reply = err.reply;
++ if let Some(source) = &err.source {
++ info.errno = source.to_errno();
+
+- {
+- let mut ee = self.inner.lock().extended_error;
+- ee.command = err.reply;
+- ee.param = source.to_errno();
++ {
++ let mut inner = self.inner.lock();
++ inner.extended_error =
++ ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno());
++ }
+ }
+
+ pr_warn!(
+- "{}:{} transaction to {} failed: {source:?}",
++ "{}:{} transaction to {} failed: {err:?}",
+ info.from_pid,
+ info.from_tid,
+ info.to_pid
+@@ -1315,18 +1336,24 @@ impl Thread {
+ let allow_fds = orig.flags & TF_ACCEPT_FDS != 0;
+ let reply = Transaction::new_reply(self, process, info, allow_fds)?;
+ self.inner.lock().push_work(completion);
+- orig.from.deliver_reply(Ok(reply), &orig);
++ orig.from.deliver_reply(Ok(reply), &orig, None);
+ Ok(())
+ })()
+ .map_err(|mut err| {
+ // At this point we only return `BR_TRANSACTION_COMPLETE` to the caller, and we must let
+ // the sender know that the transaction has completed (with an error in this case).
++
+ pr_warn!(
+- "Failure {:?} during reply - delivering BR_FAILED_REPLY to sender.",
+- err
++ "{}:{} reply to {} failed: {err:?}",
++ info.from_pid,
++ info.from_tid,
++ info.to_pid
+ );
+- let reply = Err(BR_FAILED_REPLY);
+- orig.from.deliver_reply(reply, &orig);
++
++ let param = err.source.as_ref().map_or(0, |e| e.to_errno());
++ let ee = ExtendedError::new(info.debug_id as u32, err.reply, param);
++ orig.from
++ .deliver_reply(Err(BR_FAILED_REPLY), &orig, Some(ee));
+ err.reply = BR_TRANSACTION_COMPLETE;
+ err
+ });
+diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs
+index 733f452d8f49dd..b5434a2ae8193c 100644
+--- a/drivers/android/binder/transaction.rs
++++ b/drivers/android/binder/transaction.rs
+@@ -42,6 +42,7 @@ pub(crate) struct TransactionInfo {
+ pub(crate) reply: u32,
+ pub(crate) oneway_spam_suspect: bool,
+ pub(crate) is_reply: bool,
++ pub(crate) debug_id: usize,
+ }
+
+ impl TransactionInfo {
+@@ -82,7 +83,6 @@ impl Transaction {
+ from: &Arc<Thread>,
+ info: &mut TransactionInfo,
+ ) -> BinderResult<DLArc<Self>> {
+- let debug_id = super::next_debug_id();
+ let allow_fds = node_ref.node.flags & FLAT_BINDER_FLAG_ACCEPTS_FDS != 0;
+ let txn_security_ctx = node_ref.node.flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX != 0;
+ let mut txn_security_ctx_off = if txn_security_ctx { Some(0) } else { None };
+@@ -90,7 +90,7 @@ impl Transaction {
+ let mut alloc = match from.copy_transaction_data(
+ to.clone(),
+ info,
+- debug_id,
++ info.debug_id,
+ allow_fds,
+ txn_security_ctx_off.as_mut(),
+ ) {
+@@ -117,7 +117,7 @@ impl Transaction {
+ let data_address = alloc.ptr;
+
+ Ok(DTRWrap::arc_pin_init(pin_init!(Transaction {
+- debug_id,
++ debug_id: info.debug_id,
+ target_node: Some(target_node),
+ from_parent,
+ sender_euid: from.process.task.euid(),
+@@ -141,9 +141,8 @@ impl Transaction {
+ info: &mut TransactionInfo,
+ allow_fds: bool,
+ ) -> BinderResult<DLArc<Self>> {
+- let debug_id = super::next_debug_id();
+ let mut alloc =
+- match from.copy_transaction_data(to.clone(), info, debug_id, allow_fds, None) {
++ match from.copy_transaction_data(to.clone(), info, info.debug_id, allow_fds, None) {
+ Ok(alloc) => alloc,
+ Err(err) => {
+ pr_warn!("Failure in copy_transaction_data: {:?}", err);
+@@ -154,7 +153,7 @@ impl Transaction {
+ alloc.set_info_clear_on_drop();
+ }
+ Ok(DTRWrap::arc_pin_init(pin_init!(Transaction {
+- debug_id,
++ debug_id: info.debug_id,
+ target_node: None,
+ from_parent: None,
+ sender_euid: from.process.task.euid(),
+@@ -380,7 +379,7 @@ impl DeliverToRead for Transaction {
+ let send_failed_reply = ScopeGuard::new(|| {
+ if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 {
+ let reply = Err(BR_FAILED_REPLY);
+- self.from.deliver_reply(reply, &self);
++ self.from.deliver_reply(reply, &self, None);
+ }
+ self.drop_outstanding_txn();
+ });
+@@ -462,7 +461,7 @@ impl DeliverToRead for Transaction {
+ // If this is not a reply or oneway transaction, then send a dead reply.
+ if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 {
+ let reply = Err(BR_DEAD_REPLY);
+- self.from.deliver_reply(reply, &self);
++ self.from.deliver_reply(reply, &self, None);
+ }
+
+ self.drop_outstanding_txn();
+--
+2.53.0
+
--- /dev/null
+From 33e07cce06e5933bfa04703a89685dbbe35501c2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Jul 2026 06:45:53 +0000
+Subject: rust_binder: introduce TransactionInfo
+
+From: Alice Ryhl <aliceryhl@google.com>
+
+[ Upstream commit 5326a18e3e640061ca4b65c1b732feaeace61c39 ]
+
+Rust Binder exposes information about transactions that are sent in
+various ways: printing to the kernel log, tracepoints, files in
+binderfs, and the upcoming netlink support. Currently all these
+mechanisms use disparate ways of obtaining the same information, so
+let's introduce a single Info struct that collects all the required
+information in a single place, so that all of these different mechanisms
+can operate in a more uniform way.
+
+For now, the new info struct is only used to replace a few things:
+* The BinderTransactionDataSg struct that is passed as an argument to
+ several methods is removed as the information is moved into the new
+ info struct and passed down that way.
+* The oneway spam detection fields on Transaction and Allocation can be
+ removed, as the information can be returned to the caller via the
+ mutable info struct instead.
+But several other uses of the info struct are planned in follow-up
+patches.
+
+Signed-off-by: Alice Ryhl <aliceryhl@google.com>
+Link: https://patch.msgid.link/20260306-transaction-info-v1-1-fda58fca558b@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[aliceryhl: explicitly impl Zeroable for UserPtr instead of using derive]
+Signed-off-by: Alice Ryhl <aliceryhl@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/android/binder/allocation.rs | 3 -
+ drivers/android/binder/error.rs | 10 +-
+ drivers/android/binder/process.rs | 15 +-
+ drivers/android/binder/thread.rs | 190 +++++++++++++++-----------
+ drivers/android/binder/transaction.rs | 83 ++++++-----
+ rust/kernel/uaccess.rs | 3 +
+ 6 files changed, 170 insertions(+), 134 deletions(-)
+
+diff --git a/drivers/android/binder/allocation.rs b/drivers/android/binder/allocation.rs
+index a9475e136d76fe..3aaeefef6bdd99 100644
+--- a/drivers/android/binder/allocation.rs
++++ b/drivers/android/binder/allocation.rs
+@@ -56,7 +56,6 @@ pub(crate) struct Allocation {
+ pub(crate) process: Arc<Process>,
+ allocation_info: Option<AllocationInfo>,
+ free_on_drop: bool,
+- pub(crate) oneway_spam_detected: bool,
+ #[allow(dead_code)]
+ pub(crate) debug_id: usize,
+ }
+@@ -68,7 +67,6 @@ impl Allocation {
+ offset: usize,
+ size: usize,
+ ptr: usize,
+- oneway_spam_detected: bool,
+ ) -> Self {
+ Self {
+ process,
+@@ -76,7 +74,6 @@ impl Allocation {
+ size,
+ ptr,
+ debug_id,
+- oneway_spam_detected,
+ allocation_info: None,
+ free_on_drop: true,
+ }
+diff --git a/drivers/android/binder/error.rs b/drivers/android/binder/error.rs
+index 9921827267d0d6..c6a834071f8cef 100644
+--- a/drivers/android/binder/error.rs
++++ b/drivers/android/binder/error.rs
+@@ -12,7 +12,7 @@ pub(crate) type BinderResult<T = ()> = core::result::Result<T, BinderError>;
+ /// errno.
+ pub(crate) struct BinderError {
+ pub(crate) reply: u32,
+- source: Option<Error>,
++ pub(crate) source: Option<Error>,
+ }
+
+ impl BinderError {
+@@ -40,14 +40,6 @@ impl BinderError {
+ pub(crate) fn is_dead(&self) -> bool {
+ self.reply == BR_DEAD_REPLY
+ }
+-
+- pub(crate) fn as_errno(&self) -> kernel::ffi::c_int {
+- self.source.unwrap_or(EINVAL).to_errno()
+- }
+-
+- pub(crate) fn should_pr_warn(&self) -> bool {
+- self.source.is_some()
+- }
+ }
+
+ /// Convert an errno into a `BinderError` and store the errno used to construct it. The errno
+diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs
+index 8ccc9ffbcd90e3..d33af8a043676c 100644
+--- a/drivers/android/binder/process.rs
++++ b/drivers/android/binder/process.rs
+@@ -47,6 +47,7 @@ use crate::{
+ range_alloc::{RangeAllocator, ReserveNew, ReserveNewArgs},
+ stats::BinderStats,
+ thread::{PushWorkRes, Thread},
++ transaction::TransactionInfo,
+ BinderfsProcFile, DArc, DLArc, DTRWrap, DeliverToRead,
+ };
+
+@@ -981,16 +982,15 @@ impl Process {
+ self: &Arc<Self>,
+ debug_id: usize,
+ size: usize,
+- is_oneway: bool,
+- from_pid: i32,
++ info: &mut TransactionInfo,
+ ) -> BinderResult<NewAllocation> {
+ use kernel::page::PAGE_SIZE;
+
+ let mut reserve_new_args = ReserveNewArgs {
+ debug_id,
+ size,
+- is_oneway,
+- pid: from_pid,
++ is_oneway: info.is_oneway(),
++ pid: info.from_pid,
+ ..ReserveNewArgs::default()
+ };
+
+@@ -1006,13 +1006,13 @@ impl Process {
+ reserve_new_args = alloc_request.make_alloc()?;
+ };
+
++ info.oneway_spam_suspect = new_alloc.oneway_spam_detected;
+ let res = Allocation::new(
+ self.clone(),
+ debug_id,
+ new_alloc.offset,
+ size,
+ addr + new_alloc.offset,
+- new_alloc.oneway_spam_detected,
+ );
+
+ // This allocation will be marked as in use until the `Allocation` is used to free it.
+@@ -1044,7 +1044,7 @@ impl Process {
+ let mapping = inner.mapping.as_mut()?;
+ let offset = ptr.checked_sub(mapping.address)?;
+ let (size, debug_id, odata) = mapping.alloc.reserve_existing(offset).ok()?;
+- let mut alloc = Allocation::new(self.clone(), debug_id, offset, size, ptr, false);
++ let mut alloc = Allocation::new(self.clone(), debug_id, offset, size, ptr);
+ if let Some(data) = odata {
+ alloc.set_info(data);
+ }
+@@ -1397,8 +1397,7 @@ impl Process {
+ .alloc
+ .take_for_each(|offset, size, debug_id, odata| {
+ let ptr = offset + address;
+- let mut alloc =
+- Allocation::new(self.clone(), debug_id, offset, size, ptr, false);
++ let mut alloc = Allocation::new(self.clone(), debug_id, offset, size, ptr);
+ if let Some(data) = odata {
+ alloc.set_info(data);
+ }
+diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs
+index 6a2ddf0039c145..93aa98c2a173a0 100644
+--- a/drivers/android/binder/thread.rs
++++ b/drivers/android/binder/thread.rs
+@@ -19,7 +19,7 @@ use kernel::{
+ sync::{Arc, SpinLock},
+ task::Task,
+ types::ARef,
+- uaccess::UserSlice,
++ uaccess::{UserPtr, UserSlice, UserSliceReader},
+ uapi,
+ };
+
+@@ -30,7 +30,7 @@ use crate::{
+ process::{GetWorkOrRegister, Process},
+ ptr_align,
+ stats::GLOBAL_STATS,
+- transaction::Transaction,
++ transaction::{Transaction, TransactionInfo},
+ BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverCode, DeliverToRead,
+ };
+
+@@ -948,13 +948,11 @@ impl Thread {
+ pub(crate) fn copy_transaction_data(
+ &self,
+ to_process: Arc<Process>,
+- tr: &BinderTransactionDataSg,
++ info: &mut TransactionInfo,
+ debug_id: usize,
+ allow_fds: bool,
+ txn_security_ctx_offset: Option<&mut usize>,
+ ) -> BinderResult<NewAllocation> {
+- let trd = &tr.transaction_data;
+- let is_oneway = trd.flags & TF_ONE_WAY != 0;
+ let mut secctx = if let Some(offset) = txn_security_ctx_offset {
+ let secid = self.process.cred.get_secid();
+ let ctx = match security::SecurityCtx::from_secid(secid) {
+@@ -969,10 +967,10 @@ impl Thread {
+ None
+ };
+
+- let data_size = trd.data_size.try_into().map_err(|_| EINVAL)?;
++ let data_size = info.data_size;
+ let aligned_data_size = ptr_align(data_size).ok_or(EINVAL)?;
+- let offsets_size: usize = trd.offsets_size.try_into().map_err(|_| EINVAL)?;
+- let buffers_size: usize = tr.buffers_size.try_into().map_err(|_| EINVAL)?;
++ let offsets_size = info.offsets_size;
++ let buffers_size = info.buffers_size;
+ let aligned_secctx_size = match secctx.as_ref() {
+ Some((_offset, ctx)) => ptr_align(ctx.len()).ok_or(EINVAL)?,
+ None => 0,
+@@ -995,32 +993,25 @@ impl Thread {
+ size_of::<u64>(),
+ );
+ let secctx_off = aligned_data_size + offsets_size + buffers_size;
+- let mut alloc =
+- match to_process.buffer_alloc(debug_id, len, is_oneway, self.process.task.pid()) {
+- Ok(alloc) => alloc,
+- Err(err) => {
+- pr_warn!(
+- "Failed to allocate buffer. len:{}, is_oneway:{}",
+- len,
+- is_oneway
+- );
+- return Err(err);
+- }
+- };
++ let mut alloc = match to_process.buffer_alloc(debug_id, len, info) {
++ Ok(alloc) => alloc,
++ Err(err) => {
++ pr_warn!(
++ "Failed to allocate buffer. len:{}, is_oneway:{}",
++ len,
++ info.is_oneway(),
++ );
++ return Err(err);
++ }
++ };
+
+- // SAFETY: This accesses a union field, but it's okay because the field's type is valid for
+- // all bit-patterns.
+- let trd_data_ptr = unsafe { &trd.data.ptr };
+- let mut buffer_reader =
+- UserSlice::new(UserPtr::from_addr(trd_data_ptr.buffer as _), data_size).reader();
++ let mut buffer_reader = UserSlice::new(info.data_ptr, data_size).reader();
+ let mut end_of_previous_object = 0;
+ let mut sg_state = None;
+
+ // Copy offsets if there are any.
+ if offsets_size > 0 {
+- let mut offsets_reader =
+- UserSlice::new(UserPtr::from_addr(trd_data_ptr.offsets as _), offsets_size)
+- .reader();
++ let mut offsets_reader = UserSlice::new(info.offsets_ptr, offsets_size).reader();
+
+ let offsets_start = aligned_data_size;
+ let offsets_end = aligned_data_size + offsets_size;
+@@ -1194,37 +1185,92 @@ impl Thread {
+ }
+ }
+
+- fn transaction<T>(self: &Arc<Self>, tr: &BinderTransactionDataSg, inner: T)
+- where
+- T: FnOnce(&Arc<Self>, &BinderTransactionDataSg) -> BinderResult,
+- {
+- if let Err(err) = inner(self, tr) {
+- if err.should_pr_warn() {
+- let mut ee = self.inner.lock().extended_error;
+- ee.command = err.reply;
+- ee.param = err.as_errno();
+- pr_warn!(
+- "Transaction failed: {:?} my_pid:{}",
+- err,
+- self.process.pid_in_current_ns()
+- );
++ // No inlining avoids allocating stack space for `BinderTransactionData` for the entire
++ // duration of `transaction()`.
++ #[inline(never)]
++ fn read_transaction_info(
++ &self,
++ cmd: u32,
++ reader: &mut UserSliceReader,
++ info: &mut TransactionInfo,
++ ) -> Result<()> {
++ let td = match cmd {
++ BC_TRANSACTION | BC_REPLY => {
++ reader.read::<BinderTransactionData>()?.with_buffers_size(0)
++ }
++ BC_TRANSACTION_SG | BC_REPLY_SG => reader.read::<BinderTransactionDataSg>()?,
++ _ => return Err(EINVAL),
++ };
++
++ // SAFETY: Above `read` call initializes all bytes, so this union read is ok.
++ let trd_data_ptr = unsafe { &td.transaction_data.data.ptr };
++
++ info.is_reply = matches!(cmd, BC_REPLY | BC_REPLY_SG);
++ info.from_pid = self.process.task.pid();
++ info.from_tid = self.id;
++ info.code = td.transaction_data.code;
++ info.flags = td.transaction_data.flags;
++ info.data_ptr = UserPtr::from_addr(trd_data_ptr.buffer as usize);
++ info.data_size = td.transaction_data.data_size as usize;
++ info.offsets_ptr = UserPtr::from_addr(trd_data_ptr.offsets as usize);
++ info.offsets_size = td.transaction_data.offsets_size as usize;
++ info.buffers_size = td.buffers_size as usize;
++ // SAFETY: Above `read` call initializes all bytes, so this union read is ok.
++ info.target_handle = unsafe { td.transaction_data.target.handle };
++ Ok(())
++ }
++
++ #[inline(never)]
++ fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Result<()> {
++ let mut info = TransactionInfo::zeroed();
++ self.read_transaction_info(cmd, reader, &mut info)?;
++
++ let ret = if info.is_reply {
++ self.reply_inner(&mut info)
++ } else if info.is_oneway() {
++ self.oneway_transaction_inner(&mut info)
++ } else {
++ self.transaction_inner(&mut info)
++ };
++
++ if let Err(err) = ret {
++ if err.reply != BR_TRANSACTION_COMPLETE {
++ info.reply = err.reply;
+ }
+
+ self.push_return_work(err.reply);
++ if let Some(source) = &err.source {
++ info.errno = source.to_errno();
++ info.reply = err.reply;
++
++ {
++ let mut ee = self.inner.lock().extended_error;
++ ee.command = err.reply;
++ ee.param = source.to_errno();
++ }
++
++ pr_warn!(
++ "{}:{} transaction to {} failed: {source:?}",
++ info.from_pid,
++ info.from_tid,
++ info.to_pid
++ );
++ }
+ }
++
++ Ok(())
+ }
+
+- fn transaction_inner(self: &Arc<Self>, tr: &BinderTransactionDataSg) -> BinderResult {
+- // SAFETY: Handle's type has no invalid bit patterns.
+- let handle = unsafe { tr.transaction_data.target.handle };
+- let node_ref = self.process.get_transaction_node(handle)?;
++ fn transaction_inner(self: &Arc<Self>, info: &mut TransactionInfo) -> BinderResult {
++ let node_ref = self.process.get_transaction_node(info.target_handle)?;
++ info.to_pid = node_ref.node.owner.task.pid();
+ security::binder_transaction(&self.process.cred, &node_ref.node.owner.cred)?;
+ // TODO: We need to ensure that there isn't a pending transaction in the work queue. How
+ // could this happen?
+ let top = self.top_of_transaction_stack()?;
+ let list_completion = DTRWrap::arc_try_new(DeliverCode::new(BR_TRANSACTION_COMPLETE))?;
+ let completion = list_completion.clone_arc();
+- let transaction = Transaction::new(node_ref, top, self, tr)?;
++ let transaction = Transaction::new(node_ref, top, self, info)?;
+
+ // Check that the transaction stack hasn't changed while the lock was released, then update
+ // it with the new transaction.
+@@ -1240,7 +1286,7 @@ impl Thread {
+ inner.push_work_deferred(list_completion);
+ }
+
+- if let Err(e) = transaction.submit() {
++ if let Err(e) = transaction.submit(info) {
+ completion.skip();
+ // Define `transaction` first to drop it after `inner`.
+ let transaction;
+@@ -1253,18 +1299,21 @@ impl Thread {
+ }
+ }
+
+- fn reply_inner(self: &Arc<Self>, tr: &BinderTransactionDataSg) -> BinderResult {
++ fn reply_inner(self: &Arc<Self>, info: &mut TransactionInfo) -> BinderResult {
+ let orig = self.inner.lock().pop_transaction_to_reply(self)?;
+ if !orig.from.is_current_transaction(&orig) {
+ return Err(EINVAL.into());
+ }
+
++ info.to_tid = orig.from.id;
++ info.to_pid = orig.from.process.task.pid();
++
+ // We need to complete the transaction even if we cannot complete building the reply.
+ let out = (|| -> BinderResult<_> {
+ let completion = DTRWrap::arc_try_new(DeliverCode::new(BR_TRANSACTION_COMPLETE))?;
+ let process = orig.from.process.clone();
+ let allow_fds = orig.flags & TF_ACCEPT_FDS != 0;
+- let reply = Transaction::new_reply(self, process, tr, allow_fds)?;
++ let reply = Transaction::new_reply(self, process, info, allow_fds)?;
+ self.inner.lock().push_work(completion);
+ orig.from.deliver_reply(Ok(reply), &orig);
+ Ok(())
+@@ -1285,16 +1334,12 @@ impl Thread {
+ out
+ }
+
+- fn oneway_transaction_inner(self: &Arc<Self>, tr: &BinderTransactionDataSg) -> BinderResult {
+- // SAFETY: The `handle` field is valid for all possible byte values, so reading from the
+- // union is okay.
+- let handle = unsafe { tr.transaction_data.target.handle };
+- let node_ref = self.process.get_transaction_node(handle)?;
++ fn oneway_transaction_inner(self: &Arc<Self>, info: &mut TransactionInfo) -> BinderResult {
++ let node_ref = self.process.get_transaction_node(info.target_handle)?;
++ info.to_pid = node_ref.node.owner.task.pid();
+ security::binder_transaction(&self.process.cred, &node_ref.node.owner.cred)?;
+- let transaction = Transaction::new(node_ref, None, self, tr)?;
+- let code = if self.process.is_oneway_spam_detection_enabled()
+- && transaction.oneway_spam_detected
+- {
++ let transaction = Transaction::new(node_ref, None, self, info)?;
++ let code = if self.process.is_oneway_spam_detection_enabled() && info.oneway_spam_suspect {
+ BR_ONEWAY_SPAM_SUSPECT
+ } else {
+ BR_TRANSACTION_COMPLETE
+@@ -1302,7 +1347,7 @@ impl Thread {
+ let list_completion = DTRWrap::arc_try_new(DeliverCode::new(code))?;
+ let completion = list_completion.clone_arc();
+ self.inner.lock().push_work(list_completion);
+- match transaction.submit() {
++ match transaction.submit(info) {
+ Ok(()) => Ok(()),
+ Err(err) => {
+ completion.skip();
+@@ -1323,29 +1368,8 @@ impl Thread {
+ GLOBAL_STATS.inc_bc(cmd);
+ self.process.stats.inc_bc(cmd);
+ match cmd {
+- BC_TRANSACTION => {
+- let tr = reader.read::<BinderTransactionData>()?.with_buffers_size(0);
+- if tr.transaction_data.flags & TF_ONE_WAY != 0 {
+- self.transaction(&tr, Self::oneway_transaction_inner);
+- } else {
+- self.transaction(&tr, Self::transaction_inner);
+- }
+- }
+- BC_TRANSACTION_SG => {
+- let tr = reader.read::<BinderTransactionDataSg>()?;
+- if tr.transaction_data.flags & TF_ONE_WAY != 0 {
+- self.transaction(&tr, Self::oneway_transaction_inner);
+- } else {
+- self.transaction(&tr, Self::transaction_inner);
+- }
+- }
+- BC_REPLY => {
+- let tr = reader.read::<BinderTransactionData>()?.with_buffers_size(0);
+- self.transaction(&tr, Self::reply_inner)
+- }
+- BC_REPLY_SG => {
+- let tr = reader.read::<BinderTransactionDataSg>()?;
+- self.transaction(&tr, Self::reply_inner)
++ BC_TRANSACTION | BC_TRANSACTION_SG | BC_REPLY | BC_REPLY_SG => {
++ self.transaction(cmd, &mut reader)?;
+ }
+ BC_FREE_BUFFER => {
+ let buffer = self.process.buffer_get(reader.read()?);
+diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs
+index 50bd1cee0f1a36..733f452d8f49dd 100644
+--- a/drivers/android/binder/transaction.rs
++++ b/drivers/android/binder/transaction.rs
+@@ -8,7 +8,7 @@ use kernel::{
+ seq_file::SeqFile,
+ seq_print,
+ sync::{Arc, SpinLock},
+- task::Kuid,
++ task::{Kuid, Pid},
+ time::{Instant, Monotonic},
+ types::ScopeGuard,
+ };
+@@ -24,6 +24,33 @@ use crate::{
+ BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverToRead,
+ };
+
++#[derive(Zeroable)]
++pub(crate) struct TransactionInfo {
++ pub(crate) from_pid: Pid,
++ pub(crate) from_tid: Pid,
++ pub(crate) to_pid: Pid,
++ pub(crate) to_tid: Pid,
++ pub(crate) code: u32,
++ pub(crate) flags: u32,
++ pub(crate) data_ptr: UserPtr,
++ pub(crate) data_size: usize,
++ pub(crate) offsets_ptr: UserPtr,
++ pub(crate) offsets_size: usize,
++ pub(crate) buffers_size: usize,
++ pub(crate) target_handle: u32,
++ pub(crate) errno: i32,
++ pub(crate) reply: u32,
++ pub(crate) oneway_spam_suspect: bool,
++ pub(crate) is_reply: bool,
++}
++
++impl TransactionInfo {
++ #[inline]
++ pub(crate) fn is_oneway(&self) -> bool {
++ self.flags & TF_ONE_WAY != 0
++ }
++}
++
+ #[pin_data(PinnedDrop)]
+ pub(crate) struct Transaction {
+ pub(crate) debug_id: usize,
+@@ -41,7 +68,6 @@ pub(crate) struct Transaction {
+ data_address: usize,
+ sender_euid: Kuid,
+ txn_security_ctx_off: Option<usize>,
+- pub(crate) oneway_spam_detected: bool,
+ start_time: Instant<Monotonic>,
+ }
+
+@@ -54,17 +80,16 @@ impl Transaction {
+ node_ref: NodeRef,
+ from_parent: Option<DArc<Transaction>>,
+ from: &Arc<Thread>,
+- tr: &BinderTransactionDataSg,
++ info: &mut TransactionInfo,
+ ) -> BinderResult<DLArc<Self>> {
+ let debug_id = super::next_debug_id();
+- let trd = &tr.transaction_data;
+ let allow_fds = node_ref.node.flags & FLAT_BINDER_FLAG_ACCEPTS_FDS != 0;
+ let txn_security_ctx = node_ref.node.flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX != 0;
+ let mut txn_security_ctx_off = if txn_security_ctx { Some(0) } else { None };
+ let to = node_ref.node.owner.clone();
+ let mut alloc = match from.copy_transaction_data(
+ to.clone(),
+- tr,
++ info,
+ debug_id,
+ allow_fds,
+ txn_security_ctx_off.as_mut(),
+@@ -77,15 +102,14 @@ impl Transaction {
+ return Err(err);
+ }
+ };
+- let oneway_spam_detected = alloc.oneway_spam_detected;
+- if trd.flags & TF_ONE_WAY != 0 {
++ if info.is_oneway() {
+ if from_parent.is_some() {
+ pr_warn!("Oneway transaction should not be in a transaction stack.");
+ return Err(EINVAL.into());
+ }
+ alloc.set_info_oneway_node(node_ref.node.clone());
+ }
+- if trd.flags & TF_CLEAR_BUF != 0 {
++ if info.flags & TF_CLEAR_BUF != 0 {
+ alloc.set_info_clear_on_drop();
+ }
+ let target_node = node_ref.node.clone();
+@@ -99,15 +123,14 @@ impl Transaction {
+ sender_euid: from.process.task.euid(),
+ from: from.clone(),
+ to,
+- code: trd.code,
+- flags: trd.flags,
+- data_size: trd.data_size as _,
+- offsets_size: trd.offsets_size as _,
++ code: info.code,
++ flags: info.flags,
++ data_size: info.data_size,
++ offsets_size: info.offsets_size,
+ data_address,
+ allocation <- kernel::new_spinlock!(Some(alloc.success()), "Transaction::new"),
+ is_outstanding: AtomicBool::new(false),
+ txn_security_ctx_off,
+- oneway_spam_detected,
+ start_time: Instant::now(),
+ }))?)
+ }
+@@ -115,21 +138,19 @@ impl Transaction {
+ pub(crate) fn new_reply(
+ from: &Arc<Thread>,
+ to: Arc<Process>,
+- tr: &BinderTransactionDataSg,
++ info: &mut TransactionInfo,
+ allow_fds: bool,
+ ) -> BinderResult<DLArc<Self>> {
+ let debug_id = super::next_debug_id();
+- let trd = &tr.transaction_data;
+- let mut alloc = match from.copy_transaction_data(to.clone(), tr, debug_id, allow_fds, None)
+- {
+- Ok(alloc) => alloc,
+- Err(err) => {
+- pr_warn!("Failure in copy_transaction_data: {:?}", err);
+- return Err(err);
+- }
+- };
+- let oneway_spam_detected = alloc.oneway_spam_detected;
+- if trd.flags & TF_CLEAR_BUF != 0 {
++ let mut alloc =
++ match from.copy_transaction_data(to.clone(), info, debug_id, allow_fds, None) {
++ Ok(alloc) => alloc,
++ Err(err) => {
++ pr_warn!("Failure in copy_transaction_data: {:?}", err);
++ return Err(err);
++ }
++ };
++ if info.flags & TF_CLEAR_BUF != 0 {
+ alloc.set_info_clear_on_drop();
+ }
+ Ok(DTRWrap::arc_pin_init(pin_init!(Transaction {
+@@ -139,15 +160,14 @@ impl Transaction {
+ sender_euid: from.process.task.euid(),
+ from: from.clone(),
+ to,
+- code: trd.code,
+- flags: trd.flags,
+- data_size: trd.data_size as _,
+- offsets_size: trd.offsets_size as _,
++ code: info.code,
++ flags: info.flags,
++ data_size: info.data_size,
++ offsets_size: info.offsets_size,
+ data_address: alloc.ptr,
+ allocation <- kernel::new_spinlock!(Some(alloc.success()), "Transaction::new"),
+ is_outstanding: AtomicBool::new(false),
+ txn_security_ctx_off: None,
+- oneway_spam_detected,
+ start_time: Instant::now(),
+ }))?)
+ }
+@@ -237,7 +257,7 @@ impl Transaction {
+ /// stack, otherwise uses the destination process.
+ ///
+ /// Not used for replies.
+- pub(crate) fn submit(self: DLArc<Self>) -> BinderResult {
++ pub(crate) fn submit(self: DLArc<Self>, info: &mut TransactionInfo) -> BinderResult {
+ // Defined before `process_inner` so that the destructor runs after releasing the lock.
+ let _t_outdated;
+ let _oneway_node;
+@@ -295,6 +315,7 @@ impl Transaction {
+ }
+
+ let res = if let Some(thread) = self.find_target_thread() {
++ info.to_tid = thread.id;
+ match thread.push_work(self) {
+ PushWorkRes::Ok => Ok(()),
+ PushWorkRes::FailedDead(me) => Err((BinderError::new_dead(), me)),
+diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
+index a8fb4764185a1a..2035c2877a2b2f 100644
+--- a/rust/kernel/uaccess.rs
++++ b/rust/kernel/uaccess.rs
+@@ -21,6 +21,9 @@ use core::mem::{size_of, MaybeUninit};
+ #[derive(Copy, Clone)]
+ pub struct UserPtr(*mut c_void);
+
++// SAFETY: Null pointer is a valid value.
++unsafe impl Zeroable for UserPtr {}
++
+ impl UserPtr {
+ /// Create a `UserPtr` from an integer representing the userspace address.
+ #[inline]
+--
+2.53.0
+
usb-typec-ucsi-ccg-fix-use-after-free-of-ucsi-on-remove.patch
usb-typec-ucsi-cancel-pending-work-on-system-suspend.patch
usb-gadget-f_fs-fix-dma-fence-leak.patch
+mm-shmem-fix-potential-livelock-issue-for-shmem-dire.patch
+x86-fs-resctrl-prevent-out-of-bounds-access-while-of.patch
+rust_binder-introduce-transactioninfo.patch
+rust_binder-fix-binder_get_extended_error.patch
+bpf-support-for-hardening-against-jit-spraying.patch
+x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch
+bpf-restrict-jit-predictor-flush-to-cbpf.patch
+bpf-skip-redundant-ibpb-in-pack-allocator.patch
+bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch
+bpf-prefer-dirty-packs-for-ebpf-allocations.patch
--- /dev/null
+From f5f1d5c4b0ec36c19d26e795af46a3d986b3a8e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 18:11:52 -0700
+Subject: x86/bugs: Enable IBPB flush on BPF JIT allocation
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit a3af84b0fa00ead01fcd0e28b5d773ff25990a0d upstream.
+
+Enable hardening against JIT spraying when Spectre-v2 mitigations are in
+use. Specifically, issue an IBPB flush on BPF JIT memory reuse. Skip
+enabling the IBPB flush if the BPF dispatcher is already using a retpoline
+sequence.
+
+This hardening applies only when BPF-JIT is in use. Guard the enabling
+under CONFIG_BPF_JIT so that bugs.c still builds with CONFIG_BPF_JIT=n.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/nospec-branch.h | 4 +++
+ arch/x86/kernel/cpu/bugs.c | 50 +++++++++++++++++++++++++---
+ 2 files changed, 49 insertions(+), 5 deletions(-)
+
+diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
+index 08ed5a2e46a5fd..71e9861a16a896 100644
+--- a/arch/x86/include/asm/nospec-branch.h
++++ b/arch/x86/include/asm/nospec-branch.h
+@@ -386,6 +386,10 @@ extern void srso_alias_return_thunk(void);
+ extern void entry_untrain_ret(void);
+ extern void write_ibpb(void);
+
++#ifdef CONFIG_BPF_JIT
++extern void bpf_arch_ibpb(void);
++#endif
++
+ #ifdef CONFIG_X86_64
+ extern void clear_bhb_loop(void);
+ #endif
+diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
+index d7fa03bf51b451..fd0b7880cf7e5a 100644
+--- a/arch/x86/kernel/cpu/bugs.c
++++ b/arch/x86/kernel/cpu/bugs.c
+@@ -16,6 +16,7 @@
+ #include <linux/sched/smt.h>
+ #include <linux/pgtable.h>
+ #include <linux/bpf.h>
++#include <linux/filter.h>
+
+ #include <asm/spec-ctrl.h>
+ #include <asm/cmdline.h>
+@@ -1796,8 +1797,21 @@ static inline const char *spectre_v2_module_string(void)
+ {
+ return spectre_v2_bad_module ? " - vulnerable module loaded" : "";
+ }
++
++/*
++ * The "retpoline sequence" is the "call;mov;ret" sequence that
++ * replaces normal indirect branch instructions. Differentiate
++ * *the* retpoline sequence from the LFENCE-prefixed indirect
++ * branches that simply use the retpoline infrastructure.
++ */
++static inline bool retpoline_seq_enabled(void)
++{
++ return boot_cpu_has(X86_FEATURE_RETPOLINE) && !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE);
++}
++
+ #else
+ static inline const char *spectre_v2_module_string(void) { return ""; }
++static inline bool retpoline_seq_enabled(void) { return false; }
+ #endif
+
+ #define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n"
+@@ -2240,8 +2254,7 @@ static void __init bhi_apply_mitigation(void)
+ return;
+
+ /* Retpoline mitigates against BHI unless the CPU has RRSBA behavior */
+- if (boot_cpu_has(X86_FEATURE_RETPOLINE) &&
+- !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE)) {
++ if (retpoline_seq_enabled()) {
+ spec_ctrl_disable_kernel_rrsba();
+ if (rrsba_disabled)
+ return;
+@@ -2383,6 +2396,27 @@ static void __init spectre_v2_update_mitigation(void)
+ pr_info("%s\n", spectre_v2_strings[spectre_v2_enabled]);
+ }
+
++#ifdef CONFIG_BPF_JIT
++static void __bpf_arch_ibpb(void *unused)
++{
++ write_ibpb();
++}
++
++void bpf_arch_ibpb(void)
++{
++ on_each_cpu(__bpf_arch_ibpb, NULL, 1);
++}
++
++static bool __init cpu_wants_ibpb_bpf(void)
++{
++ /* A genuine retpoline already neutralizes ring0 indirect predictions */
++ if (retpoline_seq_enabled())
++ return false;
++
++ return boot_cpu_has(X86_FEATURE_IBPB);
++}
++#endif
++
+ static void __init spectre_v2_apply_mitigation(void)
+ {
+ if (spectre_v2_enabled == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
+@@ -2459,6 +2493,14 @@ static void __init spectre_v2_apply_mitigation(void)
+ setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
+ pr_info("Enabling Restricted Speculation for firmware calls\n");
+ }
++
++#ifdef CONFIG_BPF_JIT
++ if (cpu_wants_ibpb_bpf()) {
++ static_call_update(bpf_arch_pred_flush, bpf_arch_ibpb);
++ static_branch_enable(&bpf_pred_flush_enabled);
++ pr_info("Enabling IBPB for BPF\n");
++ }
++#endif
+ }
+
+ static void update_stibp_msr(void * __unused)
+@@ -3544,9 +3586,7 @@ static const char *spectre_bhi_state(void)
+ return "; BHI: BHI_DIS_S";
+ else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP))
+ return "; BHI: SW loop, KVM: SW loop";
+- else if (boot_cpu_has(X86_FEATURE_RETPOLINE) &&
+- !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE) &&
+- rrsba_disabled)
++ else if (retpoline_seq_enabled() && rrsba_disabled)
+ return "; BHI: Retpoline";
+ else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_VMEXIT))
+ return "; BHI: Vulnerable, KVM: SW loop";
+--
+2.53.0
+
--- /dev/null
+From e004cf0dca6984afefb36be7b2ac3aa4319926de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 15:17:37 -0700
+Subject: x86,fs/resctrl: Prevent out-of-bounds access while offlining CPU when
+ SNC enabled
+
+From: Reinette Chatre <reinette.chatre@intel.com>
+
+commit fc16126cc11d9f507130bf84ab137ee0938c900e upstream.
+
+The architecture updates the cpu_mask in a domain's header to track which
+online CPUs are associated with the domain. When this mask becomes empty
+the architecture initiates offline of the domain that includes calling
+on resctrl fs to offline the domain. If it is a monitoring domain in
+which LLC occupancy is tracked resctrl fs forces the limbo handler to
+clear all busy RMID state associated with the domain.
+
+The limbo handler always reads the current event value associated with a
+busy RMID irrespective of it being checked as part of regular "is it still
+busy" check or whether it will be forced released anyway. When reading an
+RMID on a system with SNC enabled the "logical RMID" is converted to the
+"physical RMID" and this conversion requires the NUMA node ID of the
+resctrl monitoring domain that is in turn determined by querying the NUMA
+node ID of any CPU belonging to the monitoring domain.
+
+When the monitoring domain is going offline its cpu_mask is empty causing
+the NUMA node ID query via cpu_to_node() to be done with "nr_cpu_ids" as
+argument resulting in an out-of-bounds access.
+
+Refactor the limbo handler to skip reading the RMID when the RMID will
+just be forced to no longer be dirty in the domain anyway. Add a safety
+check to the architecture's RMID reader to protect against this scenario.
+
+Fixes: e13db55b5a0d ("x86/resctrl: Introduce snc_nodes_per_l3_cache")
+Closes: https://sashiko.dev/#/patchset/cover.1780456704.git.reinette.chatre%40intel.com?part=9
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Cc: <stable@kernel.org>
+Link: https://patch.msgid.link/16137433df42f85013b2f7a53626795cbd6637b9.1781029125.git.reinette.chatre@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/resctrl/monitor.c | 8 +++++-
+ fs/resctrl/monitor.c | 39 +++++++++++++++------------
+ 2 files changed, 29 insertions(+), 18 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
+index fe1a2aa53c16ab..4b2b539ddff953 100644
+--- a/arch/x86/kernel/cpu/resctrl/monitor.c
++++ b/arch/x86/kernel/cpu/resctrl/monitor.c
+@@ -243,14 +243,20 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d,
+ u64 *val, void *ignored)
+ {
+ struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d);
+- int cpu = cpumask_any(&d->hdr.cpu_mask);
+ struct arch_mbm_state *am;
+ u64 msr_val;
+ u32 prmid;
++ int cpu;
+ int ret;
+
+ resctrl_arch_rmid_read_context_check();
+
++ if (cpumask_empty(&d->hdr.cpu_mask)) {
++ pr_warn_once("Domain %d has no CPUs\n", d->hdr.id);
++ return -EINVAL;
++ }
++
++ cpu = cpumask_any(&d->hdr.cpu_mask);
+ prmid = logical_rmid_to_physical_rmid(cpu, rmid);
+ ret = __rmid_read_phys(prmid, eventid, &msr_val);
+
+diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
+index 572a9925bd6ca0..7012a75814ac36 100644
+--- a/fs/resctrl/monitor.c
++++ b/fs/resctrl/monitor.c
+@@ -135,9 +135,9 @@ void __check_limbo(struct rdt_mon_domain *d, bool force_free)
+ struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
+ u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+ struct rmid_entry *entry;
++ bool rmid_dirty = true;
+ u32 idx, cur_idx = 1;
+ void *arch_mon_ctx;
+- bool rmid_dirty;
+ u64 val = 0;
+
+ arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, QOS_L3_OCCUP_EVENT_ID);
+@@ -159,22 +159,27 @@ void __check_limbo(struct rdt_mon_domain *d, bool force_free)
+ break;
+
+ entry = __rmid_entry(idx);
+- if (resctrl_arch_rmid_read(r, d, entry->closid, entry->rmid,
+- QOS_L3_OCCUP_EVENT_ID, &val,
+- arch_mon_ctx)) {
+- rmid_dirty = true;
+- } else {
+- rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
+-
+- /*
+- * x86's CLOSID and RMID are independent numbers, so the entry's
+- * CLOSID is an empty CLOSID (X86_RESCTRL_EMPTY_CLOSID). On Arm the
+- * RMID (PMG) extends the CLOSID (PARTID) space with bits that aren't
+- * used to select the configuration. It is thus necessary to track both
+- * CLOSID and RMID because there may be dependencies between them
+- * on some architectures.
+- */
+- trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid, d->hdr.id, val);
++ if (!force_free) {
++ if (resctrl_arch_rmid_read(r, d, entry->closid,
++ entry->rmid, QOS_L3_OCCUP_EVENT_ID,
++ &val, arch_mon_ctx)) {
++ rmid_dirty = true;
++ } else {
++ rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
++
++ /*
++ * x86's CLOSID and RMID are independent numbers,
++ * so the entry's CLOSID is an empty CLOSID
++ * (X86_RESCTRL_EMPTY_CLOSID). On Arm the RMID
++ * (PMG) extends the CLOSID (PARTID) space with
++ * bits that aren't used to select the configuration.
++ * It is thus necessary to track both CLOSID and
++ * RMID because there may be dependencies between
++ * them on some architectures.
++ */
++ trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid,
++ d->hdr.id, val);
++ }
+ }
+
+ if (force_free || !rmid_dirty) {
+--
+2.53.0
+
--- /dev/null
+From d37543be961a274a8327328af56fb3f85cae2f2e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 18:45:26 +0300
+Subject: iio: temperature: ltc2983: Fix n_wires default bypassing rotation
+ check
+
+From: Liviu Stan <liviu.stan@analog.com>
+
+[ Upstream commit 434c150752675f44dc52c384a7fa22e5176bc35a ]
+
+When adi,number-of-wires is absent, n_wires is left at 0. The binding
+documents a default of 2 wires, matching the hardware default. However
+the current-rotate validation checks n_wires == 2 || n_wires == 3, so
+with n_wires = 0 the guard is bypassed and adi,current-rotate is accepted
+for a 2-wire RTD.
+
+Initialize n_wires = 2 to match the binding default and ensure the
+rotation check fires correctly when the property is absent.
+
+Fixes: f110f3188e56 ("iio: temperature: Add support for LTC2983")
+Signed-off-by: Liviu Stan <liviu.stan@analog.com>
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <jic23@kernel.org>
+Signed-off-by: Liviu Stan <liviu.stan@analog.com>
+
+[ Liviu Stan: resolve conflict - keep fwnode_handle *ref declaration
+ which was removed upstream ]
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/temperature/ltc2983.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
+index 08485c4ecd52e5..a2e4ddf095d88a 100644
+--- a/drivers/iio/temperature/ltc2983.c
++++ b/drivers/iio/temperature/ltc2983.c
+@@ -751,7 +751,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
+ int ret = 0;
+ struct device *dev = &st->spi->dev;
+ struct fwnode_handle *ref;
+- u32 excitation_current = 0, n_wires = 0;
++ u32 excitation_current = 0, n_wires = 2;
+
+ rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL);
+ if (!rtd)
+--
+2.53.0
+
--- /dev/null
+From e4d4bd7886101ffcae1eb1febf06fd435fe37442 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jul 2026 23:27:26 +0100
+Subject: PCI: Always lift 2.5GT/s restriction in PCIe failed link retraining
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 72780f7964684939d7d2f69c348876213b184484 upstream.
+
+Discard Vendor:Device ID matching in the PCIe failed link retraining quirk
+and ignore the link status for the removal of the 2.5GT/s speed clamp,
+whether applied by the quirk itself or the firmware earlier on. Revert to
+the original target link speed if this final link retraining has failed.
+
+This is so that link training noise in hot-plug scenarios does not make a
+link remain clamped to the 2.5GT/s speed where an event race has led the
+quirk to apply the speed clamp for one device, only to leave it in place
+for a subsequent device to be plugged in.
+
+Refer to the Link Capabilities register directly for the maximum link speed
+determination so as to streamline backporting.
+
+Fixes: a89c82249c37 ("PCI: Work around PCIe link training failures")
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Tested-by: Alok Tiwari <alok.a.tiwari@oracle.com>
+Cc: stable@vger.kernel.org # v6.5+
+Link: https://patch.msgid.link/alpine.DEB.2.21.2512080331530.49654@angie.orcam.me.uk
+[ Update for missing PCIe link speed helpers for 6.6.y. ]
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/quirks.c | 51 +++++++++++++++++---------------------------
+ 1 file changed, 20 insertions(+), 31 deletions(-)
+
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 5df3a6ea660187..28fa0a9b18c824 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -68,11 +68,10 @@
+ * Restrict the speed to 2.5GT/s then with the Target Link Speed field,
+ * request a retrain and check the result.
+ *
+- * If this turns out successful and we know by the Vendor:Device ID it is
+- * safe to do so, then lift the restriction, letting the devices negotiate
+- * a higher speed. Also check for a similar 2.5GT/s speed restriction the
+- * firmware may have already arranged and lift it with ports that already
+- * report their data link being up.
++ * If this turns out successful, or where a 2.5GT/s speed restriction has
++ * been previously arranged by the firmware and the port reports its link
++ * already being up, lift the restriction, in a hope it is safe to do so,
++ * letting the devices negotiate a higher speed.
+ *
+ * Otherwise revert the speed to the original setting and request a retrain
+ * again to remove any residual state, ignoring the result as it's supposed
+@@ -83,12 +82,9 @@
+ */
+ int pcie_failed_link_retrain(struct pci_dev *dev)
+ {
+- static const struct pci_device_id ids[] = {
+- { PCI_VDEVICE(ASMEDIA, 0x2824) }, /* ASMedia ASM2824 */
+- {}
+- };
+- u16 lnksta, lnkctl2;
++ u16 lnksta, lnkctl2, oldlnkctl2;
+ int ret = -ENOTTY;
++ u32 lnkcap;
+
+ if (!pci_is_pcie(dev) || !pcie_downstream_port(dev) ||
+ !pcie_cap_has_lnkctl2(dev) || !dev->link_active_reporting)
+@@ -96,10 +92,9 @@ int pcie_failed_link_retrain(struct pci_dev *dev)
+
+ pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2);
+ pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
++ oldlnkctl2 = lnkctl2;
+ if ((lnksta & (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_DLLLA)) ==
+ PCI_EXP_LNKSTA_LBMS) {
+- u16 oldlnkctl2 = lnkctl2;
+-
+ pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n");
+
+ lnkctl2 &= ~PCI_EXP_LNKCTL2_TLS;
+@@ -107,35 +102,29 @@ int pcie_failed_link_retrain(struct pci_dev *dev)
+ pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, lnkctl2);
+
+ ret = pcie_retrain_link(dev, false);
+- if (ret) {
+- pci_info(dev, "retraining failed\n");
+- pcie_capability_write_word(dev, PCI_EXP_LNKCTL2,
+- oldlnkctl2);
+- pcie_retrain_link(dev, true);
+- return ret;
+- }
+-
+- pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
++ if (ret)
++ goto err;
+ }
+
+- if ((lnksta & PCI_EXP_LNKSTA_DLLLA) &&
+- (lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT &&
+- pci_match_id(ids, dev)) {
+- u32 lnkcap;
+-
++ pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
++ if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT &&
++ (lnkcap & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
+ pci_info(dev, "removing 2.5GT/s downstream link speed restriction\n");
+- pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+ lnkctl2 &= ~PCI_EXP_LNKCTL2_TLS;
+ lnkctl2 |= lnkcap & PCI_EXP_LNKCAP_SLS;
+ pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, lnkctl2);
+
+ ret = pcie_retrain_link(dev, false);
+- if (ret) {
+- pci_info(dev, "retraining failed\n");
+- return ret;
+- }
++ if (ret)
++ goto err;
+ }
+
++ return ret;
++err:
++ pci_info(dev, "retraining failed\n");
++ pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, oldlnkctl2);
++
++ pcie_retrain_link(dev, true);
+ return ret;
+ }
+
+--
+2.53.0
+
usb-typec-ucsi-pass-full-dp-config-payload-in-set_new_cam-for-dp-alt-mode.patch
usb-typec-ucsi-ccg-fix-use-after-free-of-ucsi-on-remove.patch
usb-typec-ucsi-cancel-pending-work-on-system-suspend.patch
+iio-temperature-ltc2983-fix-n_wires-default-bypassin.patch
+pci-always-lift-2.5gt-s-restriction-in-pcie-failed-l.patch
usb-gadget-f_fs-fix-dma-fence-leak.patch
usb-gadget-f_fs-initialize-epfile-in-early-to-fix-endpoint-direction-checks.patch
usb-gadget-f_fs-tie-read_buffer-lifetime-to-ffs_epfile.patch
+wifi-mt76-mt7921-mt7925-fix-null-dereference-in-csa-.patch
--- /dev/null
+From 78c47051a33bcc1f92da0d4c5f5afc2ffad92830 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 May 2026 07:51:06 -0700
+Subject: wifi: mt76: mt7921/mt7925: fix NULL dereference in CSA beacon
+
+From: Arjan van de Ven <arjan@linux.intel.com>
+
+[ Upstream commit 351dd7d2c80d23e56dcce6faa4e62bea5b0877c7 ]
+
+This patch is based on a BUG as reported by Bongani Hlope at
+https://lore.kernel.org/all/20260502125824.425d7159@bongani-mini.home.org.za/
+
+When a channel-switch announcement (CSA) beacon is received,
+cfg80211 queues a wiphy work item that eventually calls
+mt7921_channel_switch_rx_beacon(). If the station disconnects
+(or the channel context is otherwise torn down) between the
+time the work is queued and the time it runs, the driver's
+dev->new_ctx pointer can already have been cleared to NULL.
+mt7921_channel_switch_rx_beacon() then dereferences new_ctx
+unconditionally, triggering a NULL pointer dereference at
+address 0x0:
+
+ BUG: kernel NULL pointer dereference, address: 0000000000000000
+ RIP: 0010:mt7921_channel_switch_rx_beacon+0x1f/0x100 [mt7921_common]
+
+The same missing guard exists in mt7925_channel_switch_rx_beacon(),
+which shares the same code pattern introduced by the same commit.
+
+Add an early-return NULL check for dev->new_ctx in both
+mt7921_channel_switch_rx_beacon() and
+mt7925_channel_switch_rx_beacon(). When new_ctx is NULL there is
+no pending channel switch to process, so returning immediately is
+the correct and safe action.
+
+Fixes: 8aa2f59260eb ("wifi: mt76: mt7921: introduce CSA support")
+Reported-by: Bongani Hlope <developer@hlope.org.za>
+Oops-Analysis: http://oops.fenrus.org/reports/lkml/20260502125824.425d7159@bongani-mini.home.org.za/report.html
+Link: https://lore.kernel.org/all/20260502125824.425d7159@bongani-mini.home.org.za/
+Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
+Cc: linux-wireless@vger.kernel.org
+Cc: linux-mediatek@lists.infradead.org
+Cc: Felix Fietkau <nbd@nbd.name>
+Cc: Lorenzo Bianconi <lorenzo@kernel.org>
+Cc: Ryder Lee <ryder.lee@mediatek.com>
+Link: https://patch.msgid.link/20260504145107.1329197-1-arjan@linux.intel.com
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7921/main.c | 3 +++
+ drivers/net/wireless/mediatek/mt76/mt7925/main.c | 3 +++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+index 3d74fabe74085e..a326f4c95c7c86 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+@@ -1508,6 +1508,9 @@ static void mt7921_channel_switch_rx_beacon(struct ieee80211_hw *hw,
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ u16 beacon_interval = vif->bss_conf.beacon_int;
+
++ if (!dev->new_ctx)
++ return;
++
+ if (cfg80211_chandef_identical(&chsw->chandef,
+ &dev->new_ctx->def) &&
+ chsw->count) {
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+index 79cc30a3b29efc..9dc5ee51eb9f96 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+@@ -2403,6 +2403,9 @@ static void mt7925_channel_switch_rx_beacon(struct ieee80211_hw *hw,
+ if (ieee80211_vif_is_mld(vif))
+ return;
+
++ if (!dev->new_ctx)
++ return;
++
+ beacon_interval = vif->bss_conf.beacon_int;
+
+ if (cfg80211_chandef_identical(&chsw->chandef,
+--
+2.53.0
+