mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] firmware: stratix10-rsu: Add synchronous fallback for async SVC operations
@ 2026-05-26  9:41 tze.yee.ng
  2026-07-09  9:13 ` NG, TZE YEE
  0 siblings, 1 reply; 4+ messages in thread
From: tze.yee.ng @ 2026-05-26  9:41 UTC (permalink / raw)
  To: Dinh Nguyen, linux-kernel; +Cc: Tze Yee Ng, Adrian Ng Ho Yin, Nazim Amirul

From: Mahesh Rao <mahesh.rao@altera.com>

The RSU driver was migrated to the Stratix10 asynchronous service
framework, which assumes async client registration always succeeds. On
platforms where the async controller is unavailable or RSU async support
is not present, probe fails or sysfs operations cannot reach firmware.

Detect async capability at probe via stratix10_svc_add_async_client() and
fall back to the legacy synchronous rsu_send_msg() path when registration
fails. Track capability in priv->async and branch accordingly for:

 - Initial RSU status and retry counter during probe (retry is bundled in
   async status; issue COMMAND_RSU_RETRY separately in sync mode)
 - notify sysfs store (notify, status, and retry)
 - SPT table retrieval (COMMAND_RSU_GET_SPT_TABLE async vs mbox
   COMMAND_MBOX_SEND_CMD synchronous)

Restore synchronous callbacks (rsu_status_callback, rsu_retry_callback,
rsu_get_spt_callback) and wire COMMAND_MBOX_SEND_CMD payload handling in
rsu_send_msg().

Improve probe and remove cleanup: return on intermediate probe failures,
remove the async client when registered, and free the SPT response buffer
on sync-path allocation errors.

Suggested-by: Anders Hedlund <anders.hedlund@windriver.com>
Signed-off-by: Mahesh Rao <mahesh.rao@altera.com>
Signed-off-by: Asyraaf Azhar <mohamad.asyraaf.azhar@altera.com>
Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
---
 drivers/firmware/stratix10-rsu.c | 215 +++++++++++++++++++++++++++++--
 1 file changed, 201 insertions(+), 14 deletions(-)

diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-rsu.c
index 6c5f952f48d8..17288e7235e6 100644
--- a/drivers/firmware/stratix10-rsu.c
+++ b/drivers/firmware/stratix10-rsu.c
@@ -18,6 +18,10 @@
 #include <linux/string.h>
 #include <linux/sysfs.h>
 
+#define RSU_STATE_MASK			GENMASK_ULL(31, 0)
+#define RSU_VERSION_MASK		GENMASK_ULL(63, 32)
+#define RSU_ERROR_LOCATION_MASK		GENMASK_ULL(31, 0)
+#define RSU_ERROR_DETAIL_MASK		GENMASK_ULL(63, 32)
 /*
  * INTEL_SIP_SMC_RSU_GET_DEVICE_INFO packs each flash word as:
  *   [63:32] erase_size, [31:0] size (see stratix10-smc.h).
@@ -44,6 +48,7 @@
 
 #define RSU_RETRY_SLEEP_MS		(1U)
 #define RSU_ASYNC_MSG_RETRY		(3U)
+#define RSU_GET_SPT_CMD			0x5A
 #define RSU_GET_SPT_RESP_LEN		(4 * sizeof(unsigned int))
 
 struct flash_device_info {
@@ -73,6 +78,7 @@ typedef void (*rsu_callback)(struct stratix10_svc_client *client,
  * @client: active service client
  * @completion: state for callback completion
  * @lock: a mutex to protect callback completion state
+ * @async: supports async operations
  * @status.current_image: address of image currently running in flash
  * @status.fail_image: address of failed image in flash
  * @status.version: the interface version number of RSU firmware
@@ -99,6 +105,7 @@ struct stratix10_rsu_priv {
 	struct stratix10_svc_client client;
 	struct completion completion;
 	struct mutex lock;
+	bool async;
 	struct {
 		unsigned long current_image;
 		unsigned long fail_image;
@@ -129,6 +136,8 @@ struct stratix10_rsu_priv {
 
 	unsigned long spt0_address;
 	unsigned long spt1_address;
+
+	unsigned int *get_spt_response_buf;
 };
 
 /**
@@ -148,6 +157,45 @@ static void rsu_device_info_invalidate(struct stratix10_rsu_priv *priv)
 typedef void (*rsu_async_callback)(struct device *dev,
 	struct stratix10_rsu_priv *priv, struct stratix10_svc_cb_data *data);
 
+/**
+ * rsu_status_callback() - Status callback from Intel Service Layer
+ * @client: pointer to service client
+ * @data: pointer to callback data structure
+ *
+ * Callback from Intel service layer for RSU status request. Status is
+ * only updated after a system reboot, so a get updated status call is
+ * made during driver probe.
+ */
+static void rsu_status_callback(struct stratix10_svc_client *client,
+				struct stratix10_svc_cb_data *data)
+{
+	struct stratix10_rsu_priv *priv = client->priv;
+	struct arm_smccc_res *res = (struct arm_smccc_res *)data->kaddr1;
+
+	if (data->status == BIT(SVC_STATUS_OK)) {
+		priv->status.version = FIELD_GET(RSU_VERSION_MASK,
+						 res->a2);
+		priv->status.state = FIELD_GET(RSU_STATE_MASK, res->a2);
+		priv->status.fail_image = res->a1;
+		priv->status.current_image = res->a0;
+		priv->status.error_location =
+			FIELD_GET(RSU_ERROR_LOCATION_MASK, res->a3);
+		priv->status.error_details =
+			FIELD_GET(RSU_ERROR_DETAIL_MASK, res->a3);
+	} else {
+		dev_err(client->dev, "COMMAND_RSU_STATUS returned 0x%lX\n",
+			res->a0);
+		priv->status.version = 0;
+		priv->status.state = 0;
+		priv->status.fail_image = 0;
+		priv->status.current_image = 0;
+		priv->status.error_location = 0;
+		priv->status.error_details = 0;
+	}
+
+	complete(&priv->completion);
+}
+
 /**
  * rsu_async_status_callback() - Status callback from rsu_async_send()
  * @dev: pointer to device object
@@ -192,6 +240,32 @@ static void rsu_command_callback(struct stratix10_svc_client *client,
 	complete(&priv->completion);
 }
 
+/**
+ * rsu_retry_callback() - Callback from Intel service layer for getting
+ * the current image's retry counter from the firmware
+ * @client: pointer to client
+ * @data: pointer to callback data structure
+ *
+ * Callback from Intel service layer for retry counter, which is used by
+ * user to know how many times the images is still allowed to reload
+ * itself before giving up and starting RSU fail-over flow.
+ */
+static void rsu_retry_callback(struct stratix10_svc_client *client,
+			       struct stratix10_svc_cb_data *data)
+{
+	struct stratix10_rsu_priv *priv = client->priv;
+	unsigned int *counter = (unsigned int *)data->kaddr1;
+
+	if (data->status == BIT(SVC_STATUS_OK))
+		priv->retry_counter = *counter;
+	else if (data->status == BIT(SVC_STATUS_NO_SUPPORT))
+		dev_warn(client->dev, "Secure FW doesn't support retry\n");
+	else
+		dev_err(client->dev, "Failed to get retry counter %lu\n",
+			BIT(data->status));
+
+	complete(&priv->completion);
+}
 
 /**
  * rsu_max_retry_callback() - Callback from Intel service layer for getting
@@ -337,6 +411,38 @@ static void rsu_async_get_spt_table_callback(struct device *dev,
 	priv->spt1_address = *((unsigned long *)data->kaddr2);
 }
 
+static void rsu_get_spt_callback(struct stratix10_svc_client *client,
+				 struct stratix10_svc_cb_data *data)
+{
+	struct stratix10_rsu_priv *priv = client->priv;
+	unsigned long *mbox_err = (unsigned long *)data->kaddr1;
+	unsigned long *resp_len = (unsigned long *)data->kaddr2;
+
+	if (data->status != BIT(SVC_STATUS_OK) || (*mbox_err) ||
+	    (*resp_len != RSU_GET_SPT_RESP_LEN))
+		goto error;
+
+	priv->spt0_address = priv->get_spt_response_buf[0];
+	priv->spt0_address <<= 32;
+	priv->spt0_address |= priv->get_spt_response_buf[1];
+	priv->spt1_address = priv->get_spt_response_buf[2];
+	priv->spt1_address <<= 32;
+	priv->spt1_address |= priv->get_spt_response_buf[3];
+
+	goto complete;
+
+error:
+	dev_err(priv->client.dev,
+		"failed to get SPTs (status=%#x, mbox_err=%lu, resp_len=%lu)\n",
+		data->status, mbox_err ? *mbox_err : 0,
+		resp_len ? *resp_len : 0);
+
+complete:
+	stratix10_svc_free_memory(priv->chan, priv->get_spt_response_buf);
+	priv->get_spt_response_buf = NULL;
+	complete(&priv->completion);
+}
+
 /**
  * rsu_send_msg() - send a message to Intel service layer
  * @priv: pointer to rsu private data
@@ -355,7 +461,7 @@ static int rsu_send_msg(struct stratix10_rsu_priv *priv,
 			unsigned long arg,
 			rsu_callback callback)
 {
-	struct stratix10_svc_client_msg msg;
+	struct stratix10_svc_client_msg msg = {0};
 	int ret;
 
 	mutex_lock(&priv->lock);
@@ -366,6 +472,14 @@ static int rsu_send_msg(struct stratix10_rsu_priv *priv,
 	if (arg)
 		msg.arg[0] = arg;
 
+	if (command == COMMAND_MBOX_SEND_CMD) {
+		msg.arg[1] = 0;
+		msg.payload = NULL;
+		msg.payload_length = 0;
+		msg.payload_output = priv->get_spt_response_buf;
+		msg.payload_length_output = RSU_GET_SPT_RESP_LEN;
+	}
+
 	ret = stratix10_svc_send(priv->chan, &msg);
 	if (ret < 0)
 		goto status_done;
@@ -437,6 +551,8 @@ static int rsu_send_async_msg(struct device *dev, struct stratix10_rsu_priv *pri
 
 	if (status && !handle) {
 		dev_err(dev, "Failed to send async message\n");
+		if (msg.payload_output)
+			stratix10_svc_free_memory(priv->chan, msg.payload_output);
 		return -ETIMEDOUT;
 	}
 
@@ -476,6 +592,8 @@ static int rsu_send_async_msg(struct device *dev, struct stratix10_rsu_priv *pri
 	}
 
 status_done:
+	if (msg.payload_output)
+		stratix10_svc_free_memory(priv->chan, msg.payload_output);
 	stratix10_svc_async_done(priv->chan, handle);
 	return ret;
 }
@@ -714,15 +832,30 @@ static ssize_t notify_store(struct device *dev,
 	if (ret)
 		return ret;
 
-	ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_NOTIFY, status, NULL);
+	if (priv->async)
+		ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_NOTIFY, status, NULL);
+	else
+		ret = rsu_send_msg(priv, COMMAND_RSU_NOTIFY, status, rsu_command_callback);
 	if (ret) {
 		dev_err(dev, "Error, RSU notify returned %i\n", ret);
 		return ret;
 	}
 
 	/* to get the updated state */
-	ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0,
-				 rsu_async_status_callback);
+	if (priv->async) {
+		ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0,
+					 rsu_async_status_callback);
+	} else {
+		ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 0,
+				   rsu_status_callback);
+		/*
+		 * In async mode COMMAND_RSU_RETRY is part of COMMAND_RSU_STATUS;
+		 * issue it separately only in synchronous mode.
+		 */
+		if (!ret)
+			ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0,
+					   rsu_retry_callback);
+	}
 	if (ret) {
 		dev_err(dev, "Error, getting RSU status %i\n", ret);
 		return ret;
@@ -922,6 +1055,8 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
 	priv->max_retry = INVALID_RETRY_COUNTER;
 	priv->spt0_address = INVALID_SPT_ADDRESS;
 	priv->spt1_address = INVALID_SPT_ADDRESS;
+	priv->get_spt_response_buf = NULL;
+	priv->async = false;
 	rsu_device_info_invalidate(priv);
 
 	mutex_init(&priv->lock);
@@ -934,45 +1069,73 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
 	}
 
 	ret = stratix10_svc_add_async_client(priv->chan, false);
-	if (ret) {
-		dev_err(dev, "failed to add async client\n");
-		stratix10_svc_free_channel(priv->chan);
-		return ret;
+	if (ret < 0) {
+		dev_dbg(dev, "Async operations not supported, fallback to non-async mode\n");
+		priv->async = false;
+	} else {
+		priv->async = true;
 	}
 
 	init_completion(&priv->completion);
 	platform_set_drvdata(pdev, priv);
 
 	/* get the initial state from firmware */
-	ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0,
-				 rsu_async_status_callback);
+	if (priv->async)
+		ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0,
+					 rsu_async_status_callback);
+	else
+		ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 0,
+				   rsu_status_callback);
 	if (ret) {
 		dev_err(dev, "Error, getting RSU status %i\n", ret);
-		stratix10_svc_remove_async_client(priv->chan);
+		if (priv->async)
+			stratix10_svc_remove_async_client(priv->chan);
 		stratix10_svc_free_channel(priv->chan);
 		return ret;
 	}
 
+	/*
+	 * In async mode COMMAND_RSU_RETRY is part of COMMAND_RSU_STATUS;
+	 * issue it separately only in synchronous mode.
+	 */
+	if (!priv->async) {
+		ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback);
+		if (ret) {
+			dev_err(dev, "Error, getting RSU retry %i\n", ret);
+			stratix10_svc_free_channel(priv->chan);
+			return ret;
+		}
+	}
+
 	/* get DCMF version from firmware */
 	ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_VERSION,
 			   0, rsu_dcmf_version_callback);
 	if (ret) {
 		dev_err(dev, "Error, getting DCMF version %i\n", ret);
+		if (priv->async)
+			stratix10_svc_remove_async_client(priv->chan);
 		stratix10_svc_free_channel(priv->chan);
+		return ret;
 	}
 
 	ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_STATUS,
 			   0, rsu_dcmf_status_callback);
 	if (ret) {
 		dev_err(dev, "Error, getting DCMF status %i\n", ret);
+		if (priv->async)
+			stratix10_svc_remove_async_client(priv->chan);
 		stratix10_svc_free_channel(priv->chan);
+		return ret;
 	}
 
 	ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0,
 			   rsu_max_retry_callback);
 	if (ret) {
 		dev_err(dev, "Error, getting RSU max retry %i\n", ret);
+		if (priv->async)
+			stratix10_svc_remove_async_client(priv->chan);
 		stratix10_svc_free_channel(priv->chan);
+		return ret;
 	}
 
 	/* get QSPI device info from firmware */
@@ -980,15 +1143,36 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
 			   rsu_get_device_info_callback);
 	if (ret) {
 		dev_err(dev, "Error, getting QSPI Device Info %i\n", ret);
-		stratix10_svc_remove_async_client(priv->chan);
+		if (priv->async)
+			stratix10_svc_remove_async_client(priv->chan);
 		stratix10_svc_free_channel(priv->chan);
 		return ret;
 	}
 
-	ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_GET_SPT_TABLE, 0,
-				 rsu_async_get_spt_table_callback);
+	if (priv->async) {
+		ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_GET_SPT_TABLE,
+					 0, rsu_async_get_spt_table_callback);
+	} else {
+		priv->get_spt_response_buf =
+			stratix10_svc_allocate_memory(priv->chan, RSU_GET_SPT_RESP_LEN);
+		if (IS_ERR(priv->get_spt_response_buf)) {
+			ret = PTR_ERR(priv->get_spt_response_buf);
+			priv->get_spt_response_buf = NULL;
+			dev_err(dev, "failed to allocate get spt buffer\n");
+		} else {
+			ret = rsu_send_msg(priv, COMMAND_MBOX_SEND_CMD,
+					   RSU_GET_SPT_CMD, rsu_get_spt_callback);
+		}
+	}
 	if (ret) {
 		dev_err(dev, "Error, getting SPT table %i\n", ret);
+		if (priv->async) {
+			stratix10_svc_remove_async_client(priv->chan);
+		} else if (!IS_ERR_OR_NULL(priv->get_spt_response_buf)) {
+			stratix10_svc_free_memory(priv->chan,
+						  priv->get_spt_response_buf);
+			priv->get_spt_response_buf = NULL;
+		}
 		stratix10_svc_free_channel(priv->chan);
 	}
 
@@ -999,6 +1183,9 @@ static void stratix10_rsu_remove(struct platform_device *pdev)
 {
 	struct stratix10_rsu_priv *priv = platform_get_drvdata(pdev);
 
+	if (priv->async)
+		stratix10_svc_remove_async_client(priv->chan);
+
 	stratix10_svc_free_channel(priv->chan);
 }
 
-- 
2.43.7


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] firmware: stratix10-rsu: Add synchronous fallback for async SVC operations
  2026-05-26  9:41 [PATCH] firmware: stratix10-rsu: Add synchronous fallback for async SVC operations tze.yee.ng
@ 2026-07-09  9:13 ` NG, TZE YEE
  2026-07-09 15:19   ` Dinh Nguyen
  0 siblings, 1 reply; 4+ messages in thread
From: NG, TZE YEE @ 2026-07-09  9:13 UTC (permalink / raw)
  To: Dinh Nguyen, linux-kernel
  Cc: NG, ADRIAN HO YIN, Nazle Asmade, Muhammad Nazim Amirul

On 26/5/2026 5:41 pm, NG, TZE YEE wrote:
> From: Mahesh Rao <mahesh.rao@altera.com>
> 
> The RSU driver was migrated to the Stratix10 asynchronous service
> framework, which assumes async client registration always succeeds. On
> platforms where the async controller is unavailable or RSU async support
> is not present, probe fails or sysfs operations cannot reach firmware.
> 
> Detect async capability at probe via stratix10_svc_add_async_client() and
> fall back to the legacy synchronous rsu_send_msg() path when registration
> fails. Track capability in priv->async and branch accordingly for:
> 
>   - Initial RSU status and retry counter during probe (retry is bundled in
>     async status; issue COMMAND_RSU_RETRY separately in sync mode)
>   - notify sysfs store (notify, status, and retry)
>   - SPT table retrieval (COMMAND_RSU_GET_SPT_TABLE async vs mbox
>     COMMAND_MBOX_SEND_CMD synchronous)
> 
> Restore synchronous callbacks (rsu_status_callback, rsu_retry_callback,
> rsu_get_spt_callback) and wire COMMAND_MBOX_SEND_CMD payload handling in
> rsu_send_msg().
> 
> Improve probe and remove cleanup: return on intermediate probe failures,
> remove the async client when registered, and free the SPT response buffer
> on sync-path allocation errors.
> 
> Suggested-by: Anders Hedlund <anders.hedlund@windriver.com>
> Signed-off-by: Mahesh Rao <mahesh.rao@altera.com>
> Signed-off-by: Asyraaf Azhar <mohamad.asyraaf.azhar@altera.com>
> Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
> ---
>   drivers/firmware/stratix10-rsu.c | 215 +++++++++++++++++++++++++++++--
>   1 file changed, 201 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-rsu.c
> index 6c5f952f48d8..17288e7235e6 100644
> --- a/drivers/firmware/stratix10-rsu.c
> +++ b/drivers/firmware/stratix10-rsu.c
> @@ -18,6 +18,10 @@
>   #include <linux/string.h>
>   #include <linux/sysfs.h>
>   
> +#define RSU_STATE_MASK			GENMASK_ULL(31, 0)
> +#define RSU_VERSION_MASK		GENMASK_ULL(63, 32)
> +#define RSU_ERROR_LOCATION_MASK		GENMASK_ULL(31, 0)
> +#define RSU_ERROR_DETAIL_MASK		GENMASK_ULL(63, 32)
>   /*
>    * INTEL_SIP_SMC_RSU_GET_DEVICE_INFO packs each flash word as:
>    *   [63:32] erase_size, [31:0] size (see stratix10-smc.h).
> @@ -44,6 +48,7 @@
>   
>   #define RSU_RETRY_SLEEP_MS		(1U)
>   #define RSU_ASYNC_MSG_RETRY		(3U)
> +#define RSU_GET_SPT_CMD			0x5A
>   #define RSU_GET_SPT_RESP_LEN		(4 * sizeof(unsigned int))
>   
>   struct flash_device_info {
> @@ -73,6 +78,7 @@ typedef void (*rsu_callback)(struct stratix10_svc_client *client,
>    * @client: active service client
>    * @completion: state for callback completion
>    * @lock: a mutex to protect callback completion state
> + * @async: supports async operations
>    * @status.current_image: address of image currently running in flash
>    * @status.fail_image: address of failed image in flash
>    * @status.version: the interface version number of RSU firmware
> @@ -99,6 +105,7 @@ struct stratix10_rsu_priv {
>   	struct stratix10_svc_client client;
>   	struct completion completion;
>   	struct mutex lock;
> +	bool async;
>   	struct {
>   		unsigned long current_image;
>   		unsigned long fail_image;
> @@ -129,6 +136,8 @@ struct stratix10_rsu_priv {
>   
>   	unsigned long spt0_address;
>   	unsigned long spt1_address;
> +
> +	unsigned int *get_spt_response_buf;
>   };
>   
>   /**
> @@ -148,6 +157,45 @@ static void rsu_device_info_invalidate(struct stratix10_rsu_priv *priv)
>   typedef void (*rsu_async_callback)(struct device *dev,
>   	struct stratix10_rsu_priv *priv, struct stratix10_svc_cb_data *data);
>   
> +/**
> + * rsu_status_callback() - Status callback from Intel Service Layer
> + * @client: pointer to service client
> + * @data: pointer to callback data structure
> + *
> + * Callback from Intel service layer for RSU status request. Status is
> + * only updated after a system reboot, so a get updated status call is
> + * made during driver probe.
> + */
> +static void rsu_status_callback(struct stratix10_svc_client *client,
> +				struct stratix10_svc_cb_data *data)
> +{
> +	struct stratix10_rsu_priv *priv = client->priv;
> +	struct arm_smccc_res *res = (struct arm_smccc_res *)data->kaddr1;
> +
> +	if (data->status == BIT(SVC_STATUS_OK)) {
> +		priv->status.version = FIELD_GET(RSU_VERSION_MASK,
> +						 res->a2);
> +		priv->status.state = FIELD_GET(RSU_STATE_MASK, res->a2);
> +		priv->status.fail_image = res->a1;
> +		priv->status.current_image = res->a0;
> +		priv->status.error_location =
> +			FIELD_GET(RSU_ERROR_LOCATION_MASK, res->a3);
> +		priv->status.error_details =
> +			FIELD_GET(RSU_ERROR_DETAIL_MASK, res->a3);
> +	} else {
> +		dev_err(client->dev, "COMMAND_RSU_STATUS returned 0x%lX\n",
> +			res->a0);
> +		priv->status.version = 0;
> +		priv->status.state = 0;
> +		priv->status.fail_image = 0;
> +		priv->status.current_image = 0;
> +		priv->status.error_location = 0;
> +		priv->status.error_details = 0;
> +	}
> +
> +	complete(&priv->completion);
> +}
> +
>   /**
>    * rsu_async_status_callback() - Status callback from rsu_async_send()
>    * @dev: pointer to device object
> @@ -192,6 +240,32 @@ static void rsu_command_callback(struct stratix10_svc_client *client,
>   	complete(&priv->completion);
>   }
>   
> +/**
> + * rsu_retry_callback() - Callback from Intel service layer for getting
> + * the current image's retry counter from the firmware
> + * @client: pointer to client
> + * @data: pointer to callback data structure
> + *
> + * Callback from Intel service layer for retry counter, which is used by
> + * user to know how many times the images is still allowed to reload
> + * itself before giving up and starting RSU fail-over flow.
> + */
> +static void rsu_retry_callback(struct stratix10_svc_client *client,
> +			       struct stratix10_svc_cb_data *data)
> +{
> +	struct stratix10_rsu_priv *priv = client->priv;
> +	unsigned int *counter = (unsigned int *)data->kaddr1;
> +
> +	if (data->status == BIT(SVC_STATUS_OK))
> +		priv->retry_counter = *counter;
> +	else if (data->status == BIT(SVC_STATUS_NO_SUPPORT))
> +		dev_warn(client->dev, "Secure FW doesn't support retry\n");
> +	else
> +		dev_err(client->dev, "Failed to get retry counter %lu\n",
> +			BIT(data->status));
> +
> +	complete(&priv->completion);
> +}
>   
>   /**
>    * rsu_max_retry_callback() - Callback from Intel service layer for getting
> @@ -337,6 +411,38 @@ static void rsu_async_get_spt_table_callback(struct device *dev,
>   	priv->spt1_address = *((unsigned long *)data->kaddr2);
>   }
>   
> +static void rsu_get_spt_callback(struct stratix10_svc_client *client,
> +				 struct stratix10_svc_cb_data *data)
> +{
> +	struct stratix10_rsu_priv *priv = client->priv;
> +	unsigned long *mbox_err = (unsigned long *)data->kaddr1;
> +	unsigned long *resp_len = (unsigned long *)data->kaddr2;
> +
> +	if (data->status != BIT(SVC_STATUS_OK) || (*mbox_err) ||
> +	    (*resp_len != RSU_GET_SPT_RESP_LEN))
> +		goto error;
> +
> +	priv->spt0_address = priv->get_spt_response_buf[0];
> +	priv->spt0_address <<= 32;
> +	priv->spt0_address |= priv->get_spt_response_buf[1];
> +	priv->spt1_address = priv->get_spt_response_buf[2];
> +	priv->spt1_address <<= 32;
> +	priv->spt1_address |= priv->get_spt_response_buf[3];
> +
> +	goto complete;
> +
> +error:
> +	dev_err(priv->client.dev,
> +		"failed to get SPTs (status=%#x, mbox_err=%lu, resp_len=%lu)\n",
> +		data->status, mbox_err ? *mbox_err : 0,
> +		resp_len ? *resp_len : 0);
> +
> +complete:
> +	stratix10_svc_free_memory(priv->chan, priv->get_spt_response_buf);
> +	priv->get_spt_response_buf = NULL;
> +	complete(&priv->completion);
> +}
> +
>   /**
>    * rsu_send_msg() - send a message to Intel service layer
>    * @priv: pointer to rsu private data
> @@ -355,7 +461,7 @@ static int rsu_send_msg(struct stratix10_rsu_priv *priv,
>   			unsigned long arg,
>   			rsu_callback callback)
>   {
> -	struct stratix10_svc_client_msg msg;
> +	struct stratix10_svc_client_msg msg = {0};
>   	int ret;
>   
>   	mutex_lock(&priv->lock);
> @@ -366,6 +472,14 @@ static int rsu_send_msg(struct stratix10_rsu_priv *priv,
>   	if (arg)
>   		msg.arg[0] = arg;
>   
> +	if (command == COMMAND_MBOX_SEND_CMD) {
> +		msg.arg[1] = 0;
> +		msg.payload = NULL;
> +		msg.payload_length = 0;
> +		msg.payload_output = priv->get_spt_response_buf;
> +		msg.payload_length_output = RSU_GET_SPT_RESP_LEN;
> +	}
> +
>   	ret = stratix10_svc_send(priv->chan, &msg);
>   	if (ret < 0)
>   		goto status_done;
> @@ -437,6 +551,8 @@ static int rsu_send_async_msg(struct device *dev, struct stratix10_rsu_priv *pri
>   
>   	if (status && !handle) {
>   		dev_err(dev, "Failed to send async message\n");
> +		if (msg.payload_output)
> +			stratix10_svc_free_memory(priv->chan, msg.payload_output);
>   		return -ETIMEDOUT;
>   	}
>   
> @@ -476,6 +592,8 @@ static int rsu_send_async_msg(struct device *dev, struct stratix10_rsu_priv *pri
>   	}
>   
>   status_done:
> +	if (msg.payload_output)
> +		stratix10_svc_free_memory(priv->chan, msg.payload_output);
>   	stratix10_svc_async_done(priv->chan, handle);
>   	return ret;
>   }
> @@ -714,15 +832,30 @@ static ssize_t notify_store(struct device *dev,
>   	if (ret)
>   		return ret;
>   
> -	ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_NOTIFY, status, NULL);
> +	if (priv->async)
> +		ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_NOTIFY, status, NULL);
> +	else
> +		ret = rsu_send_msg(priv, COMMAND_RSU_NOTIFY, status, rsu_command_callback);
>   	if (ret) {
>   		dev_err(dev, "Error, RSU notify returned %i\n", ret);
>   		return ret;
>   	}
>   
>   	/* to get the updated state */
> -	ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0,
> -				 rsu_async_status_callback);
> +	if (priv->async) {
> +		ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0,
> +					 rsu_async_status_callback);
> +	} else {
> +		ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 0,
> +				   rsu_status_callback);
> +		/*
> +		 * In async mode COMMAND_RSU_RETRY is part of COMMAND_RSU_STATUS;
> +		 * issue it separately only in synchronous mode.
> +		 */
> +		if (!ret)
> +			ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0,
> +					   rsu_retry_callback);
> +	}
>   	if (ret) {
>   		dev_err(dev, "Error, getting RSU status %i\n", ret);
>   		return ret;
> @@ -922,6 +1055,8 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
>   	priv->max_retry = INVALID_RETRY_COUNTER;
>   	priv->spt0_address = INVALID_SPT_ADDRESS;
>   	priv->spt1_address = INVALID_SPT_ADDRESS;
> +	priv->get_spt_response_buf = NULL;
> +	priv->async = false;
>   	rsu_device_info_invalidate(priv);
>   
>   	mutex_init(&priv->lock);
> @@ -934,45 +1069,73 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
>   	}
>   
>   	ret = stratix10_svc_add_async_client(priv->chan, false);
> -	if (ret) {
> -		dev_err(dev, "failed to add async client\n");
> -		stratix10_svc_free_channel(priv->chan);
> -		return ret;
> +	if (ret < 0) {
> +		dev_dbg(dev, "Async operations not supported, fallback to non-async mode\n");
> +		priv->async = false;
> +	} else {
> +		priv->async = true;
>   	}
>   
>   	init_completion(&priv->completion);
>   	platform_set_drvdata(pdev, priv);
>   
>   	/* get the initial state from firmware */
> -	ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0,
> -				 rsu_async_status_callback);
> +	if (priv->async)
> +		ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0,
> +					 rsu_async_status_callback);
> +	else
> +		ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 0,
> +				   rsu_status_callback);
>   	if (ret) {
>   		dev_err(dev, "Error, getting RSU status %i\n", ret);
> -		stratix10_svc_remove_async_client(priv->chan);
> +		if (priv->async)
> +			stratix10_svc_remove_async_client(priv->chan);
>   		stratix10_svc_free_channel(priv->chan);
>   		return ret;
>   	}
>   
> +	/*
> +	 * In async mode COMMAND_RSU_RETRY is part of COMMAND_RSU_STATUS;
> +	 * issue it separately only in synchronous mode.
> +	 */
> +	if (!priv->async) {
> +		ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback);
> +		if (ret) {
> +			dev_err(dev, "Error, getting RSU retry %i\n", ret);
> +			stratix10_svc_free_channel(priv->chan);
> +			return ret;
> +		}
> +	}
> +
>   	/* get DCMF version from firmware */
>   	ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_VERSION,
>   			   0, rsu_dcmf_version_callback);
>   	if (ret) {
>   		dev_err(dev, "Error, getting DCMF version %i\n", ret);
> +		if (priv->async)
> +			stratix10_svc_remove_async_client(priv->chan);
>   		stratix10_svc_free_channel(priv->chan);
> +		return ret;
>   	}
>   
>   	ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_STATUS,
>   			   0, rsu_dcmf_status_callback);
>   	if (ret) {
>   		dev_err(dev, "Error, getting DCMF status %i\n", ret);
> +		if (priv->async)
> +			stratix10_svc_remove_async_client(priv->chan);
>   		stratix10_svc_free_channel(priv->chan);
> +		return ret;
>   	}
>   
>   	ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0,
>   			   rsu_max_retry_callback);
>   	if (ret) {
>   		dev_err(dev, "Error, getting RSU max retry %i\n", ret);
> +		if (priv->async)
> +			stratix10_svc_remove_async_client(priv->chan);
>   		stratix10_svc_free_channel(priv->chan);
> +		return ret;
>   	}
>   
>   	/* get QSPI device info from firmware */
> @@ -980,15 +1143,36 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
>   			   rsu_get_device_info_callback);
>   	if (ret) {
>   		dev_err(dev, "Error, getting QSPI Device Info %i\n", ret);
> -		stratix10_svc_remove_async_client(priv->chan);
> +		if (priv->async)
> +			stratix10_svc_remove_async_client(priv->chan);
>   		stratix10_svc_free_channel(priv->chan);
>   		return ret;
>   	}
>   
> -	ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_GET_SPT_TABLE, 0,
> -				 rsu_async_get_spt_table_callback);
> +	if (priv->async) {
> +		ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_GET_SPT_TABLE,
> +					 0, rsu_async_get_spt_table_callback);
> +	} else {
> +		priv->get_spt_response_buf =
> +			stratix10_svc_allocate_memory(priv->chan, RSU_GET_SPT_RESP_LEN);
> +		if (IS_ERR(priv->get_spt_response_buf)) {
> +			ret = PTR_ERR(priv->get_spt_response_buf);
> +			priv->get_spt_response_buf = NULL;
> +			dev_err(dev, "failed to allocate get spt buffer\n");
> +		} else {
> +			ret = rsu_send_msg(priv, COMMAND_MBOX_SEND_CMD,
> +					   RSU_GET_SPT_CMD, rsu_get_spt_callback);
> +		}
> +	}
>   	if (ret) {
>   		dev_err(dev, "Error, getting SPT table %i\n", ret);
> +		if (priv->async) {
> +			stratix10_svc_remove_async_client(priv->chan);
> +		} else if (!IS_ERR_OR_NULL(priv->get_spt_response_buf)) {
> +			stratix10_svc_free_memory(priv->chan,
> +						  priv->get_spt_response_buf);
> +			priv->get_spt_response_buf = NULL;
> +		}
>   		stratix10_svc_free_channel(priv->chan);
>   	}
>   
> @@ -999,6 +1183,9 @@ static void stratix10_rsu_remove(struct platform_device *pdev)
>   {
>   	struct stratix10_rsu_priv *priv = platform_get_drvdata(pdev);
>   
> +	if (priv->async)
> +		stratix10_svc_remove_async_client(priv->chan);
> +
>   	stratix10_svc_free_channel(priv->chan);
>   }
>   

Hi,

Gentle ping on this patch — any chance for a review when you have time?
Happy to rebase or revise based on your feedback.

Thanks,
Tze Yee

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] firmware: stratix10-rsu: Add synchronous fallback for async SVC operations
  2026-07-09  9:13 ` NG, TZE YEE
