atomisp: Make sure acceleration fw gets freed when closing the device
authorIlkka Koskinen <ilkka.koskinen@intel.com>
Fri, 2 Mar 2012 13:36:42 +0000 (15:36 +0200)
committerbuildbot <buildbot@intel.com>
Wed, 14 Mar 2012 15:50:10 +0000 (08:50 -0700)
BZ: 15864

In the case the client has requested to load acceleration firmware but
hasn't asked to unload it before closing the device, the resources
reserved for the fw haven't been released.

Change-Id: I23a9832167392dea4b2c4211202a8c95b36d3251
Signed-off-by: Ilkka Koskinen <ilkka.koskinen@intel.com>
Reviewed-on: http://android.intel.com:8080/36863
Reviewed-by: Shevchenko, Andriy <andriy.shevchenko@intel.com>
Reviewed-by: Cohen, David A <david.a.cohen@intel.com>
Tested-by: Koski, Anttu <anttu.koski@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
drivers/media/video/atomisp/atomisp_cmd.c
drivers/media/video/atomisp/atomisp_cmd.h
drivers/media/video/atomisp/atomisp_fops.c

index 6351796..4a3df36 100644 (file)
@@ -3754,44 +3754,34 @@ out:
        return ret;
 }
 
-int atomisp_acc_unload(struct atomisp_device *isp, unsigned int *handle)
+/*
+ * returns   1  if caller needs to wait for completion,
+ *           0  if there's no need to wait or
+ *         < 0  if an error occurred.
+ */
+static int __acc_unload(struct atomisp_device *isp, struct sh_css_acc_fw *fw)
 {
-       struct sh_css_acc_fw *fw;
-       int ret = 0;
-
-       mutex_lock(&isp->input_lock);
-       mutex_lock(&isp->isp_lock);
-
-       fw = __acc_get_fw(isp, *handle);
-
        if (fw == NULL) {
                v4l2_err(&atomisp_dev, "%s: Invalid acceleration firmware "
                                       "handle\n", __func__);
-               ret = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
-       if (!fw->header.loaded) {
-               ret = -EINVAL;
-               goto out;
-       }
+       if (!fw->header.loaded)
+               return -EINVAL;
 
        if (isp->marked_fw_for_unload != NULL) {
                v4l2_err(&atomisp_dev, "%s: Acceleration firmware unload "
                                       "pending\n", __func__);
-               ret = -EBUSY;
-               goto out;
+               return -EBUSY;
        }
 
        if (isp->sw_contex.isp_streaming == false) {
                /* We're not streaming, so it's safe to unload now */
-
                __acc_fw_free_args(isp, fw);
                sh_css_unload_acceleration(fw);
                __acc_fw_free(isp, fw);
-
-               ret = 0;
-               goto out;
+               return 0;
        }
 
        /*
@@ -3800,18 +3790,63 @@ int atomisp_acc_unload(struct atomisp_device *isp, unsigned int *handle)
         */
        init_completion(&isp->acc_unload_fw_complete);
        isp->marked_fw_for_unload = fw;
+       return 1;
+}
+
+int atomisp_acc_unload(struct atomisp_device *isp, unsigned int *handle)
+{
+       struct sh_css_acc_fw *fw;
+       int need_to_wait = 0;
+
+       mutex_lock(&isp->input_lock);
+       mutex_lock(&isp->isp_lock);
+
+       fw  = __acc_get_fw(isp, *handle);
+       need_to_wait = __acc_unload(isp, fw);
 
        mutex_unlock(&isp->isp_lock);
        mutex_unlock(&isp->input_lock);
 
-       wait_for_completion_timeout(&isp->acc_unload_fw_complete, 1 * HZ);
+       if (need_to_wait < 0)
+               return need_to_wait;
 
+       if (need_to_wait > 0)
+               wait_for_completion_timeout(&isp->acc_unload_fw_complete,
+                                           1 * HZ);
        return 0;
+}
 
-out:
+/*
+ * Call with input_lock held
+ */
+void atomisp_acc_unload_all(struct atomisp_device *isp)
+{
+       struct sh_css_acc_fw *fw;
+       int i, need_to_wait;
+
+       if (!isp)
+               return;
+
+       mutex_lock(&isp->isp_lock);
+       for (i = 0; i < ATOMISP_ACC_FW_MAX; i++) {
+               fw = isp->acc_fw[i];
+               if (!fw)
+                       continue;
+
+               need_to_wait = __acc_unload(isp, fw);
+
+               if (need_to_wait > 0) {
+                       mutex_unlock(&isp->isp_lock);
+                       mutex_unlock(&isp->input_lock);
+
+                       wait_for_completion_timeout(
+                               &isp->acc_unload_fw_complete, 1 * HZ);
+
+                       mutex_lock(&isp->input_lock);
+                       mutex_lock(&isp->isp_lock);
+               }
+       }
        mutex_unlock(&isp->isp_lock);
-       mutex_unlock(&isp->input_lock);
-       return ret;
 }
 
 int atomisp_acc_set_arg(struct atomisp_device *isp,
index 8b6d91b..cdb174a 100644 (file)
@@ -286,6 +286,8 @@ int atomisp_acc_load(struct atomisp_device *isp,
 int atomisp_acc_unload(struct atomisp_device *isp,
                       unsigned int *handler);
 
+void atomisp_acc_unload_all(struct atomisp_device *isp);
+
 int atomisp_acc_set_arg(struct atomisp_device *isp,
                        struct atomisp_acc_fw_arg *fw_arg);
 
index 9bde8cc..d751d90 100644 (file)
@@ -464,6 +464,8 @@ static int atomisp_release(struct file *file)
        isp->hw_contex.mmu_l1_base = sh_css_mmu_get_page_table_base_address();
        isp->sw_contex.init = false;
 
+       atomisp_acc_unload_all(isp);
+
 #ifdef CONFIG_PM
        if (pm_runtime_put_sync(vdev->v4l2_dev->dev))
                v4l2_err(&atomisp_dev,