drm/rockchip: Clear all interrupts before requesting the IRQ
authorMarc Zyngier <marc.zyngier@arm.com>
Tue, 20 Feb 2018 13:01:18 +0000 (13:01 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Apr 2018 07:36:35 +0000 (09:36 +0200)
commit 5f9e93fed4d45e9a8f84728aff1a8f2ab8922902 upstream.

Calling request_irq() followed by disable_irq() is usually a bad idea,
specially if the interrupt can be pending, and you're not yet in a
position to handle it.

This is exactly what happens on my kevin system when rebooting in a
second kernel using kexec: Some interrupt is left pending from
the previous kernel, and we take it too early, before disable_irq()
could do anything.

Let's clear the pending interrupts as we initialize the HW, and move
the interrupt request after that point. This ensures that we're in
a sane state when the interrupt is requested.

Cc: stable@vger.kernel.org
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
[adapted to recent rockchip-drm changes]
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20180220130120.5254-2-marc.zyngier@arm.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/rockchip/rockchip_drm_vop.c

index bf9ed0e639731cf15d0847674856a7082986ac76..f1fa8d5c9b52464f0c372763d8abbd4110c6dd01 100644 (file)
@@ -1413,6 +1413,9 @@ static int vop_initial(struct vop *vop)
        usleep_range(10, 20);
        reset_control_deassert(ahb_rst);
 
+       VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1);
+       VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0);
+
        memcpy(vop->regsbak, vop->regs, vop->len);
 
        VOP_REG_SET(vop, misc, global_regdone_en, 1);
@@ -1568,17 +1571,9 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
 
        mutex_init(&vop->vsync_mutex);
 
-       ret = devm_request_irq(dev, vop->irq, vop_isr,
-                              IRQF_SHARED, dev_name(dev), vop);
-       if (ret)
-               return ret;
-
-       /* IRQ is initially disabled; it gets enabled in power_on */
-       disable_irq(vop->irq);
-
        ret = vop_create_crtc(vop);
        if (ret)
-               goto err_enable_irq;
+               return ret;
 
        pm_runtime_enable(&pdev->dev);
 
@@ -1588,13 +1583,19 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
                goto err_disable_pm_runtime;
        }
 
+       ret = devm_request_irq(dev, vop->irq, vop_isr,
+                              IRQF_SHARED, dev_name(dev), vop);
+       if (ret)
+               goto err_disable_pm_runtime;
+
+       /* IRQ is initially disabled; it gets enabled in power_on */
+       disable_irq(vop->irq);
+
        return 0;
 
 err_disable_pm_runtime:
        pm_runtime_disable(&pdev->dev);
        vop_destroy_crtc(vop);
-err_enable_irq:
-       enable_irq(vop->irq); /* To balance out the disable_irq above */
        return ret;
 }