mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Thomas Zimmermann <tzimmermann@suse.de>
To: Thorsten Leemhuis <regressions@leemhuis.info>,
	Roman Ilin <me@romanilin.is>
Cc: "David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Maxime Ripard" <mripard@kernel.org>,
	"Louis Chauvet" <louis.chauvet@bootlin.com>,
	"Javier Martinez Canillas" <javierm@redhat.com>,
	"Dmitry Osipenko" <dmitry.osipenko@collabora.com>,
	dri-devel@lists.freedesktop.org, virtualization@lists.linux.dev,
	linux-kernel@vger.kernel.org,
	"Ville Syrjälä" <ville.syrjala@linux.intel.com>,
	"Peter Arnesen" <peter.m.arnesen@gmail.com>,
	"Linux kernel regressions list" <regressions@lists.linux.dev>,
	"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>
Subject: Re: [PATCH v3] drm/vblank: Don't arm vblank timer with invalid frame duration
Date: Fri, 4 Sep 2026 08:19:16 +0200	[thread overview]
Message-ID: <f0e4cc76-5cf3-4fdb-b42c-f405a09c0d2a@suse.de> (raw)
In-Reply-To: <0600a3f0-b2d2-4a07-ab21-f590c2979612@leemhuis.info>

Hi Thorsten

Am 03.09.26 um 16:07 schrieb Thorsten Leemhuis:
> On 7/3/26 09:26, Thomas Zimmermann wrote:
>> Am 02.07.26 um 20:23 schrieb Roman Ilin:
>>> Apologies, I accidentally fired off send-email before saving my final
>>> changelog notes. Please ignore the changelog and notes in the original
>>> v3 email.
>>>
>>> The actual changes in v3 are:
>>>
>>> - Changed the WARN_ON_ONCE to drm_dbg_kms (to avoid user-triggerable
>>>     panics).
>> We want to know when this happens. And user space will only be able to
>> trigger this once, so there's no risk of spamming the kernel log.
> Hmmm, just wondering: what's the status here?
>
> Roman Ilin, did you loose interest? Or was this continued somewhere or
> maybe even resolved and I just missed that?
>
> Thomas: if Roman left this behind, could you maybe handle this, as it
> fixes a regressions that iirc is caused by a change of yours? Or is it
> fine for some reason to ignore this, even if the userland problem that
> triggers this is still unfixed afaics? Side note: I by chance saw that
> the latter a few days ago got a new comment from someone that ran into it.
> https://gitlab.freedesktop.org/spice/linux/vd_agent/-/work_items/52

AFAICT it was almost there except for the error messaging. The v4 then 
never happened. I can finish the patch if Roman is no longer around.

Best regards
Thomas

