diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2018-02-20 08:01:18 -0500 |
---|---|---|
committer | Heiko Stuebner <heiko@sntech.de> | 2018-03-14 09:02:05 -0400 |
commit | 5f9e93fed4d45e9a8f84728aff1a8f2ab8922902 (patch) | |
tree | e927501cc748b896159558c7be94e56ec56dc630 | |
parent | ce31ddd5c40c0662ffb9957b868fbd58f6eac5b3 (diff) |
drm/rockchip: Clear all interrupts before requesting the IRQ
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
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 23 |
1 files changed, 12 insertions, 11 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index b601c59e76a8..7a1de09d45d8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
@@ -1401,6 +1401,9 @@ static int vop_initial(struct vop *vop) | |||
1401 | usleep_range(10, 20); | 1401 | usleep_range(10, 20); |
1402 | reset_control_deassert(ahb_rst); | 1402 | reset_control_deassert(ahb_rst); |
1403 | 1403 | ||
1404 | VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1); | ||
1405 | VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0); | ||
1406 | |||
1404 | memcpy(vop->regsbak, vop->regs, vop->len); | 1407 | memcpy(vop->regsbak, vop->regs, vop->len); |
1405 | 1408 | ||
1406 | VOP_REG_SET(vop, misc, global_regdone_en, 1); | 1409 | VOP_REG_SET(vop, misc, global_regdone_en, 1); |
@@ -1564,17 +1567,9 @@ static int vop_bind(struct device *dev, struct device *master, void *data) | |||
1564 | spin_lock_init(&vop->irq_lock); | 1567 | spin_lock_init(&vop->irq_lock); |
1565 | mutex_init(&vop->vop_lock); | 1568 | mutex_init(&vop->vop_lock); |
1566 | 1569 | ||
1567 | ret = devm_request_irq(dev, vop->irq, vop_isr, | ||
1568 | IRQF_SHARED, dev_name(dev), vop); | ||
1569 | if (ret) | ||
1570 | return ret; | ||
1571 | |||
1572 | /* IRQ is initially disabled; it gets enabled in power_on */ | ||
1573 | disable_irq(vop->irq); | ||
1574 | |||
1575 | ret = vop_create_crtc(vop); | 1570 | ret = vop_create_crtc(vop); |
1576 | if (ret) | 1571 | if (ret) |
1577 | goto err_enable_irq; | 1572 | return ret; |
1578 | 1573 | ||
1579 | pm_runtime_enable(&pdev->dev); | 1574 | pm_runtime_enable(&pdev->dev); |
1580 | 1575 | ||
@@ -1585,13 +1580,19 @@ static int vop_bind(struct device *dev, struct device *master, void *data) | |||
1585 | goto err_disable_pm_runtime; | 1580 | goto err_disable_pm_runtime; |
1586 | } | 1581 | } |
1587 | 1582 | ||
1583 | ret = devm_request_irq(dev, vop->irq, vop_isr, | ||
1584 | IRQF_SHARED, dev_name(dev), vop); | ||
1585 | if (ret) | ||
1586 | goto err_disable_pm_runtime; | ||
1587 | |||
1588 | /* IRQ is initially disabled; it gets enabled in power_on */ | ||
1589 | disable_irq(vop->irq); | ||
1590 | |||
1588 | return 0; | 1591 | return 0; |
1589 | 1592 | ||
1590 | err_disable_pm_runtime: | 1593 | err_disable_pm_runtime: |
1591 | pm_runtime_disable(&pdev->dev); | 1594 | pm_runtime_disable(&pdev->dev); |
1592 | vop_destroy_crtc(vop); | 1595 | vop_destroy_crtc(vop); |
1593 | err_enable_irq: | ||
1594 | enable_irq(vop->irq); /* To balance out the disable_irq above */ | ||
1595 | return ret; | 1596 | return ret; |
1596 | } | 1597 | } |
1597 | 1598 | ||