From bc43f7114a0e8173968085b21535d57b8030d571 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 28 Apr 2025 13:37:13 +0200 Subject: drm: adp: Use spin_lock_irqsave for drm device event_lock The lock is used in the interrupt handler so use spin_lock_irqsave to disable interrupts and avoid deadlocks with the irq handler. Fixes: 332122eba628 ("drm: adp: Add Apple Display Pipe driver") Reviewed-by: Alyssa Rosenzweig Signed-off-by: Janne Grunau Link: https://lore.kernel.org/r/20250428-drm_adp_fixes-v2-1-912e081e55d8@jannau.net Signed-off-by: Alyssa Rosenzweig --- drivers/gpu/drm/adp/adp_drv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/adp/adp_drv.c') diff --git a/drivers/gpu/drm/adp/adp_drv.c b/drivers/gpu/drm/adp/adp_drv.c index c98c647f981d..157298a8ff42 100644 --- a/drivers/gpu/drm/adp/adp_drv.c +++ b/drivers/gpu/drm/adp/adp_drv.c @@ -310,6 +310,7 @@ static void adp_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) { u32 frame_num = 1; + unsigned long flags; struct adp_drv_private *adp = crtc_to_adp(crtc); struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state, crtc); u64 new_size = ALIGN(new_state->mode.hdisplay * @@ -330,13 +331,13 @@ static void adp_crtc_atomic_flush(struct drm_crtc *crtc, } writel(ADBE_FIFO_SYNC | frame_num, adp->be + ADBE_FIFO); //FIXME: use adbe flush interrupt - spin_lock_irq(&crtc->dev->event_lock); + spin_lock_irqsave(&crtc->dev->event_lock, flags); if (crtc->state->event) { drm_crtc_vblank_get(crtc); adp->event = crtc->state->event; } crtc->state->event = NULL; - spin_unlock_irq(&crtc->dev->event_lock); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); } static const struct drm_crtc_funcs adp_crtc_funcs = { -- cgit v1.2.3 From 7a7d6681d5adde7dc7e648dcc6b9e9be6ca93d5d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 28 Apr 2025 13:37:14 +0200 Subject: drm: adp: Handle drm_crtc_vblank_get() errors drm_crtc_vblank_get() may fail when it's called before drm_crtc_vblank_on() on a resetted CRTC. This occurs in drm_crtc_helper_funcs' atomic_flush() calls after drm_atomic_helper_crtc_reset() for example directly after probe. Send the vblank event directly in such cases. Avoids following warning in the subsequent drm_crtc_vblank_put() call from the vblank irq handler as below: adp 228200000.display-pipe: [drm] drm_WARN_ON(atomic_read(&vblank->refcount) == 0) WARNING: CPU: 5 PID: 1206 at drivers/gpu/drm/drm_vblank.c:1247 drm_vblank_put+0x158/0x170 ... Call trace: drm_vblank_put+0x158/0x170 (P) drm_crtc_vblank_put+0x24/0x38 adp_fe_irq+0xd8/0xe8 [adpdrm] __handle_irq_event_percpu+0x94/0x318 handle_irq_event+0x54/0xd0 handle_fasteoi_irq+0xa8/0x240 handle_irq_desc+0x3c/0x68 generic_handle_domain_irq+0x24/0x40 Modifying `crtc->state->event` here is fine as crtc->mutex is locked by the non-async atomic commit. In retrospect this looks so obvious that it doesn't warrant a comment in the file. Signed-off-by: Janne Grunau Reviewed-by: Alyssa Rosenzweig Link: https://lore.kernel.org/r/20250428-drm_adp_fixes-v2-2-912e081e55d8@jannau.net Signed-off-by: Alyssa Rosenzweig --- drivers/gpu/drm/adp/adp_drv.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/adp/adp_drv.c') diff --git a/drivers/gpu/drm/adp/adp_drv.c b/drivers/gpu/drm/adp/adp_drv.c index 157298a8ff42..bdf27ee742ea 100644 --- a/drivers/gpu/drm/adp/adp_drv.c +++ b/drivers/gpu/drm/adp/adp_drv.c @@ -331,13 +331,19 @@ static void adp_crtc_atomic_flush(struct drm_crtc *crtc, } writel(ADBE_FIFO_SYNC | frame_num, adp->be + ADBE_FIFO); //FIXME: use adbe flush interrupt - spin_lock_irqsave(&crtc->dev->event_lock, flags); if (crtc->state->event) { - drm_crtc_vblank_get(crtc); - adp->event = crtc->state->event; + struct drm_pending_vblank_event *event = crtc->state->event; + + crtc->state->event = NULL; + spin_lock_irqsave(&crtc->dev->event_lock, flags); + + if (drm_crtc_vblank_get(crtc) != 0) + drm_crtc_send_vblank_event(crtc, event); + else + adp->event = event; + + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); } - crtc->state->event = NULL; - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); } static const struct drm_crtc_funcs adp_crtc_funcs = { -- cgit v1.2.3 From c082a52125d9007b488d590c412fd126aa78c345 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 28 Apr 2025 13:37:15 +0200 Subject: drm: adp: Enable vblank interrupts in crtc's .atomic_enable Calling drm_crtc_vblank_on() drm_crtc_helper_funcs' atomic_enable is expected to enable vblank interrupts. It may have been avoided here to due to drm_crtc_vblank_get()'s error behavior after drm_crtc_vblank_reset(). With that fixed in the preceding change the driver can call drm_crtc_vblank_on() from adp_crtc_atomic_enable(). Reviewed-by: Alyssa Rosenzweig Signed-off-by: Janne Grunau Link: https://lore.kernel.org/r/20250428-drm_adp_fixes-v2-3-912e081e55d8@jannau.net Signed-off-by: Alyssa Rosenzweig --- drivers/gpu/drm/adp/adp_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/adp/adp_drv.c') diff --git a/drivers/gpu/drm/adp/adp_drv.c b/drivers/gpu/drm/adp/adp_drv.c index bdf27ee742ea..50d26c73301c 100644 --- a/drivers/gpu/drm/adp/adp_drv.c +++ b/drivers/gpu/drm/adp/adp_drv.c @@ -288,6 +288,7 @@ static void adp_crtc_atomic_enable(struct drm_crtc *crtc, writel(BIT(0), adp->be + ADBE_BLEND_EN3); writel(BIT(0), adp->be + ADBE_BLEND_BYPASS); writel(BIT(0), adp->be + ADBE_BLEND_EN4); + drm_crtc_vblank_on(crtc); } static void adp_crtc_atomic_disable(struct drm_crtc *crtc, @@ -519,8 +520,7 @@ static int adp_drm_bind(struct device *dev) struct adp_drv_private *adp = to_adp(drm); int err; - adp_disable_vblank(adp); - writel(ADP_CTRL_FIFO_ON | ADP_CTRL_VBLANK_ON, adp->fe + ADP_CTRL); + writel(ADP_CTRL_FIFO_ON, adp->fe + ADP_CTRL); adp->next_bridge = drmm_of_get_bridge(&adp->drm, dev->of_node, 0, 0); if (IS_ERR(adp->next_bridge)) { -- cgit v1.2.3 From 8f6dfc4d7037e88cc0a4be4f290829946999341f Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 28 Apr 2025 13:37:16 +0200 Subject: drm: adp: Remove pointless irq_lock spin lock Interrupt handlers run with interrupts disabled so it is not necessary to protect them against reentrancy. Reviewed-by: Alyssa Rosenzweig Signed-off-by: Janne Grunau Link: https://lore.kernel.org/r/20250428-drm_adp_fixes-v2-4-912e081e55d8@jannau.net Signed-off-by: Alyssa Rosenzweig --- drivers/gpu/drm/adp/adp_drv.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/gpu/drm/adp/adp_drv.c') diff --git a/drivers/gpu/drm/adp/adp_drv.c b/drivers/gpu/drm/adp/adp_drv.c index 50d26c73301c..54cde090c3f4 100644 --- a/drivers/gpu/drm/adp/adp_drv.c +++ b/drivers/gpu/drm/adp/adp_drv.c @@ -121,7 +121,6 @@ struct adp_drv_private { dma_addr_t mask_iova; int be_irq; int fe_irq; - spinlock_t irq_lock; struct drm_pending_vblank_event *event; }; @@ -490,8 +489,6 @@ static irqreturn_t adp_fe_irq(int irq, void *arg) u32 int_status; u32 int_ctl; - spin_lock(&adp->irq_lock); - int_status = readl(adp->fe + ADP_INT_STATUS); if (int_status & ADP_INT_STATUS_VBLANK) { drm_crtc_handle_vblank(&adp->crtc); @@ -509,7 +506,6 @@ static irqreturn_t adp_fe_irq(int irq, void *arg) writel(int_status, adp->fe + ADP_INT_STATUS); - spin_unlock(&adp->irq_lock); return IRQ_HANDLED; } @@ -574,8 +570,6 @@ static int adp_probe(struct platform_device *pdev) if (IS_ERR(adp)) return PTR_ERR(adp); - spin_lock_init(&adp->irq_lock); - dev_set_drvdata(&pdev->dev, &adp->drm); err = adp_parse_of(pdev, adp); -- cgit v1.2.3