From nobody Sun May 24 20:34:05 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 766C43BBA01 for ; Thu, 21 May 2026 12:27:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779366422; cv=none; b=HeKTpuwLzuFBmM3JardfsW987sYdCMK0tgwrXbmN1diJjwyrbChv8dmxgZ6Kf5+0Vg6gcDGZXHcPQn/TP7/yEoUB0iVT3GHm+V9sFZYYHDN6c1G6dSpP4qrQrEUw2oO/zlLQj06hSbOaM+y1xKM1vFdEaw0EKh1Pmf9/pHImcpQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779366422; c=relaxed/simple; bh=S8QFJdAcNZoGxh/yARLNDLCixjyLtBo0qqkUetRCP6Q=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=RbGsGJK5PvXaVMGKUeiYLKEkljRsEHR/M99KZ+R5AP/5ybXHZUFGDv0IFI7SEqKjMcNKMnNay+qfp+ss0ZBIZQ2e5enZAdXKi75WZpyUHrtRgMq0U/zSuNgfMnZntkh9zY0Qmw+h2/PlwpgpS0jcY9O5KbLdz9e354ctOEkZcfQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=edldmHOO; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="edldmHOO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 754641F00A3B; Thu, 21 May 2026 12:27:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1779366420; bh=+cf80q5DC/CawMmDO3ecsgsvD2XsOLoN6ayxjmW4JZM=; h=From:To:Cc:Subject:Date; b=edldmHOOU0FjkfI5OeK2MjMqoGEXaX+nyulgQJIQxSlOzjuoRJ+T5AJ/47kitrrVk HWgLfEUKj7GagPTRK4RgMpFKxjiF3kxKBsGzw9XGXrt6YCc+itLypFisr5B6qu6oQQ GotSptfu5r+CE5O1hiuuq9HtXNuD2IDiQHvjxgI280Aa5TRrZABhNZX6OkffL7ddPt +cBKghK/Kpoi4w60h2V+ACRQZ3EDdntVSBjPV0thU+HWdh+EvyRDfiTVLycQxih+dE Fu7U05qlV3qCN5txYaknaoxVj0AlanXpVSsYKsj83yzV8kKpbWp/0ynjmlP+xgPVkF CGnwruaIBBh/g== From: Dinh Nguyen To: tze.yee.ng@altera.com Cc: dinguyen@kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] firmware: stratix10-rsu: avoid blocking reboot_image sysfs when busy Date: Thu, 21 May 2026 07:26:56 -0500 Message-ID: <20260521122656.3296297-1-dinguyen@kernel.org> X-Mailer: git-send-email 2.42.0.411.g813d9a9188 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Writes to the reboot_image sysfs attribute went through rsu_send_msg(), which unconditionally takes priv->lock with mutex_lock(). If another RSU operation is in flight (e.g. a DCMF status query from probe or a concurrent sysfs read path), userspace writers get stuck in the kernel waiting on the mutex instead of being told the device is busy. Split rsu_send_msg() into an inner __rsu_send_msg_locked() helper that performs the SMC transaction with the caller holding priv->lock, plus two thin wrappers: rsu_send_msg() preserves the original blocking behaviour for existing callers, and rsu_try_send_msg() uses mutex_trylock() and returns -EBUSY immediately when the lock is held. Use rsu_try_send_msg() from reboot_image_store() so the write returns -EBUSY without blocking when an RSU operation is already running. Userspace can retry on -EBUSY. No functional change for other sysfs attributes. This keeps blocking rsu_send_msg() for existing callers, add rsu_try_send_msg() with -EBUSY only for reboot_image_store(). That matches the original goal (avoid a second reboot_image write blocking behind priv->lock) without changing sysfs behaviour for the other attributes. The earlier idea of using mutex_trylock() in all of rsu_send_msg() and returning -EAGAIN would have been harder to justify for userspace (echo does not retry on that). Tze Yee tested the patch on an Agilex SoC devkit. [Test 1] Idle reboot_image write (success path) Result: # insmod stratix10-rsu.ko # echo 0x01000000 > .../reboot_image # echo "exit=3D$?" exit=3D0 # ./rsu_client --log VERSION: 0x00000202 STATE: 0x00000000 CURRENT IMAGE: 0x0000000001000000 FAIL IMAGE: 0x0000000000000000 ERROR LOC: 0x00000000 ERROR DETAILS: 0x00000000 RETRY COUNTER: 0x00000000 Operation completed [Test 2] reboot_image while priv->lock is held (-EBUSY path) To get a deterministic busy window without flooding the service layer, add a local debug helper (module parameter debug_hold_lock_sec + kthread that holds priv->lock for N seconds after probe). Result: # insmod stratix10-rsu.ko debug_hold_lock_sec=3D60 [ 121.220904] stratix10-rsu stratix10-rsu.0: TEST: RSU lock held for 60 s - try reboot_image now # echo 0x01000000 > .../reboot_image -sh: echo: write error: Device or resource busy # echo "during hold: exit=3D$?" during hold: exit=3D1 [ 183.268706] stratix10-rsu stratix10-rsu.0: TEST: RSU lock released # echo 0x01000000 > .../reboot_image # echo "after release: exit=3D$?" after release: exit=3D0 Together, these results match the intended behaviour: reboot_image fails fast with -EBUSY when the RSU mutex is already held, and succeeds once the lock is available. Assisted-by: Claude:claude-opus-4-7 Tested-by: Tze Yee Ng Signed-off-by: Dinh Nguyen --- drivers/firmware/stratix10-rsu.c | 85 +++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-= rsu.c index 6c5f952f48d8f..a420eb0c13e1c 100644 --- a/drivers/firmware/stratix10-rsu.c +++ b/drivers/firmware/stratix10-rsu.c @@ -338,27 +338,26 @@ static void rsu_async_get_spt_table_callback(struct d= evice *dev, } =20 /** - * rsu_send_msg() - send a message to Intel service layer + * __rsu_send_msg_locked() - send a message to Intel service layer * @priv: pointer to rsu private data * @command: RSU status or update command * @arg: the request argument, the bitstream address or notify status * @callback: function pointer for the callback (status or update) * - * Start an Intel service layer transaction to perform the SMC call that - * is necessary to get RSU boot log or set the address of bitstream to - * boot after reboot. + * Perform the actual SMC transaction. The caller must hold @priv->lock. * - * Returns 0 on success or -ETIMEDOUT on error. + * Returns 0 on success or a negative errno on failure. */ -static int rsu_send_msg(struct stratix10_rsu_priv *priv, - enum stratix10_svc_command_code command, - unsigned long arg, - rsu_callback callback) +static int __rsu_send_msg_locked(struct stratix10_rsu_priv *priv, + enum stratix10_svc_command_code command, + unsigned long arg, + rsu_callback callback) { struct stratix10_svc_client_msg msg; int ret; =20 - mutex_lock(&priv->lock); + lockdep_assert_held(&priv->lock); + reinit_completion(&priv->completion); priv->client.receive_cb =3D callback; =20 @@ -387,6 +386,59 @@ static int rsu_send_msg(struct stratix10_rsu_priv *pri= v, =20 status_done: stratix10_svc_done(priv->chan); + return ret; +} + +/** + * rsu_send_msg() - send a message to Intel service layer + * @priv: pointer to rsu private data + * @command: RSU status or update command + * @arg: the request argument, the bitstream address or notify status + * @callback: function pointer for the callback (status or update) + * + * Start an Intel service layer transaction to perform the SMC call that + * is necessary to get RSU boot log or set the address of bitstream to + * boot after reboot. This call will block until the RSU lock can be + * acquired. + * + * Returns 0 on success or a negative errno on failure. + */ +static int rsu_send_msg(struct stratix10_rsu_priv *priv, + enum stratix10_svc_command_code command, + unsigned long arg, + rsu_callback callback) +{ + int ret; + + mutex_lock(&priv->lock); + ret =3D __rsu_send_msg_locked(priv, command, arg, callback); + mutex_unlock(&priv->lock); + return ret; +} + +/** + * rsu_try_send_msg() - non-blocking variant of rsu_send_msg() + * @priv: pointer to rsu private data + * @command: RSU status or update command + * @arg: the request argument, the bitstream address or notify status + * @callback: function pointer for the callback (status or update) + * + * Same as rsu_send_msg() but returns -EBUSY immediately when another + * RSU operation is already in flight, instead of waiting for the lock. + * + * Returns 0 on success, -EBUSY if the RSU is busy, or another negative + * errno on failure. + */ +static int rsu_try_send_msg(struct stratix10_rsu_priv *priv, + enum stratix10_svc_command_code command, + unsigned long arg, + rsu_callback callback) +{ + int ret; + + if (!mutex_trylock(&priv->lock)) + return -EBUSY; + ret =3D __rsu_send_msg_locked(priv, command, arg, callback); mutex_unlock(&priv->lock); return ret; } @@ -689,8 +741,17 @@ static ssize_t reboot_image_store(struct device *dev, if (ret) return ret; =20 - ret =3D rsu_send_msg(priv, COMMAND_RSU_UPDATE, - address, rsu_command_callback); + /* + * Use the non-blocking variant so a write to this sysfs attribute + * does not stall the caller while another RSU operation is in + * flight. Userspace can retry on -EBUSY. + */ + ret =3D rsu_try_send_msg(priv, COMMAND_RSU_UPDATE, + address, rsu_command_callback); + if (ret =3D=3D -EBUSY) { + dev_dbg(dev, "RSU busy, reboot_image write rejected\n"); + return ret; + } if (ret) { dev_err(dev, "Error, RSU update returned %i\n", ret); return ret; --=20 2.42.0.411.g813d9a9188