From 093da48782df3d50953c520626b345ca70af8cbd Mon Sep 17 00:00:00 2001 From: Nazim Amirul Date: Tue, 22 Sep 2026 22:32:33 -0700 Subject: [PATCH] fpga: altera-cvp: Retry teardown and reset CVP state on failure The driver polls CFG_RDY for 0 as notification that the endpoint has finished teardown and a new session can start safely. After a bad bitstream that poll can time out: CFG_RDY may stay stuck when HIP_CLK_SEL=0 if the device has already left usermode before the poll. Retrying teardown alone is not enough. Exit CvP mode and switch the HIP clock that feeds CFG_RDY so CVP_STATUS becomes responsive again, then try the teardown once more. Introduce altera_cvp_recovery() to wrap this cleanup and single retry. Signed-off-by: Nazim Amirul Reviewed-by: Xu Yilun Link: https://lore.kernel.org/r/20260923053233.10890-3-muhammad.nazim.amirul.nazle.asmade@altera.com Signed-off-by: Xu Yilun --- drivers/fpga/altera-cvp.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c index 99aa078e94cf..507e29d3a79f 100644 --- a/drivers/fpga/altera-cvp.c +++ b/drivers/fpga/altera-cvp.c @@ -318,7 +318,29 @@ static int altera_cvp_teardown(struct fpga_manager *mgr, ret = altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, 0, conf->priv->poll_time_us); if (ret) - dev_err(&mgr->dev, "CFG_RDY == 0 timeout\n"); + dev_warn(&mgr->dev, "CFG_RDY == 0 timeout\n"); + + return ret; +} + +static int altera_cvp_recovery(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + struct altera_cvp_conf *conf = mgr->priv; + int ret; + + ret = altera_cvp_teardown(mgr, info); + if (ret) { + /* + * CVP_STATUS may get stuck if the device left user mode + * before the poll. Exit CvP mode to switch back the clock + * feeding CVP_STATUS, then try the teardown again. + */ + altera_cvp_disable_cvp_mode(conf); + ret = altera_cvp_teardown(mgr, info); + if (ret) + dev_err(&mgr->dev, "Tear-down failed\n"); + } return ret; } @@ -355,7 +377,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; } @@ -496,7 +518,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;