@ 2026-07-09 15:19   ` Dinh Nguyen
  2026-07-10  7:10     ` NG, TZE YEE
  0 siblings, 1 reply; 4+ messages in thread
From: Dinh Nguyen @ 2026-07-09 15:19 UTC (permalink / raw)
  To: NG, TZE YEE, linux-kernel
  Cc: NG, ADRIAN HO YIN, Nazle Asmade, Muhammad Nazim Amirul



On 7/9/26 04:13, NG, TZE YEE wrote:
> On 26/5/2026 5:41 pm, NG, TZE YEE wrote:
>> From: Mahesh Rao <mahesh.rao@altera.com>
>>
>> The RSU driver was migrated to the Stratix10 asynchronous service
>> framework, which assumes async client registration always succeeds. On
>> platforms where the async controller is unavailable or RSU async support
>> is not present, probe fails or sysfs operations cannot reach firmware.
>>
>> Detect async capability at probe via stratix10_svc_add_async_client() and
>> fall back to the legacy synchronous rsu_send_msg() path when registration
>> fails. Track capability in priv->async and branch accordingly for:
>>
>>    - Initial RSU status and retry counter during probe (retry is bundled in
>>      async status; issue COMMAND_RSU_RETRY separately in sync mode)
>>    - notify sysfs store (notify, status, and retry)
>>    - SPT table retrieval (COMMAND_RSU_GET_SPT_TABLE async vs mbox
>>      COMMAND_MBOX_SEND_CMD synchronous)
>>
>> Restore synchronous callbacks (rsu_status_callback, rsu_retry_callback,
>> rsu_get_spt_callback) and wire COMMAND_MBOX_SEND_CMD payload handling in
>> rsu_send_msg().
>>
>> Improve probe and remove cleanup: return on intermediate probe failures,
>> remove the async client when registered, and free the SPT response buffer
>> on sync-path allocation errors.
>>


