[PATCH v3 2/3] fpga: stratix10-soc: use config_complete_timeout_us as a deadline
From: Adrian Ng Ho Yin
Date: Tue Oct 20 2026 - 03:52:24 EST
config_complete_timeout_us is the maximum time the FPGA may take to
enter user mode after programming. Other FPGA managers (xilinx-core,
efinix-spi, altera-pr-ip-core) turn it into a deadline for their own
"is configuration done" polling. s10_ops_write_complete() instead
passes it as the timeout of every wait for a service layer reply.
That couples two unrelated timeouts. of-fpga-region leaves the field at
0 when the DT property is absent, so usecs_to_jiffies(0) makes the very
first wait time out before the service layer has answered, and
write_complete fails even though configuration succeeds.
For COMMAND_RECONFIG_STATUS the service layer polls the firmware for up
to 30 seconds before it replies with COMPLETED, ERROR or BUSY. Wait for
that reply with a driver timeout that covers the polling window
(SVC_COMPLETED_TIMEOUT_MS plus the usual request timeout), and use
config_complete_timeout_us only as the deadline for re-sending the
status request after a BUSY reply. A value of 0 therefore results in a
single status request, as in the other drivers.
The deadline is only checked between replies, and one reply can take up
to the service layer polling window, so values shorter than that behave
like a single request and the deadline can be exceeded by up to one
reply wait. The service layer cannot be interrupted while it polls:
stratix10_svc_done() waits for its thread to finish.
Signed-off-by: Adrian Ng Ho Yin <adrian.ho.yin.ng@xxxxxxxxxx>
---
Notes:
Changes in v3:
- Replaces "floor config_complete_timeout_us". Drop the max() floor and
stop using config_complete_timeout_us as the per-reply wait. Wait for
each RECONFIG_STATUS reply with a driver timeout that covers the
service layer polling window, and use config_complete_timeout_us as
the deadline for re-polling after BUSY, as other FPGA managers do
(Xu Yilun).
- Moved before the helper patch so that no intermediate commit can
re-poll without a bound.
drivers/fpga/stratix10-soc.c | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c
index 3ba0ffa1d9e0..a69f63f0236b 100644
--- a/drivers/fpga/stratix10-soc.c
+++ b/drivers/fpga/stratix10-soc.c
@@ -25,6 +25,13 @@
#define S10_BUFFER_TIMEOUT (msecs_to_jiffies(SVC_RECONFIG_BUFFER_TIMEOUT_MS))
#define S10_RECONFIG_TIMEOUT (msecs_to_jiffies(SVC_RECONFIG_REQUEST_TIMEOUT_MS))
+/*
+ * The service layer polls the configuration status for up to 30 seconds
+ * (SVC_COMPLETED_TIMEOUT_MS) before it replies to COMMAND_RECONFIG_STATUS.
+ */
+#define S10_RECONFIG_STATUS_TIMEOUT \
+ (msecs_to_jiffies(SVC_COMPLETED_TIMEOUT_MS) + S10_RECONFIG_TIMEOUT)
+
/*
* struct s10_svc_buf
* buf: virtual address of buf provided by service layer
@@ -353,10 +360,10 @@ static int s10_ops_write_complete(struct fpga_manager *mgr,
{
struct s10_priv *priv = mgr->priv;
struct device *dev = priv->client.dev;
- unsigned long timeout;
+ unsigned long deadline;
int ret;
- timeout = usecs_to_jiffies(info->config_complete_timeout_us);
+ deadline = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
do {
reinit_completion(&priv->status_return_completion);
@@ -365,17 +372,12 @@ static int s10_ops_write_complete(struct fpga_manager *mgr,
if (ret < 0)
break;
- ret = wait_for_completion_timeout(
- &priv->status_return_completion, timeout);
- if (!ret) {
- dev_err(dev,
- "timeout waiting for RECONFIG_COMPLETED\n");
+ if (!wait_for_completion_timeout(&priv->status_return_completion,
+ S10_RECONFIG_STATUS_TIMEOUT)) {
+ dev_err(dev, "timeout waiting for RECONFIG_STATUS\n");
ret = -ETIMEDOUT;
break;
}
- /* Not error or timeout, so ret is # of jiffies until timeout */
- timeout = ret;
- ret = 0;
if (test_and_clear_bit(SVC_STATUS_COMPLETED, &priv->status))
break;
@@ -385,6 +387,13 @@ static int s10_ops_write_complete(struct fpga_manager *mgr,
ret = -EFAULT;
break;
}
+
+ if (time_after_eq(jiffies, deadline)) {
+ dev_err(dev,
+ "timeout waiting for RECONFIG_COMPLETED\n");
+ ret = -ETIMEDOUT;
+ break;
+ }
} while (1);
stratix10_svc_done(priv->chan);
--
2.49.GIT