[PATCH] fpga: altera-cvp: Retry teardown and reset CVP state on failure

[email protected] Thu, 18 Jun 2026 04:24:10 -0700
Newsgroups org.kernel.vger.linux-fpga,org.kernel.vger.linux-kernel
Message-ID <20260618112410.303-1-muhammad.nazim.amirul.nazle.asmade@altera.com>
From: Nazim Amirul <[email protected]>

If an incorrect bitstream is sent, the teardown may fail due to a
CFG_RDY timeout. When this happens, reset CVP_MODE and HIP_CLK_SEL
bits to clean up the hardware state and return -EAGAIN, allowing the
caller to retry. Introduce altera_cvp_recovery() to wrap this retry
logic with a maximum of CVP_TEARDOWN_MAX_RETRY attempts.

Signed-off-by: Nazim Amirul <[email protected]>
---
 drivers/fpga/altera-cvp.c | 36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c
index 44badfd11e1b..29faf6f5bde1 100644
--- a/drivers/fpga/altera-cvp.c
+++ b/drivers/fpga/altera-cvp.c
@@ -63,6 +63,8 @@
 #define ALTERA_CVP_V1_SIZE	4
 #define ALTERA_CVP_V2_SIZE	4096
 
+/* Tear-down retry */
+#define CVP_TEARDOWN_MAX_RETRY 10
 /* Optional CvP config error status check for debugging */
 static bool altera_cvp_chkcfg;
 
@@ -305,12 +307,40 @@ static int altera_cvp_teardown(struct fpga_manager *mgr,
 	/* STEP 15 - poll CVP_CONFIG_READY bit for 0 with 10us timeout */
 	ret = altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, 0,
 				     conf->priv->poll_time_us);
-	if (ret)
+	if (ret) {
 		dev_err(&mgr->dev, "CFG_RDY == 0 timeout\n");
+		goto error_path;
+	}
 
 	return ret;
+
+error_path:
+	/* reset CVP_MODE and HIP_CLK_SEL bit */
+	altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val);
+	val &= ~VSE_CVP_MODE_CTRL_HIP_CLK_SEL;
+	val &= ~VSE_CVP_MODE_CTRL_CVP_MODE;
+	altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val);
+
+	return -EAGAIN;
+
 }
 
+static int altera_cvp_recovery(struct fpga_manager *mgr,
+			      struct fpga_image_info *info)
+{
+	int ret = 0, retry = 0;
+
+	for (retry = 0; retry < CVP_TEARDOWN_MAX_RETRY; retry++) {
+		ret = altera_cvp_teardown(mgr, info);
+		if (!ret)
+			break;
+		dev_warn(&mgr->dev,
+				 "%s: [%d] Tear-down failed. Retrying\n",
+				 __func__,
+				 retry);
+	}
+	return ret;
+}
 static int altera_cvp_write_init(struct fpga_manager *mgr,
 				 struct fpga_image_info *info,
 				 const char *buf, size_t count)
@@ -343,7 +373,7 @@ static int altera_cvp_write_init(struct fpga_manager *mgr,
 
 	if (val & VSE_CVP_STATUS_CFG_RDY) {
 		dev_warn(&mgr->dev, "CvP already started, tear down first\n");
-		ret = altera_cvp_teardown(mgr, info);
+		ret = altera_cvp_recovery(mgr, info);
 		if (ret)
 			return ret;
 	}
@@ -484,7 +514,7 @@ static int altera_cvp_write_complete(struct fpga_manager *mgr,
 	u32 mask, val;
 	int ret;
 
-	ret = altera_cvp_teardown(mgr, info);
+	ret = altera_cvp_recovery(mgr, info);
 	if (ret)
 		return ret;
 
-- 
2.43.7