]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/tidss: Clear the interrupt status for interrupts being disabled
authorDevarsh Thakkar <devarsht@ti.com>
Mon, 21 Oct 2024 14:07:49 +0000 (17:07 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 13 Mar 2025 11:47:22 +0000 (12:47 +0100)
commit 361a2ebb5cad211732ec3c5d962de49b21895590 upstream.

The driver does not touch the irqstatus register when it is disabling
interrupts.  This might cause an interrupt to trigger for an interrupt
that was just disabled.

To fix the issue, clear the irqstatus registers right after disabling
the interrupts.

Fixes: 32a1795f57ee ("drm/tidss: New driver for TI Keystone platform Display SubSystem")
Cc: stable@vger.kernel.org
Reported-by: Jonathan Cormier <jcormier@criticallink.com>
Closes: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1394222/am625-issue-about-tidss-rcu_preempt-self-detected-stall-on-cpu/5424479#5424479
Signed-off-by: Devarsh Thakkar <devarsht@ti.com>
[Tomi: mostly rewrote the patch]
Reviewed-by: Jonathan Cormier <jcormier@criticallink.com>
Tested-by: Jonathan Cormier <jcormier@criticallink.com>
Reviewed-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241021-tidss-irq-fix-v1-5-82ddaec94e4a@ideasonboard.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/tidss/tidss_dispc.c

index c82708123a795171d8b95c0c0a7005aa83d23b4c..b1093dc1b79a23683b9b336feeb9b5ed2a789eaf 100644 (file)
@@ -596,7 +596,7 @@ void dispc_k2g_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask)
 {
        dispc_irq_t old_mask = dispc_k2g_read_irqenable(dispc);
 
-       /* clear the irqstatus for newly enabled irqs */
+       /* clear the irqstatus for irqs that will be enabled */
        dispc_k2g_clear_irqstatus(dispc, (mask ^ old_mask) & mask);
 
        dispc_k2g_vp_set_irqenable(dispc, 0, mask);
@@ -604,6 +604,9 @@ void dispc_k2g_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask)
 
        dispc_write(dispc, DISPC_IRQENABLE_SET, (1 << 0) | (1 << 7));
 
+       /* clear the irqstatus for irqs that were disabled */
+       dispc_k2g_clear_irqstatus(dispc, (mask ^ old_mask) & old_mask);
+
        /* flush posted write */
        dispc_k2g_read_irqenable(dispc);
 }
@@ -735,7 +738,7 @@ static void dispc_k3_set_irqenable(struct dispc_device *dispc,
 
        old_mask = dispc_k3_read_irqenable(dispc);
 
-       /* clear the irqstatus for newly enabled irqs */
+       /* clear the irqstatus for irqs that will be enabled */
        dispc_k3_clear_irqstatus(dispc, (old_mask ^ mask) & mask);
 
        for (i = 0; i < dispc->feat->num_vps; ++i) {
@@ -760,6 +763,9 @@ static void dispc_k3_set_irqenable(struct dispc_device *dispc,
        if (main_disable)
                dispc_write(dispc, DISPC_IRQENABLE_CLR, main_disable);
 
+       /* clear the irqstatus for irqs that were disabled */
+       dispc_k3_clear_irqstatus(dispc, (old_mask ^ mask) & old_mask);
+
        /* Flush posted writes */
        dispc_read(dispc, DISPC_IRQENABLE_SET);
 }