[PATCH -next 1/1] firmware: arm_scmi: Fix possible deadlock in shmem_tx_prepare()

Yaxiong Tian iambestgod at qq.com
Thu Sep 29 19:14:50 PDT 2022


From: Yaxiong Tian <tianyaxiong at kylinos.cn>

In shmem_tx_prepare() ,it use spin_until_cond() to wait the chanel to be
free. Though it can avoid risk about overwriting the old command.But
when the platform has some problem in setting the chanel to free(such as
Improper initialization ),it can lead to the chanel never to be free.So
the os is sticked in it.In addition when shmem_tx_prepare() called,this
indicates that the previous transfer has commpleted or timed out.It
unsuitable for unconditional waiting the chanel to be free.

So for system stablility,we can add timeout condition in waiting the
chanel to be free.

Fixes: 9dc34d635c67 ("firmware: arm_scmi: Check if platform has released shmem before using")
Signed-off-by: Yaxiong Tian <tianyaxiong at kylinos.cn>
Cc: stable at vger.kernel.org
Cc: Sudeep Holla <sudeep.holla at arm.com>
Cc: Jim Quinlan <james.quinlan at broadcom.com>
---
 drivers/firmware/arm_scmi/shmem.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c
index 0e3eaea5d852..ae6110a81855 100644
--- a/drivers/firmware/arm_scmi/shmem.c
+++ b/drivers/firmware/arm_scmi/shmem.c
@@ -8,6 +8,7 @@
 #include <linux/io.h>
 #include <linux/processor.h>
 #include <linux/types.h>
+#include <linux/ktime.h>
 
 #include "common.h"
 
@@ -29,17 +30,27 @@ struct scmi_shared_mem {
 	u8 msg_payload[];
 };
 
+#define SCMI_MAX_TX_PREPARE_TIMEOUT_MS 30
+
 void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem,
 		      struct scmi_xfer *xfer)
 {
+	ktime_t stop = ktime_add_ms(ktime_get(), SCMI_MAX_TX_PREPARE_TIMEOUT_MS);
 	/*
 	 * Ideally channel must be free by now unless OS timeout last
 	 * request and platform continued to process the same, wait
 	 * until it releases the shared memory, otherwise we may endup
 	 * overwriting its response with new message payload or vice-versa
 	 */
-	spin_until_cond(ioread32(&shmem->channel_status) &
-			SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
+	spin_until_cond((ioread32(&shmem->channel_status) &
+			SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE) ||
+			ktime_after(ktime_get(), stop));
+
+	if (unlikely(ktime_after(ktime_get(), stop))) {
+		pr_err("timed out in shmem_tx_prepare(caller: %pS).\n",
+					(void *)_RET_IP_);
+	}
+
 	/* Mark channel busy + clear error */
 	iowrite32(0x0, &shmem->channel_status);
 	iowrite32(xfer->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED,
-- 
2.25.1




More information about the linux-arm-kernel mailing list