On Mon, Nov 10, 2025 at 06:17:41PM +0200, Jani Nikula wrote:
> Now that drm_vblank_crtc() is the only place that indexes dev->vblank[],
> and its usage has reduced considerably, add the primary pipe
> out-of-bounds check there, and return NULL. Expect callers to check it
> and act accordingly.
>
> In drm_crtc_vblank_crtc(), warn and return NULL, and let it go boom. If
> the crtc->pipe is out of bounds, it's a driver error that needs to be
> fixed.
>
> Remove superfluous pipe checks all around.
>
> Signed-off-by: Jani Nikula <[email protected]>
> ---
> drivers/gpu/drm/drm_vblank.c | 36 +++++++++++++++---------------------
> 1 file changed, 15 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> index 44fb8d225485..7829e64e42b4 100644
> --- a/drivers/gpu/drm/drm_vblank.c
> +++ b/drivers/gpu/drm/drm_vblank.c
> @@ -177,13 +177,22 @@ MODULE_PARM_DESC(timestamp_precision_usec, "Max. error
> on timestamps [usecs]");
> static struct drm_vblank_crtc *
> drm_vblank_crtc(struct drm_device *dev, unsigned int pipe)
> {
> + if (pipe >= dev->num_crtcs)
> + return NULL;
> +
> return &dev->vblank[pipe];
> }
>
> struct drm_vblank_crtc *
> drm_crtc_vblank_crtc(struct drm_crtc *crtc)
> {
> - return drm_vblank_crtc(crtc->dev, drm_crtc_index(crtc));
> + struct drm_vblank_crtc *vblank;
> +
> + vblank = drm_vblank_crtc(crtc->dev, drm_crtc_index(crtc));
> + if (drm_WARN_ON(crtc->dev, !vblank))
> + return NULL;
> +
> + return vblank;
> }
> EXPORT_SYMBOL(drm_crtc_vblank_crtc);
>
> @@ -631,7 +640,6 @@ void 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;
> int dotclock = mode->crtc_clock;
> @@ -639,9 +647,6 @@ void drm_calc_timestamping_constants(struct drm_crtc
> *crtc,
> if (!drm_dev_has_vblank(dev))
> return;
I belive this at least gets called from the atomic helpers even
for drivers that don't have vblank support. In which case the
drm_crtc_vblank_crtc() call would have to be done after the
drm_dev_has_vblank() check or else you'll get spurious WARNs.
I don't remember if there are other cases like this as well.
>
> - if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
> - return;
> -
> /* Valid dotclock? */
> if (dotclock > 0) {
> int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
> @@ -724,11 +729,6 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal(
> int vpos, hpos, i;
> int delta_ns, duration_ns;
>
> - if (pipe >= dev->num_crtcs) {
> - drm_err(dev, "Invalid crtc %u\n", pipe);
> - return false;
> - }
> -
> /* Scanout position query not supported? Should not happen. */
> if (!get_scanout_position) {
> drm_err(dev, "Called from CRTC w/o get_scanout_position()!?\n");
> @@ -1339,9 +1339,6 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc)
> ktime_t now;
> u64 seq;
>
> - if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
> - return;
> -
> /*
> * Grab event_lock early to prevent vblank work from being scheduled
> * while we're in the middle of shutting down vblank interrupts
> @@ -1480,9 +1477,6 @@ void drm_crtc_vblank_on_config(struct drm_crtc *crtc,
> unsigned int pipe = drm_crtc_index(crtc);
> struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
>
> - if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
> - return;
> -
> spin_lock_irq(&dev->vbl_lock);
> drm_dbg_vbl(dev, "crtc %d, vblank enabled %d, inmodeset %d\n",
> pipe, vblank->enabled, vblank->inmodeset);
> @@ -1764,10 +1758,9 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void
> *data,
> pipe = pipe_index;
> }
>
> - if (pipe >= dev->num_crtcs)
> - return -EINVAL;
> -
> vblank = drm_vblank_crtc(dev, pipe);
> + if (!vblank)
> + return -EINVAL;
>
> /* If the counter is currently enabled and accurate, short-circuit
> * queries to return the cached timestamp of the last vblank.
> @@ -1902,14 +1895,15 @@ static void drm_handle_vblank_events(struct
> drm_vblank_crtc *vblank)
> */
> bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe)
> {
> - struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe);
> + struct drm_vblank_crtc *vblank;
> unsigned long irqflags;
> bool disable_irq;
>
> if (drm_WARN_ON_ONCE(dev, !drm_dev_has_vblank(dev)))
> return false;
>
> - if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
> + vblank = drm_vblank_crtc(dev, pipe);
> + if (drm_WARN_ON(dev, !vblank))
> return false;
>
> spin_lock_irqsave(&dev->event_lock, irqflags);
> --
> 2.47.3
--
Ville Syrjälä
Intel