From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DCC11EB1063 for ; Tue, 10 Mar 2026 11:57:33 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id AE65910E26F; Tue, 10 Mar 2026 11:57:26 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (2048-bit key; unprotected) header.d=lankhorst.se header.i=@lankhorst.se header.b="a2Ts1n2p"; dkim-atps=neutral Received: from lankhorst.se (unknown [141.105.120.124]) by gabe.freedesktop.org (Postfix) with ESMTPS id BB9E010E1F2; Tue, 10 Mar 2026 11:57:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=lankhorst.se; s=default; t=1773143843; bh=Le2Q5cdMSlLs9kI11LADAcVP/SWnrgTi+QvLCNbuBRo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=a2Ts1n2pGTJkPY+MQoCQBcFg8KNoBf9Qsss4eh8Bo1hmLGp1FYhzuS7+qgGR8Q1+0 cA7V7VmU6xJ6DeRsXhwohqKn7ZfalN7ikgtdNEx3dyC2QPXii6804ZaIwx1hi7trU+ yd3gGrbQ9g/n3N3dskmPGCC3OlCEKpyLLuVfJ2RGkep1vQh09iWAUkR4gN/rxut1Nr gg/ZsHJWb/mc33SIUhN6UmtVNFK5l1KeLFA+PugDV7g9dv4CXAIiznDHuDRbSv6s9l nbvjat4hRjhYpT48Ubk7w3RBanDT2uIMa6j+EMZT3D8sl0T2ngh9rONElAfjN8DuGu 2hq4YPcpPZbyA== From: Maarten Lankhorst To: intel-xe@lists.freedesktop.org, intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org, Maarten Lankhorst Subject: [PATCH v7 02/26] drm/vblank: Add a 2-stage version of drm_crtc_arm_vblank_event Date: Tue, 10 Mar 2026 12:56:44 +0100 Message-ID: <20260310115709.2276203-3-dev@lankhorst.se> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260310115709.2276203-1-dev@lankhorst.se> References: <20260310115709.2276203-1-dev@lankhorst.se> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" When trying to fix the hardware programming in intel/display, I had to take all the vblank locks with local_irqs_disabled(). This required converting the entire vblank code to raw spinlocks. In the alternative approach, do all preparations in advance, and only enable the vblank_event with interrupts disabled, this requires only a simple write and prevents a complete re-architecture of the code. Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/drm_vblank.c | 61 +++++++++++++++++++++++++++++++++++- include/drm/drm_vblank.h | 14 ++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index f78bf37f1e0a7..388d94e2e961f 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -1118,12 +1118,68 @@ void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, assert_spin_locked(&dev->event_lock); + WARN_ON(e->postponed); e->pipe = pipe; e->sequence = drm_crtc_accurate_vblank_count(crtc) + 1; list_add_tail(&e->base.link, &dev->vblank_event_list); } EXPORT_SYMBOL(drm_crtc_arm_vblank_event); +/** + * drm_crtc_prepare_arm_vblank_event - arm vblank event *before* pageflip. + * @crtc: the source CRTC of the vblank event + * @e: the event to send + * + * See drm_crtc_arm_vblank_event(). This function is a 2-stage version of + * that call. This function is called *BEFORE* programming the hardware. + * + * After programming, call drm_crtc_arm_prepared_vblank_event() and the + * event will be scheduled on the next vblank. + * + * This is mainly useful for code that has to run on PREEMPT_RT kernels, + * with interrupts disabled, since all vblank spinlocks are converted to + * rtmutexes, and code running with irqs disabled cannot take any vblank lock. + * + * It also increases determinism for any hardware + * programming, since no vblank related locks are taking when arming. + */ +void drm_crtc_prepare_arm_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e) +{ + drm_crtc_arm_vblank_event(crtc, e); + + /* Set the flag, so that the event is not fired yet */ + e->postponed = true; +} +EXPORT_SYMBOL(drm_crtc_prepare_arm_vblank_event); + +/** + * drm_crtc_arm_prepared_vblank_event - arm prepared vblank event *after* pageflip. + * @crtc: the source CRTC of the vblank event + * @e: the event to send + * + * See drm_crtc_prepare_arm_vblank_event(). This function is a 2-stage version of + * that call. This function is called directly *AFTER* programming the hardware. + * + * Before this function is called, drm_crtc_prepare_arm_vblank_event() should be + * called instead. + * + * This is mainly useful for code that has to run on PREEMPT_RT kernels, + * with interrupts disabled, since all vblank spinlocks are converted to + * rtmutexes, and code running with irqs disabled cannot take any vblank lock. + * + * It also increases determinism for any hardware + * programming, since no vblank related locks are taking when arming. + */ +void drm_crtc_arm_prepared_vblank_event(struct drm_pending_vblank_event *e) +{ + WARN_ON(!e->postponed); + + /* remove the flag to be processed as a normal event */ + WRITE_ONCE(e->postponed, false); +} +EXPORT_SYMBOL(drm_crtc_arm_prepared_vblank_event); + /** * drm_crtc_send_vblank_event - helper to send vblank event after pageflip * @crtc: the source CRTC of the vblank event @@ -1381,6 +1437,8 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { if (e->pipe != pipe) continue; + + WARN_ON(e->postponed); drm_dbg_core(dev, "Sending premature vblank event on disable: " "wanted %llu, current %llu\n", e->sequence, seq); @@ -1886,7 +1944,8 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) seq = drm_vblank_count_and_time(dev, pipe, &now); list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { - if (e->pipe != pipe) + /* Matches WRITE_ONCE in drm_crtc_arm_prepared_vblank_event() */ + if (e->pipe != pipe || READ_ONCE(e->postponed)) continue; if (!drm_vblank_passed(seq, e->sequence)) continue; diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h index 2fcef9c0f5b1b..956d5621eb7f9 100644 --- a/include/drm/drm_vblank.h +++ b/include/drm/drm_vblank.h @@ -53,6 +53,13 @@ struct drm_pending_vblank_event { * @sequence: frame event should be triggered at */ u64 sequence; + + /** + * @postponed: whether drm_crtc_prepare_arm_vblank_event() is called, + * and drm_crtc_arm_prepared_vblank_event has yet to be called to arm. + */ + bool postponed; + /** * @event: Actual event which will be sent to userspace. */ @@ -294,7 +301,12 @@ int drm_crtc_next_vblank_start(struct drm_crtc *crtc, ktime_t *vblanktime); void drm_crtc_send_vblank_event(struct drm_crtc *crtc, struct drm_pending_vblank_event *e); void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, - struct drm_pending_vblank_event *e); + struct drm_pending_vblank_event *e); + +void drm_crtc_prepare_arm_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e); +void drm_crtc_arm_prepared_vblank_event(struct drm_pending_vblank_event *e); + void drm_vblank_set_event(struct drm_pending_vblank_event *e, u64 *seq, ktime_t *now); -- 2.51.0