>>    }
>>    
> 
> Hi,
> 
> Gentle ping on this patch — any chance for a review when you have time?
> Happy to rebase or revise based on your feedback.
> 

Sorry for missing this. Can you please rebase this to 
socfpga_firmware_for_v7.3 on my tree and I will review it.

Thanks,
Dinh


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] firmware: stratix10-rsu: Add synchronous fallback for async SVC operations
  2026-07-09 15:19   ` Dinh Nguyen
@ 2026-07-10  7:10     ` NG, TZE YEE
  0 siblings, 0 replies; 4+ messages in thread
From: NG, TZE YEE @ 2026-07-10  7:10 UTC (permalink / raw)
  To: Dinh Nguyen, linux-kernel
  Cc: NG, ADRIAN HO YIN, Nazle Asmade, Muhammad Nazim Amirul

On 9/7/2026 11:19 pm, Dinh Nguyen wrote:
> 
> 
> On 7/9/26 04:13, NG, TZE YEE wrote:
>> On 26/5/2026 5:41 pm, NG, TZE YEE wrote:
>>> From: Mahesh Rao <mahesh.rao@altera.com>
>>>
>>> The RSU driver was migrated to the Stratix10 asynchronous service
>>> framework, which assumes async client registration always succeeds. On
>>> platforms where the async controller is unavailable or RSU async support
>>> is not present, probe fails or sysfs operations cannot reach firmware.
>>>
>>> Detect async capability at probe via stratix10_svc_add_async_client() 
>>> and
>>> fall back to the legacy synchronous rsu_send_msg() path when 
>>> registration
>>> fails. Track capability in priv->async and branch accordingly for:
>>>
>>>    - Initial RSU status and retry counter during probe (retry is 
>>> bundled in
>>>      async status; issue COMMAND_RSU_RETRY separately in sync mode)
>>>    - notify sysfs store (notify, status, and retry)
>>>    - SPT table retrieval (COMMAND_RSU_GET_SPT_TABLE async vs mbox
>>>      COMMAND_MBOX_SEND_CMD synchronous)
>>>
>>> Restore synchronous callbacks (rsu_status_callback, rsu_retry_callback,
>>> rsu_get_spt_callback) and wire COMMAND_MBOX_SEND_CMD payload handling in
>>> rsu_send_msg().
>>>
>>> Improve probe and remove cleanup: return on intermediate probe failures,
>>> remove the async client when registered, and free the SPT response 
>>> buffer
>>> on sync-path allocation errors.
>>>
> 
> 
>>>    }
>>
>> Hi,
>>
>> Gentle ping on this patch — any chance for a review when you have time?
>> Happy to rebase or revise based on your feedback.
>>
> 
> Sorry for missing this. Can you please rebase this to 
> socfpga_firmware_for_v7.3 on my tree and I will review it.
> 
> Thanks,
> Dinh
> 

Hi Dinh,

Sure. I have rebased to socfpga_firmware_for_v7.3 in v2: 
https://lore.kernel.org/all/e991a29b0c7bd567da6b9e9a3a59486774a34ab2.1783666551.git.tze.yee.ng@altera.com/

Thanks for checking.
Tze Yee

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-07-10  7:10 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-26  9:41 [PATCH] firmware: stratix10-rsu: Add synchronous fallback for async SVC operations tze.yee.ng
2026-07-09  9:13 ` NG, TZE YEE
2026-07-09 15:19   ` Dinh Nguyen
2026-07-10  7:10     ` NG, TZE YEE

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox