From 3953e72a2be2c199002094a63f4436b03b3f7a2f Mon Sep 17 00:00:00 2001 From: Dmitry Perchanov Date: Thu, 23 Mar 2023 17:32:15 +0200 Subject: [PATCH] ipu-isys: fw init procedures moved to queue. - Move firmware bring-up from video open to queue start streaming This will increase firmware stability for start-stop toggling without closing video node for all streams. - Move firmware shutdown from video close to queue stop streaming Improves recovery process for multithread processes that not close video handle. Signed-off-by: Dmitry Perchanov --- drivers/media/pci/intel/ipu-isys-queue.c | 125 +++++++++++++++++++++++ drivers/media/pci/intel/ipu-isys-video.c | 90 ---------------- 2 files changed, 125 insertions(+), 90 deletions(-) diff --git a/drivers/media/pci/intel/ipu-isys-queue.c b/drivers/media/pci/intel/ipu-isys-queue.c index bb8a017f7a7d..937f3040a8d7 100644 --- a/drivers/media/pci/intel/ipu-isys-queue.c +++ b/drivers/media/pci/intel/ipu-isys-queue.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -898,12 +899,93 @@ static int __start_streaming(struct vb2_queue *q, unsigned int count) return rval; } +static int isys_fw_open(struct ipu_isys_video *av) +{ + struct ipu_isys *isys = av->isys; + struct ipu_bus_device *adev = to_ipu_bus_device(&isys->adev->dev); + struct ipu_device *isp = adev->isp; + int rval; + const struct ipu_isys_internal_pdata *ipdata; + + dev_warn(&isys->adev->dev, "%s:%d %s: enter\n", + __func__, __LINE__, av->vdev.name); + + mutex_lock(&isys->mutex); + + if (isys->reset_needed || isp->flr_done) { + mutex_unlock(&isys->mutex); + dev_warn(&isys->adev->dev, "%s:%d %s: isys power cycle required\n", + __func__, __LINE__, av->vdev.name); + return -EIO; + } + mutex_unlock(&isys->mutex); + + rval = pm_runtime_get_sync(&isys->adev->dev); + if (rval < 0) { + pm_runtime_put_noidle(&isys->adev->dev); + return rval; + } + + mutex_lock(&isys->mutex); + if (isys->video_opened++) { + /* Already open */ + mutex_unlock(&isys->mutex); + dev_warn(&isys->adev->dev, "%s:%d %s: Already open, exit %d\n", + __func__, __LINE__, av->vdev.name, isys->video_opened); + return 0; + } + + ipdata = isys->pdata->ipdata; + ipu_configure_spc(adev->isp, + &ipdata->hw_variant, + IPU_CPD_PKG_DIR_ISYS_SERVER_IDX, + isys->pdata->base, isys->pkg_dir, + isys->pkg_dir_dma_addr); + + /* + * Buffers could have been left to wrong queue at last closure. + * Move them now back to empty buffer queue. + */ + ipu_cleanup_fw_msg_bufs(isys); + + if (isys->fwcom) { + /* + * Something went wrong in previous shutdown. As we are now + * restarting isys we can safely delete old context. + */ + dev_err(&isys->adev->dev, "%s:%d %s Clearing old context\n", + __func__, __LINE__, av->vdev.name); + ipu_fw_isys_cleanup(isys); + } + + rval = ipu_fw_isys_init(av->isys, ipdata->num_parallel_streams); + if (rval < 0) + goto out_lib_init; + + mutex_unlock(&isys->mutex); + + dev_warn(&isys->adev->dev, "%s:%d %s: exit\n", + __func__, __LINE__, av->vdev.name); + return 0; + +out_lib_init: + isys->video_opened--; + mutex_unlock(&isys->mutex); + pm_runtime_put(&isys->adev->dev); + + return rval; +} + static int start_streaming(struct vb2_queue *q, unsigned int count) { struct ipu_isys_queue *aq = vb2_queue_to_ipu_isys_queue(q); struct ipu_isys_video *av = ipu_isys_queue_to_video(aq); int rval; + rval = isys_fw_open(av); + if (rval < 0) { + dev_err(&av->isys->adev->dev, "isys_fw_open failed: %d\n", rval); + } mutex_unlock(&av->mutex); mutex_lock(&av->isys->reset_mutex); while (av->isys->in_stop_streaming) { @@ -1119,6 +1201,48 @@ static int ipu_isys_reset(struct ipu_isys_video *self_av) return 0; } +static int isys_fw_release(struct ipu_isys_video *av) +{ + struct ipu_isys *isys = av->isys; + int ret = 0; + + dev_warn(&isys->adev->dev, "%s:%d %s: enter\n", + __func__, __LINE__, av->vdev.name); + mutex_lock(&isys->reset_mutex); + while (isys->in_reset) { + mutex_unlock(&isys->reset_mutex); + dev_warn(&isys->adev->dev, "%s:%d %s: wait for reset\n", + __func__, __LINE__, av->vdev.name); + usleep_range(10000, 11000); + mutex_lock(&isys->reset_mutex); + } + mutex_unlock(&isys->reset_mutex); + + mutex_lock(&isys->mutex); + + if (!--isys->video_opened) { + dev_warn(&isys->adev->dev, "%s:%d %s: close fw\n", + __func__, __LINE__, av->vdev.name); + ipu_fw_isys_close(isys); + // isys->reset_needed = true; // force reset + if (isys->fwcom) { + isys->reset_needed = true; + ret = -EIO; + } + } + + mutex_unlock(&isys->mutex); + + if (isys->reset_needed) + pm_runtime_put_sync(&isys->adev->dev); + else + pm_runtime_put(&isys->adev->dev); + + dev_warn(&isys->adev->dev, "%s:%d %s: exit\n", + __func__, __LINE__, av->vdev.name); + return ret; +} + static void stop_streaming(struct vb2_queue *q) { struct ipu_isys_queue *aq = vb2_queue_to_ipu_isys_queue(q); @@ -1187,6 +1311,7 @@ static void stop_streaming(struct vb2_queue *q) av->isys->in_stop_streaming = false; mutex_unlock(&av->isys->reset_mutex); + isys_fw_release(av); } static unsigned int diff --git a/drivers/media/pci/intel/ipu-isys-video.c b/drivers/media/pci/intel/ipu-isys-video.c index f966932847a3..fa9c07e43d1f 100644 --- a/drivers/media/pci/intel/ipu-isys-video.c +++ b/drivers/media/pci/intel/ipu-isys-video.c @@ -145,26 +145,7 @@ const struct ipu_isys_pixelformat ipu_isys_pfmts_packed[] = { static int video_open(struct file *file) { struct ipu_isys_video *av = video_drvdata(file); - struct ipu_isys *isys = av->isys; - struct ipu_bus_device *adev = to_ipu_bus_device(&isys->adev->dev); - struct ipu_device *isp = adev->isp; int rval; - const struct ipu_isys_internal_pdata *ipdata; - - mutex_lock(&isys->mutex); - - if (isys->reset_needed || isp->flr_done) { - mutex_unlock(&isys->mutex); - dev_warn(&isys->adev->dev, "isys power cycle required\n"); - return -EIO; - } - mutex_unlock(&isys->mutex); - - rval = pm_runtime_get_sync(&isys->adev->dev); - if (rval < 0) { - pm_runtime_put_noidle(&isys->adev->dev); - return rval; - } rval = v4l2_fh_open(file); if (rval) @@ -180,47 +161,9 @@ static int video_open(struct file *file) if (rval) goto out_v4l2_fh_release; - mutex_lock(&isys->mutex); - - if (isys->video_opened++) { - /* Already open */ - mutex_unlock(&isys->mutex); - return 0; - } - - ipdata = isys->pdata->ipdata; - ipu_configure_spc(adev->isp, - &ipdata->hw_variant, - IPU_CPD_PKG_DIR_ISYS_SERVER_IDX, - isys->pdata->base, isys->pkg_dir, - isys->pkg_dir_dma_addr); - - /* - * Buffers could have been left to wrong queue at last closure. - * Move them now back to empty buffer queue. - */ - ipu_cleanup_fw_msg_bufs(isys); - - if (isys->fwcom) { - /* - * Something went wrong in previous shutdown. As we are now - * restarting isys we can safely delete old context. - */ - dev_err(&isys->adev->dev, "Clearing old context\n"); - ipu_fw_isys_cleanup(isys); - } - - rval = ipu_fw_isys_init(av->isys, ipdata->num_parallel_streams); - if (rval < 0) - goto out_lib_init; - - mutex_unlock(&isys->mutex); return 0; -out_lib_init: - isys->video_opened--; - mutex_unlock(&isys->mutex); #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) ipu_pipeline_pm_use(&av->vdev.entity, 0); #elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) @@ -232,8 +175,6 @@ static int video_open(struct file *file) out_v4l2_fh_release: v4l2_fh_release(file); out_power_down: - pm_runtime_put(&isys->adev->dev); - return rval; } @@ -246,31 +187,6 @@ static int video_release(struct file *file) av->vdev.name); vb2_fop_release(file); - mutex_lock(&av->isys->reset_mutex); - while (av->isys->in_reset) { - mutex_unlock(&av->isys->reset_mutex); - dev_dbg(&av->isys->adev->dev, "release: %s: wait for reset\n", - av->vdev.name - ); - usleep_range(10000, 11000); - mutex_lock(&av->isys->reset_mutex); - } - mutex_unlock(&av->isys->reset_mutex); - - mutex_lock(&av->isys->mutex); - - if (!--av->isys->video_opened) { - dev_dbg(&av->isys->adev->dev, "release: %s: close fw\n", - av->vdev.name); - ipu_fw_isys_close(av->isys); - if (av->isys->fwcom) { - av->isys->reset_needed = true; - ret = -EIO; - } - } - - mutex_unlock(&av->isys->mutex); - #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) ipu_pipeline_pm_use(&av->vdev.entity, 0); #elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) @@ -278,12 +194,6 @@ static int video_release(struct file *file) #else v4l2_pipeline_pm_put(&av->vdev.entity); #endif - - if (av->isys->reset_needed) - pm_runtime_put_sync(&av->isys->adev->dev); - else - pm_runtime_put(&av->isys->adev->dev); - dev_dbg(&av->isys->adev->dev, "release: %s: exit\n", av->vdev.name); return ret;