--- /dev/null
+From stable+bounces-296929-greg=kroah.com@vger.kernel.org Thu Aug 6 18:18:31 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 12:14:28 -0400
+Subject: ALSA: hda: codecs: hdmi: disable keep-alive before audio format change
+To: stable@vger.kernel.org
+Cc: Kai Vehmanen <kai.vehmanen@linux.intel.com>, Alexander Kaplan <alexander.kaplan@sms-medipool.de>, Takashi Iwai <tiwai@suse.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260806161428.1142408-1-sashal@kernel.org>
+
+From: Kai Vehmanen <kai.vehmanen@linux.intel.com>
+
+[ Upstream commit a3d6d3cedfe87bbd5a677d52b22ac20d28e59cf8 ]
+
+When a keep-alive (KAE) silent stream is active on an Intel HDMI/DP
+codec, opening a real PCM stream reprograms the converter format and the
+audio infoframe in snd_hda_hdmi_generic_pcm_prepare(). Part of that
+reprogramming - the converter channel count and the channel mapping in
+snd_hda_hdmi_setup_audio_infoframe() - is not safe to do while a
+keep-alive stream is active. This is most visible when switching to a
+multichannel PCM configuration, where the active channel count actually
+changes. In that case the newly opened PCM stream plays no sound.
+
+Add an optional hdmi_ops .prepare hook, called at the start of the
+PCM prepare sequence (before the format and infoframe are touched), and
+implement it for HSW+ to release keep-alive. Keep-alive is then
+re-enabled as before once the new stream has been set up, in the
+setup_stream op.
+
+Fixes: 15175a4f2bbb ("ALSA: hda/hdmi: add keep-alive support for ADL-P and DG2")
+Reported-by: Alexander Kaplan <alexander.kaplan@sms-medipool.de>
+Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/8412
+Tested-by: Alexander Kaplan <alexander.kaplan@sms-medipool.de>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
+Link: https://patch.msgid.link/20260715180610.1371243-1-kai.vehmanen@linux.intel.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+[ adapted three hunks from the post-6.12 split files (hdmi.c/hdmi_local.h/intelhdmi.c) back into the monolithic sound/pci/hda/patch_hdmi.c, with the prepare hook un-indented one level since 6.12 uses plain mutex_lock() instead of scoped_guard() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/pci/hda/patch_hdmi.c | 48 +++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 42 insertions(+), 6 deletions(-)
+
+--- a/sound/pci/hda/patch_hdmi.c
++++ b/sound/pci/hda/patch_hdmi.c
+@@ -111,6 +111,15 @@ struct hdmi_ops {
+ hda_nid_t pin_nid, int dev_id, u32 stream_tag,
+ int format);
+
++ /*
++ * Optional hook invoked at the beginning of the PCM prepare
++ * sequence, before the audio infoframe and stream format are
++ * (re)programmed. Used to disable keep-alive / silent stream so
++ * that the format change is not done while keep-alive is active.
++ */
++ void (*prepare)(struct hda_codec *codec,
++ struct hdmi_spec_per_pin *per_pin);
++
+ void (*pin_cvt_fixup)(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ hda_nid_t cvt_nid);
+@@ -2134,6 +2143,9 @@ static int generic_hdmi_playback_pcm_pre
+ per_pin->channels = substream->runtime->channels;
+ per_pin->setup = true;
+
++ if (spec->ops.prepare)
++ spec->ops.prepare(codec, per_pin);
++
+ if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) {
+ stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core,
+ substream);
+@@ -2901,6 +2913,28 @@ static void register_i915_notifier(struc
+ codec->relaxed_resume = 1;
+ }
+
++/*
++ * prepare ops override for HSW+
++ *
++ * Disable keep-alive before the converter format and audio infoframe are
++ * reprogrammed by the PCM prepare sequence. Changing the audio format (e.g.
++ * the channel count when switching to multichannel PCM) while a keep-alive
++ * stream is active is not safe, so release keep-alive here, early in the
++ * sequence. It is re-enabled once the new stream has been set up, in
++ * i915_hsw_setup_stream().
++ */
++static void i915_hsw_prepare(struct hda_codec *codec,
++ struct hdmi_spec_per_pin *per_pin)
++{
++ struct hdmi_spec *spec = codec->spec;
++
++ if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin->silent_stream) {
++ silent_stream_set_kae(codec, per_pin, false);
++ /* wait for pending transfers in codec to clear */
++ usleep_range(100, 200);
++ }
++}
++
+ /* setup_stream ops override for HSW+ */
+ static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+ hda_nid_t pin_nid, int dev_id, u32 stream_tag,
+@@ -2918,15 +2952,16 @@ static int i915_hsw_setup_stream(struct
+
+ haswell_verify_D0(codec, cvt_nid, pin_nid);
+
+- if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
+- silent_stream_set_kae(codec, per_pin, false);
+- /* wait for pending transfers in codec to clear */
+- usleep_range(100, 200);
+- }
+-
+ res = hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
+ stream_tag, format);
+
++ /*
++ * Keep-alive was disabled in i915_hsw_prepare(), re-enable it now.
++ * The pin lookup above resolves to the same per_pin that prepare
++ * used (pin_nid comes from that per_pin), so this stays balanced; a
++ * NULL per_pin only occurs on a lookup failure that also implies no
++ * active keep-alive stream to restore.
++ */
+ if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
+ usleep_range(100, 200);
+ silent_stream_set_kae(codec, per_pin, true);
+@@ -3100,6 +3135,7 @@ static int intel_hsw_common_init(struct
+ codec->depop_delay = 0;
+ codec->auto_runtime_pm = 1;
+
++ spec->ops.prepare = i915_hsw_prepare;
+ spec->ops.setup_stream = i915_hsw_setup_stream;
+ spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
+
(cherry picked from commit a02b8950d619123da64f69b70fe1dadef217dfe4)
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- drivers/gpio/gpio-pch.c | 28 ++++++++++++++--------------
+ drivers/gpio/gpio-pch.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
-diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
-index 63f25c72eac2f..75dd65957e4a2 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -96,7 +96,7 @@ struct pch_gpio {
};
static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
-@@ -105,7 +105,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+@@ -105,7 +105,7 @@ static void pch_gpio_set(struct gpio_chi
struct pch_gpio *chip = gpiochip_get_data(gpio);
unsigned long flags;
reg_val = ioread32(&chip->reg->po);
if (val)
reg_val |= BIT(nr);
-@@ -113,7 +113,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+@@ -113,7 +113,7 @@ static void pch_gpio_set(struct gpio_chi
reg_val &= ~BIT(nr);
iowrite32(reg_val, &chip->reg->po);
}
static int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr)
-@@ -131,7 +131,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+@@ -131,7 +131,7 @@ static int pch_gpio_direction_output(str
u32 reg_val;
unsigned long flags;
reg_val = ioread32(&chip->reg->po);
if (val)
-@@ -145,7 +145,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+@@ -145,7 +145,7 @@ static int pch_gpio_direction_output(str
pm |= BIT(nr);
iowrite32(pm, &chip->reg->pm);
return 0;
}
-@@ -156,12 +156,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
+@@ -156,12 +156,12 @@ static int pch_gpio_direction_input(stru
u32 pm;
unsigned long flags;
return 0;
}
-@@ -263,7 +263,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+@@ -263,7 +263,7 @@ static int pch_irq_type(struct irq_data
return 0;
}
/* Set interrupt mode */
im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
-@@ -275,7 +275,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+@@ -275,7 +275,7 @@ static int pch_irq_type(struct irq_data
else if (type & IRQ_TYPE_EDGE_BOTH)
irq_set_handler_locked(d, handle_edge_irq);
return 0;
}
-@@ -372,7 +372,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
+@@ -372,7 +372,7 @@ static int pch_gpio_probe(struct pci_dev
chip->ioh = id->driver_data;
chip->reg = chip->base;
pci_set_drvdata(pdev, chip);
pch_gpio_setup(chip);
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
-@@ -405,9 +405,9 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)
+@@ -405,9 +405,9 @@ static int __maybe_unused pch_gpio_suspe
struct pch_gpio *chip = dev_get_drvdata(dev);
unsigned long flags;
return 0;
}
-@@ -417,11 +417,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)
+@@ -417,11 +417,11 @@ static int __maybe_unused pch_gpio_resum
struct pch_gpio *chip = dev_get_drvdata(dev);
unsigned long flags;
return 0;
}
---
-2.53.0
-
--- /dev/null
+From stable+bounces-297111-greg=kroah.com@vger.kernel.org Fri Aug 7 04:36:29 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 22:36:14 -0400
+Subject: kmemleak: iommu/iova: fix transient kmemleak false positive
+To: stable@vger.kernel.org
+Cc: Catalin Marinas <catalin.marinas@arm.com>, Ido Schimmel <idosch@idosch.org>, Ido Schimmel <idosch@nvidia.com>, Robin Murphy <robin.murphy@arm.com>, Joerg Roedel <joro@8bytes.org>, Will Deacon <will@kernel.org>, Andrew Morton <akpm@linux-foundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260807023615.1684238-1-sashal@kernel.org>
+
+From: Catalin Marinas <catalin.marinas@arm.com>
+
+[ Upstream commit 7591c127f3b17d5879f18819cad7058bf3a2e276 ]
+
+The introduction of iova_depot_pop() in 911aa1245da8 ("iommu/iova: Make
+the rcache depot scale better") confused kmemleak by moving a struct
+iova_magazine object from a singly linked list to rcache->depot and
+resetting the 'next' pointer referencing it. Unlike doubly linked lists,
+the content of the object being referred is never changed on removal from
+a singly linked list and the kmemleak checksum heuristics do not detect
+such scenario. This leads to false positives like:
+
+unreferenced object 0xffff8881a5301000 (size 1024):
+ comm "softirq", pid 0, jiffies 4306297099 (age 462.991s)
+ hex dump (first 32 bytes):
+ 00 00 00 00 00 00 00 00 e7 7d 05 00 00 00 00 00 .........}......
+ 0f b4 05 00 00 00 00 00 b4 96 05 00 00 00 00 00 ................
+ backtrace:
+ [<ffffffff819f5f08>] __kmem_cache_alloc_node+0x1e8/0x320
+ [<ffffffff818a239a>] kmalloc_trace+0x2a/0x60
+ [<ffffffff8231d31e>] free_iova_fast+0x28e/0x4e0
+ [<ffffffff82310860>] fq_ring_free_locked+0x1b0/0x310
+ [<ffffffff8231225d>] fq_flush_timeout+0x19d/0x2e0
+ [<ffffffff813e95ba>] call_timer_fn+0x19a/0x5c0
+ [<ffffffff813ea16b>] __run_timers+0x78b/0xb80
+ [<ffffffff813ea5bd>] run_timer_softirq+0x5d/0xd0
+ [<ffffffff82f1d915>] __do_softirq+0x205/0x8b5
+
+Introduce kmemleak_transient_leak() which resets the object checksum
+requiring another scan pass before it is reported (if still unreferenced).
+Call this new API in iova_depot_pop().
+
+Link: https://lkml.kernel.org/r/20241104111944.2207155-1-catalin.marinas@arm.com
+Link: https://lore.kernel.org/r/ZY1osaGLyT-sdKE8@shredder/
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Reported-by: Ido Schimmel <idosch@idosch.org>
+Tested-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Robin Murphy <robin.murphy@arm.com>
+Cc: Joerg Roedel <joro@8bytes.org>
+Cc: Will Deacon <will@kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: 79c37ae3733e ("mm/kmemleak: fix checksum computation for per-cpu objects")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ Documentation/dev-tools/kmemleak.rst | 1
+ drivers/iommu/iova.c | 6 +++++
+ include/linux/kmemleak.h | 4 +++
+ mm/kmemleak.c | 39 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 50 insertions(+)
+
+--- a/Documentation/dev-tools/kmemleak.rst
++++ b/Documentation/dev-tools/kmemleak.rst
+@@ -161,6 +161,7 @@ See the include/linux/kmemleak.h header
+ - ``kmemleak_free_percpu`` - notify of a percpu memory block freeing
+ - ``kmemleak_update_trace`` - update object allocation stack trace
+ - ``kmemleak_not_leak`` - mark an object as not a leak
++- ``kmemleak_transient_leak`` - mark an object as a transient leak
+ - ``kmemleak_ignore`` - do not scan or report an object as leak
+ - ``kmemleak_scan_area`` - add scan areas inside a memory block
+ - ``kmemleak_no_scan`` - do not scan a memory block
+--- a/drivers/iommu/iova.c
++++ b/drivers/iommu/iova.c
+@@ -6,6 +6,7 @@
+ */
+
+ #include <linux/iova.h>
++#include <linux/kmemleak.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/smp.h>
+@@ -673,6 +674,11 @@ static struct iova_magazine *iova_depot_
+ {
+ struct iova_magazine *mag = rcache->depot;
+
++ /*
++ * As the mag->next pointer is moved to rcache->depot and reset via
++ * the mag->size assignment, mark it as a transient false positive.
++ */
++ kmemleak_transient_leak(mag->next);
+ rcache->depot = mag->next;
+ mag->size = IOVA_MAG_SIZE;
+ rcache->depot_size--;
+--- a/include/linux/kmemleak.h
++++ b/include/linux/kmemleak.h
+@@ -26,6 +26,7 @@ extern void kmemleak_free_part(const voi
+ extern void kmemleak_free_percpu(const void __percpu *ptr) __ref;
+ extern void kmemleak_update_trace(const void *ptr) __ref;
+ extern void kmemleak_not_leak(const void *ptr) __ref;
++extern void kmemleak_transient_leak(const void *ptr) __ref;
+ extern void kmemleak_ignore(const void *ptr) __ref;
+ extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref;
+ extern void kmemleak_no_scan(const void *ptr) __ref;
+@@ -93,6 +94,9 @@ static inline void kmemleak_update_trace
+ static inline void kmemleak_not_leak(const void *ptr)
+ {
+ }
++static inline void kmemleak_transient_leak(const void *ptr)
++{
++}
+ static inline void kmemleak_ignore(const void *ptr)
+ {
+ }
+--- a/mm/kmemleak.c
++++ b/mm/kmemleak.c
+@@ -951,6 +951,28 @@ static void make_black_object(unsigned l
+ }
+
+ /*
++ * Reset the checksum of an object. The immediate effect is that it will not
++ * be reported as a leak during the next scan until its checksum is updated.
++ */
++static void reset_checksum(unsigned long ptr)
++{
++ unsigned long flags;
++ struct kmemleak_object *object;
++
++ object = find_and_get_object(ptr, 0);
++ if (!object) {
++ kmemleak_warn("Not resetting the checksum of an unknown object at 0x%08lx\n",
++ ptr);
++ return;
++ }
++
++ raw_spin_lock_irqsave(&object->lock, flags);
++ object->checksum = 0;
++ raw_spin_unlock_irqrestore(&object->lock, flags);
++ put_object(object);
++}
++
++/*
+ * Add a scanning area to the object. If at least one such area is added,
+ * kmemleak will only scan these ranges rather than the whole memory block.
+ */
+@@ -1219,6 +1241,23 @@ void __ref kmemleak_not_leak(const void
+ EXPORT_SYMBOL(kmemleak_not_leak);
+
+ /**
++ * kmemleak_transient_leak - mark an allocated object as transient false positive
++ * @ptr: pointer to beginning of the object
++ *
++ * Calling this function on an object will cause the memory block to not be
++ * reported as a leak temporarily. This may happen, for example, if the object
++ * is part of a singly linked list and the ->next reference to it is changed.
++ */
++void __ref kmemleak_transient_leak(const void *ptr)
++{
++ pr_debug("%s(0x%px)\n", __func__, ptr);
++
++ if (kmemleak_enabled && ptr && !IS_ERR(ptr))
++ reset_checksum((unsigned long)ptr);
++}
++EXPORT_SYMBOL(kmemleak_transient_leak);
++
++/**
+ * kmemleak_ignore - ignore an allocated object
+ * @ptr: pointer to beginning of the object
+ *
--- /dev/null
+From stable+bounces-295133-greg=kroah.com@vger.kernel.org Tue Aug 4 13:27:56 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 07:21:44 -0400
+Subject: media: chips-media: wave5: Support CBP profile
+To: stable@vger.kernel.org
+Cc: Jackson Lee <jackson.lee@chipsnmedia.com>, Nas Chung <nas.chung@chipsnmedia.com>, Brandon Brnich <b-brnich@ti.com>, Nicolas Dufresne <nicolas.dufresne@collabora.com>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260804112144.2939763-1-sashal@kernel.org>
+
+From: Jackson Lee <jackson.lee@chipsnmedia.com>
+
+[ Upstream commit f8505f9d6b223a26854003bfdba1a0772457886d ]
+
+Constrained Baseline Profile (CBP) and Baseline Profile (BP) have been
+treated as the same.
+Introduce the ability to differentiate between the two.
+
+Fixes: 9707a6254a8a ("media: chips-media: wave5: Add the v4l2 layer")
+Cc: stable@vger.kernel.org
+Signed-off-by: Jackson Lee <jackson.lee@chipsnmedia.com>
+Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
+Tested-by: Brandon Brnich <b-brnich@ti.com>
+Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/platform/chips-media/wave5/wave5-hw.c | 3 +++
+ drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c | 5 ++++-
+ drivers/media/platform/chips-media/wave5/wave5-vpuapi.h | 1 +
+ 3 files changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/platform/chips-media/wave5/wave5-hw.c
++++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c
+@@ -1753,6 +1753,9 @@ int wave5_vpu_enc_init_seq(struct vpu_in
+ (p_param->skip_intra_trans << 25) |
+ (p_param->strong_intra_smooth_enable << 27) |
+ (p_param->en_still_picture << 30);
++ else if (inst->std == W_AVC_ENC)
++ reg_val |= (p_param->constraint_set1_flag << 29);
++
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SPS_PARAM, reg_val);
+
+ reg_val = (p_param->lossless_enable) |
+--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
++++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
+@@ -906,6 +906,8 @@ static int wave5_vpu_enc_s_ctrl(struct v
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+ inst->enc_param.profile = H264_PROFILE_BP;
+ inst->bit_depth = 8;
++ if (ctrl->val == V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE)
++ inst->enc_param.constraint_set1_flag = 1;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ inst->enc_param.profile = H264_PROFILE_MP;
+@@ -1168,6 +1170,7 @@ static void wave5_set_enc_openparam(stru
+ open_param->wave_param.intra_period = input.avc_idr_period;
+ }
+ } else {
++ open_param->wave_param.constraint_set1_flag = input.constraint_set1_flag;
+ open_param->wave_param.avc_idr_period = input.avc_idr_period;
+ }
+ open_param->wave_param.entropy_coding_mode = input.entropy_coding_mode;
+@@ -1631,7 +1634,7 @@ static int wave5_vpu_open_enc(struct fil
+ -6, 6, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+- 0, 1, 1, 1);
++ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION,
+ 0, 1, 1, 0);
+--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
++++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
+@@ -568,6 +568,7 @@ struct enc_wave_param {
+ u32 lambda_scaling_enable: 1; /* enable lambda scaling using custom GOP */
+ u32 transform8x8_enable: 1; /* enable 8x8 intra prediction and 8x8 transform */
+ u32 mb_level_rc_enable: 1; /* enable MB-level rate control */
++ u32 constraint_set1_flag: 1; /* enable CBP */
+ };
+
+ struct enc_open_param {
--- /dev/null
+From stable+bounces-294966-greg=kroah.com@vger.kernel.org Tue Aug 4 03:06:52 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 21:06:41 -0400
+Subject: media: i2c: imx219: Rename VTS to FRM_LENGTH
+To: stable@vger.kernel.org
+Cc: Jai Luthra <jai.luthra@ideasonboard.com>, Dave Stevenson <dave.stevenson@raspberrypi.com>, Sakari Ailus <sakari.ailus@linux.intel.com>, Hans Verkuil <hverkuil@xs4all.nl>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260804010642.2350939-1-sashal@kernel.org>
+
+From: Jai Luthra <jai.luthra@ideasonboard.com>
+
+[ Upstream commit 04f78503f99ae7e9887c7fe5e4bc54a7cfb10fe0 ]
+
+The IMX219 datasheet refers to the vertical length + blanking as
+FRM_LENGTH instead of VTS.
+
+Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Stable-dep-of: 2c4f1ba73543 ("media: imx219: Fix maximum frame length in lines")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/i2c/imx219.c | 31 +++++++++++++++----------------
+ 1 file changed, 15 insertions(+), 16 deletions(-)
+
+--- a/drivers/media/i2c/imx219.c
++++ b/drivers/media/i2c/imx219.c
+@@ -71,9 +71,8 @@
+ #define IMX219_EXPOSURE_MAX 65535
+
+ /* V_TIMING internal */
+-#define IMX219_REG_VTS CCI_REG16(0x0160)
+-#define IMX219_VTS_MAX 0xffff
+-
++#define IMX219_REG_FRM_LENGTH_A CCI_REG16(0x0160)
++#define IMX219_FLL_MAX 0xffff
+ #define IMX219_VBLANK_MIN 32
+
+ /* HBLANK control - read only */
+@@ -156,7 +155,7 @@ struct imx219_mode {
+ unsigned int height;
+
+ /* V-timing */
+- unsigned int vts_def;
++ unsigned int fll_def;
+ };
+
+ static const struct cci_reg_sequence imx219_common_regs[] = {
+@@ -315,25 +314,25 @@ static const struct imx219_mode supporte
+ /* 8MPix 15fps mode */
+ .width = 3280,
+ .height = 2464,
+- .vts_def = 3526,
++ .fll_def = 3526,
+ },
+ {
+ /* 1080P 30fps cropped */
+ .width = 1920,
+ .height = 1080,
+- .vts_def = 1763,
++ .fll_def = 1763,
+ },
+ {
+ /* 2x2 binned 30fps mode */
+ .width = 1640,
+ .height = 1232,
+- .vts_def = 1763,
++ .fll_def = 1763,
+ },
+ {
+ /* 640x480 30fps mode */
+ .width = 640,
+ .height = 480,
+- .vts_def = 1763,
++ .fll_def = 1763,
+ },
+ };
+
+@@ -444,7 +443,7 @@ static int imx219_set_ctrl(struct v4l2_c
+ imx219->hflip->val | imx219->vflip->val << 1, &ret);
+ break;
+ case V4L2_CID_VBLANK:
+- cci_write(imx219->regmap, IMX219_REG_VTS,
++ cci_write(imx219->regmap, IMX219_REG_FRM_LENGTH_A,
+ format->height + ctrl->val, &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN_RED:
+@@ -519,15 +518,15 @@ static int imx219_init_controls(struct i
+ /* Initial vblank/hblank/exposure parameters based on current mode */
+ imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
+- IMX219_VTS_MAX - mode->height, 1,
+- mode->vts_def - mode->height);
++ IMX219_FLL_MAX - mode->height, 1,
++ mode->fll_def - mode->height);
+ hblank = IMX219_PPL_DEFAULT - mode->width;
+ imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank,
+ 1, hblank);
+ if (imx219->hblank)
+ imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+- exposure_max = mode->vts_def - 4;
++ exposure_max = mode->fll_def - 4;
+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+ exposure_max : IMX219_EXPOSURE_DEFAULT;
+ imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+@@ -878,12 +877,12 @@ static int imx219_set_pad_format(struct
+
+ /* Update limits and set FPS to default */
+ __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
+- IMX219_VTS_MAX - mode->height, 1,
+- mode->vts_def - mode->height);
++ IMX219_FLL_MAX - mode->height, 1,
++ mode->fll_def - mode->height);
+ __v4l2_ctrl_s_ctrl(imx219->vblank,
+- mode->vts_def - mode->height);
++ mode->fll_def - mode->height);
+ /* Update max exposure while meeting expected vblanking */
+- exposure_max = mode->vts_def - 4;
++ exposure_max = mode->fll_def - 4;
+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+ exposure_max : IMX219_EXPOSURE_DEFAULT;
+ __v4l2_ctrl_modify_range(imx219->exposure,
--- /dev/null
+From stable+bounces-294967-greg=kroah.com@vger.kernel.org Tue Aug 4 03:09:49 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 21:06:42 -0400
+Subject: media: imx219: Fix maximum frame length in lines
+To: stable@vger.kernel.org
+Cc: Sakari Ailus <sakari.ailus@linux.intel.com>, Dave Stevenson <dave.stevenson@raspberrypi.com>, Laurent Pinchart <laurent.pinchart@ideasonboard.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260804010642.2350939-2-sashal@kernel.org>
+
+From: Sakari Ailus <sakari.ailus@linux.intel.com>
+
+[ Upstream commit 2c4f1ba7354312ad2d6e34e70a518a51a9344715 ]
+
+The driver used the maximum frame length in lines value of 0xffff, but the
+maximum appears to be 0xfffe instead. Fix it.
+
+Fixes: 1283b3b8f82b ("media: i2c: Add driver for Sony IMX219 sensor")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/i2c/imx219.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/media/i2c/imx219.c
++++ b/drivers/media/i2c/imx219.c
+@@ -72,7 +72,7 @@
+
+ /* V_TIMING internal */
+ #define IMX219_REG_FRM_LENGTH_A CCI_REG16(0x0160)
+-#define IMX219_FLL_MAX 0xffff
++#define IMX219_FLL_MAX 0xfffe
+ #define IMX219_VBLANK_MIN 32
+
+ /* HBLANK control - read only */
--- /dev/null
+From stable+bounces-296812-greg=kroah.com@vger.kernel.org Thu Aug 6 15:13:19 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 09:06:55 -0400
+Subject: media: uapi: rkisp: Correct name version enum
+To: stable@vger.kernel.org
+Cc: "Niklas Söderlund" <niklas.soderlund+renesas@ragnatech.se>, "Laurent Pinchart" <laurent.pinchart@ideasonboard.com>, "Hans Verkuil" <hverkuil+cisco@kernel.org>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260806130655.335225-1-sashal@kernel.org>
+
+From: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
+
+[ Upstream commit c4c01c4fd4a3916ffdfb35ad9f511c48e289f51c ]
+
+The name of the enum to hold the mapping of parameter buffer versions
+have a typo in the name, correct it. While this is a uAPI header the
+impact should be minimal as the enum is only used as a collection for
+the one version number supported.
+
+Fixes: e9d05e9d5db1 ("media: uapi: rkisp1-config: Add extensible params format")
+Cc: stable@vger.kernel.org
+Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Link: https://patch.msgid.link/20260501190339.3449193-1-niklas.soderlund+renesas@ragnatech.se
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+[ Adjusted context to keep the tree's `RKISP1_EXT_PARAM_BUFFER_V1 = 1` initializer instead of upstream's `V4L2_ISP_PARAMS_VERSION_V1`, which does not exist in this tree. ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/uapi/linux/rkisp1-config.h | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/include/uapi/linux/rkisp1-config.h
++++ b/include/uapi/linux/rkisp1-config.h
+@@ -1487,11 +1487,11 @@ struct rkisp1_ext_params_compand_curve_c
+ sizeof(struct rkisp1_ext_params_compand_curve_config))
+
+ /**
+- * enum rksip1_ext_param_buffer_version - RkISP1 extensible parameters version
++ * enum rkisp1_ext_param_buffer_version - RkISP1 extensible parameters version
+ *
+ * @RKISP1_EXT_PARAM_BUFFER_V1: First version of RkISP1 extensible parameters
+ */
+-enum rksip1_ext_param_buffer_version {
++enum rkisp1_ext_param_buffer_version {
+ RKISP1_EXT_PARAM_BUFFER_V1 = 1,
+ };
+
+@@ -1563,7 +1563,7 @@ enum rksip1_ext_param_buffer_version {
+ * +---------------------------------------------------------------------+
+ *
+ * @version: The RkISP1 extensible parameters buffer version, see
+- * :c:type:`rksip1_ext_param_buffer_version`
++ * :c:type:`rkisp1_ext_param_buffer_version`
+ * @data_size: The RkISP1 configuration data effective size, excluding this
+ * header
+ * @data: The RkISP1 extensible configuration data blocks
--- /dev/null
+From stable+bounces-297112-greg=kroah.com@vger.kernel.org Fri Aug 7 04:37:09 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 22:36:15 -0400
+Subject: mm/kmemleak: fix checksum computation for per-cpu objects
+To: stable@vger.kernel.org
+Cc: Breno Leitao <leitao@debian.org>, Catalin Marinas <catalin.marinas@arm.com>, Pavel Tikhomirov <ptikhomirov@virtuozzo.com>, Andrew Morton <akpm@linux-foundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260807023615.1684238-2-sashal@kernel.org>
+
+From: Breno Leitao <leitao@debian.org>
+
+[ Upstream commit 79c37ae3733e93d9d8ea12ecb44f717e61439024 ]
+
+The per-cpu object checksum folds each CPU's CRC together with XOR and
+seeds every CRC with 0. Both choices make update_checksum() miss content
+changes:
+
+ - XOR is self-cancelling, so equal contents on two CPUs cancel out and
+ simultaneous identical changes leave the checksum unchanged.
+ - crc32(0, ...) over all-zero content is 0, so a freshly allocated,
+ zeroed per-cpu area checksums to 0, matching the initial value, and
+ the object is never seen to change.
+
+See discussions at [0].
+
+When update_checksum() wrongly reports an actively modified object as
+unchanged, kmemleak stops greying it for an extra scan and can report a
+live per-cpu object as a leak.
+
+Fold the per-cpu CRC as a single rolling checksum across all CPUs and
+initialise the object checksum to ~0 so the first computed value always
+registers as a change, even for content that hashes to 0.
+reset_checksum() is seeded the same way.
+
+Link: https://lore.kernel.org/all/akfYImSNDh3OjIfR@gmail.com [0]
+Link: https://lore.kernel.org/20260703-kmemleak_checksum-v1-1-5e0ab7d6966f@debian.org
+Fixes: 6c99d4eb7c5e ("kmemleak: enable tracking for percpu pointers")
+Signed-off-by: Breno Leitao <leitao@debian.org>
+Co-developed-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Reviewed-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/kmemleak.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/mm/kmemleak.c
++++ b/mm/kmemleak.c
+@@ -671,7 +671,7 @@ static struct kmemleak_object *__alloc_o
+ atomic_set(&object->use_count, 1);
+ object->excess_ref = 0;
+ object->count = 0; /* white color initially */
+- object->checksum = 0;
++ object->checksum = ~0;
+ object->del_state = 0;
+
+ /* task information */
+@@ -967,7 +967,7 @@ static void reset_checksum(unsigned long
+ }
+
+ raw_spin_lock_irqsave(&object->lock, flags);
+- object->checksum = 0;
++ object->checksum = ~0;
+ raw_spin_unlock_irqrestore(&object->lock, flags);
+ put_object(object);
+ }
+@@ -1382,7 +1382,8 @@ static bool update_checksum(struct kmeml
+ for_each_possible_cpu(cpu) {
+ void *ptr = per_cpu_ptr((void __percpu *)object->pointer, cpu);
+
+- object->checksum ^= crc32(0, kasan_reset_tag((void *)ptr), object->size);
++ object->checksum = crc32(object->checksum,
++ kasan_reset_tag((void *)ptr), object->size);
+ }
+ } else {
+ object->checksum = crc32(0, kasan_reset_tag((void *)object->pointer), object->size);
--- /dev/null
+From stable+bounces-297105-greg=kroah.com@vger.kernel.org Fri Aug 7 04:36:38 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 22:36:04 -0400
+Subject: mptcp: add mptcp_userspace_pm_lookup_addr helper
+To: stable@vger.kernel.org
+Cc: Geliang Tang <tanggeliang@kylinos.cn>, "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260807023606.1683287-2-sashal@kernel.org>
+
+From: Geliang Tang <tanggeliang@kylinos.cn>
+
+[ Upstream commit e7b4083b90b7213902124d13fd1ed808360e32b1 ]
+
+Like __lookup_addr() helper in pm_netlink.c, a new helper
+mptcp_userspace_pm_lookup_addr() is also defined in pm_userspace.c.
+It looks up the corresponding mptcp_pm_addr_entry address in
+userspace_pm_local_addr_list through the passed "addr" parameter
+and returns the found address entry.
+
+This helper can be used in mptcp_userspace_pm_delete_local_addr(),
+mptcp_userspace_pm_set_flags(), mptcp_userspace_pm_get_local_id()
+and mptcp_userspace_pm_is_backup() to simplify the code.
+
+Please note that with this change now list_for_each_entry() is used in
+mptcp_userspace_pm_append_new_local_addr(), not list_for_each_entry_safe(),
+but that's OK to do so because mptcp_userspace_pm_lookup_addr() only
+returns an entry from the list, the list hasn't been modified here.
+
+Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20241213-net-next-mptcp-pm-misc-cleanup-v1-1-ddb6d00109a8@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 9bc6d5e4ca9f ("mptcp: pm: userspace: fix use-after-free in get_local_id")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm_userspace.c | 71 +++++++++++++++++++++++------------------------
+ 1 file changed, 36 insertions(+), 35 deletions(-)
+
+--- a/net/mptcp/pm_userspace.c
++++ b/net/mptcp/pm_userspace.c
+@@ -26,6 +26,19 @@ void mptcp_free_local_addr_list(struct m
+ }
+ }
+
++static struct mptcp_pm_addr_entry *
++mptcp_userspace_pm_lookup_addr(struct mptcp_sock *msk,
++ const struct mptcp_addr_info *addr)
++{
++ struct mptcp_pm_addr_entry *entry;
++
++ list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
++ if (mptcp_addresses_equal(&entry->addr, addr, false))
++ return entry;
++ }
++ return NULL;
++}
++
+ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
+ struct mptcp_pm_addr_entry *entry,
+ bool needs_id)
+@@ -90,22 +103,20 @@ append_err:
+ static int mptcp_userspace_pm_delete_local_addr(struct mptcp_sock *msk,
+ struct mptcp_pm_addr_entry *addr)
+ {
+- struct mptcp_pm_addr_entry *entry, *tmp;
+ struct sock *sk = (struct sock *)msk;
++ struct mptcp_pm_addr_entry *entry;
+
+- list_for_each_entry_safe(entry, tmp, &msk->pm.userspace_pm_local_addr_list, list) {
+- if (mptcp_addresses_equal(&entry->addr, &addr->addr, false)) {
+- /* TODO: a refcount is needed because the entry can
+- * be used multiple times (e.g. fullmesh mode).
+- */
+- list_del_rcu(&entry->list);
+- sock_kfree_s(sk, entry, sizeof(*entry));
+- msk->pm.local_addr_used--;
+- return 0;
+- }
+- }
+-
+- return -EINVAL;
++ entry = mptcp_userspace_pm_lookup_addr(msk, &addr->addr);
++ if (!entry)
++ return -EINVAL;
++
++ /* TODO: a refcount is needed because the entry can
++ * be used multiple times (e.g. fullmesh mode).
++ */
++ list_del_rcu(&entry->list);
++ sock_kfree_s(sk, entry, sizeof(*entry));
++ msk->pm.local_addr_used--;
++ return 0;
+ }
+
+ static struct mptcp_pm_addr_entry *
+@@ -123,17 +134,12 @@ mptcp_userspace_pm_lookup_addr_by_id(str
+ int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk,
+ struct mptcp_addr_info *skc)
+ {
+- struct mptcp_pm_addr_entry *entry = NULL, *e, new_entry;
++ struct mptcp_pm_addr_entry *entry = NULL, new_entry;
+ __be16 msk_sport = ((struct inet_sock *)
+ inet_sk((struct sock *)msk))->inet_sport;
+
+ spin_lock_bh(&msk->pm.lock);
+- list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) {
+- if (mptcp_addresses_equal(&e->addr, skc, false)) {
+- entry = e;
+- break;
+- }
+- }
++ entry = mptcp_userspace_pm_lookup_addr(msk, skc);
+ spin_unlock_bh(&msk->pm.lock);
+ if (entry)
+ return entry->addr.id;
+@@ -153,15 +159,11 @@ bool mptcp_userspace_pm_is_backup(struct
+ struct mptcp_addr_info *skc)
+ {
+ struct mptcp_pm_addr_entry *entry;
+- bool backup = false;
++ bool backup;
+
+ spin_lock_bh(&msk->pm.lock);
+- list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
+- if (mptcp_addresses_equal(&entry->addr, skc, false)) {
+- backup = !!(entry->flags & MPTCP_PM_ADDR_FLAG_BACKUP);
+- break;
+- }
+- }
++ entry = mptcp_userspace_pm_lookup_addr(msk, skc);
++ backup = entry && !!(entry->flags & MPTCP_PM_ADDR_FLAG_BACKUP);
+ spin_unlock_bh(&msk->pm.lock);
+
+ return backup;
+@@ -607,13 +609,12 @@ int mptcp_userspace_pm_set_flags(struct
+ bkup = 1;
+
+ spin_lock_bh(&msk->pm.lock);
+- list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
+- if (mptcp_addresses_equal(&entry->addr, &loc.addr, false)) {
+- if (bkup)
+- entry->flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
+- else
+- entry->flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
+- }
++ entry = mptcp_userspace_pm_lookup_addr(msk, &loc.addr);
++ if (entry) {
++ if (bkup)
++ entry->flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
++ else
++ entry->flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
+ }
+ spin_unlock_bh(&msk->pm.lock);
+
--- /dev/null
+From stable+bounces-297104-greg=kroah.com@vger.kernel.org Fri Aug 7 04:36:36 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 22:36:03 -0400
+Subject: mptcp: pm: avoid code duplication to lookup endp
+To: stable@vger.kernel.org
+Cc: Geliang Tang <tanggeliang@kylinos.cn>, "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260807023606.1683287-1-sashal@kernel.org>
+
+From: Geliang Tang <tanggeliang@kylinos.cn>
+
+[ Upstream commit 1d7fa6ceb91fddbe38cae3521d5d1075bce6a00e ]
+
+The helper __lookup_addr() can be used in mptcp_pm_nl_get_local_id()
+and mptcp_pm_nl_is_backup() to simplify the code, and avoid code
+duplication.
+
+Co-developed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20241115-net-next-mptcp-pm-lockless-dump-v1-2-f4a1bcb4ca2c@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 9bc6d5e4ca9f ("mptcp: pm: userspace: fix use-after-free in get_local_id")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm_netlink.c | 20 ++++++--------------
+ 1 file changed, 6 insertions(+), 14 deletions(-)
+
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -1278,17 +1278,13 @@ int mptcp_pm_nl_get_local_id(struct mptc
+ {
+ struct mptcp_pm_addr_entry *entry;
+ struct pm_nl_pernet *pernet;
+- int ret = -1;
++ int ret;
+
+ pernet = pm_nl_get_pernet_from_msk(msk);
+
+ rcu_read_lock();
+- list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) {
+- if (mptcp_addresses_equal(&entry->addr, skc, entry->addr.port)) {
+- ret = entry->addr.id;
+- break;
+- }
+- }
++ entry = __lookup_addr(pernet, skc);
++ ret = entry ? entry->addr.id : -1;
+ rcu_read_unlock();
+ if (ret >= 0)
+ return ret;
+@@ -1315,15 +1311,11 @@ bool mptcp_pm_nl_is_backup(struct mptcp_
+ {
+ struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk);
+ struct mptcp_pm_addr_entry *entry;
+- bool backup = false;
++ bool backup;
+
+ rcu_read_lock();
+- list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) {
+- if (mptcp_addresses_equal(&entry->addr, skc, entry->addr.port)) {
+- backup = !!(entry->flags & MPTCP_PM_ADDR_FLAG_BACKUP);
+- break;
+- }
+- }
++ entry = __lookup_addr(pernet, skc);
++ backup = entry && !!(entry->flags & MPTCP_PM_ADDR_FLAG_BACKUP);
+ rcu_read_unlock();
+
+ return backup;
--- /dev/null
+From stable+bounces-297106-greg=kroah.com@vger.kernel.org Fri Aug 7 04:36:18 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 22:36:05 -0400
+Subject: mptcp: pm: use addr entry for get_local_id
+To: stable@vger.kernel.org
+Cc: Geliang Tang <tanggeliang@kylinos.cn>, "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260807023606.1683287-3-sashal@kernel.org>
+
+From: Geliang Tang <tanggeliang@kylinos.cn>
+
+[ Upstream commit 7462fe22cc74321eb663768848976d42eba3ddbb ]
+
+The following code in mptcp_userspace_pm_get_local_id() that assigns "skc"
+to "new_entry" is not allowed in BPF if we use the same code to implement
+the get_local_id() interface of a BFP path manager:
+
+ memset(&new_entry, 0, sizeof(struct mptcp_pm_addr_entry));
+ new_entry.addr = *skc;
+ new_entry.addr.id = 0;
+ new_entry.flags = MPTCP_PM_ADDR_FLAG_IMPLICIT;
+
+To solve the issue, this patch moves this assignment to "new_entry" forward
+to mptcp_pm_get_local_id(), and then passing "new_entry" as a parameter to
+both mptcp_pm_nl_get_local_id() and mptcp_userspace_pm_get_local_id().
+
+No behavioural changes intended.
+
+Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20250307-net-next-mptcp-pm-reorg-v1-1-abef20ada03b@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 9bc6d5e4ca9f ("mptcp: pm: userspace: fix use-after-free in get_local_id")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm.c | 9 ++++++---
+ net/mptcp/pm_netlink.c | 11 ++++-------
+ net/mptcp/pm_userspace.c | 17 ++++++-----------
+ net/mptcp/protocol.h | 6 ++++--
+ 4 files changed, 20 insertions(+), 23 deletions(-)
+
+--- a/net/mptcp/pm.c
++++ b/net/mptcp/pm.c
+@@ -427,7 +427,7 @@ out_unlock:
+
+ int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
+ {
+- struct mptcp_addr_info skc_local;
++ struct mptcp_pm_addr_entry skc_local = { 0 };
+ struct mptcp_addr_info msk_local;
+
+ if (WARN_ON_ONCE(!msk))
+@@ -437,10 +437,13 @@ int mptcp_pm_get_local_id(struct mptcp_s
+ * addr
+ */
+ mptcp_local_address((struct sock_common *)msk, &msk_local);
+- mptcp_local_address((struct sock_common *)skc, &skc_local);
+- if (mptcp_addresses_equal(&msk_local, &skc_local, false))
++ mptcp_local_address((struct sock_common *)skc, &skc_local.addr);
++ if (mptcp_addresses_equal(&msk_local, &skc_local.addr, false))
+ return 0;
+
++ skc_local.addr.id = 0;
++ skc_local.flags = MPTCP_PM_ADDR_FLAG_IMPLICIT;
++
+ if (mptcp_pm_is_userspace(msk))
+ return mptcp_userspace_pm_get_local_id(msk, &skc_local);
+ return mptcp_pm_nl_get_local_id(msk, &skc_local);
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -1274,7 +1274,8 @@ static int mptcp_pm_nl_create_listen_soc
+ return err;
+ }
+
+-int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc)
++int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk,
++ struct mptcp_pm_addr_entry *skc)
+ {
+ struct mptcp_pm_addr_entry *entry;
+ struct pm_nl_pernet *pernet;
+@@ -1283,7 +1284,7 @@ int mptcp_pm_nl_get_local_id(struct mptc
+ pernet = pm_nl_get_pernet_from_msk(msk);
+
+ rcu_read_lock();
+- entry = __lookup_addr(pernet, skc);
++ entry = __lookup_addr(pernet, &skc->addr);
+ ret = entry ? entry->addr.id : -1;
+ rcu_read_unlock();
+ if (ret >= 0)
+@@ -1294,12 +1295,8 @@ int mptcp_pm_nl_get_local_id(struct mptc
+ if (!entry)
+ return -ENOMEM;
+
+- entry->addr = *skc;
+- entry->addr.id = 0;
++ *entry = *skc;
+ entry->addr.port = 0;
+- entry->ifindex = 0;
+- entry->flags = MPTCP_PM_ADDR_FLAG_IMPLICIT;
+- entry->lsk = NULL;
+ ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, false);
+ if (ret < 0)
+ kfree(entry);
+--- a/net/mptcp/pm_userspace.c
++++ b/net/mptcp/pm_userspace.c
+@@ -132,27 +132,22 @@ mptcp_userspace_pm_lookup_addr_by_id(str
+ }
+
+ int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk,
+- struct mptcp_addr_info *skc)
++ struct mptcp_pm_addr_entry *skc)
+ {
+- struct mptcp_pm_addr_entry *entry = NULL, new_entry;
+ __be16 msk_sport = ((struct inet_sock *)
+ inet_sk((struct sock *)msk))->inet_sport;
++ struct mptcp_pm_addr_entry *entry;
+
+ spin_lock_bh(&msk->pm.lock);
+- entry = mptcp_userspace_pm_lookup_addr(msk, skc);
++ entry = mptcp_userspace_pm_lookup_addr(msk, &skc->addr);
+ spin_unlock_bh(&msk->pm.lock);
+ if (entry)
+ return entry->addr.id;
+
+- memset(&new_entry, 0, sizeof(struct mptcp_pm_addr_entry));
+- new_entry.addr = *skc;
+- new_entry.addr.id = 0;
+- new_entry.flags = MPTCP_PM_ADDR_FLAG_IMPLICIT;
++ if (skc->addr.port == msk_sport)
++ skc->addr.port = 0;
+
+- if (new_entry.addr.port == msk_sport)
+- new_entry.addr.port = 0;
+-
+- return mptcp_userspace_pm_append_new_local_addr(msk, &new_entry, true);
++ return mptcp_userspace_pm_append_new_local_addr(msk, skc, true);
+ }
+
+ bool mptcp_userspace_pm_is_backup(struct mptcp_sock *msk,
+--- a/net/mptcp/protocol.h
++++ b/net/mptcp/protocol.h
+@@ -1136,8 +1136,10 @@ bool mptcp_pm_add_addr_signal(struct mpt
+ bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
+ struct mptcp_rm_list *rm_list);
+ int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);
+-int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
+-int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
++int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk,
++ struct mptcp_pm_addr_entry *skc);
++int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk,
++ struct mptcp_pm_addr_entry *skc);
+ bool mptcp_pm_is_backup(struct mptcp_sock *msk, struct sock_common *skc);
+ bool mptcp_pm_nl_is_backup(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
+ bool mptcp_userspace_pm_is_backup(struct mptcp_sock *msk, struct mptcp_addr_info *skc);
--- /dev/null
+From stable+bounces-297107-greg=kroah.com@vger.kernel.org Fri Aug 7 04:36:20 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 22:36:06 -0400
+Subject: mptcp: pm: userspace: fix use-after-free in get_local_id
+To: stable@vger.kernel.org
+Cc: Geliang Tang <tanggeliang@kylinos.cn>, Xuanqiang Luo <luoxuanqiang@kylinos.cn>, "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260807023606.1683287-4-sashal@kernel.org>
+
+From: Geliang Tang <tanggeliang@kylinos.cn>
+
+[ Upstream commit 9bc6d5e4ca9f3cbb41d43400b3a31cb0403796c9 ]
+
+In mptcp_pm_userspace_get_local_id(), the address entry is looked up under
+spinlock, but its id is read after dropping the lock. A concurrent deletion
+can free the entry between the unlock and the read, leading to UAF.
+
+The race window is narrow. It was reproduced only with a locally
+constructed stress test that repeatedly overlaps an MP_JOIN SYN with a
+MPTCP_PM_CMD_SUBFLOW_DESTROY request.
+
+However, the KASAN report below confirms that the race is reachable:
+
+ [ 666.319376] BUG: KASAN: slab-use-after-free in mptcp_userspace_pm_get_local_id+0x1dc/0x1f0
+ [ 666.319386] Read of size 1 at addr ffff888124845610 by task swapper/0/0
+ ...
+ [ 666.319401] Call Trace:
+ [ 666.319405] <IRQ>
+ [ 666.319408] dump_stack_lvl+0x53/0x70
+ [ 666.319412] print_address_description.constprop.0+0x2c/0x3b0
+ [ 666.319418] print_report+0xbe/0x2b0
+ [ 666.319421] ? mptcp_userspace_pm_get_local_id+0x1dc/0x1f0
+ [ 666.319423] kasan_report+0xce/0x100
+ [ 666.319426] ? mptcp_userspace_pm_get_local_id+0x1dc/0x1f0
+ [ 666.319429] mptcp_userspace_pm_get_local_id+0x1dc/0x1f0
+ [ 666.319433] mptcp_pm_get_local_id+0x371/0x440
+ ...
+ [ 666.319821] Allocated by task 45539:
+ [ 666.319844] kasan_save_stack+0x33/0x60
+ [ 666.319855] kasan_save_track+0x14/0x30
+ [ 666.319858] __kasan_kmalloc+0x8f/0xa0
+ [ 666.319863] __kmalloc_noprof+0x1e7/0x520
+ [ 666.319867] sock_kmalloc+0xdf/0x130
+ [ 666.319885] sock_kmemdup+0x1b/0x40
+ [ 666.319888] mptcp_userspace_pm_append_new_local_addr+0x261/0x500
+ [ 666.319910] mptcp_pm_nl_announce_doit+0x16a/0x610
+ ...
+ [ 666.319967] Freed by task 45560:
+ [ 666.319988] kasan_save_stack+0x33/0x60
+ [ 666.319991] kasan_save_track+0x14/0x30
+ [ 666.319994] kasan_save_free_info+0x3b/0x60
+ [ 666.319998] __kasan_slab_free+0x43/0x70
+ [ 666.320000] kfree+0x166/0x440
+ [ 666.320003] sock_kfree_s+0x1d/0x50
+ [ 666.320007] mptcp_userspace_pm_delete_local_addr.isra.0+0x157/0x200
+ [ 666.320011] mptcp_pm_nl_subflow_destroy_doit+0x51d/0xea0
+
+Fix by copying the id into a local variable while still holding the lock,
+and use -1 as a "not found" sentinel.
+
+Fixes: f012d796a6de ("mptcp: check addrs list in userspace_pm_get_local_id")
+Cc: stable@vger.kernel.org
+Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
+Tested-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
+Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20260722-net-mptcp-misc-fixes-7-2-rc5-v1-2-6fb595bc86ef@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm_userspace.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/net/mptcp/pm_userspace.c
++++ b/net/mptcp/pm_userspace.c
+@@ -137,12 +137,15 @@ int mptcp_userspace_pm_get_local_id(stru
+ __be16 msk_sport = ((struct inet_sock *)
+ inet_sk((struct sock *)msk))->inet_sport;
+ struct mptcp_pm_addr_entry *entry;
++ int id;
+
+ spin_lock_bh(&msk->pm.lock);
+ entry = mptcp_userspace_pm_lookup_addr(msk, &skc->addr);
++ id = entry ? entry->addr.id : -1;
+ spin_unlock_bh(&msk->pm.lock);
+- if (entry)
+- return entry->addr.id;
++
++ if (id != -1)
++ return id;
+
+ if (skc->addr.port == msk_sport)
+ skc->addr.port = 0;
lib-alloc_tag-introduce-mem_alloc_profiling_permanen.patch
mm-slab-prevent-unbounded-recursion-in-free-path-wit.patch
gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
+usb-gadget-f_tcm-synchronize-delayed-set_alt-with-teardown.patch
+usb-typec-ucsi-split-connector-lock-classes.patch
+usb-typec-ucsi-fix-race-condition-and-ordering-in-port-unregistration.patch
+media-i2c-imx219-rename-vts-to-frm_length.patch
+media-imx219-fix-maximum-frame-length-in-lines.patch
+media-chips-media-wave5-support-cbp-profile.patch
+media-uapi-rkisp-correct-name-version-enum.patch
+wifi-brcmfmac-drain-bus_reset-work-on-device-removal.patch
+wifi-ath6kl-fix-use-after-free-in-aggr_reset_state.patch
+wifi-brcmfmac-fix-43752-sdio-fwvid-incorrectly-labelled-as-cypress-cyw.patch
+wifi-brcmfmac-set-f2-blocksize-to-256-for-bcm43752.patch
+alsa-hda-codecs-hdmi-disable-keep-alive-before-audio-format-change.patch
+mptcp-pm-avoid-code-duplication-to-lookup-endp.patch
+mptcp-add-mptcp_userspace_pm_lookup_addr-helper.patch
+mptcp-pm-use-addr-entry-for-get_local_id.patch
+mptcp-pm-userspace-fix-use-after-free-in-get_local_id.patch
+kmemleak-iommu-iova-fix-transient-kmemleak-false-positive.patch
+mm-kmemleak-fix-checksum-computation-for-per-cpu-objects.patch
--- /dev/null
+From sashal@kernel.org Thu Jul 30 21:29:51 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 15:29:48 -0400
+Subject: usb: gadget: f_tcm: synchronize delayed set_alt with teardown
+To: stable@vger.kernel.org
+Cc: Cen Zhang <zzzccc427@gmail.com>, stable <stable@kernel.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260730192948.3124448-1-sashal@kernel.org>
+
+From: Cen Zhang <zzzccc427@gmail.com>
+
+[ Upstream commit 79e2d75725c85607f8a9d87ae9cace62a19f767d ]
+
+The f_tcm set_alt() path defers endpoint setup to a work item and
+completes the delayed status response from process context. The delayed
+work uses f_tcm private state and may complete the setup request after
+disconnect or function teardown has already moved on.
+
+Cancel and drain the delayed set_alt work when the function is unbound or
+freed. For disable paths, which are reached under the composite device
+lock, use a small state machine and a non-sleeping cancellation path
+instead of cancel_work_sync(). If the work is already running, mark it
+cancelled and let the worker own the cleanup; otherwise tcm_disable() can
+cancel the queued work and clean up immediately.
+
+Also serialize the final delayed-status completion with the cancellation
+check while holding the composite device lock. This prevents a disconnect
+from clearing delayed_status while the worker is about to complete the
+control request.
+
+Validation reproduced this kernel report:
+BUG: KASAN: slab-use-after-free in tcm_delayed_set_alt+0x6c/0xef0
+
+Call Trace:
+ <TASK>
+ dump_stack_lvl+0x66/0xa0
+ print_report+0xce/0x630
+ ? tcm_delayed_set_alt+0x6c/0xef0
+ ? srso_alias_return_thunk+0x5/0xfbef5
+ ? __virt_addr_valid+0x188/0x320
+ ? tcm_delayed_set_alt+0x6c/0xef0
+ kasan_report+0xe0/0x110
+ ? tcm_delayed_set_alt+0x6c/0xef0
+ tcm_delayed_set_alt+0x6c/0xef0
+ ? __pfx_tcm_delayed_set_alt+0x10/0x10
+ ? process_one_work+0x4cb/0xb90
+ ? rcu_is_watching+0x20/0x50
+ ? tcm_delayed_set_alt+0x9/0xef0
+ process_one_work+0x4d7/0xb90
+ ? __pfx_process_one_work+0x10/0x10
+ ? srso_alias_return_thunk+0x5/0xfbef5
+ ? __list_add_valid_or_report+0x37/0xf0
+ ? __pfx_tcm_delayed_set_alt+0x10/0x10
+ ? srso_alias_return_thunk+0x5/0xfbef5
+ worker_thread+0x2d8/0x570
+ ? __pfx_worker_thread+0x10/0x10
+ kthread+0x1ad/0x1f0
+ ? __pfx_kthread+0x10/0x10
+ ret_from_fork+0x3c9/0x540
+ ? __pfx_ret_from_fork+0x10/0x10
+ ? srso_alias_return_thunk+0x5/0xfbef5
+ ? __switch_to+0x2e9/0x730
+ ? __pfx_kthread+0x10/0x10
+ ret_from_fork_asm+0x1a/0x30
+ </TASK>
+
+Allocated by task 544:
+ kasan_save_stack+0x33/0x60
+ kasan_save_track+0x14/0x30
+ __kasan_kmalloc+0x8f/0xa0
+ tcm_alloc+0x68/0x180
+ usb_get_function+0x36/0x60
+ config_usb_cfg_link+0x125/0x1b0
+ configfs_symlink+0x322/0x890
+ vfs_symlink+0xc2/0x270
+ filename_symlinkat+0x295/0x2f0
+ __x64_sys_symlinkat+0x62/0x90
+ do_syscall_64+0x115/0x6a0
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Freed by task 661:
+ kasan_save_stack+0x33/0x60
+ kasan_save_track+0x14/0x30
+ kasan_save_free_info+0x3b/0x60
+ __kasan_slab_free+0x43/0x70
+ kfree+0x2f9/0x530
+ config_usb_cfg_unlink+0x173/0x1e0
+ configfs_unlink+0x1fa/0x340
+ vfs_unlink+0x15c/0x510
+ filename_unlinkat+0x2ba/0x450
+ __x64_sys_unlinkat+0x63/0x90
+ do_syscall_64+0x115/0x6a0
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Fixes: c52661d60f63 ("usb-gadget: Initial merge of target module for UASP + BOT")
+Cc: stable <stable@kernel.org>
+Assisted-by: Codex:gpt-5.5
+Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
+Link: https://patch.msgid.link/20260627104153.3822495-1-zzzccc427@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[ adjusted context for 6.12's scalar `struct usbg_cdb cmd` and missing `stream_hash`, dropping the `hash_init()` context line ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_tcm.c | 192 ++++++++++++++++++++++++++++++------
+ drivers/usb/gadget/function/tcm.h | 13 ++
+ 2 files changed, 177 insertions(+), 28 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_tcm.c
++++ b/drivers/usb/gadget/function/f_tcm.c
+@@ -2014,31 +2014,158 @@ ep_fail:
+ return -ENOTSUPP;
+ }
+
+-struct guas_setup_wq {
+- struct work_struct work;
+- struct f_uas *fu;
+- unsigned int alt;
+-};
++static void tcm_cleanup_old_alt(struct f_uas *fu)
++{
++ if (fu->flags & USBG_IS_UAS)
++ uasp_cleanup_old_alt(fu);
++ else if (fu->flags & USBG_IS_BOT)
++ bot_cleanup_old_alt(fu);
++ fu->flags = 0;
++}
++
++static void tcm_delayed_set_alt_done(struct f_uas *fu)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
++ fu->delayed_set_alt_cancel = false;
++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
++}
++
++static bool tcm_delayed_set_alt_cancelled(struct f_uas *fu)
++{
++ bool cancelled;
++ unsigned long flags;
++
++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
++ cancelled = fu->delayed_set_alt_cancel;
++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
++
++ return cancelled;
++}
++
++static bool tcm_complete_delayed_status(struct f_uas *fu)
++{
++ struct usb_composite_dev *cdev = fu->function.config->cdev;
++ struct usb_request *req = cdev->req;
++ unsigned long cdev_flags;
++ bool cancelled;
++ int ret;
++
++ spin_lock_irqsave(&cdev->lock, cdev_flags);
++ spin_lock(&fu->delayed_set_alt_lock);
++ cancelled = fu->delayed_set_alt_cancel;
++ if (!cancelled) {
++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
++ fu->delayed_set_alt_cancel = false;
++ }
++ spin_unlock(&fu->delayed_set_alt_lock);
++
++ if (cancelled) {
++ spin_unlock_irqrestore(&cdev->lock, cdev_flags);
++ return false;
++ }
++
++ if (cdev->delayed_status == 0) {
++ WARN(cdev, "%s: Unexpected call\n", __func__);
++ } else if (--cdev->delayed_status == 0) {
++ req->length = 0;
++ req->context = cdev;
++ ret = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
++ if (ret == 0) {
++ cdev->setup_pending = true;
++ } else {
++ req->status = 0;
++ req->complete(cdev->gadget->ep0, req);
++ }
++ }
++
++ spin_unlock_irqrestore(&cdev->lock, cdev_flags);
++
++ return true;
++}
++
++static bool tcm_cancel_delayed_set_alt(struct f_uas *fu)
++{
++ bool cleanup = false;
++ bool cancel = false;
++ unsigned long flags;
++
++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
++ switch (fu->delayed_set_alt_state) {
++ case USBG_DELAYED_SET_ALT_IDLE:
++ cleanup = true;
++ break;
++ case USBG_DELAYED_SET_ALT_QUEUED:
++ case USBG_DELAYED_SET_ALT_RUNNING:
++ fu->delayed_set_alt_cancel = true;
++ cancel = true;
++ break;
++ }
++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
++
++ if (cancel && cancel_work(&fu->delayed_set_alt)) {
++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
++ if (fu->delayed_set_alt_state == USBG_DELAYED_SET_ALT_QUEUED) {
++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
++ fu->delayed_set_alt_cancel = false;
++ cleanup = true;
++ }
++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
++ }
++
++ return cleanup;
++}
++
++static void tcm_cancel_delayed_set_alt_sync(struct f_uas *fu)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
++ if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_IDLE)
++ fu->delayed_set_alt_cancel = true;
++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
++
++ cancel_work_sync(&fu->delayed_set_alt);
++
++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
++ fu->delayed_set_alt_cancel = false;
++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
++}
+
+ static void tcm_delayed_set_alt(struct work_struct *wq)
+ {
+- struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
+- work);
+- struct f_uas *fu = work->fu;
+- int alt = work->alt;
++ struct f_uas *fu = container_of(wq, struct f_uas, delayed_set_alt);
++ unsigned long flags;
++ unsigned int alt;
++
++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
++ if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_QUEUED) {
++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
++ return;
++ }
++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_RUNNING;
++ alt = fu->delayed_alt;
++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
+
+- kfree(work);
++ tcm_cleanup_old_alt(fu);
+
+- if (fu->flags & USBG_IS_BOT)
+- bot_cleanup_old_alt(fu);
+- if (fu->flags & USBG_IS_UAS)
+- uasp_cleanup_old_alt(fu);
++ if (tcm_delayed_set_alt_cancelled(fu))
++ goto out_done;
+
+ if (alt == USB_G_ALT_INT_BBB)
+ bot_set_alt(fu);
+ else if (alt == USB_G_ALT_INT_UAS)
+ uasp_set_alt(fu);
+- usb_composite_setup_continue(fu->function.config->cdev);
++
++ if (tcm_complete_delayed_status(fu))
++ return;
++
++ tcm_cleanup_old_alt(fu);
++out_done:
++ tcm_delayed_set_alt_done(fu);
+ }
+
+ static int tcm_get_alt(struct usb_function *f, unsigned intf)
+@@ -2064,15 +2191,20 @@ static int tcm_set_alt(struct usb_functi
+ return -EOPNOTSUPP;
+
+ if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
+- struct guas_setup_wq *work;
++ unsigned long flags;
++
++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
++ if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_IDLE) {
++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock,
++ flags);
++ return -EBUSY;
++ }
++ fu->delayed_alt = alt;
++ fu->delayed_set_alt_cancel = false;
++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_QUEUED;
++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
+
+- work = kmalloc(sizeof(*work), GFP_ATOMIC);
+- if (!work)
+- return -ENOMEM;
+- INIT_WORK(&work->work, tcm_delayed_set_alt);
+- work->fu = fu;
+- work->alt = alt;
+- schedule_work(&work->work);
++ schedule_work(&fu->delayed_set_alt);
+ return USB_GADGET_DELAYED_STATUS;
+ }
+ return -EOPNOTSUPP;
+@@ -2082,11 +2214,8 @@ static void tcm_disable(struct usb_funct
+ {
+ struct f_uas *fu = to_f_uas(f);
+
+- if (fu->flags & USBG_IS_UAS)
+- uasp_cleanup_old_alt(fu);
+- else if (fu->flags & USBG_IS_BOT)
+- bot_cleanup_old_alt(fu);
+- fu->flags = 0;
++ if (tcm_cancel_delayed_set_alt(fu))
++ tcm_cleanup_old_alt(fu);
+ }
+
+ static int tcm_setup(struct usb_function *f,
+@@ -2234,11 +2363,16 @@ static void tcm_free(struct usb_function
+ {
+ struct f_uas *tcm = to_f_uas(f);
+
++ tcm_cancel_delayed_set_alt_sync(tcm);
+ kfree(tcm);
+ }
+
+ static void tcm_unbind(struct usb_configuration *c, struct usb_function *f)
+ {
++ struct f_uas *fu = to_f_uas(f);
++
++ tcm_cancel_delayed_set_alt_sync(fu);
++ tcm_cleanup_old_alt(fu);
+ usb_free_all_descriptors(f);
+ }
+
+@@ -2271,6 +2405,8 @@ static struct usb_function *tcm_alloc(st
+ fu->function.disable = tcm_disable;
+ fu->function.free_func = tcm_free;
+ fu->tpg = tpg_instances[i].tpg;
++ INIT_WORK(&fu->delayed_set_alt, tcm_delayed_set_alt);
++ spin_lock_init(&fu->delayed_set_alt_lock);
+ mutex_unlock(&tpg_instances_lock);
+
+ return &fu->function;
+--- a/drivers/usb/gadget/function/tcm.h
++++ b/drivers/usb/gadget/function/tcm.h
+@@ -3,6 +3,7 @@
+ #define __TARGET_USB_GADGET_H__
+
+ #include <linux/kref.h>
++#include <linux/spinlock.h>
+ /* #include <linux/usb/uas.h> */
+ #include <linux/usb/composite.h>
+ #include <linux/usb/uas.h>
+@@ -26,6 +27,12 @@ enum {
+
+ #define USB_G_DEFAULT_SESSION_TAGS 128
+
++enum {
++ USBG_DELAYED_SET_ALT_IDLE = 0,
++ USBG_DELAYED_SET_ALT_QUEUED,
++ USBG_DELAYED_SET_ALT_RUNNING,
++};
++
+ struct tcm_usbg_nexus {
+ struct se_session *tvn_se_sess;
+ };
+@@ -117,6 +124,12 @@ struct f_uas {
+ #define USBG_IS_BOT (1 << 3)
+ #define USBG_BOT_CMD_PEND (1 << 4)
+
++ struct work_struct delayed_set_alt;
++ spinlock_t delayed_set_alt_lock; /* protects delayed_set_alt_* */
++ unsigned int delayed_alt;
++ unsigned int delayed_set_alt_state;
++ bool delayed_set_alt_cancel;
++
+ struct usbg_cdb cmd;
+ struct usb_ep *ep_in;
+ struct usb_ep *ep_out;
--- /dev/null
+From sashal@kernel.org Thu Jul 30 21:39:03 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 15:38:59 -0400
+Subject: usb: typec: ucsi: Fix race condition and ordering in port unregistration
+To: stable@vger.kernel.org
+Cc: Andrei Kuchynski <akuchynski@chromium.org>, stable <stable@kernel.org>, Benson Leung <bleung@chromium.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260730193859.3130212-2-sashal@kernel.org>
+
+From: Andrei Kuchynski <akuchynski@chromium.org>
+
+[ Upstream commit 7aa7d4bf9d3fa9a6a47b640ad103ab433b7ff261 ]
+
+A synchronization issue exists during port unregistration where pending
+partner work items can race against workqueue destruction, leading to
+use-after-free conditions:
+
+ cros_ec_ucsi cros_ec_ucsi.3.auto: error -ETIMEDOUT: PPM init failed
+ BUG: kernel NULL pointer dereference, address: 0000000000000000
+ RIP: 0010:__queue_work+0x83/0x4a0
+ Call Trace:
+ <IRQ>
+ __cfi_delayed_work_timer_fn+0x10/0x10
+ run_timer_softirq+0x3b6/0xbd0
+ sched_clock_cpu+0xc/0x110
+ irq_exit_rcu+0x18d/0x330
+ fred_sysvec_apic_timer_interrupt+0x5e/0x80
+
+Fix this by ensuring strict ordering and proper serialization during
+teardown:
+
+1. Move ucsi_unregister_partner() to the beginning of the teardown
+sequence and protect it under the connector mutex lock.
+2. Ensure all pending partner tasks are explicitly flushed and finished
+before the workqueue is destroyed.
+3. Switch from mod_delayed_work() to a cancel_delayed_work() and
+queue_delayed_work() sequence. This guarantees that items currently marked
+as pending won't be scheduled an additional time, preventing a double
+release of resources which leads to the following crash:
+
+ Oops: general protection fault, probably for non-canonical address
+ 0xdead000000000122: 0000 [#1] SMP NOPTI
+ Workqueue: cros_ec_ucsi.3.auto-con2 ucsi_poll_worker
+ RIP: 0010:ucsi_poll_worker+0x65/0x1e0
+ Call Trace:
+ <TASK>
+ process_scheduled_works+0x218/0x6d0
+ worker_thread+0x188/0x3f0
+ __cfi_worker_thread+0x10/0x10
+ kthread+0x226/0x2a0
+
+To ensure these rules are applied identically across both the normal
+teardown and the ucsi_init() error paths, consolidate the cleanup logic
+into a new helper, ucsi_unregister_port().
+
+Cc: stable <stable@kernel.org>
+Fixes: b9aa02ca39a4 ("usb: typec: ucsi: Add polling mechanism for partner tasks like alt mode checking")
+Fixes: b13abcb7ddd8 ("usb: typec: ucsi: Fix NULL pointer access")
+Fixes: fac4b8633fd6 ("usb: ucsi: Ensure connector delayed work items are flushed")
+Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
+Reviewed-by: Benson Leung <bleung@chromium.org>
+Link: https://patch.msgid.link/20260707141736.1635698-1-akuchynski@chromium.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c | 82 +++++++++++++++++++-----------------------
+ 1 file changed, 39 insertions(+), 43 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -1719,6 +1719,42 @@ out_unlock:
+ return ret;
+ }
+
++static void ucsi_unregister_port(struct ucsi_connector *con)
++{
++ struct ucsi_work *uwork;
++
++ if (con->wq) {
++ mutex_lock(&con->lock);
++ ucsi_unregister_partner(con);
++ /*
++ * queue delayed items immediately so they can execute
++ * and free themselves before the wq is destroyed
++ */
++ list_for_each_entry(uwork, &con->partner_tasks, node) {
++ if (cancel_delayed_work(&uwork->work))
++ queue_delayed_work(con->wq, &uwork->work, 0);
++ }
++ mutex_unlock(&con->lock);
++
++ destroy_workqueue(con->wq);
++ con->wq = NULL;
++ } else {
++ ucsi_unregister_partner(con);
++ }
++
++ ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
++ ucsi_unregister_port_psy(con);
++
++ usb_power_delivery_unregister_capabilities(con->port_sink_caps);
++ con->port_sink_caps = NULL;
++ usb_power_delivery_unregister_capabilities(con->port_source_caps);
++ con->port_source_caps = NULL;
++ usb_power_delivery_unregister(con->pd);
++ con->pd = NULL;
++ typec_unregister_port(con->port);
++ con->port = NULL;
++}
++
+ static u64 ucsi_get_supported_notifications(struct ucsi *ucsi)
+ {
+ u16 features = ucsi->cap.features;
+@@ -1844,22 +1880,8 @@ err_unregister:
+ for (i = 0; i < ucsi->cap.num_connectors; i++)
+ lockdep_unregister_key(&connector[i].lock_key);
+
+- for (con = connector; con->port; con++) {
+- if (con->wq)
+- destroy_workqueue(con->wq);
+- ucsi_unregister_partner(con);
+- ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
+- ucsi_unregister_port_psy(con);
+-
+- usb_power_delivery_unregister_capabilities(con->port_sink_caps);
+- con->port_sink_caps = NULL;
+- usb_power_delivery_unregister_capabilities(con->port_source_caps);
+- con->port_source_caps = NULL;
+- usb_power_delivery_unregister(con->pd);
+- con->pd = NULL;
+- typec_unregister_port(con->port);
+- con->port = NULL;
+- }
++ for (con = connector; con->port; con++)
++ ucsi_unregister_port(con);
+ kfree(connector);
+ err_reset:
+ memset(&ucsi->cap, 0, sizeof(ucsi->cap));
+@@ -2087,33 +2109,7 @@ void ucsi_unregister(struct ucsi *ucsi)
+
+ for (i = 0; i < ucsi->cap.num_connectors; i++) {
+ cancel_work_sync(&ucsi->connector[i].work);
+-
+- if (ucsi->connector[i].wq) {
+- struct ucsi_work *uwork;
+-
+- mutex_lock(&ucsi->connector[i].lock);
+- /*
+- * queue delayed items immediately so they can execute
+- * and free themselves before the wq is destroyed
+- */
+- list_for_each_entry(uwork, &ucsi->connector[i].partner_tasks, node)
+- mod_delayed_work(ucsi->connector[i].wq, &uwork->work, 0);
+- mutex_unlock(&ucsi->connector[i].lock);
+- destroy_workqueue(ucsi->connector[i].wq);
+- }
+-
+- ucsi_unregister_partner(&ucsi->connector[i]);
+- ucsi_unregister_altmodes(&ucsi->connector[i],
+- UCSI_RECIPIENT_CON);
+- ucsi_unregister_port_psy(&ucsi->connector[i]);
+-
+- usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_sink_caps);
+- ucsi->connector[i].port_sink_caps = NULL;
+- usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_source_caps);
+- ucsi->connector[i].port_source_caps = NULL;
+- usb_power_delivery_unregister(ucsi->connector[i].pd);
+- ucsi->connector[i].pd = NULL;
+- typec_unregister_port(ucsi->connector[i].port);
++ ucsi_unregister_port(&ucsi->connector[i]);
+ lockdep_unregister_key(&ucsi->connector[i].lock_key);
+ }
+
--- /dev/null
+From sashal@kernel.org Thu Jul 30 21:39:02 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 15:38:58 -0400
+Subject: usb: typec: ucsi: split connector lock classes
+To: stable@vger.kernel.org
+Cc: Sergey Senozhatsky <senozhatsky@chromium.org>, Heikki Krogerus <heikki.krogerus@linux.intel.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260730193859.3130212-1-sashal@kernel.org>
+
+From: Sergey Senozhatsky <senozhatsky@chromium.org>
+
+[ Upstream commit 8c22256bbafad3dc5fdbe9f684d045b67ff06a68 ]
+
+Lockdep detects a possible recursive locking scenario during
+ucsi init:
+
+[ 5.418616] ============================================
+[ 5.418634] WARNING: possible recursive locking detected
+[ 5.418706] --------------------------------------------
+[ 5.418725] kworker/4:1/82 is trying to acquire lock:
+[ 5.418759] ffff888119a34648 (&con->lock){+.+.}-{3:3}, at: ucsi_init_work+0x1a78/0x2eb0 [typec_ucsi]
+[ 5.418801]
+ but task is already holding lock:
+[ 5.418835] ffff888119a34080 (&con->lock){+.+.}-{3:3}, at: ucsi_init_work+0x1a78/0x2eb0 [typec_ucsi]
+[ 5.418884]
+ other info that might help us debug this:
+[ 5.418904] Possible unsafe locking scenario:
+
+[ 5.418937] CPU0
+[ 5.418956] ----
+[ 5.418991] lock(&con->lock);
+[ 5.419013] lock(&con->lock);
+[ 5.419033]
+ *** DEADLOCK ***
+
+[ 5.419387] Call Trace:
+[ 5.419406] <TASK>
+[ 5.419425] dump_stack_lvl+0x61/0xa0
+[ 5.419448] print_deadlock_bug+0x4a6/0x650
+[ 5.419483] __lock_acquire+0x62b6/0x7f50
+[ 5.419507] lock_acquire+0x11b/0x390
+[ 5.419654] __mutex_lock+0xbc/0xcd0
+[ 5.419741] ucsi_init_work+0x1a78/0x2eb0
+[ 5.419785] ? worker_thread+0xf53/0x2bc0
+[ 5.419819] worker_thread+0xff4/0x2bc0
+[ 5.419842] kthread+0x2a7/0x330
+[ 5.419863] ? __pfx_worker_thread+0x10/0x10
+[ 5.419896] ? __pfx_kthread+0x10/0x10
+[ 5.419916] ret_from_fork+0x38/0x70
+[ 5.419936] ? __pfx_kthread+0x10/0x10
+[ 5.419969] ret_from_fork_asm+0x1b/0x30
+[ 5.419991] </TASK>
+[ 5.420009] ---[ end trace 0000000000000000 ]---
+
+The problem is that all connector locks belong to the same
+lockdep lock class, so the following loop:
+
+ for (i = 0; i < ucsi->cap.num_connectors; i++)
+ ucsi_register_port(connector[i])
+ mutex_lock(&connector[i]->lock)
+
+looks like a recursive acquire of the same mutex. Put each connector
+lock into a dedicated lock class so that lockdep doesn't see it as a
+possible recursion.
+
+Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://patch.msgid.link/20260515060042.136083-1-senozhatsky@chromium.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 7aa7d4bf9d3f ("usb: typec: ucsi: Fix race condition and ordering in port unregistration")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c | 8 ++++++++
+ drivers/usb/typec/ucsi/ucsi.h | 1 +
+ 2 files changed, 9 insertions(+)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -1569,6 +1569,7 @@ static int ucsi_register_port(struct ucs
+ INIT_WORK(&con->work, ucsi_handle_connector_change);
+ init_completion(&con->complete);
+ mutex_init(&con->lock);
++ lockdep_set_class(&con->lock, &con->lock_key);
+ INIT_LIST_HEAD(&con->partner_tasks);
+ con->ucsi = ucsi;
+
+@@ -1808,6 +1809,9 @@ static int ucsi_init(struct ucsi *ucsi)
+ goto err_reset;
+ }
+
++ for (i = 0; i < ucsi->cap.num_connectors; i++)
++ lockdep_register_key(&connector[i].lock_key);
++
+ /* Register all connectors */
+ for (i = 0; i < ucsi->cap.num_connectors; i++) {
+ connector[i].num = i + 1;
+@@ -1837,6 +1841,9 @@ static int ucsi_init(struct ucsi *ucsi)
+ return 0;
+
+ err_unregister:
++ for (i = 0; i < ucsi->cap.num_connectors; i++)
++ lockdep_unregister_key(&connector[i].lock_key);
++
+ for (con = connector; con->port; con++) {
+ if (con->wq)
+ destroy_workqueue(con->wq);
+@@ -2107,6 +2114,7 @@ void ucsi_unregister(struct ucsi *ucsi)
+ usb_power_delivery_unregister(ucsi->connector[i].pd);
+ ucsi->connector[i].pd = NULL;
+ typec_unregister_port(ucsi->connector[i].port);
++ lockdep_unregister_key(&ucsi->connector[i].lock_key);
+ }
+
+ kfree(ucsi->connector);
+--- a/drivers/usb/typec/ucsi/ucsi.h
++++ b/drivers/usb/typec/ucsi/ucsi.h
+@@ -422,6 +422,7 @@ struct ucsi_connector {
+
+ struct ucsi *ucsi;
+ struct mutex lock; /* port lock */
++ struct lock_class_key lock_key;
+ struct work_struct work;
+ struct completion complete;
+ struct workqueue_struct *wq;
--- /dev/null
+From stable+bounces-296831-greg=kroah.com@vger.kernel.org Thu Aug 6 15:51:53 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 09:44:31 -0400
+Subject: wifi: ath6kl: fix use-after-free in aggr_reset_state()
+To: stable@vger.kernel.org
+Cc: Daniel Hodges <git@danielhodges.dev>, Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>, Jeff Johnson <jeff.johnson@oss.qualcomm.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260806134431.555434-1-sashal@kernel.org>
+
+From: Daniel Hodges <git@danielhodges.dev>
+
+[ Upstream commit ba7debb4dd6427386862220e8335a53a4bfc235d ]
+
+The aggr_reset_state() function uses timer_delete() (non-synchronous)
+for the aggregation timer before proceeding to delete TID state and
+before the structure is freed by callers like aggr_module_destroy().
+
+If the timer callback (aggr_timeout) is executing when aggr_reset_state()
+is called, the callback will continue to access aggr_conn fields like
+rx_tid[] and stat[] which may be freed immediately after by
+kfree(aggr_info->aggr_conn) in aggr_module_destroy().
+
+Additionally, the timer callback can re-arm itself via mod_timer() while
+aggr_reset_state() is running, creating a more complex race condition.
+
+Use timer_delete_sync() instead to ensure any running timer callback
+has completed before returning.
+
+Fixes: bdcd81707973 ("Add ath6kl cleaned up driver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Hodges <git@danielhodges.dev>
+Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260206185207.30098-1-git@danielhodges.dev
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/ath/ath6kl/txrx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ath/ath6kl/txrx.c
++++ b/drivers/net/wireless/ath/ath6kl/txrx.c
+@@ -1829,7 +1829,7 @@ void aggr_reset_state(struct aggr_info_c
+ return;
+
+ if (aggr_conn->timer_scheduled) {
+- del_timer(&aggr_conn->timer);
++ timer_delete_sync(&aggr_conn->timer);
+ aggr_conn->timer_scheduled = false;
+ }
+
--- /dev/null
+From stable+bounces-296820-greg=kroah.com@vger.kernel.org Thu Aug 6 15:32:56 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 09:22:30 -0400
+Subject: wifi: brcmfmac: drain bus_reset work on device removal
+To: stable@vger.kernel.org
+Cc: Fan Wu <fanwu01@zju.edu.cn>, Arend van Spriel <arend.vanspriel@broadcom.com>, Johannes Berg <johannes.berg@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260806132230.416656-1-sashal@kernel.org>
+
+From: Fan Wu <fanwu01@zju.edu.cn>
+
+[ Upstream commit 43b25879f004c98defa2776bedc6ca4763c51945 ]
+
+brcmf_fw_crashed() and the debugfs "reset" entry both schedule
+drvr->bus_reset, whose callback recovers drvr through container_of()
+and dereferences it. The removal path frees drvr (brcmf_free ->
+wiphy_free) without draining the work, so a bus_reset callback pending
+or running during removal can outlive drvr.
+
+Cancellation cannot live in brcmf_detach() or brcmf_free(): the work
+callback reaches teardown through the bus .reset op (PCIe
+brcmf_pcie_reset -> brcmf_detach; SDIO brcmf_sdio_bus_reset ->
+brcmf_sdiod_remove -> brcmf_free), so cancelling there would wait for
+the running work and deadlock.
+
+Add a per-bus mutex (bus_reset_lock) and route all arming through
+brcmf_bus_schedule_reset(), which under the lock skips when the bus is
+marked removing. Each bus remove entry calls
+brcmf_bus_cancel_reset_work(), which under the same lock sets removing
+and cancels the work. Holding the mutex across cancel_work_sync() makes
+the set-removing + drain step atomic. Every producer reaches the arming
+path from process context -- the PCIe firmware-halt notification runs in
+the threaded IRQ handler (brcmf_pcie_isr_thread) and the SDIO hostmail
+path runs from the data workqueue -- so the mutex is taken only in
+sleepable contexts. Where applicable the remove entry first stops the
+firmware-crash producer: on PCIe mask the mailbox and synchronize_irq;
+on SDIO unregister the bus interrupt and cancel the data worker, which
+also reports firmware halts through brcmf_fw_crashed(). The mutex is
+initialized at bus allocation. The SDIO suspend power-off path frees
+drvr through the same brcmf_sdiod_remove() and takes the same lock;
+resume re-allows the work only on a successful re-probe.
+
+Also guard brcmf_fw_crashed() against a NULL bus_if/drvr: it can fire
+before brcmf_attach() wires up drvr, and it dereferences drvr
+(bphy_err/brcmf_dev_coredump) before reaching the arming gate.
+
+The bus_reset work is shared across buses, so the drain is applied to
+every remove path: PCIe (the .reset op introduced by the Fixes commit),
+SDIO (arms the same work through brcmf_fw_crashed()), and USB (via the
+debugfs "reset" entry). cancel_work_sync() drains a running or pending
+bus_reset work item before removal frees drvr, and patch 1/2 makes the
+scratch-buffer release safe when reset teardown has already released
+those DMA buffers.
+
+This patch fixes the lifetime of the bus_reset work item itself. It does
+not attempt to address the separate, pre-existing lifetime of the
+asynchronous firmware completion started by the PCIe reset path. That
+callback needs its own lifetime/ownership protocol and is being tracked
+separately.
+
+This issue was found by an in-house static analysis tool.
+
+Fixes: 4684997d9eea ("brcmfmac: reset PCIe bus on a firmware crash")
+Cc: stable@vger.kernel.org
+Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
+Assisted-by: Codex:gpt-5.6
+Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Link: https://patch.msgid.link/20260718024353.3147201-3-fanwu01@zju.edu.cn
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 13 +++
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 6 +
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 46 ++++++++++++--
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 6 +
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 6 +
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h | 1
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 3
+ 7 files changed, 77 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+@@ -1064,6 +1064,7 @@ static int brcmf_ops_sdio_probe(struct s
+ bus_if = kzalloc(sizeof(*bus_if), GFP_KERNEL);
+ if (!bus_if)
+ return -ENOMEM;
++ mutex_init(&bus_if->bus_reset_lock);
+ sdiodev = kzalloc(sizeof(*sdiodev), GFP_KERNEL);
+ if (!sdiodev) {
+ kfree(bus_if);
+@@ -1125,6 +1126,14 @@ static void brcmf_ops_sdio_remove(struct
+ if (func->num != 1)
+ return;
+
++ /* Drain bus_reset before the shared brcmf_sdiod_remove()
++ * teardown, which the SDIO reset callback also reaches. The
++ * data worker can arm bus_reset via brcmf_fw_crashed(); cancel
++ * it first.
++ */
++ brcmf_sdio_cancel_datawork(sdiodev->bus);
++ brcmf_bus_cancel_reset_work(bus_if);
++
+ /* only proceed with rest of cleanup if func 1 */
+ brcmf_sdiod_remove(sdiodev);
+
+@@ -1199,6 +1208,8 @@ static int brcmf_ops_sdio_suspend(struct
+ } else {
+ /* power will be cut so remove device, probe again in resume */
+ brcmf_sdiod_intr_unregister(sdiodev);
++ brcmf_sdio_cancel_datawork(sdiodev->bus);
++ brcmf_bus_cancel_reset_work(bus_if);
+ ret = brcmf_sdiod_remove(sdiodev);
+ if (ret)
+ brcmf_err("Failed to remove device on suspend\n");
+@@ -1224,6 +1235,8 @@ static int brcmf_ops_sdio_resume(struct
+ ret = brcmf_sdiod_probe(sdiodev);
+ if (ret)
+ brcmf_err("Failed to probe device on resume\n");
++ else
++ brcmf_bus_allow_reset_work(bus_if);
+ } else {
+ if (sdiodev->wowl_enabled && sdiodev->settings->bus.sdio.oob_irq_supported)
+ disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+@@ -9,6 +9,7 @@
+ #include <linux/kernel.h>
+ #include <linux/firmware.h>
+ #include <linux/device.h>
++#include <linux/mutex.h>
+ #include "debug.h"
+
+ /* IDs of the 6 default common rings of msgbuf protocol */
+@@ -179,6 +180,8 @@ struct brcmf_bus {
+ enum brcmf_fwvendor fwvid;
+ bool always_use_fws_queue;
+ bool wowl_supported;
++ bool removing; /* device removal in progress; quiesce async work */
++ struct mutex bus_reset_lock;
+
+ const struct brcmf_bus_ops *ops;
+ struct brcmf_bus_msgbuf *msgbuf;
+@@ -186,6 +189,9 @@ struct brcmf_bus {
+ struct list_head list;
+ };
+
++void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if);
++void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if);
++
+ /*
+ * callback wrappers
+ */
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -1162,6 +1162,35 @@ static int brcmf_revinfo_read(struct seq
+ return 0;
+ }
+
++/*
++ * Serialize arming from debugfs reset and brcmf_fw_crashed() against
++ * teardown. The remove path sets ->removing and drains the work while
++ * holding bus_reset_lock, so a racing armer is either drained or skips it.
++ */
++static void brcmf_bus_schedule_reset(struct brcmf_bus *bus_if)
++{
++ mutex_lock(&bus_if->bus_reset_lock);
++ if (bus_if->drvr && bus_if->drvr->bus_reset.func && !bus_if->removing)
++ schedule_work(&bus_if->drvr->bus_reset);
++ mutex_unlock(&bus_if->bus_reset_lock);
++}
++
++void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if)
++{
++ mutex_lock(&bus_if->bus_reset_lock);
++ bus_if->removing = true;
++ if (bus_if->drvr)
++ cancel_work_sync(&bus_if->drvr->bus_reset);
++ mutex_unlock(&bus_if->bus_reset_lock);
++}
++
++void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if)
++{
++ mutex_lock(&bus_if->bus_reset_lock);
++ bus_if->removing = false;
++ mutex_unlock(&bus_if->bus_reset_lock);
++}
++
+ static void brcmf_core_bus_reset(struct work_struct *work)
+ {
+ struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
+@@ -1182,7 +1211,7 @@ static ssize_t bus_reset_write(struct fi
+ if (value != 1)
+ return -EINVAL;
+
+- schedule_work(&drvr->bus_reset);
++ brcmf_bus_schedule_reset(drvr->bus_if);
+
+ return count;
+ }
+@@ -1410,14 +1439,23 @@ void brcmf_dev_coredump(struct device *d
+ void brcmf_fw_crashed(struct device *dev)
+ {
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+- struct brcmf_pub *drvr = bus_if->drvr;
++ struct brcmf_pub *drvr;
++
++ /* May fire before brcmf_attach() wires up drvr, or after removal
++ * has cleared it; guard the derefs below (and the arming gate in
++ * brcmf_bus_schedule_reset() already checks drvr/->removing).
++ */
++ if (!bus_if)
++ return;
++ drvr = bus_if->drvr;
++ if (!drvr)
++ return;
+
+ bphy_err(drvr, "Firmware has halted or crashed\n");
+
+ brcmf_dev_coredump(dev);
+
+- if (drvr->bus_reset.func)
+- schedule_work(&drvr->bus_reset);
++ brcmf_bus_schedule_reset(bus_if);
+ }
+
+ void brcmf_detach(struct device *dev)
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+@@ -2462,6 +2462,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, c
+ ret = -ENOMEM;
+ goto fail;
+ }
++ mutex_init(&bus->bus_reset_lock);
+ bus->msgbuf = kzalloc(sizeof(*bus->msgbuf), GFP_KERNEL);
+ if (!bus->msgbuf) {
+ ret = -ENOMEM;
+@@ -2547,6 +2548,11 @@ brcmf_pcie_remove(struct pci_dev *pdev)
+ if (devinfo->ci)
+ brcmf_pcie_intr_disable(devinfo);
+
++ if (devinfo->irq_allocated)
++ synchronize_irq(pdev->irq);
++
++ brcmf_bus_cancel_reset_work(bus);
++
+ brcmf_detach(&pdev->dev);
+ brcmf_free(&pdev->dev);
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -4550,6 +4550,12 @@ fail:
+ return NULL;
+ }
+
++void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus)
++{
++ if (bus)
++ cancel_work_sync(&bus->datawork);
++}
++
+ /* Detach and free everything */
+ void brcmf_sdio_remove(struct brcmf_sdio *bus)
+ {
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
+@@ -361,6 +361,7 @@ int brcmf_sdiod_remove(struct brcmf_sdio
+ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
+ void brcmf_sdio_remove(struct brcmf_sdio *bus);
+ void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr);
++void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus);
+
+ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, bool active);
+ void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -1254,6 +1254,7 @@ static int brcmf_usb_probe_cb(struct brc
+ ret = -ENOMEM;
+ goto fail;
+ }
++ mutex_init(&bus->bus_reset_lock);
+
+ bus->dev = dev;
+ bus_pub->bus = bus;
+@@ -1320,6 +1321,8 @@ brcmf_usb_disconnect_cb(struct brcmf_usb
+ return;
+ brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);
+
++ brcmf_bus_cancel_reset_work(devinfo->bus_pub.bus);
++
+ brcmf_detach(devinfo->dev);
+ brcmf_free(devinfo->dev);
+ kfree(devinfo->bus_pub.bus);
--- /dev/null
+From stable+bounces-296832-greg=kroah.com@vger.kernel.org Thu Aug 6 15:50:30 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 09:49:36 -0400
+Subject: wifi: brcmfmac: fix 43752 SDIO FWVID incorrectly labelled as Cypress (CYW)
+To: stable@vger.kernel.org
+Cc: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>, Arend van Spriel <arend.vanspriel@broadcom.com>, Johannes Berg <johannes.berg@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260806134937.599576-1-sashal@kernel.org>
+
+From: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>
+
+[ Upstream commit 74e2ef72bd4b25ce21c8f309d4f5b91b5df9ff5b ]
+
+Cypress(Infineon) is not the vendor for this 43752 SDIO WLAN chip, and so
+has not officially released any firmware binary for it. It is incorrect to
+maintain this WLAN chip with firmware vendor ID as "CYW". So relabel the
+chip's firmware Vendor ID as "WCC" as suggested by the maintainer.
+
+Fixes: d2587c57ffd8 ("brcmfmac: add 43752 SDIO ids and initialization")
+Fixes: f74f1ec22dc2 ("wifi: brcmfmac: add support for Cypress firmware api")
+Signed-off-by: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>
+Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Link: https://patch.msgid.link/20250724101136.6691-1-gokulkumar.sivakumar@infineon.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Stable-dep-of: 29ab31f3f271 ("wifi: brcmfmac: set F2 blocksize to 256 for BCM43752")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 2 +-
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 4 ++--
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 8 ++++----
+ drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h | 2 +-
+ include/linux/mmc/sdio_ids.h | 2 +-
+ 5 files changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+@@ -991,9 +991,9 @@ static const struct sdio_device_id brcmf
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359, WCC),
++ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43752, WCC),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373, CYW),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012, CYW),
+- BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, CYW),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359, CYW),
+ CYW_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439, CYW),
+ { /* end: all zeroes */ }
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+@@ -738,7 +738,7 @@ static u32 brcmf_chip_tcm_rambase(struct
+ case BRCM_CC_4364_CHIP_ID:
+ case CY_CC_4373_CHIP_ID:
+ return 0x160000;
+- case CY_CC_43752_CHIP_ID:
++ case BRCM_CC_43752_CHIP_ID:
+ case BRCM_CC_4377_CHIP_ID:
+ return 0x170000;
+ case BRCM_CC_4378_CHIP_ID:
+@@ -1465,7 +1465,7 @@ bool brcmf_chip_sr_capable(struct brcmf_
+ reg = chip->ops->read32(chip->ctx, addr);
+ return (reg & CC_SR_CTL0_ENABLE_MASK) != 0;
+ case BRCM_CC_4359_CHIP_ID:
+- case CY_CC_43752_CHIP_ID:
++ case BRCM_CC_43752_CHIP_ID:
+ case CY_CC_43012_CHIP_ID:
+ addr = CORE_CC_REG(pmu->base, retention_ctl);
+ reg = chip->ops->read32(chip->ctx, addr);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -654,10 +654,10 @@ static const struct brcmf_firmware_mappi
+ BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
+ BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
+ BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
++ BRCMF_FW_ENTRY(BRCM_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752),
+ BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373),
+ BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012),
+ BRCMF_FW_ENTRY(CY_CC_43439_CHIP_ID, 0xFFFFFFFF, 43439),
+- BRCMF_FW_ENTRY(CY_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752)
+ };
+
+ #define TXCTL_CREDITS 2
+@@ -3425,8 +3425,8 @@ err:
+
+ static bool brcmf_sdio_aos_no_decode(struct brcmf_sdio *bus)
+ {
+- if (bus->ci->chip == CY_CC_43012_CHIP_ID ||
+- bus->ci->chip == CY_CC_43752_CHIP_ID)
++ if (bus->ci->chip == BRCM_CC_43752_CHIP_ID ||
++ bus->ci->chip == CY_CC_43012_CHIP_ID)
+ return true;
+ else
+ return false;
+@@ -4274,8 +4274,8 @@ static void brcmf_sdio_firmware_callback
+ bus->hostintmask, NULL);
+
+ switch (sdiod->func1->device) {
++ case SDIO_DEVICE_ID_BROADCOM_43752:
+ case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373:
+- case SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752:
+ brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n",
+ CY_4373_F2_WATERMARK);
+ brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK,
+--- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
++++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
+@@ -52,13 +52,13 @@
+ #define BRCM_CC_43664_CHIP_ID 43664
+ #define BRCM_CC_43666_CHIP_ID 43666
+ #define BRCM_CC_4371_CHIP_ID 0x4371
++#define BRCM_CC_43752_CHIP_ID 43752
+ #define BRCM_CC_4377_CHIP_ID 0x4377
+ #define BRCM_CC_4378_CHIP_ID 0x4378
+ #define BRCM_CC_4387_CHIP_ID 0x4387
+ #define CY_CC_4373_CHIP_ID 0x4373
+ #define CY_CC_43012_CHIP_ID 43012
+ #define CY_CC_43439_CHIP_ID 43439
+-#define CY_CC_43752_CHIP_ID 43752
+
+ /* USB Device IDs */
+ #define BRCM_USB_43143_DEVICE_ID 0xbd1e
+--- a/include/linux/mmc/sdio_ids.h
++++ b/include/linux/mmc/sdio_ids.h
+@@ -76,7 +76,7 @@
+ #define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6
+ #define SDIO_DEVICE_ID_BROADCOM_43439 0xa9af
+ #define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf
+-#define SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752 0xaae8
++#define SDIO_DEVICE_ID_BROADCOM_43752 0xaae8
+
+ #define SDIO_VENDOR_ID_CYPRESS 0x04b4
+ #define SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439 0xbd3d
--- /dev/null
+From stable+bounces-296833-greg=kroah.com@vger.kernel.org Thu Aug 6 15:50:34 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 09:49:37 -0400
+Subject: wifi: brcmfmac: set F2 blocksize to 256 for BCM43752
+To: stable@vger.kernel.org
+Cc: LiangCheng Wang <zaq14760@gmail.com>, Arend van Spriel <arend.vanspriel@broadcom.com>, Johannes Berg <johannes.berg@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260806134937.599576-2-sashal@kernel.org>
+
+From: LiangCheng Wang <zaq14760@gmail.com>
+
+[ Upstream commit 29ab31f3f27157648f2f7e6d5e1fd9792fdf0614 ]
+
+The BCM43752 is not reliable with the default 512-byte SDIO function 2
+block size: on an i.MX8MP board with an AMPAK AP6275S module at
+SDR104 / 200 MHz, an iperf TX stress test kills WLAN within seconds:
+
+ mmc_submit_one: CMD53 sg block write failed -84
+ brcmf_sdio_dpc: failed backplane access over SDIO, halting operation
+
+Commit d2587c57ffd8 ("brcmfmac: add 43752 SDIO ids and initialization")
+set up the 43752 like the 4373 for the F2 watermark but missed the F2
+block size, which the 4373 limits to 256 bytes. The vendor driver
+(bcmdhd) also programs a 256-byte F2 block size for this chip and runs
+the same hardware without errors.
+
+Group the 43752 with the 4373, matching the F2 watermark handling.
+With this change a 10-minute bidirectional iperf3 soak completes with
+zero SDIO errors at ~270 Mbit/s in each direction.
+
+Backporting note: kernels before v6.18 name this id
+SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, so on those trees the case
+label added by this patch must be adjusted to that name. Cherry-picking
+the rename commit 74e2ef72bd4b ("wifi: brcmfmac: fix 43752 SDIO FWVID
+incorrectly labelled as Cypress (CYW)") first is not a clean
+alternative: on trees before v6.17 its context collides with the 43751
+additions, and trees before v6.2 lack the FWVID framework it touches.
+
+Fixes: d2587c57ffd8 ("brcmfmac: add 43752 SDIO ids and initialization")
+Cc: stable@vger.kernel.org # see patch description, needs adjustments for <= 6.17
+Signed-off-by: LiangCheng Wang <zaq14760@gmail.com>
+Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Link: https://patch.msgid.link/20260715-b43752-f2-blksz-v2-1-f9be49856050@gmail.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+@@ -906,6 +906,7 @@ int brcmf_sdiod_probe(struct brcmf_sdio_
+ return ret;
+ }
+ switch (sdiodev->func2->device) {
++ case SDIO_DEVICE_ID_BROADCOM_43752:
+ case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373:
+ f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE;
+ break;