Merge remote-tracking branch 'lightnvm/for-next'
[deliverable/linux.git] / drivers / media / platform / s5p-mfc / s5p_mfc.c
index e3f104fafd0ae864c2f4e5f955dee50ee6d4a5e5..0a5b8f5e011e7ec83ddafee74165989f603cb1d4 100644 (file)
@@ -153,7 +153,7 @@ static void s5p_mfc_watchdog(unsigned long arg)
                 * error. Now it is time to kill all instances and
                 * reset the MFC. */
                mfc_err("Time out during waiting for HW\n");
-               queue_work(dev->watchdog_workqueue, &dev->watchdog_work);
+               schedule_work(&dev->watchdog_work);
        }
        dev->watchdog_timer.expires = jiffies +
                                        msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
@@ -494,7 +494,6 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
        s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
        s5p_mfc_clock_off();
        wake_up_dev(dev, reason, err);
-       return;
 }
 
 /* Header parsing interrupt handling */
@@ -759,7 +758,6 @@ static int s5p_mfc_open(struct file *file)
        /* Allocate memory for context */
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
        if (!ctx) {
-               mfc_err("Not enough memory\n");
                ret = -ENOMEM;
                goto err_alloc;
        }
@@ -776,7 +774,7 @@ static int s5p_mfc_open(struct file *file)
        while (dev->ctx[ctx->num]) {
                ctx->num++;
                if (ctx->num >= MFC_NUM_CONTEXTS) {
-                       mfc_err("Too many open contexts\n");
+                       mfc_debug(2, "Too many open contexts\n");
                        ret = -EBUSY;
                        goto err_no_ctx;
                }
@@ -924,39 +922,50 @@ static int s5p_mfc_release(struct file *file)
        struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
        struct s5p_mfc_dev *dev = ctx->dev;
 
+       /* if dev is null, do cleanup that doesn't need dev */
        mfc_debug_enter();
-       mutex_lock(&dev->mfc_mutex);
+       if (dev)
+               mutex_lock(&dev->mfc_mutex);
        s5p_mfc_clock_on();
        vb2_queue_release(&ctx->vq_src);
        vb2_queue_release(&ctx->vq_dst);
-       /* Mark context as idle */
-       clear_work_bit_irqsave(ctx);
-       /* If instance was initialised and not yet freed,
-        * return instance and free resources */
-       if (ctx->state != MFCINST_FREE && ctx->state != MFCINST_INIT) {
-               mfc_debug(2, "Has to free instance\n");
-               s5p_mfc_close_mfc_inst(dev, ctx);
-       }
-       /* hardware locking scheme */
-       if (dev->curr_ctx == ctx->num)
-               clear_bit(0, &dev->hw_lock);
-       dev->num_inst--;
-       if (dev->num_inst == 0) {
-               mfc_debug(2, "Last instance\n");
-               s5p_mfc_deinit_hw(dev);
-               del_timer_sync(&dev->watchdog_timer);
-               if (s5p_mfc_power_off() < 0)
-                       mfc_err("Power off failed\n");
+       if (dev) {
+               /* Mark context as idle */
+               clear_work_bit_irqsave(ctx);
+               /*
+                * If instance was initialised and not yet freed,
+                * return instance and free resources
+               */
+               if (ctx->state != MFCINST_FREE && ctx->state != MFCINST_INIT) {
+                       mfc_debug(2, "Has to free instance\n");
+                       s5p_mfc_close_mfc_inst(dev, ctx);
+               }
+               /* hardware locking scheme */
+               if (dev->curr_ctx == ctx->num)
+                       clear_bit(0, &dev->hw_lock);
+               dev->num_inst--;
+               if (dev->num_inst == 0) {
+                       mfc_debug(2, "Last instance\n");
+                       s5p_mfc_deinit_hw(dev);
+                       del_timer_sync(&dev->watchdog_timer);
+                       if (s5p_mfc_power_off() < 0)
+                               mfc_err("Power off failed\n");
+               }
        }
        mfc_debug(2, "Shutting down clock\n");
        s5p_mfc_clock_off();
-       dev->ctx[ctx->num] = NULL;
+       if (dev)
+               dev->ctx[ctx->num] = NULL;
        s5p_mfc_dec_ctrls_delete(ctx);
        v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
+       /* vdev is gone if dev is null */
+       if (dev)
+               v4l2_fh_exit(&ctx->fh);
        kfree(ctx);
        mfc_debug_leave();
-       mutex_unlock(&dev->mfc_mutex);
+       if (dev)
+               mutex_unlock(&dev->mfc_mutex);
+
        return 0;
 }
 
@@ -1158,10 +1167,6 @@ static int s5p_mfc_probe(struct platform_device *pdev)
        dev->variant = mfc_get_drv_data(pdev);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "failed to get io resource\n");
-               return -ENOENT;
-       }
        dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(dev->regs_base))
                return PTR_ERR(dev->regs_base);
@@ -1241,7 +1246,6 @@ static int s5p_mfc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, dev);
 
        dev->hw_lock = 0;
-       dev->watchdog_workqueue = create_singlethread_workqueue(S5P_MFC_NAME);
        INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker);
        atomic_set(&dev->watchdog_cnt, 0);
        init_timer(&dev->watchdog_timer);
@@ -1298,12 +1302,28 @@ err_dma:
 static int s5p_mfc_remove(struct platform_device *pdev)
 {
        struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
+       struct s5p_mfc_ctx *ctx;
+       int i;
 
        v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name);
 
+       /*
+        * Clear ctx dev pointer to avoid races between s5p_mfc_remove()
+        * and s5p_mfc_release() and s5p_mfc_release() accessing ctx->dev
+        * after s5p_mfc_remove() is run during unbind.
+       */
+       mutex_lock(&dev->mfc_mutex);
+       for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+               ctx = dev->ctx[i];
+               if (!ctx)
+                       continue;
+               /* clear ctx->dev */
+               ctx->dev = NULL;
+       }
+       mutex_unlock(&dev->mfc_mutex);
+
        del_timer_sync(&dev->watchdog_timer);
-       flush_workqueue(dev->watchdog_workqueue);
-       destroy_workqueue(dev->watchdog_workqueue);
+       flush_work(&dev->watchdog_work);
 
        video_unregister_device(dev->vfd_enc);
        video_unregister_device(dev->vfd_dec);
This page took 0.026805 seconds and 5 git commands to generate.