>
> Ciao, Thorsten
>> So this is not really a problem. drm_WARN_ON_ONCE was ok for that. You
>> can also use a regular DRM print macro. But instead of drm_dbg_kms()
>> should use drm_err_once(). But please also output linedur_ns and
>> framedur_ns in the error. We want to know which of them is incorrect.
>> You can also add more information to the error message. See [1] for the
>> mode-formating macros.
>>
>> [1] https://elixir.bootlin.com/linux/v7.1.2/source/include/drm/
>> drm_modes.h#L422
>>
>>
>>> - Updated drm_calc_timestamping_constants with the goto error fallback
>>>     to clear the stale state.
>>>
>>> Also, an automated review bot pointed out an AB-BA deadlock in
>>> drm_crtc_vblank_start_timer(). But I am leaving this out of the patch to
>>> keep the fixes orthogonal.
>>>
>>> Sorry for the noise.
>>>
>>>> On Jul 2, 2026, at 21:10, Roman Ilin <me@romanilin.is> wrote:
>>>>
>>>> When a CRTC's display mode carries a too small pixel clock,
>>>> drm_calc_timestamping_constants() computes a frame duration that
>>>> exceeds INT_MAX. drm_vblank_crtc.framedur_ns becomes negative.
>>>> drm_crtc_vblank_start_timer() then arms the vblank hrtimer with this
>>>> interval, after which vblank events are no longer delivered. Pending
>>>> page flips never complete and the display appears frozen.
>>>>
>>>> This could be triggered on virtio-gpu guests that have dynamic
>>>> resolution
>>>> enabled: when the SPICE agent or the X server resizes the output, it
>>>> submits a mode whose pixel clock is off by a factor of 1000, e.g.:
>>>>
>>>>      clock = 406 kHz, htotal = 3152, vtotal = 2148
>>>>
>>>>      framedur_ns = 3152 * 2148 * 1000000 / 406 = 16675852216 ns (~16.7 s)
>>>>
>>>> 16675852216 does not fit into an int and wraps to roughly -504000000.
>>>> ns_to_ktime() then yields a negative interval and the timer stops
>>>> working.
>>>>
>>>> Found by bisection, which pointed at commit a036f5fceedb ("drm/virtgpu:
>>>> Use vblank timer"). That commit merely made virtio-gpu use the vblank
>>>> timer and thereby exposed the pre-existing problem in the timer setup
>>>> added by commit 74afeb812850 ("drm/vblank: Add vblank timer").
>>>>
>>>> To fix this, modify drm_calc_timestamping_constants() to use u64 for
>>>> calculations, check for INT_MAX overflows, and return an error code.
>>>> drm_crtc_vblank_start_timer() will then propagate the error, enabling
>>>> the driver to fall back to immediate vblank events. Valid modes are
>>>> unaffected, and the timer self-heals on the next mode with a sane clock.
>>>>
>>>> Fixes: 74afeb812850 ("drm/vblank: Add vblank timer")
>>>> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
>>>> Signed-off-by: Roman Ilin <me@romanilin.is>
>>>> ---
>>>> Changes in v3:
>>>>
>>>> - Changed the WARN_ON_ONCE to drm_err_once
>>>>
>>>> Notes:
>>>>
>>>>
>>>>
>>>> drivers/gpu/drm/drm_vblank.c | 71 +++++++++++++++++++++++-------------
>>>> include/drm/drm_vblank.h     |  4 +-
>>>> 2 files changed, 48 insertions(+), 27 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
>>>> index f90fb2d13..629b9fcc7 100644
>>>> --- a/drivers/gpu/drm/drm_vblank.c
>>>> +++ b/drivers/gpu/drm/drm_vblank.c
>>>> @@ -631,42 +631,51 @@ EXPORT_SYMBOL(drm_crtc_vblank_waitqueue);
>>>>    * drm_crtc_vblank_helper_get_vblank_timestamp(). They are derived from
>>>>    * CRTC's true scanout timing, so they take things like panel
>>>> scaling or
>>>>    * other adjustments into account.
>>>> + *
>>>> + * Returns:
>>>> + * 0 on success, or a negative errno code otherwise.
>>>>    */
>>>> -void drm_calc_timestamping_constants(struct drm_crtc *crtc,
>>>> -     const struct drm_display_mode *mode)
>>>> +int drm_calc_timestamping_constants(struct drm_crtc *crtc,
>>>> +    const struct drm_display_mode *mode)
>>>> {
>>>> struct drm_device *dev = crtc->dev;
>>>> unsigned int pipe = drm_crtc_index(crtc);
>>>> struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
>>>> - int linedur_ns = 0, framedur_ns = 0;
>>>> + u64 linedur_ns, framedur_ns;
>>>> int dotclock = mode->crtc_clock;
>>>> + unsigned int frame_size;
>>>>
>>>> if (!drm_dev_has_vblank(dev))
>>>> - return;
>>>> + return 0;
>>>>
>>>> if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
>>>> - return;
>>>> + return -EINVAL;
>>>>
>>>> - /* Valid dotclock? */
>>>> - if (dotclock > 0) {
>>>> - int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
>>>> + if (dotclock <= 0) {
>>>> + drm_err(dev, "crtc %u: Can't calculate constants, dotclock = %d!\n",
>> Please turn this into drm_err_once() because this call can actually be
>> triggered repeatedly from userspace.
>>
>> Best regards
>> Thomas
>>
>>
>>>> + crtc->base.id, dotclock);
>>>> + goto error;
>>>> + }
>>>>
>>>> - /*
>>>> - * Convert scanline length in pixels and video
>>>> - * dot clock to line duration and frame duration
>>>> - * in nanoseconds:
>>>> - */
>>>> - linedur_ns  = div_u64((u64) mode->crtc_htotal * 1000000, dotclock);
>>>> - framedur_ns = div_u64((u64) frame_size * 1000000, dotclock);
>>>> + frame_size = (unsigned int)mode->crtc_htotal * (unsigned int)mode-
>>>>> crtc_vtotal;
>>>> - /*
>>>> - * Fields of interlaced scanout modes are only half a frame duration.
>>>> - */
>>>> - if (mode->flags & DRM_MODE_FLAG_INTERLACE)
>>>> - framedur_ns /= 2;
>>>> - } else {
>>>> - drm_err(dev, "crtc %u: Can't calculate constants, dotclock = 0!\n",
>>>> - crtc->base.id);
>>>> + /*
>>>> + * Convert scanline length in pixels and video dot clock to line
>>>> duration
>>>> + * and frame duration in nanoseconds.
>>>> + */
>>>> + linedur_ns  = div_u64((u64)mode->crtc_htotal * 1000000, dotclock);
>>>> + framedur_ns = div_u64((u64)frame_size * 1000000, dotclock);
>>>> +
>>>> + /*
>>>> + * Fields of interlaced scanout modes are only half a frame duration.
>>>> + */
>>>> + if (mode->flags & DRM_MODE_FLAG_INTERLACE)
>>>> + framedur_ns /= 2;
>>>> +
>>>> + if (linedur_ns > INT_MAX || framedur_ns > INT_MAX) {
>>>> + drm_dbg_kms(dev, "crtc %u: Can't calculate constants, mode clock
>>>> too small!\n",
>>>> +    crtc->base.id);
>>>> + goto error;
>>>> }
>>>>
>>>> vblank->linedur_ns  = linedur_ns;
>>>> @@ -678,7 +687,16 @@ void drm_calc_timestamping_constants(struct
>>>> drm_crtc *crtc,
>>>>       crtc->base.id, mode->crtc_htotal,
>>>>       mode->crtc_vtotal, mode->crtc_vdisplay);
>>>> drm_dbg_core(dev, "crtc %u: clock %d kHz framedur %d linedur %d\n",
>>>> -     crtc->base.id, dotclock, framedur_ns, linedur_ns);
>>>> +     crtc->base.id, dotclock,
>>>> +     vblank->framedur_ns, vblank->linedur_ns);
>>>> +
>>>> + return 0;
>>>> +
>>>> +error:
>>>> + vblank->linedur_ns  = 0;
>>>> + vblank->framedur_ns = 0;
>>>> + drm_mode_copy(&vblank->hwmode, mode);
>>>> + return -EINVAL;
>>>> }
>>>> EXPORT_SYMBOL(drm_calc_timestamping_constants);
>>>>
>>>> @@ -2221,6 +2239,7 @@ int drm_crtc_vblank_start_timer(struct drm_crtc
>>>> *crtc)
>>>> struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
>>>> struct drm_vblank_crtc_timer *vtimer = &vblank->vblank_timer;
>>>> unsigned long flags;
>>>> + int ret;
>>>>
>>>> if (!vtimer->crtc) {
>>>> /*
>>>> @@ -2239,7 +2258,9 @@ int drm_crtc_vblank_start_timer(struct drm_crtc
>>>> *crtc)
>>>> hrtimer_try_to_cancel(&vtimer->timer);
>>>> }
>>>>
>>>> - drm_calc_timestamping_constants(crtc, &crtc->mode);
>>>> + ret = drm_calc_timestamping_constants(crtc, &crtc->mode);
>>>> + if (ret)
>>>> + return ret;
>>>>
>>>> spin_lock_irqsave(&vtimer->interval_lock, flags);
>>>> vtimer->interval = ns_to_ktime(vblank->framedur_ns);
>>>> diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
>>>> index 2fcef9c0f..d99772dfa 100644
>>>> --- a/include/drm/drm_vblank.h
>>>> +++ b/include/drm/drm_vblank.h
>>>> @@ -311,8 +311,8 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc);
>>>> u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc);
>>>> void drm_crtc_vblank_restore(struct drm_crtc *crtc);
>>>>
>>>> -void drm_calc_timestamping_constants(struct drm_crtc *crtc,
>>>> -     const struct drm_display_mode *mode);
>>>> +int drm_calc_timestamping_constants(struct drm_crtc *crtc,
>>>> +    const struct drm_display_mode *mode);
>>>> wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
>>>> void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
>>>>     u32 max_vblank_count);
>>>> -- 
>>>> 2.54.0
>>>>

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, (HRB 36809, AG Nürnberg)



  reply	other threads:[~2026-09-04  6:19 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-13 22:44 [PATCH] " Roman Ilin
2026-06-30 12:06 ` Thorsten Leemhuis
2026-06-30 12:09   ` Thomas Zimmermann
2026-06-30 12:58 ` Thomas Zimmermann
2026-07-02 15:23 ` [PATCH v2] " Roman Ilin
2026-07-02 18:10 ` [PATCH v3] " Roman Ilin
2026-07-02 18:23   ` Roman Ilin
2026-07-03  7:26     ` Thomas Zimmermann
2026-09-03 14:07       ` Thorsten Leemhuis
2026-09-04  6:19         ` Thomas Zimmermann [this message]
2026-09-11  7:39           ` Thorsten Leemhuis
2026-09-14 11:00             ` Thomas Zimmermann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f0e4cc76-5cf3-4fdb-b42c-f405a09c0d2a@suse.de \
    --to=tzimmermann@suse.de \
    --cc=airlied@gmail.com \
    --cc=dmitry.osipenko@collabora.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=javierm@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=louis.chauvet@bootlin.com \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=me@romanilin.is \
    --cc=mripard@kernel.org \
    --cc=peter.m.arnesen@gmail.com \
    --cc=regressions@leemhuis.info \
    --cc=regressions@lists.linux.dev \
    --cc=simona@ffwll.ch \
    --cc=ville.syrjala@linux.intel.com \
    --cc=virtualization@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®