| From 5f9e93fed4d45e9a8f84728aff1a8f2ab8922902 Mon Sep 17 00:00:00 2001 |
| From: Marc Zyngier <marc.zyngier@arm.com> |
| Date: Tue, 20 Feb 2018 13:01:18 +0000 |
| Subject: drm/rockchip: Clear all interrupts before requesting the IRQ |
| |
| From: Marc Zyngier <marc.zyngier@arm.com> |
| |
| 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 | 23 ++++++++++++----------- |
| 1 file changed, 12 insertions(+), 11 deletions(-) |
| |
| --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c |
| +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c |
| @@ -1386,6 +1386,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); |
| |
| for (i = 0; i < vop_data->table_size; i++) |
| @@ -1541,17 +1544,9 @@ static int vop_bind(struct device *dev, |
| |
| 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); |
| |
| @@ -1561,13 +1556,19 @@ static int vop_bind(struct device *dev, |
| 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; |
| } |
| |