The primary IRQ handler latches HPD status for the threaded handler
before servicing DP controller interrupts.
When an HPD interrupt was pending, the handler set its return value to
IRQ_WAKE_THREAD and then ORed it with msm_dp_ctrl_isr()'s return value.
If the controller ISR returned IRQ_HANDLED, the primary handler returned
IRQ_HANDLED | IRQ_WAKE_THREAD instead.
The IRQ core wakes an action's thread only when its primary handler
returns IRQ_WAKE_THREAD exactly. In that case, the HPD status was latched
for the threaded handler, but the handler itself was not woken.
Return IRQ_WAKE_THREAD directly whenever an unmasked HPD interrupt is
pending, after servicing controller interrupts in hardirq context, while
retaining the existing IRQ_HANDLED fallback for non-HPD interrupts.
Also report STATUS2 interrupts as handled. msm_dp_ctrl_get_interrupt()
acknowledges every pending STATUS2 source, including sources that need no
additional action, so they must not be reported as IRQ_NONE.
Fixes: 5043357e75ba ("drm/msm/dp: rework HPD handling")
Cc: [email protected] # v7.2+
Signed-off-by: Yongxing Mou <[email protected]>
---
drivers/gpu/drm/msm/dp/dp_ctrl.c | 3 +++
drivers/gpu/drm/msm/dp/dp_display.c | 7 ++++---
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index f1642413e4a3..53dd7a23e091 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -3051,6 +3051,9 @@ irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl
*msm_dp_ctrl,
}
isr = msm_dp_ctrl_get_interrupt(ctrl);
+ /* All status2 sources are ACKed by msm_dp_ctrl_get_interrupt(). */
+ if (isr & DP_INTERRUPT_STATUS2)
+ ret = IRQ_HANDLED;
if (isr & DP_CTRL_INTR_READY_FOR_VIDEO) {
drm_dbg_dp(ctrl->drm_dev, "dp_video_ready\n");
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c
b/drivers/gpu/drm/msm/dp/dp_display.c
index 327777f5c95e..ed0b93e3bd08 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1089,23 +1089,24 @@ static irqreturn_t msm_dp_display_irq_handler(int irq,
void *dev_id)
u32 hpd_isr_status;
unsigned long flags;
irqreturn_t ret = IRQ_HANDLED;
+ bool hpd_irq_pending;
hpd_isr_status = msm_dp_aux_get_hpd_intr_status(dp->aux);
+ hpd_irq_pending = hpd_isr_status & DP_DP_HPD_INT_MASK;
- if (hpd_isr_status & 0x0F) {
+ if (hpd_irq_pending) {
drm_dbg_dp(dp->drm_dev, "type=%d isr=0x%x\n",
dp->msm_dp_display.connector_type, hpd_isr_status);
spin_lock_irqsave(&dp->irq_thread_lock, flags);
dp->hpd_isr_status |= hpd_isr_status;
- ret = IRQ_WAKE_THREAD;
spin_unlock_irqrestore(&dp->irq_thread_lock, flags);
}
/* DP controller isr */
ret |= msm_dp_ctrl_isr(dp->ctrl, dp->panel);
- return ret;
+ return hpd_irq_pending ? IRQ_WAKE_THREAD : ret;
}
static irqreturn_t msm_dp_display_irq_thread(int irq, void *dev_id)
--
2.43.0