From nobody Mon Sep 28 23:56:19 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4457A377A8E; Fri, 14 Aug 2026 20:16:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786738611; cv=none; b=HwG6ZutsYayx248E2wIVUz3/WLvfBEtkJX/p6SReYWvNO+ADFE23BkBsYJzlYfTvdagGGlbia4EijW+ZyYEvRwO9tr/2jBkYlr4KkSZswR/JQcaP+gaNn91jOnKpBmYoZurcw0goCkW74+10sbFVIMYaA7s7vsWNoyDPiYTNeco= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786738611; c=relaxed/simple; bh=XfOxtLqm+gTaszkcqBFfA+yichex03j+Zn51l2FB75A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=GARHHPP2UHB12EjIg3RUkboFt4UbXuvkPKaucOZHwvjJEQsKsx4FYvavykWQjjGb0UbAsLxmfNX5yr5nF/GHL9mhNI4WbKXzQ9lZ35Z7hAbLxdp4AeySj2jrUL+P9S0BFQHuw1SF7tFjIjngKXafHh/flVmvJxlJSdNR8OMWw60= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=sx6iy5xj; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="sx6iy5xj" Received: by smtp.kernel.org (Postfix) with ESMTPS id DCDEFC2BCF6; Fri, 14 Aug 2026 20:16:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786738610; bh=XfOxtLqm+gTaszkcqBFfA+yichex03j+Zn51l2FB75A=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=sx6iy5xjJCRiOo0GUqnLsxAZ6VNrFdnYE786CUnOFElvGfO/ob/msGvKhfV7AvugK Sf/3FvIWeBpenuN0TkJTHq+aIA8YziT90m7ewRKcfyG3mkh/KglcnZkitRxq9f4Tc2 My9nZXgNcn52rWpmi9J0tiUSUNFo9SZ/jUUObt6PuG8chRl0l2jGtaF+Bciesy2rV4 LMZK1Bg/PyOhZ3HNsh7/MY1Oasrc10Z2DEXmwEEG83VhdYuLYAQOpoDjJicoCrOgh4 DgdkmfR+wvBCfzFCv+C4khsxkSigCxJUicFAH1ILU+i08uQai2gOGJV9qGlpO1bLZE 9GqZMmtDaBPWA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id BEC67C5CFC1; Fri, 14 Aug 2026 20:16:50 +0000 (UTC) From: Roland Dreier via B4 Relay Date: Fri, 14 Aug 2026 20:15:33 +0000 Subject: [PATCH 1/2] firmware: arm_scmi: Protect xfer->async_done with xfer->lock Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-scmi-async-done-race-v1-1-335b163d77ee@rivian.com> References: <20260814-scmi-async-done-race-v1-0-335b163d77ee@rivian.com> In-Reply-To: <20260814-scmi-async-done-race-v1-0-335b163d77ee@rivian.com> To: Sudeep Holla , Cristian Marussi Cc: arm-scmi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786738610; l=9843; i=rolanddreier@rivian.com; s=20260814; h=from:subject:message-id; bh=KwnqXNyT6Amma15ZNEtaoQkZXX80va0zk2YGE2S3CtM=; b=OvOwIEoLb6m3ktIPx8G0AaYkYWUS/gxsFOqerimJi/1sCeP2XOL5lJIoYIxbSo2ExYbxi7IMQ 6jihaGXyNaDC4J7zfmhBLRpRMnCdhSBdlbKPZ2TiAwjtGjPjrZA/mrD X-Developer-Key: i=rolanddreier@rivian.com; a=ed25519; pk=C7SBXsDIlarq7BpINqyDL67XV/AGNqNt09NCCpFcExk= X-Endpoint-Received: by B4 Relay for rolanddreier@rivian.com/20260814 with auth_id=952 X-Original-From: Roland Dreier Reply-To: rolanddreier@rivian.com From: Roland Dreier Asynchronous SCMI commands are completed by a delayed response. The RX path signals the response with complete(xfer->async_done). Unlike xfer->done, xfer->async_done is a pointer to a completion owned by whoever is waiting for the delayed response, and it stays valid only for as long as that waiter is still waiting. In do_xfer_with_response() it is a DECLARE_COMPLETION_ONSTACK() in the caller's stack frame. Nothing serialises the RX path against a waiter that gives up on a timeout. scmi_msg_response_validate() does read xfer->async_done under xfer->lock, and documents that as a requirement, but the lock is dropped again before scmi_handle_response() dereferences the pointer, and neither the arming nor the disarming side takes it at all. So a delayed response arriving just as the wait times out can be signalled on a completion that is already gone: waiter RX path (IRQ context) ------ --------------------- do_xfer_with_response(): xfer->async_done =3D &async_response do_xfer(xfer) wait_for_completion_timeout(xfer->async_done, tmo) /* returns 0, gives up */ /* response receive interrupt */ scmi_handle_response(): scmi_xfer_command_acquire() lock xfer->lock validate: async_done !=3D NULL unlock xfer->lock xfer->async_done =3D NULL return -ETIMEDOUT /* async_response goes out of scope */ complete(xfer->async_done) That last complete() has two possible bad outcomes: it either dereferences the NULL just stored by the waiter or - if that store is not yet visible on the RX CPU - it takes a lock and writes to a stack frame that the waiter maybe has already returned from. Fix this by making xfer->lock cover xfer->async_done end-to-end. Add helpers to arm and disarm it under the lock, use them on both the regular and the raw paths, and have the RX path read and signal the completion under that same lock. A waiter that is timing out then either completes its disarm before the RX path looks, in which case the delayed response is dropped, or blocks in the disarm until the RX path is done with the completion, in which case the completion is still alive. Account for the dropped case with a new "delayed_response_dropped" debugfs counter to make it visible if this ever happens. Fixes: 58ecdf03dbb9 ("firmware: arm_scmi: Add support for asynchronous comm= ands and delayed response") Signed-off-by: Roland Dreier --- drivers/firmware/arm_scmi/common.h | 23 +++++++++++++++++++++++ drivers/firmware/arm_scmi/driver.c | 35 ++++++++++++++++++++++++++++++-= ---- drivers/firmware/arm_scmi/protocols.h | 9 ++++++--- drivers/firmware/arm_scmi/raw_mode.c | 4 ++-- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi= /common.h index b9723c105fc1..fc2f69bcebff 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -282,6 +282,28 @@ static inline bool is_polling_enabled(struct scmi_chan= _info *cinfo, is_transport_polling_capable(desc); } =20 +/** + * scmi_xfer_async_response_arm - Arm the delayed response completion + * + * @xfer: A reference to the xfer to arm + * @async_done: The completion to signal upon reception of a delayed respo= nse, + * or NULL to disarm @xfer. + */ +static inline void scmi_xfer_async_response_arm(struct scmi_xfer *xfer, + struct completion *async_done) +{ + unsigned long flags; + + spin_lock_irqsave(&xfer->lock, flags); + xfer->async_done =3D async_done; + spin_unlock_irqrestore(&xfer->lock, flags); +} + +static inline void scmi_xfer_async_response_disarm(struct scmi_xfer *xfer) +{ + scmi_xfer_async_response_arm(xfer, NULL); +} + void scmi_xfer_raw_put(const struct scmi_handle *handle, struct scmi_xfer *xfer); struct scmi_xfer *scmi_xfer_raw_get(const struct scmi_handle *handle); @@ -303,6 +325,7 @@ enum debug_counters { RESPONSE_OK, NOTIFICATION_OK, DELAYED_RESPONSE_OK, + DELAYED_RESPONSE_DROPPED, XFERS_RESPONSE_TIMEOUT, XFERS_RESPONSE_POLLED_TIMEOUT, RESPONSE_POLLED_OK, diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi= /driver.c index 3e0d975ec94c..5c295bdc15ca 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -1063,6 +1063,28 @@ static inline void scmi_xfer_command_release(struct = scmi_info *info, __scmi_xfer_put(&info->tx_minfo, xfer); } =20 +/** + * scmi_xfer_async_response_complete - Signal a received delayed response + * + * @xfer: A reference to the xfer whose delayed response was received + * + * Return: True if a completion was still armed on @xfer and has been + * signalled, false if a timed-out waiter had already disarmed it. + */ +static bool scmi_xfer_async_response_complete(struct scmi_xfer *xfer) +{ + unsigned long flags; + struct completion *async_done; + + spin_lock_irqsave(&xfer->lock, flags); + async_done =3D xfer->async_done; + if (async_done) + complete(async_done); + spin_unlock_irqrestore(&xfer->lock, flags); + + return !!async_done; +} + static inline void scmi_clear_channel(struct scmi_info *info, struct scmi_chan_info *cinfo) { @@ -1166,8 +1188,10 @@ static void scmi_handle_response(struct scmi_chan_in= fo *cinfo, =20 if (xfer->hdr.type =3D=3D MSG_TYPE_DELAYED_RESP) { scmi_clear_channel(info, cinfo); - complete(xfer->async_done); - scmi_inc_count(info->dbg, DELAYED_RESPONSE_OK); + if (scmi_xfer_async_response_complete(xfer)) + scmi_inc_count(info->dbg, DELAYED_RESPONSE_OK); + else + scmi_inc_count(info->dbg, DELAYED_RESPONSE_DROPPED); } else { complete(&xfer->done); scmi_inc_count(info->dbg, RESPONSE_OK); @@ -1509,7 +1533,7 @@ static int do_xfer_with_response(const struct scmi_pr= otocol_handle *ph, int ret, timeout =3D msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT); DECLARE_COMPLETION_ONSTACK(async_response); =20 - xfer->async_done =3D &async_response; + scmi_xfer_async_response_arm(xfer, &async_response); =20 /* * Delayed responses should not be polled, so an async command should @@ -1521,7 +1545,7 @@ static int do_xfer_with_response(const struct scmi_pr= otocol_handle *ph, =20 ret =3D do_xfer(ph, xfer); if (!ret) { - if (!wait_for_completion_timeout(xfer->async_done, timeout)) { + if (!wait_for_completion_timeout(&async_response, timeout)) { dev_err(ph->dev, "timed out in delayed resp(caller: %pS)\n", (void *)_RET_IP_); @@ -1531,7 +1555,7 @@ static int do_xfer_with_response(const struct scmi_pr= otocol_handle *ph, } } =20 - xfer->async_done =3D NULL; + scmi_xfer_async_response_disarm(xfer); return ret; } =20 @@ -2989,6 +3013,7 @@ static const char * const dbg_counter_strs[] =3D { "response_ok", "notification_ok", "delayed_response_ok", + "delayed_response_dropped", "xfers_response_timeout", "xfers_response_polled_timeout", "response_polled_ok", diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_s= cmi/protocols.h index 15ad5162e37a..8583159059e6 100644 --- a/drivers/firmware/arm_scmi/protocols.h +++ b/drivers/firmware/arm_scmi/protocols.h @@ -100,7 +100,10 @@ struct scmi_msg_hdr { * message. If request-ACK protocol is used, we can reuse the same * buffer for the rx path as we use for the tx path. * @done: command message transmit completion event - * @async_done: pointer to delayed response message received event complet= ion + * @async_done: pointer to delayed response message received event complet= ion, + * or NULL when no delayed response is expected. Protected by + * @lock, since the completion is owned by the waiter and can + * vanish once the wait times out. * @pending: True for xfers added to @pending_xfers hashtable * @node: An hlist_node reference used to store this xfer, alternatively, = on * the free list @free_xfers or in the @pending_xfers hashtable @@ -121,7 +124,7 @@ struct scmi_msg_hdr { * - SCMI_XFER_SENT_OK -> SCMI_XFER_DRESP_OK * (Missing synchronous response is assumed OK and ignored) * @flags: Optional flags associated to this xfer. - * @lock: A spinlock to protect state and busy fields. + * @lock: A spinlock to protect state, busy and async_done fields. * @priv: A pointer for transport private usage. */ struct scmi_xfer { @@ -147,7 +150,7 @@ struct scmi_xfer { #define SCMI_XFER_IS_CHAN_SET(x) \ ((x)->flags & SCMI_XFER_FLAG_CHAN_SET) int flags; - /* A lock to protect state and busy fields */ + /* A lock to protect state, busy and async_done fields */ spinlock_t lock; void *priv; }; diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_sc= mi/raw_mode.c index 1f6e51670208..8751cff5fa4e 100644 --- a/drivers/firmware/arm_scmi/raw_mode.c +++ b/drivers/firmware/arm_scmi/raw_mode.c @@ -346,7 +346,7 @@ scmi_xfer_raw_waiter_get(struct scmi_raw_mode_info *raw= , struct scmi_xfer *xfer, =20 if (async) { reinit_completion(&rw->async_response); - xfer->async_done =3D &rw->async_response; + scmi_xfer_async_response_arm(xfer, &rw->async_response); } =20 rw->cinfo =3D cinfo; @@ -361,7 +361,7 @@ static void scmi_xfer_raw_waiter_put(struct scmi_raw_mo= de_info *raw, struct scmi_xfer_raw_waiter *rw) { if (rw->xfer) { - rw->xfer->async_done =3D NULL; + scmi_xfer_async_response_disarm(rw->xfer); rw->xfer =3D NULL; } =20 --=20 2.54.0 From nobody Mon Sep 28 23:56:19 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 444EA36C0AB; Fri, 14 Aug 2026 20:16:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786738611; cv=none; b=LVKJZKbK1jW92QbYnbvKjOmESvRArdNdZcBqcr9HUOJJXYCdfPI7Hmrn5mk/M8lZpfuE4F03dw3kA01MNRmd+LvgwJLWnuW4GgfjOarSgq4RjTFVUeavrnbz409e0uN+cmCAGhhmzkBvHZtTH+ZxF69XfmxZv/asJ94mV6fneuM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786738611; c=relaxed/simple; bh=LZjtXCDShyRpD0WCxXfHRzNphgo0OLUug+gzLi3ndAw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IcHZd8RbDadChrSKCrKVde8ou4y0k4S5qKHjlS163AqHQ5I6hFzLOdWW2GrozYq/oVZHn4nlfb27DL04r337YqKzt2ZCDFcqMMkhqVNEOJAWtzDNYKk+wXW4ji8k2gYa/plGacVdlKcNOmGLT5ZZ6rQOxDrx5w7cOnml6bJafco= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=chRfl/I+; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="chRfl/I+" Received: by smtp.kernel.org (Postfix) with ESMTPS id EC8A5C2BCC7; Fri, 14 Aug 2026 20:16:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786738611; bh=LZjtXCDShyRpD0WCxXfHRzNphgo0OLUug+gzLi3ndAw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=chRfl/I+DbGm/4LsFDA53YW/5tC8k3g12PCZHkz1Es2/m5si2FWVRNG7CCXVZjrXQ pL0IRsenMrOz8cKe9kSfwFVBEsZ7trzNSNQDdas4ggufSEX3ipfGUxR6acpz3kMg5B ch2PwOtjgyg2YDbU59Q3/6aZaqOYFnBVQTZoqcy9sVCu/eell0er4JS5CHGnh72+CO cjiy1re7R7eHhtW43bG5n2bP72CLw8Kmtq6YQLio6mxO43RKfK/YFYWXuUIUQ9qe2L NMzYducnHE+DjtAEB2xtkGD5XkUnlEDttCeNHVULNAOfbjBYMjDIxmkozQL4TLG43D SO/cuudMT9qNw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id CE715C5B572; Fri, 14 Aug 2026 20:16:50 +0000 (UTC) From: Roland Dreier via B4 Relay Date: Fri, 14 Aug 2026 20:15:34 +0000 Subject: [PATCH 2/2] firmware: arm_scmi: Don't reuse raw xfers with async_done still armed Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-scmi-async-done-race-v1-2-335b163d77ee@rivian.com> References: <20260814-scmi-async-done-race-v1-0-335b163d77ee@rivian.com> In-Reply-To: <20260814-scmi-async-done-race-v1-0-335b163d77ee@rivian.com> To: Sudeep Holla , Cristian Marussi Cc: arm-scmi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786738610; l=4879; i=rolanddreier@rivian.com; s=20260814; h=from:subject:message-id; bh=aqIhjaSz9fKkzEo4GuOhvlrH00CQYmUwOQr9QXIf5Jo=; b=evzyvugfDaX7dnnkvKbVe3CKGKGcTE6vnyM11pz/nchePPP9ujKpxeu5l4QqKyATZaSwS4jjo NK/c7jWsmjzBBAX5JaJYLt0UNaC6J+eRkZOqnLiAQdVULDmiDghK5UV X-Developer-Key: i=rolanddreier@rivian.com; a=ed25519; pk=C7SBXsDIlarq7BpINqyDL67XV/AGNqNt09NCCpFcExk= X-Endpoint-Received: by B4 Relay for rolanddreier@rivian.com/20260814 with auth_id=952 X-Original-From: Roland Dreier Reply-To: rolanddreier@rivian.com From: Roland Dreier In SCMI raw mode, scmi_xfer_raw_worker() releases the xfer before releasing the waiter that disarms xfer->async_done, and scmi_xfer_get() does not clear async_done when it hands out a recycled xfer. A concurrent transaction can therefore pick up the xfer while it still points at the old waiter's completion, so: - a delayed response arriving for the new transaction can be signalled on the old waiter's completion, which may already be re-armed for yet another unrelated transaction, making that transaction's wait return early; and - the old waiter's disarm, which still runs after the xfer has been released, clobbers the arming just installed by the new transaction, so the new waiter times out even if its delayed response arrives. Release the waiter first, while the worker still holds a reference on the xfer, so that an xfer can never reach the free list still armed. Track whether a delayed response is expected in the waiter itself instead of peeking at xfer->async_done outside xfer->lock, and wait on the waiter's own embedded completion. (The new async flag is not strictly needed but it makes the logic easier to reason about) Finally, harden scmi_xfer_get() to clear async_done when handing out an xfer, so that no future release-ordering change can leak a stale arming into a new transaction. Fixes: 3c3d818a9317 ("firmware: arm_scmi: Add core raw transmission support= ") Signed-off-by: Roland Dreier Reviewed-by: Cristian Marussi Tested-by: Cristian Marussi --- drivers/firmware/arm_scmi/driver.c | 1 + drivers/firmware/arm_scmi/raw_mode.c | 25 +++++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi= /driver.c index 5c295bdc15ca..2d8884f0036b 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -717,6 +717,7 @@ static struct scmi_xfer *scmi_xfer_get(const struct scm= i_handle *handle, =20 refcount_set(&xfer->users, 1); atomic_set(&xfer->busy, SCMI_XFER_FREE); + xfer->async_done =3D NULL; spin_unlock_irqrestore(&minfo->xfer_lock, flags); =20 return xfer; diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_sc= mi/raw_mode.c index 8751cff5fa4e..5ee21f6b7001 100644 --- a/drivers/firmware/arm_scmi/raw_mode.c +++ b/drivers/firmware/arm_scmi/raw_mode.c @@ -198,6 +198,8 @@ struct scmi_raw_mode_info { * @async_response: A completion to be, optionally, used for async waits: = it * will be setup by @scmi_do_xfer_raw_start, if needed, to be * pointed at by xfer->async_done. + * @async: True if @async_response was armed on @xfer, i.e. if a delayed + * response has to be waited for. * @node: A list node. */ struct scmi_xfer_raw_waiter { @@ -205,6 +207,7 @@ struct scmi_xfer_raw_waiter { struct scmi_chan_info *cinfo; struct scmi_xfer *xfer; struct completion async_response; + bool async; struct list_head node; }; =20 @@ -349,6 +352,7 @@ scmi_xfer_raw_waiter_get(struct scmi_raw_mode_info *raw= , struct scmi_xfer *xfer, scmi_xfer_async_response_arm(xfer, &rw->async_response); } =20 + rw->async =3D async; rw->cinfo =3D cinfo; rw->xfer =3D xfer; } @@ -361,8 +365,16 @@ static void scmi_xfer_raw_waiter_put(struct scmi_raw_m= ode_info *raw, struct scmi_xfer_raw_waiter *rw) { if (rw->xfer) { + /* + * Disarm the delayed response before this waiter, and its + * embedded completion, can be picked up again for a new + * transaction: a delayed response received late, after the + * related wait timed out, must not signal a completion which + * has been in the meantime re-armed on a different xfer. + */ scmi_xfer_async_response_disarm(rw->xfer); rw->xfer =3D NULL; + rw->async =3D false; } =20 mutex_lock(&raw->free_mtx); @@ -479,18 +491,23 @@ static void scmi_xfer_raw_worker(struct work_struct *= work) ret, scmi_inflight_count(raw->handle)); =20 /* Wait also for an async delayed response if needed */ - if (!ret && xfer->async_done) { + if (!ret && rw->async) { unsigned long tmo =3D msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT); =20 - if (!wait_for_completion_timeout(xfer->async_done, tmo)) + if (!wait_for_completion_timeout(&rw->async_response, tmo)) dev_err(dev, "timed out in RAW delayed resp - HDR:%08X\n", pack_scmi_header(&xfer->hdr)); } =20 - /* Release waiter and xfer */ - scmi_xfer_raw_put(raw->handle, xfer); + /* + * Release the waiter first: this disarms the delayed response + * while we still hold a reference on the xfer, so that the xfer + * cannot be recycled by a new transaction while it still points + * at this waiter's completion. + */ scmi_xfer_raw_waiter_put(raw, rw); + scmi_xfer_raw_put(raw->handle, xfer); } while (1); } =20 --=20 2.54.0