--- /dev/null
+From stable+bounces-295111-greg=kroah.com@vger.kernel.org Tue Aug 4 13:01:09 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 06:47:12 -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: <20260804104712.2825343-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
+@@ -1762,6 +1762,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
+@@ -915,6 +915,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;
+@@ -1190,6 +1192,7 @@ static int wave5_set_enc_openparam(struc
+ 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;
+@@ -1662,7 +1665,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
+@@ -570,6 +570,7 @@ struct enc_wave_param {
+ u32 transform8x8_enable: 1; /* enable 8x8 intra prediction and 8x8 transform */
+ u32 mb_level_rc_enable: 1; /* enable MB-level rate control */
+ u32 forced_idr_header_enable: 1; /* enable header encoding before IDR frame */
++ u32 constraint_set1_flag: 1; /* enable CBP */
+ };
+
+ struct enc_open_param {
--- /dev/null
+From stable+bounces-295295-greg=kroah.com@vger.kernel.org Wed Aug 5 02:10:21 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 20:08:32 -0400
+Subject: media: qcom: camss: csid-340: Fix unused variables
+To: stable@vger.kernel.org
+Cc: Loic Poulain <loic.poulain@oss.qualcomm.com>, Bryan O'Donoghue <bryan.odonoghue@linaro.org>, Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>, Bryan O'Donoghue <bod@kernel.org>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260805000833.3902619-1-sashal@kernel.org>
+
+From: Loic Poulain <loic.poulain@oss.qualcomm.com>
+
+[ Upstream commit 0b61ce8dc4a71ea7baa19275c655677c612dde6d ]
+
+The CSID driver has some unused variables and function parameters
+that are no longer needed (due to refactoring). Clean up those
+unused elements:
+
+- Remove the `vc` parameter from `__csid_configure_rx()`.
+- Drop the unused `lane_cnt` variable.
+- Adjust call to `__csid_configure_rx()` accordingly.
+
+Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
+Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
+Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+Stable-dep-of: cc1c35619c98 ("media: qcom: camss: Fix RDI streaming for CSID 340")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/platform/qcom/camss/camss-csid-340.c | 10 +++-------
+ 1 file changed, 3 insertions(+), 7 deletions(-)
+
+--- a/drivers/media/platform/qcom/camss/camss-csid-340.c
++++ b/drivers/media/platform/qcom/camss/camss-csid-340.c
+@@ -55,8 +55,7 @@
+ #define CSID_RDI_CTRL_HALT_AT_FRAME_BOUNDARY 0
+ #define CSID_RDI_CTRL_RESUME_AT_FRAME_BOUNDARY 1
+
+-static void __csid_configure_rx(struct csid_device *csid,
+- struct csid_phy_config *phy, int vc)
++static void __csid_configure_rx(struct csid_device *csid, struct csid_phy_config *phy)
+ {
+ u32 val;
+
+@@ -81,13 +80,9 @@ static void __csid_configure_rdi_stream(
+ const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats,
+ csid->res->formats->nformats,
+ input_format->code);
+- u8 lane_cnt = csid->phy.lane_cnt;
+ u8 dt_id;
+ u32 val;
+
+- if (!lane_cnt)
+- lane_cnt = 4;
+-
+ /*
+ * DT_ID is a two bit bitfield that is concatenated with
+ * the four least significant bits of the five bit VC
+@@ -120,10 +115,11 @@ static void csid_configure_stream(struct
+ {
+ int i;
+
++ __csid_configure_rx(csid, &csid->phy);
++
+ for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) {
+ if (csid->phy.en_vc & BIT(i)) {
+ __csid_configure_rdi_stream(csid, enable, i);
+- __csid_configure_rx(csid, &csid->phy, i);
+ __csid_ctrl_rdi(csid, enable, i);
+ }
+ }
--- /dev/null
+From stable+bounces-295296-greg=kroah.com@vger.kernel.org Wed Aug 5 02:10:26 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 20:08:33 -0400
+Subject: media: qcom: camss: Fix RDI streaming for CSID 340
+To: stable@vger.kernel.org
+Cc: Bryan O'Donoghue <bryan.odonoghue@linaro.org>, Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>, Loic Poulain <loic.poulain@oss.qualcomm.com>, Bryan O'Donoghue <bod@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260805000833.3902619-2-sashal@kernel.org>
+
+From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+
+[ Upstream commit cc1c35619c9895f918f9e388e3caa6ab2ff2fbe7 ]
+
+Fix streaming from CSIDn RDI1 and RDI2 to VFEn RDI1 and RDI2. A pattern we
+have replicated throughout CAMSS where we use the VC number to populate
+both the VC fields and port fields of the CSID means that in practice only
+VC = 0 on CSIDn:RDI0 to VFEn:RDI0 works.
+
+Fix that for CSID 340 by separating VC and port. Fix to VC zero as a bugfix
+we will look to properly populate the VC field with follow on patches
+later.
+
+Fixes: f0fc808a466a ("media: qcom: camss: Add CSID 340 support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
+Reviewed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
+Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/platform/qcom/camss/camss-csid-340.c | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+--- a/drivers/media/platform/qcom/camss/camss-csid-340.c
++++ b/drivers/media/platform/qcom/camss/camss-csid-340.c
+@@ -74,9 +74,9 @@ static void __csid_ctrl_rdi(struct csid_
+ writel_relaxed(!!enable, csid->base + CSID_RDI_CTRL(rdi));
+ }
+
+-static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc)
++static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc)
+ {
+- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc];
++ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port];
+ const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats,
+ csid->res->formats->nformats,
+ input_format->code);
+@@ -88,14 +88,14 @@ static void __csid_configure_rdi_stream(
+ * the four least significant bits of the five bit VC
+ * bitfield to generate an internal CID value.
+ *
+- * CSID_RDI_CFG0(vc)
++ * CSID_RDI_CFG0(port)
+ * DT_ID : 28:27
+ * VC : 26:22
+ * DT : 21:16
+ *
+ * CID : VC 3:0 << 2 | DT_ID 1:0
+ */
+- dt_id = vc & 0x03;
++ dt_id = port & 0x03;
+
+ val = CSID_RDI_CFG0_DECODE_FORMAT_NOP; /* only for RDI path */
+ val |= FIELD_PREP(CSID_RDI_CFG0_DT_MASK, format->data_type);
+@@ -105,10 +105,11 @@ static void __csid_configure_rdi_stream(
+ if (enable)
+ val |= CSID_RDI_CFG0_ENABLE;
+
+- dev_dbg(csid->camss->dev, "CSID%u: Stream %s (dt:0x%x vc=%u)\n",
+- csid->id, enable ? "enable" : "disable", format->data_type, vc);
++ dev_dbg(csid->camss->dev, "CSID%u: Stream %s (dt:0x%x port=%u vc=%u)\n",
++ csid->id, enable ? "enable" : "disable", format->data_type,
++ port, vc);
+
+- writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc));
++ writel_relaxed(val, csid->base + CSID_RDI_CFG0(port));
+ }
+
+ static void csid_configure_stream(struct csid_device *csid, u8 enable)
+@@ -117,9 +118,10 @@ static void csid_configure_stream(struct
+
+ __csid_configure_rx(csid, &csid->phy);
+
++ /* Loop through all enabled ports and configure a stream for each */
+ for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) {
+ if (csid->phy.en_vc & BIT(i)) {
+- __csid_configure_rdi_stream(csid, enable, i);
++ __csid_configure_rdi_stream(csid, enable, i, 0);
+ __csid_ctrl_rdi(csid, enable, i);
+ }
+ }
--- /dev/null
+From stable+bounces-296805-greg=kroah.com@vger.kernel.org Thu Aug 6 14:46:50 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 08:46:34 -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: <20260806124634.299943-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
+@@ -1583,11 +1583,11 @@ struct rkisp1_ext_params_wdr_config {
+ sizeof(struct rkisp1_ext_params_wdr_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,
+ };
+
+@@ -1667,7 +1667,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
net-handshake-hand-off-the-pinned-file-reference-to-.patch
net-handshake-close-the-submit-side-sock_hold-race.patch
net-handshake-drain-pending-requests-at-net-namespac.patch
+usb-typec-ucsi-split-connector-lock-classes.patch
+usb-typec-ucsi-fix-race-condition-and-ordering-in-port-unregistration.patch
+media-chips-media-wave5-support-cbp-profile.patch
+media-qcom-camss-csid-340-fix-unused-variables.patch
+media-qcom-camss-fix-rdi-streaming-for-csid-340.patch
+media-uapi-rkisp-correct-name-version-enum.patch
+wifi-brcmfmac-drain-bus_reset-work-on-device-removal.patch
+userfaultfd-prevent-registration-of-special-vmas.patch
--- /dev/null
+From sashal@kernel.org Thu Jul 30 21:29:55 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 15:29:52 -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: <20260730192952.3124595-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
+@@ -1891,6 +1891,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;
+@@ -2017,22 +2053,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));
+@@ -2260,33 +2282,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:29:55 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 15:29:51 -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: <20260730192952.3124595-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
+@@ -1741,6 +1741,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;
+
+@@ -1981,6 +1982,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;
+@@ -2010,6 +2014,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);
+@@ -2280,6 +2287,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
+@@ -502,6 +502,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-297128-greg=kroah.com@vger.kernel.org Fri Aug 7 05:36:00 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 23:34:59 -0400
+Subject: userfaultfd: prevent registration of special VMAs
+To: stable@vger.kernel.org
+Cc: "Mike Rapoport (Microsoft)" <rppt@kernel.org>, vova tokarev <vladimirelitokarev@gmail.com>, "David Hildenbrand (Arm)" <david@kernel.org>, Lorenzo Stoakes <ljs@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>, Christian Brauner <brauner@kernel.org>, Jan Kara <jack@suse.cz>, Linus Torvalds <torvalds@linuxfoundation.org>, Oleg Nesterov <oleg@redhat.com>, Peter Xu <peterx@redhat.com>, Andrew Morton <akpm@linux-foundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260807033459.1725973-1-sashal@kernel.org>
+
+From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
+
+[ Upstream commit 3c58f641e813c3c71039f8fd4d4e2a3aab713288 ]
+
+Vova Tokarev says:
+
+ userfaultfd allows registration on shadow stack VMAs. With userfaultfd
+ access, you can register on the shadow stack, discard a page ... and
+ inject a page with chosen return addresses via UFFDIO_COPY.
+
+Update vma_can_userfault() to reject VM_SHADOW_STACK.
+
+While on it, also reject VM_SPECIAL so that if a driver would implement
+vm_uffd_ops, it wouldn't be possible to register special VMAs with
+userfaultfd.
+
+Since VM_SPECIAL includes VM_DONTEXPAND which is set but hugetlb, exclude
+hugetlb VMAs from the check for VM_SPECIAL.
+
+Link: https://lore.kernel.org/20260618095017.2553004-1-rppt@kernel.org
+Fixes: 54007f818206 ("mm: Introduce VM_SHADOW_STACK for shadow stack memory")
+Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
+Reported-by: vova tokarev <vladimirelitokarev@gmail.com>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
+Cc: Al Viro <viro@zeniv.linux.org.uk>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: Jan Kara <jack@suse.cz>
+Cc: Linus Torvalds <torvalds@linuxfoundation.org>
+Cc: Mike Rapoport <rppt@kernel.org>
+Cc: Oleg Nesterov <oleg@redhat.com>
+Cc: Peter Xu <peterx@redhat.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>
+---
+ include/linux/userfaultfd_k.h | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/include/linux/userfaultfd_k.h
++++ b/include/linux/userfaultfd_k.h
+@@ -214,7 +214,10 @@ static inline bool vma_can_userfault(str
+ {
+ vm_flags &= __VM_UFFD_FLAGS;
+
+- if (vma->vm_flags & VM_DROPPABLE)
++ if (vma->vm_flags & (VM_DROPPABLE | VM_SHADOW_STACK))
++ return false;
++
++ if (!is_vm_hugetlb_page(vma) && (vma->vm_flags & VM_SPECIAL))
+ return false;
+
+ if ((vm_flags & VM_UFFD_MINOR) &&
--- /dev/null
+From stable+bounces-296817-greg=kroah.com@vger.kernel.org Thu Aug 6 15:18:34 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 09:17:40 -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: <20260806131740.402812-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
+@@ -1070,6 +1070,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);
+@@ -1131,6 +1132,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);
+
+@@ -1205,6 +1214,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");
+@@ -1230,6 +1241,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
+@@ -1167,6 +1167,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,
+@@ -1187,7 +1216,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;
+ }
+@@ -1417,14 +1446,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
+@@ -2504,6 +2504,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;
+@@ -2599,6 +2600,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
+@@ -4560,6 +4560,12 @@ fail:
+ return ret;
+ }
+
++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
+ int 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
+@@ -1260,6 +1260,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;
+@@ -1329,6 +1330,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);