drm/msm/sde: take irq callback lock before reading cb list

Take the callback spinlock before checking whether the callback
table list is empty. This resolves a race condition where the
callback list could be empty during the servicing of an
interrupt.

Change-Id: I8d59c0211526173ce98c8ca2dac36ec4743dc8f8
Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org>
Signed-off-by: Lakshmi Narayana Kalavala <lkalaval@codeaurora.org>
This commit is contained in:
Lloyd Atkinson 2017-09-18 16:51:24 -04:00 committed by Lakshmi Narayana Kalavala
parent 1f9861ad38
commit 3c6964a08c

View file

@ -31,23 +31,35 @@ static void sde_core_irq_callback_handler(void *arg, int irq_idx)
struct sde_irq *irq_obj = &sde_kms->irq_obj; struct sde_irq *irq_obj = &sde_kms->irq_obj;
struct sde_irq_callback *cb; struct sde_irq_callback *cb;
unsigned long irq_flags; unsigned long irq_flags;
bool cb_tbl_error = false;
int enable_counts = 0;
pr_debug("irq_idx=%d\n", irq_idx); pr_debug("irq_idx=%d\n", irq_idx);
if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
SDE_ERROR("irq_idx=%d has no registered callback\n", irq_idx); if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) {
/* print error outside lock */
cb_tbl_error = true;
enable_counts = atomic_read(
&sde_kms->irq_obj.enable_counts[irq_idx]);
}
atomic_inc(&irq_obj->irq_counts[irq_idx]); atomic_inc(&irq_obj->irq_counts[irq_idx]);
/* /*
* Perform registered function callback * Perform registered function callback
*/ */
spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
list_for_each_entry(cb, &irq_obj->irq_cb_tbl[irq_idx], list) list_for_each_entry(cb, &irq_obj->irq_cb_tbl[irq_idx], list)
if (cb->func) if (cb->func)
cb->func(cb->arg, irq_idx); cb->func(cb->arg, irq_idx);
spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags); spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags);
if (cb_tbl_error) {
SDE_ERROR("irq has no registered callback, idx %d enables %d\n",
irq_idx, enable_counts);
SDE_EVT32_IRQ(irq_idx, enable_counts, SDE_EVTLOG_ERROR);
}
/* /*
* Clear pending interrupt status in HW. * Clear pending interrupt status in HW.
* NOTE: sde_core_irq_callback_handler is protected by top-level * NOTE: sde_core_irq_callback_handler is protected by top-level