* [PATCH 0/5] drm/vblank: Enforce all-or-nothing vblank support
@ 2026-08-14 20:35 Lyude Paul
2026-08-14 20:35 ` [PATCH 1/5] drm/vblank: Add drm_device.has_hw_vblank Lyude Paul
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Lyude Paul @ 2026-08-14 20:35 UTC (permalink / raw)
To: dri-devel, linux-kernel, freedreno, linux-arm-kernel, nouveau,
linux-arm-msm, linux-hyperv, linux-sunxi, asahi, linux-stm32,
linux-samsung-soc, linux-amlogic, linux-mediatek, intel-gfx,
linux-aspeed, linux-rockchip, linux-tegra, linux-renesas-soc,
linux-mips, amd-gfx, spice-devel, intel-xe, imx
One of the oddities with DRM that is leftover from the old days is how
vblank support is implemented by drivers. This has caused some minor
issues for the rust bindings for KMS which could be worked around.
However, it seems like a much better idea to fix this on the C side.
Those oddities are mainly:
* There's nothing in the vblank core that actually ensures that all
CRTCs implement vblank support if one of them do. On Rust's side, we
can't have this and have to ensure either the whole device has vblank
support or not - otherwise it would be quite painful ensuring we don't
expose vblank methods to drivers that can't use them.
This additionally means such a situation would lead to UB.
* There is a second variable for keeping track of the number of CRTCs
and it's kind of broken and confusing. Even worse, we currently allow
the vblank API to allow a driver to specify a different number of
CRTCs then it actually has.
So, let's just go ahead and fix this across the whole tree, and enforce
that a driver must either implement hardware vblank support for all
CRTCs or no CRTCs.
Lyude Paul (5):
drm/vblank: Add drm_device.has_hw_vblank
drm/vblank: Remove drm->num_crtcs
drm/vblank: Remove num_crtcs argument from drm_vblank_init()
drm/vblank: Use drm_for_each_crtc() in drm_vblank_init()
drm/vblank: Require all CRTCs implement vblank support in
drm_vblank_init()
drivers/gpu/drm/adp/adp_drv.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c | 2 +-
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 2 +-
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 2 +-
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 2 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
.../gpu/drm/arm/display/komeda/komeda_kms.c | 2 +-
drivers/gpu/drm/arm/hdlcd_drv.c | 2 +-
drivers/gpu/drm/arm/malidp_drv.c | 2 +-
drivers/gpu/drm/armada/armada_drv.c | 2 +-
drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 2 +-
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 2 +-
drivers/gpu/drm/drm_vblank.c | 60 ++++++++++++-------
drivers/gpu/drm/exynos/exynos_drm_drv.c | 2 +-
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | 2 +-
drivers/gpu/drm/gma500/psb_drv.c | 2 +-
drivers/gpu/drm/gma500/psb_irq.c | 4 +-
.../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 2 +-
.../gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 2 +-
drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 2 +-
.../drm/i915/display/intel_display_driver.c | 3 +-
drivers/gpu/drm/imx/dc/dc-kms.c | 2 +-
drivers/gpu/drm/imx/dcss/dcss-kms.c | 2 +-
drivers/gpu/drm/imx/ipuv3/imx-drm-core.c | 2 +-
drivers/gpu/drm/imx/lcdc/imx-lcdc.c | 2 +-
drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 2 +-
drivers/gpu/drm/kmb/kmb_drv.c | 2 +-
drivers/gpu/drm/logicvc/logicvc_mode.c | 2 +-
drivers/gpu/drm/loongson/lsdc_drv.c | 2 +-
drivers/gpu/drm/mcde/mcde_drv.c | 2 +-
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 2 +-
drivers/gpu/drm/meson/meson_drv.c | 2 +-
drivers/gpu/drm/msm/msm_kms.c | 2 +-
drivers/gpu/drm/mxsfb/lcdif_drv.c | 2 +-
drivers/gpu/drm/mxsfb/mxsfb_drv.c | 2 +-
drivers/gpu/drm/nouveau/nouveau_display.c | 2 +-
drivers/gpu/drm/omapdrm/omap_drv.c | 2 +-
drivers/gpu/drm/pl111/pl111_drv.c | 2 +-
drivers/gpu/drm/qxl/qxl_display.c | 2 +-
drivers/gpu/drm/radeon/atombios_crtc.c | 4 +-
drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 +-
drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 4 +-
drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c | 2 +-
drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 2 +-
.../gpu/drm/renesas/shmobile/shmob_drm_drv.c | 2 +-
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +-
drivers/gpu/drm/sprd/sprd_drm.c | 2 +-
drivers/gpu/drm/sti/sti_compositor.c | 2 +-
drivers/gpu/drm/stm/ltdc.c | 2 +-
drivers/gpu/drm/sun4i/sun4i_drv.c | 2 +-
drivers/gpu/drm/tegra/drm.c | 2 +-
drivers/gpu/drm/tidss/tidss_kms.c | 2 +-
drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 +-
drivers/gpu/drm/tiny/bochs.c | 2 +-
drivers/gpu/drm/tiny/cirrus-qemu.c | 2 +-
drivers/gpu/drm/tve200/tve200_drv.c | 2 +-
drivers/gpu/drm/vc4/vc4_kms.c | 6 +-
drivers/gpu/drm/verisilicon/vs_drm.c | 2 +-
drivers/gpu/drm/virtio/virtgpu_display.c | 2 +-
drivers/gpu/drm/vkms/vkms_drv.c | 3 +-
drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c | 2 +-
drivers/gpu/drm/xlnx/zynqmp_kms.c | 2 +-
include/drm/drm_device.h | 10 +++-
include/drm/drm_vblank.h | 2 +-
64 files changed, 114 insertions(+), 92 deletions(-)
base-commit: 568d4cb5dcc5ec4e22975699b6ea67a30806884c
--
2.55.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/5] drm/vblank: Add drm_device.has_hw_vblank
2026-08-14 20:35 [PATCH 0/5] drm/vblank: Enforce all-or-nothing vblank support Lyude Paul
@ 2026-08-14 20:35 ` Lyude Paul
2026-08-14 20:35 ` [PATCH 2/5] drm/vblank: Remove drm->num_crtcs Lyude Paul
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Lyude Paul @ 2026-08-14 20:35 UTC (permalink / raw)
To: dri-devel, linux-kernel, freedreno, linux-arm-kernel, nouveau,
linux-arm-msm, linux-hyperv, linux-sunxi, asahi, linux-stm32,
linux-samsung-soc, linux-amlogic, linux-mediatek, intel-gfx,
linux-aspeed, linux-rockchip, linux-tegra, linux-renesas-soc,
linux-mips, amd-gfx, spice-devel, intel-xe, imx
Currently the way we check if a driver supports hardware vblanks or not is
actually funny and cursed! Likely because it predates KMS.
As it turns out, we only check dev->num_crtcs to see if we have vblank
support. Why? Because it doesn't actually represent the number of CRTCs on
the device, unless drm_vblank_init() has been called - which sets
dev->num_crtcs. And as it turns out, this is the second place we keep track
of the number of CRTCs we have.
Let's clean this up by starting with adding a variable specifically for
tracking whether drm_vblank_init() has been called or not.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
drivers/gpu/drm/drm_vblank.c | 3 ++-
include/drm/drm_device.h | 7 +++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index f90fb2d13e423..d317148af8cb3 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -557,6 +557,7 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs)
if (!dev->vblank)
return -ENOMEM;
+ dev->has_hw_vblank = true;
dev->num_crtcs = num_crtcs;
for (i = 0; i < num_crtcs; i++) {
@@ -600,7 +601,7 @@ EXPORT_SYMBOL(drm_vblank_init);
*/
bool drm_dev_has_vblank(const struct drm_device *dev)
{
- return dev->num_crtcs != 0;
+ return dev->has_hw_vblank;
}
EXPORT_SYMBOL(drm_dev_has_vblank);
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
index 768a8dae83c52..2df08c756afd3 100644
--- a/include/drm/drm_device.h
+++ b/include/drm/drm_device.h
@@ -287,6 +287,13 @@ struct drm_device {
*/
struct drm_vblank_crtc *vblank;
+ /**
+ * @has_hw_vblank:
+ *
+ * Has the driver called drm_vblank_init() to setup hardware vblank support?
+ */
+ bool has_hw_vblank;
+
/**
* @vblank_time_lock:
*
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/5] drm/vblank: Remove drm->num_crtcs
2026-08-14 20:35 [PATCH 0/5] drm/vblank: Enforce all-or-nothing vblank support Lyude Paul
2026-08-14 20:35 ` [PATCH 1/5] drm/vblank: Add drm_device.has_hw_vblank Lyude Paul
@ 2026-08-14 20:35 ` Lyude Paul
2026-08-14 20:35 ` [PATCH 3/5] drm/vblank: Remove num_crtcs argument from drm_vblank_init() Lyude Paul
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Lyude Paul @ 2026-08-14 20:35 UTC (permalink / raw)
To: dri-devel, linux-kernel, freedreno, linux-arm-kernel, nouveau,
linux-arm-msm, linux-hyperv, linux-sunxi, asahi, linux-stm32,
linux-samsung-soc, linux-amlogic, linux-mediatek, intel-gfx,
linux-aspeed, linux-rockchip, linux-tegra, linux-renesas-soc,
linux-mips, amd-gfx, spice-devel, intel-xe, imx
While working on the Rust bindings for KMS, I asked myself "why does
drm_vblank_init() need the number of CRTCs with vblank support passed to
it?".
After some digging, I noticed the reason and it's silly and likely a
holdover from the pre-KMS days. We actually have ended up with two
different variables that claim to track the number of CRTCs a KMS device
has:
- dev->num_crtcs: Setup -from- drm_vblank_init(), meaning it's 0 if the
driver has no vblank support.
- dev->mode_config.num_crtc: The correct one
There's no real need for this and it's probably confusing, and it's quite
easy to just drop this variable and convert everything over to
mode_config.num_crtc. So, let's do that with the following coccinelle
patch:
virtual patch
@depends on patch@
struct drm_device *dev;
@@
- dev->num_crtcs
+ dev->mode_config.num_crtc
Signed-off-by: Lyude Paul <lyude@redhat.com>
Assisted-by: Coccinelle
---
drivers/gpu/drm/drm_vblank.c | 23 ++++++++++-----------
drivers/gpu/drm/gma500/psb_irq.c | 4 ++--
drivers/gpu/drm/radeon/atombios_crtc.c | 4 ++--
drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 4 ++--
drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
include/drm/drm_device.h | 3 ---
6 files changed, 19 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index d317148af8cb3..c6f61a39b5d16 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -398,7 +398,7 @@ u64 drm_vblank_count(struct drm_device *dev, unsigned int pipe)
struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe);
u64 count;
- if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
+ if (drm_WARN_ON(dev, pipe >= dev->mode_config.num_crtc))
return 0;
count = atomic64_read(&vblank->count);
@@ -558,7 +558,6 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs)
return -ENOMEM;
dev->has_hw_vblank = true;
- dev->num_crtcs = num_crtcs;
for (i = 0; i < num_crtcs; i++) {
struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, i);
@@ -645,7 +644,7 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc,
if (!drm_dev_has_vblank(dev))
return;
- if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
+ if (drm_WARN_ON(dev, pipe >= dev->mode_config.num_crtc))
return;
/* Valid dotclock? */
@@ -729,7 +728,7 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal(
int vpos, hpos, i;
int delta_ns, duration_ns;
- if (pipe >= dev->num_crtcs) {
+ if (pipe >= dev->mode_config.num_crtc) {
drm_err(dev, "Invalid crtc %u\n", pipe);
return false;
}
@@ -970,7 +969,7 @@ static u64 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe,
u64 vblank_count;
unsigned int seq;
- if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) {
+ if (drm_WARN_ON(dev, pipe >= dev->mode_config.num_crtc)) {
*vblanktime = 0;
return 0;
}
@@ -1227,7 +1226,7 @@ int drm_vblank_get(struct drm_device *dev, unsigned int pipe)
if (!drm_dev_has_vblank(dev))
return -EINVAL;
- if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
+ if (drm_WARN_ON(dev, pipe >= dev->mode_config.num_crtc))
return -EINVAL;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -1266,7 +1265,7 @@ void drm_vblank_put(struct drm_device *dev, unsigned int pipe)
struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, pipe);
int vblank_offdelay = vblank->config.offdelay_ms;
- if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
+ if (drm_WARN_ON(dev, pipe >= dev->mode_config.num_crtc))
return;
if (drm_WARN_ON(dev, atomic_read(&vblank->refcount) == 0))
@@ -1355,7 +1354,7 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc)
ktime_t now;
u64 seq;
- if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
+ if (drm_WARN_ON(dev, pipe >= dev->mode_config.num_crtc))
return;
/*
@@ -1496,7 +1495,7 @@ 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))
+ if (drm_WARN_ON(dev, pipe >= dev->mode_config.num_crtc))
return;
spin_lock_irq(&dev->vbl_lock);
@@ -1555,7 +1554,7 @@ static void drm_vblank_restore(struct drm_device *dev, unsigned int pipe)
u32 cur_vblank, diff = 1;
u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
- if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
+ if (drm_WARN_ON(dev, pipe >= dev->mode_config.num_crtc))
return;
assert_spin_locked(&dev->vbl_lock);
@@ -1788,7 +1787,7 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
pipe = pipe_index;
}
- if (pipe >= dev->num_crtcs)
+ if (pipe >= dev->mode_config.num_crtc)
return -EINVAL;
vblank = drm_vblank_crtc(dev, pipe);
@@ -1931,7 +1930,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe)
if (drm_WARN_ON_ONCE(dev, !drm_dev_has_vblank(dev)))
return false;
- if (drm_WARN_ON(dev, pipe >= dev->num_crtcs))
+ if (drm_WARN_ON(dev, pipe >= dev->mode_config.num_crtc))
return false;
spin_lock_irqsave(&dev->event_lock, irqflags);
diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c
index c224c7ff353ce..f0b234a84bd55 100644
--- a/drivers/gpu/drm/gma500/psb_irq.c
+++ b/drivers/gpu/drm/gma500/psb_irq.c
@@ -292,7 +292,7 @@ void gma_irq_postinstall(struct drm_device *dev)
PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
- for (i = 0; i < dev->num_crtcs; ++i) {
+ for (i = 0; i < dev->mode_config.num_crtc; ++i) {
if (dev->vblank[i].enabled)
gma_enable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
else
@@ -350,7 +350,7 @@ void gma_irq_uninstall(struct drm_device *dev)
PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
- for (i = 0; i < dev->num_crtcs; ++i) {
+ for (i = 0; i < dev->mode_config.num_crtc; ++i) {
if (dev->vblank[i].enabled)
gma_disable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
}
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 2fc0334e0d6c5..054a24376aee0 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -277,14 +277,14 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev))
atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
atombios_blank_crtc(crtc, ATOM_DISABLE);
- if (dev->num_crtcs > radeon_crtc->crtc_id)
+ if (dev->mode_config.num_crtc > radeon_crtc->crtc_id)
drm_crtc_vblank_on(crtc);
radeon_crtc_load_lut(crtc);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
- if (dev->num_crtcs > radeon_crtc->crtc_id)
+ if (dev->mode_config.num_crtc > radeon_crtc->crtc_id)
drm_crtc_vblank_off(crtc);
if (radeon_crtc->enabled)
atombios_blank_crtc(crtc, ATOM_ENABLE);
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index a1054c8094d46..954a877b1fad2 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -334,14 +334,14 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
RADEON_CRTC_DISP_REQ_EN_B));
WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl));
}
- if (dev->num_crtcs > radeon_crtc->crtc_id)
+ if (dev->mode_config.num_crtc > radeon_crtc->crtc_id)
drm_crtc_vblank_on(crtc);
radeon_crtc_load_lut(crtc);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
- if (dev->num_crtcs > radeon_crtc->crtc_id)
+ if (dev->mode_config.num_crtc > radeon_crtc->crtc_id)
drm_crtc_vblank_off(crtc);
if (radeon_crtc->crtc_id)
WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask));
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index b17e73bce3841..8f08567d28fc6 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -936,7 +936,7 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
* If the layout changes and doesn't give us that in the future,
* we will need to have something smarter, but it works so far.
*/
- sorted_crtcs = kmalloc_objs(*sorted_crtcs, dev->num_crtcs);
+ sorted_crtcs = kmalloc_objs(*sorted_crtcs, dev->mode_config.num_crtc);
if (!sorted_crtcs)
return -ENOMEM;
@@ -946,7 +946,7 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
sort(sorted_crtcs, i, sizeof(*sorted_crtcs), cmp_vc4_crtc_hvs_output, NULL);
- for (i = 0; i < dev->num_crtcs; i++) {
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
struct vc4_crtc_state *old_vc4_crtc_state, *new_vc4_crtc_state;
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
struct vc4_crtc *vc4_crtc;
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
index 2df08c756afd3..2a9115da90ae7 100644
--- a/include/drm/drm_device.h
+++ b/include/drm/drm_device.h
@@ -340,9 +340,6 @@ struct drm_device {
*/
spinlock_t event_lock;
- /** @num_crtcs: Number of CRTCs on this device */
- unsigned int num_crtcs;
-
/** @mode_config: Current mode config */
struct drm_mode_config mode_config;
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/5] drm/vblank: Remove num_crtcs argument from drm_vblank_init()
2026-08-14 20:35 [PATCH 0/5] drm/vblank: Enforce all-or-nothing vblank support Lyude Paul
2026-08-14 20:35 ` [PATCH 1/5] drm/vblank: Add drm_device.has_hw_vblank Lyude Paul
2026-08-14 20:35 ` [PATCH 2/5] drm/vblank: Remove drm->num_crtcs Lyude Paul
@ 2026-08-14 20:35 ` Lyude Paul
2026-08-14 20:35 ` [PATCH 4/5] drm/vblank: Use drm_for_each_crtc() in drm_vblank_init() Lyude Paul
2026-08-14 20:35 ` [PATCH 5/5] drm/vblank: Require all CRTCs implement vblank support " Lyude Paul
4 siblings, 0 replies; 6+ messages in thread
From: Lyude Paul @ 2026-08-14 20:35 UTC (permalink / raw)
To: dri-devel, linux-kernel, freedreno, linux-arm-kernel, nouveau,
linux-arm-msm, linux-hyperv, linux-sunxi, asahi, linux-stm32,
linux-samsung-soc, linux-amlogic, linux-mediatek, intel-gfx,
linux-aspeed, linux-rockchip, linux-tegra, linux-renesas-soc,
linux-mips, amd-gfx, spice-devel, intel-xe, imx
As it turns out: the entire reason we ever asked for the number of CRTCs as
a parameter for drm_vblank_init() is because that function was previously
in charge of setting up the legacy drm_device.num_crtcs variable, which
itself was also used to keep track of whether or not drm_vblank_init() was
called. And, that number was kept in addition to a properly maintained
drm_device->mode_config.num_crtc.
Now that we've removed that legacy variable entirely, let's stop requiring
the num_crtc argument for drm_vblank_init() entirely. The main motivation
for this is the fact that at the moment, we've had to workaround this
oddity in the Rust kernel bindings for a few reasons:
* We can't know the number of CRTCs until they've all been created, which
meant that we had to keep track of that.
* Additionally, we also had to keep track of which CRTCs did and did not
have vblank support. This is especially silly, because I am not aware of
any physical hardware that only supports vblank interrupts on certain
heads - and I can't think of any reasonable explanation for any hardware
manufacturer making a design choice like that.
* This also implies that drivers could, with the current C API, register
that they have a different number of CRTCs then they have actually
created. This appears to be an edge case that could easily lead to UB
since it's not obvious and as such has likely never really been tested.
And we can't have that in Rust!
While the last point could technically still be an issue if a driver
doesn't fill out the vblank handling callbacks for all CRTCs, this is a
good start at cleaning this strange behavior up.
So, just get rid of this parameter entirely and start using the DRM's
internal count of CRTCs. We apply this change across the tree using this
coccinelle patch:
virtual patch
@depends on patch@
expression dev;
@@
- drm_vblank_init(dev, ...)
+ drm_vblank_init(dev)
And then fixup some of the funky whitespace errors that introduces by hand.
Signed-off-by: Lyude Paul <lyude@redhat.com>
Assisted-by: Coccinelle
---
drivers/gpu/drm/adp/adp_drv.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c | 2 +-
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 2 +-
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 2 +-
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 2 +-
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
drivers/gpu/drm/arm/display/komeda/komeda_kms.c | 2 +-
drivers/gpu/drm/arm/hdlcd_drv.c | 2 +-
drivers/gpu/drm/arm/malidp_drv.c | 2 +-
drivers/gpu/drm/armada/armada_drv.c | 2 +-
drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 2 +-
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 2 +-
drivers/gpu/drm/drm_vblank.c | 6 +++---
drivers/gpu/drm/exynos/exynos_drm_drv.c | 2 +-
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | 2 +-
drivers/gpu/drm/gma500/psb_drv.c | 2 +-
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 2 +-
drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 2 +-
drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 2 +-
drivers/gpu/drm/i915/display/intel_display_driver.c | 3 +--
drivers/gpu/drm/imx/dc/dc-kms.c | 2 +-
drivers/gpu/drm/imx/dcss/dcss-kms.c | 2 +-
drivers/gpu/drm/imx/ipuv3/imx-drm-core.c | 2 +-
drivers/gpu/drm/imx/lcdc/imx-lcdc.c | 2 +-
drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 2 +-
drivers/gpu/drm/kmb/kmb_drv.c | 2 +-
drivers/gpu/drm/logicvc/logicvc_mode.c | 2 +-
drivers/gpu/drm/loongson/lsdc_drv.c | 2 +-
drivers/gpu/drm/mcde/mcde_drv.c | 2 +-
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 2 +-
drivers/gpu/drm/meson/meson_drv.c | 2 +-
drivers/gpu/drm/msm/msm_kms.c | 2 +-
drivers/gpu/drm/mxsfb/lcdif_drv.c | 2 +-
drivers/gpu/drm/mxsfb/mxsfb_drv.c | 2 +-
drivers/gpu/drm/nouveau/nouveau_display.c | 2 +-
drivers/gpu/drm/omapdrm/omap_drv.c | 2 +-
drivers/gpu/drm/pl111/pl111_drv.c | 2 +-
drivers/gpu/drm/qxl/qxl_display.c | 2 +-
drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 +-
drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c | 2 +-
drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c | 2 +-
drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c | 2 +-
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +-
drivers/gpu/drm/sprd/sprd_drm.c | 2 +-
drivers/gpu/drm/sti/sti_compositor.c | 2 +-
drivers/gpu/drm/stm/ltdc.c | 2 +-
drivers/gpu/drm/sun4i/sun4i_drv.c | 2 +-
drivers/gpu/drm/tegra/drm.c | 2 +-
drivers/gpu/drm/tidss/tidss_kms.c | 2 +-
drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 +-
drivers/gpu/drm/tiny/bochs.c | 2 +-
drivers/gpu/drm/tiny/cirrus-qemu.c | 2 +-
drivers/gpu/drm/tve200/tve200_drv.c | 2 +-
drivers/gpu/drm/vc4/vc4_kms.c | 2 +-
drivers/gpu/drm/verisilicon/vs_drm.c | 2 +-
drivers/gpu/drm/virtio/virtgpu_display.c | 2 +-
drivers/gpu/drm/vkms/vkms_drv.c | 3 +--
drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c | 2 +-
drivers/gpu/drm/xlnx/zynqmp_kms.c | 2 +-
include/drm/drm_vblank.h | 2 +-
60 files changed, 62 insertions(+), 64 deletions(-)
diff --git a/drivers/gpu/drm/adp/adp_drv.c b/drivers/gpu/drm/adp/adp_drv.c
index ce9dd6222634d..cc1ed68806cf1 100644
--- a/drivers/gpu/drm/adp/adp_drv.c
+++ b/drivers/gpu/drm/adp/adp_drv.c
@@ -444,7 +444,7 @@ static int adp_setup_mode_config(struct adp_drv_private *adp)
if (IS_ERR(adp->connector))
return PTR_ERR(adp->connector);
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ ret = drm_vblank_init(drm);
if (ret < 0) {
drm_err(drm, "failed to initialize vblank");
return ret;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
index 170adaf7e76ab..79aaa9d8fcdaf 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
@@ -413,7 +413,7 @@ static int amdgpu_vkms_sw_init(struct amdgpu_ip_block *ip_block)
return r;
}
- r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
+ r = drm_vblank_init(adev_to_drm(adev));
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index f2977fe6d8242..649d331973280 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -2809,7 +2809,7 @@ static int dce_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
/* XXX: can this be enabled for DC? */
adev_to_drm(adev)->vblank_disable_immediate = true;
- r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
+ r = drm_vblank_init(adev_to_drm(adev));
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
index c68de0fe1d7d3..d82272ca3b33d 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
@@ -2759,7 +2759,7 @@ static int dce_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
/* XXX: can this be enabled for DC? */
adev_to_drm(adev)->vblank_disable_immediate = true;
- r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
+ r = drm_vblank_init(adev_to_drm(adev));
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
index c3906270f25ef..76d6db1959643 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
@@ -2728,7 +2728,7 @@ static int dce_v8_0_sw_init(struct amdgpu_ip_block *ip_block)
/* XXX: can this be enabled for DC? */
adev_to_drm(adev)->vblank_disable_immediate = true;
- r = drm_vblank_init(adev_to_drm(adev), adev->mode_info.num_crtc);
+ r = drm_vblank_init(adev_to_drm(adev));
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 38cffe1279896..07b83584c7a9d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -893,7 +893,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
adev_to_drm(adev)->mode_config.cursor_width = adev->dm.dc->caps.max_cursor_size;
adev_to_drm(adev)->mode_config.cursor_height = adev->dm.dc->caps.max_cursor_size;
- if (drm_vblank_init(adev_to_drm(adev), adev->dm.display_indexes_num)) {
+ if (drm_vblank_init(adev_to_drm(adev))) {
drm_err(adev_to_drm(adev),
"failed to initialize vblank for display support.\n");
goto error;
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
index faa8b041373a7..02e7037c9b46e 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
@@ -297,7 +297,7 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
if (err)
goto cleanup_mode_config;
- err = drm_vblank_init(drm, kms->n_crtcs);
+ err = drm_vblank_init(drm);
if (err)
goto cleanup_mode_config;
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
index 81d45f2dd6a70..f353406d0f7fd 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.c
+++ b/drivers/gpu/drm/arm/hdlcd_drv.c
@@ -275,7 +275,7 @@ static int hdlcd_drm_bind(struct device *dev)
pm_runtime_enable(dev);
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ ret = drm_vblank_init(drm);
if (ret < 0) {
DRM_ERROR("failed to initialise vblank\n");
goto err_vblank;
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 23fa942ae4bbe..96df6790444fe 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -849,7 +849,7 @@ static int malidp_bind(struct device *dev)
if (ret < 0)
goto irq_init_fail;
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ ret = drm_vblank_init(drm);
if (ret < 0) {
DRM_ERROR("failed to initialise vblank\n");
goto vblank_fail;
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index cae25ad66c749..3638b13d0cee9 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -122,7 +122,7 @@ static int armada_drm_bind(struct device *dev)
if (ret)
goto err_kms;
- ret = drm_vblank_init(&priv->drm, priv->drm.mode_config.num_crtc);
+ ret = drm_vblank_init(&priv->drm);
if (ret)
goto err_comp;
diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
index d4577663a1f0e..ba78695d1015c 100644
--- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
@@ -205,7 +205,7 @@ static int aspeed_gfx_load(struct drm_device *drm)
if (ret < 0)
return ret;
- ret = drm_vblank_init(drm, 1);
+ ret = drm_vblank_init(drm);
if (ret < 0) {
dev_err(drm->dev, "Failed to initialise vblank\n");
return ret;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 2f41bce574dc5..1a5f273527bb4 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -867,7 +867,7 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
pm_runtime_enable(dev->dev);
- ret = drm_vblank_init(dev, 1);
+ ret = drm_vblank_init(dev);
if (ret < 0) {
drm_err(dev, "failed to initialize vblank\n");
goto err_periph_clk_disable;
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index c6f61a39b5d16..17283e8920378 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -536,18 +536,18 @@ static void drm_vblank_init_release(struct drm_device *dev, void *ptr)
/**
* drm_vblank_init - initialize vblank support
* @dev: DRM device
- * @num_crtcs: number of CRTCs supported by @dev
*
- * This function initializes vblank support for @num_crtcs display pipelines.
+ * This function initializes vblank support for display pipelines.
* Cleanup is handled automatically through a cleanup function added with
* drmm_add_action_or_reset().
*
* Returns:
* Zero on success or a negative error code on failure.
*/
-int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs)
+int drm_vblank_init(struct drm_device *dev)
{
int ret;
+ unsigned int num_crtcs = dev->mode_config.num_crtc;
unsigned int i;
spin_lock_init(&dev->vbl_lock);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 9ee30086879f9..42c6053cdc9ec 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -273,7 +273,7 @@ static int exynos_drm_bind(struct device *dev)
if (ret)
goto err_mode_config_cleanup;
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ ret = drm_vblank_init(drm);
if (ret)
goto err_unbind_all;
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
index 3bbfc1b56a655..39768565b437e 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
@@ -122,7 +122,7 @@ static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
return dev_err_probe(dev->dev, ret, "failed to enable pixclk\n");
}
- ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ ret = drm_vblank_init(dev);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n");
goto done_vblank;
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index d17cb5b4a4bf2..bef32d29046df 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -364,7 +364,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
acpi_video_register();
/* Setup vertical blanking handling */
- ret = drm_vblank_init(dev, dev_priv->num_pipe);
+ ret = drm_vblank_init(dev);
if (ret)
goto out_err;
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 4d85c89f3f882..8f622732830e6 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -398,7 +398,7 @@ static int hibmc_load(struct drm_device *dev)
if (ret)
goto err;
- ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ ret = drm_vblank_init(dev);
if (ret) {
drm_err(dev, "failed to initialize vblank: %d\n", ret);
goto err;
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
index 8a11c2df5b886..617d8884ef649 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
@@ -181,7 +181,7 @@ static int kirin_drm_kms_init(struct drm_device *dev,
}
/* vblank init */
- ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ ret = drm_vblank_init(dev);
if (ret) {
DRM_ERROR("failed to initialize vblank.\n");
goto err_unbind_all;
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
index 1855749c1e41f..99833f5ce3610 100644
--- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
+++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c
@@ -330,7 +330,7 @@ int hv_drm_mode_config_init(struct hv_drm_device *hv)
return ret;
}
- ret = drm_vblank_init(dev, 1);
+ ret = drm_vblank_init(dev);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c
index bb5301b90231a..501a4bc9dfd50 100644
--- a/drivers/gpu/drm/i915/display/intel_display_driver.c
+++ b/drivers/gpu/drm/i915/display/intel_display_driver.c
@@ -217,8 +217,7 @@ int intel_display_driver_probe_noirq(struct intel_display *display)
intel_bw_init_hw(display);
if (HAS_DISPLAY(display)) {
- ret = drm_vblank_init(display->drm,
- INTEL_NUM_PIPES(display));
+ ret = drm_vblank_init(display->drm);
if (ret)
goto cleanup_opregion;
}
diff --git a/drivers/gpu/drm/imx/dc/dc-kms.c b/drivers/gpu/drm/imx/dc/dc-kms.c
index 0f8cfaf4c4d15..fbff307c87240 100644
--- a/drivers/gpu/drm/imx/dc/dc-kms.c
+++ b/drivers/gpu/drm/imx/dc/dc-kms.c
@@ -118,7 +118,7 @@ int dc_kms_init(struct dc_drm_device *dc_drm)
return ret;
}
- ret = drm_vblank_init(drm, DC_DISPLAYS);
+ ret = drm_vblank_init(drm);
if (ret) {
dev_err(drm->dev, "failed to init vblank support: %d\n", ret);
return ret;
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c
index 7c5a6e2bc89ac..d3b9d69254273 100644
--- a/drivers/gpu/drm/imx/dcss/dcss-kms.c
+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c
@@ -129,7 +129,7 @@ struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss)
dcss_kms_mode_config_init(kms);
- ret = drm_vblank_init(drm, 1);
+ ret = drm_vblank_init(drm);
if (ret)
goto cleanup_mode_config;
diff --git a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c
index 51a0ec0432484..53ea896d53353 100644
--- a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c
@@ -233,7 +233,7 @@ static int imx_drm_bind(struct device *dev)
if (ret)
goto err_kms;
- ret = drm_vblank_init(drm, MAX_CRTC);
+ ret = drm_vblank_init(drm);
if (ret)
goto err_kms;
diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
index c67fe80b8115e..cc2a2c386730a 100644
--- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
+++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
@@ -435,7 +435,7 @@ static int imx_lcdc_probe(struct platform_device *pdev)
if (ret < 0)
return dev_err_probe(drm->dev, ret, "Cannot setup simple display pipe\n");
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ ret = drm_vblank_init(drm);
if (ret < 0)
return dev_err_probe(drm->dev, ret, "Failed to initialize vblank\n");
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index 738a80b2550ff..4e17f5707e708 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -1348,7 +1348,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
goto err_drvdata;
}
- ret = drm_vblank_init(drm, 1);
+ ret = drm_vblank_init(drm);
if (ret) {
dev_err(dev, "Failed calling drm_vblank_init()\n");
goto err_drvdata;
diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c
index 7c2eb1152fc2f..6026702fa31f9 100644
--- a/drivers/gpu/drm/kmb/kmb_drv.c
+++ b/drivers/gpu/drm/kmb/kmb_drv.c
@@ -191,7 +191,7 @@ static int kmb_setup_mode_config(struct drm_device *drm)
ret = kmb_dsi_encoder_init(drm, kmb->kmb_dsi);
/* Set the CRTC's port so that the encoder component can find it */
kmb->crtc.port = of_graph_get_port_by_id(drm->dev->of_node, 0);
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ ret = drm_vblank_init(drm);
if (ret < 0) {
drm_err(drm, "failed to initialize vblank\n");
pm_runtime_disable(drm->dev);
diff --git a/drivers/gpu/drm/logicvc/logicvc_mode.c b/drivers/gpu/drm/logicvc/logicvc_mode.c
index 3cf04b70bd271..9b67f12f32757 100644
--- a/drivers/gpu/drm/logicvc/logicvc_mode.c
+++ b/drivers/gpu/drm/logicvc/logicvc_mode.c
@@ -36,7 +36,7 @@ int logicvc_mode_init(struct logicvc_drm *logicvc)
uint32_t preferred_depth;
int ret;
- ret = drm_vblank_init(drm_dev, mode_config->num_crtc);
+ ret = drm_vblank_init(drm_dev);
if (ret) {
drm_err(drm_dev, "Failed to initialize vblank\n");
return ret;
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c
index 3fd828d23271c..19a7e98e6cd04 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.c
+++ b/drivers/gpu/drm/loongson/lsdc_drv.c
@@ -296,7 +296,7 @@ static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
drmm_kms_helper_poll_init(ddev);
if (loongson_vblank) {
- ret = drm_vblank_init(ddev, descp->num_of_crtc);
+ ret = drm_vblank_init(ddev);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c
index 53275b575f0cb..f94750d93fd55 100644
--- a/drivers/gpu/drm/mcde/mcde_drv.c
+++ b/drivers/gpu/drm/mcde/mcde_drv.c
@@ -174,7 +174,7 @@ static int mcde_modeset_init(struct drm_device *drm)
mode_config->min_height = 1;
mode_config->max_height = 1080;
- ret = drm_vblank_init(drm, 1);
+ ret = drm_vblank_init(drm);
if (ret) {
dev_err(drm->dev, "failed to init vblank\n");
return ret;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index c86a3f54f35bc..40b3877350fd9 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -574,7 +574,7 @@ static int mtk_drm_kms_init(struct drm_device *drm)
*/
dma_set_max_seg_size(dma_dev, UINT_MAX);
- ret = drm_vblank_init(drm, MAX_CRTC);
+ ret = drm_vblank_init(drm);
if (ret < 0)
goto err_component_unbind;
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 49ff9f1f16d32..d87a91135ecb3 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -262,7 +262,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
priv->vsync_irq = platform_get_irq(pdev, 0);
- ret = drm_vblank_init(drm, 1);
+ ret = drm_vblank_init(drm);
if (ret)
goto free_canvas_vd1_2;
diff --git a/drivers/gpu/drm/msm/msm_kms.c b/drivers/gpu/drm/msm/msm_kms.c
index e5d0ea6294484..23f0f2a25ea68 100644
--- a/drivers/gpu/drm/msm/msm_kms.c
+++ b/drivers/gpu/drm/msm/msm_kms.c
@@ -317,7 +317,7 @@ int msm_drm_kms_init(struct device *dev, const struct drm_driver *drv)
sched_set_fifo(ev_thread->worker->task);
}
- ret = drm_vblank_init(ddev, ddev->mode_config.num_crtc);
+ ret = drm_vblank_init(ddev);
if (ret < 0) {
DRM_DEV_ERROR(dev, "failed to initialize vblank\n");
goto err_msm_uninit;
diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.c b/drivers/gpu/drm/mxsfb/lcdif_drv.c
index e2173c4d6fc28..7fa1591a74bdd 100644
--- a/drivers/gpu/drm/mxsfb/lcdif_drv.c
+++ b/drivers/gpu/drm/mxsfb/lcdif_drv.c
@@ -175,7 +175,7 @@ static int lcdif_load(struct drm_device *drm)
return ret;
}
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ ret = drm_vblank_init(drm);
if (ret < 0) {
dev_err(drm->dev, "Failed to initialise vblank\n");
return ret;
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
index 8b4a500347fbd..87d38a84ed169 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
@@ -257,7 +257,7 @@ static int mxsfb_load(struct drm_device *drm,
goto err_vblank;
}
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ ret = drm_vblank_init(drm);
if (ret < 0) {
dev_err(drm->dev, "Failed to initialise vblank\n");
goto err_vblank;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index d71dcfc6ee66b..9305876bdad33 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -713,7 +713,7 @@ nouveau_display_create(struct drm_device *dev)
drm_mode_config_reset(dev);
if (dev->mode_config.num_crtc) {
- ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ ret = drm_vblank_init(dev);
if (ret)
goto vblank_err;
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 92d6a1f9c0a1a..aad57533780cd 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -731,7 +731,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
}
/* Initialize vblank handling, start with all CRTCs disabled. */
- ret = drm_vblank_init(ddev, priv->num_pipes);
+ ret = drm_vblank_init(ddev);
if (ret) {
dev_err(priv->dev, "could not init vblank\n");
goto err_cleanup_modeset;
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c
index 8ec659b3c08eb..e20a63ad1a0e1 100644
--- a/drivers/gpu/drm/pl111/pl111_drv.c
+++ b/drivers/gpu/drm/pl111/pl111_drv.c
@@ -175,7 +175,7 @@ static int pl111_modeset_init(struct drm_device *dev)
return ret;
if (!priv->variant->broken_vblank) {
- ret = drm_vblank_init(dev, 1);
+ ret = drm_vblank_init(dev);
if (ret != 0) {
drm_err(dev, "Failed to init vblank\n");
goto out_bridge;
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 7f4178800afd7..0ed93be0439f1 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -1304,7 +1304,7 @@ int qxl_modeset_init(struct qxl_device *qdev)
qxl_display_read_client_monitors_config(qdev);
- ret = drm_vblank_init(&qdev->ddev, qxl_num_crtc);
+ ret = drm_vblank_init(&qdev->ddev);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 839d619e5602b..e6880d3f665ee 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -314,7 +314,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
/* Disable vblank irqs aggressively for power-saving */
rdev_to_drm(rdev)->vblank_disable_immediate = true;
- r = drm_vblank_init(rdev_to_drm(rdev), rdev->num_crtc);
+ r = drm_vblank_init(rdev_to_drm(rdev));
if (r) {
return r;
}
diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c
index 9228a7ad0dfa4..c9e29da53d056 100644
--- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c
@@ -888,7 +888,7 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
* Initialize vertical blanking interrupts handling. Start with vblank
* disabled for all CRTCs.
*/
- ret = drm_vblank_init(dev, rcdu->num_crtcs);
+ ret = drm_vblank_init(dev);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
index 87f171145a230..497f3891c586a 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_kms.c
@@ -430,7 +430,7 @@ int rzg2l_du_modeset_init(struct rzg2l_du_device *rcdu)
* Initialize vertical blanking interrupts handling. Start with vblank
* disabled for all CRTCs.
*/
- ret = drm_vblank_init(dev, rcdu->num_crtcs);
+ ret = drm_vblank_init(dev);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c
index 2f31822b22458..713a1abb364b9 100644
--- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c
+++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c
@@ -228,7 +228,7 @@ static int shmob_drm_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = drm_vblank_init(ddev, 1);
+ ret = drm_vblank_init(ddev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to initialize vblank\n");
return ret;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 3099408e9d050..6e14c3832abff 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -186,7 +186,7 @@ static int rockchip_drm_bind(struct device *dev)
if (ret)
goto err_unbind_all;
- ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
+ ret = drm_vblank_init(drm_dev);
if (ret)
goto err_iommu_cleanup;
diff --git a/drivers/gpu/drm/sprd/sprd_drm.c b/drivers/gpu/drm/sprd/sprd_drm.c
index c2fd5380a834f..a49247a6cc25d 100644
--- a/drivers/gpu/drm/sprd/sprd_drm.c
+++ b/drivers/gpu/drm/sprd/sprd_drm.c
@@ -89,7 +89,7 @@ static int sprd_drm_bind(struct device *dev)
}
/* vblank init */
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ ret = drm_vblank_init(drm);
if (ret) {
drm_err(drm, "failed to initialize vblank.\n");
goto err_unbind_all;
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c
index 8c529b0cca8b4..5478826aeb420 100644
--- a/drivers/gpu/drm/sti/sti_compositor.c
+++ b/drivers/gpu/drm/sti/sti_compositor.c
@@ -145,7 +145,7 @@ static int sti_compositor_bind(struct device *dev,
}
}
- drm_vblank_init(drm_dev, crtc_id);
+ drm_vblank_init(drm_dev);
return 0;
}
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index 8818dcf98da79..1e8ac7bbbea5c 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -2076,7 +2076,7 @@ int ltdc_load(struct drm_device *ddev)
goto err;
}
- ret = drm_vblank_init(ddev, NB_CRTC);
+ ret = drm_vblank_init(ddev);
if (ret) {
drm_err(ddev, "Failed calling drm_vblank_init()\n");
goto err;
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index e9baca360160b..b74ab1bcb41ee 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -95,7 +95,7 @@ static int sun4i_drv_bind(struct device *dev)
}
/* drm_vblank_init calls kcalloc, which can fail */
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ ret = drm_vblank_init(drm);
if (ret)
goto unbind_all;
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 324480c87fb1f..d5fe8f35107e9 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -1241,7 +1241,7 @@ static int host1x_drm_probe(struct host1x_device *dev)
/* syncpoints are used for full 32-bit hardware VBLANK counters */
drm->max_vblank_count = 0xffffffff;
- err = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ err = drm_vblank_init(drm);
if (err < 0)
goto hub;
diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
index 70c14c3be10d5..8b45ac6a5e704 100644
--- a/drivers/gpu/drm/tidss/tidss_kms.c
+++ b/drivers/gpu/drm/tidss/tidss_kms.c
@@ -289,7 +289,7 @@ int tidss_modeset_init(struct tidss_device *tidss)
if (ret)
return ret;
- ret = drm_vblank_init(ddev, tidss->num_crtcs);
+ ret = drm_vblank_init(ddev);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 1d6c9a423a410..37508fcd261c0 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -405,7 +405,7 @@ static int tilcdc_pdev_probe(struct platform_device *pdev)
goto unregister_cpufreq_notif;
}
- ret = drm_vblank_init(ddev, 1);
+ ret = drm_vblank_init(ddev);
if (ret < 0) {
drm_err(ddev, "failed to initialize vblank\n");
goto unregister_cpufreq_notif;
diff --git a/drivers/gpu/drm/tiny/bochs.c b/drivers/gpu/drm/tiny/bochs.c
index e2d957e51505c..36196682ace2f 100644
--- a/drivers/gpu/drm/tiny/bochs.c
+++ b/drivers/gpu/drm/tiny/bochs.c
@@ -677,7 +677,7 @@ static int bochs_kms_init(struct bochs_device *bochs)
drm_connector_attach_edid_property(connector);
drm_connector_attach_encoder(connector, encoder);
- ret = drm_vblank_init(dev, 1);
+ ret = drm_vblank_init(dev);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/tiny/cirrus-qemu.c b/drivers/gpu/drm/tiny/cirrus-qemu.c
index 075221b431d37..d6730763acade 100644
--- a/drivers/gpu/drm/tiny/cirrus-qemu.c
+++ b/drivers/gpu/drm/tiny/cirrus-qemu.c
@@ -501,7 +501,7 @@ static int cirrus_pipe_init(struct cirrus_device *cirrus)
if (ret)
return ret;
- ret = drm_vblank_init(dev, 1);
+ ret = drm_vblank_init(dev);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c
index 8d0e7c7c82e84..f41748436ac5a 100644
--- a/drivers/gpu/drm/tve200/tve200_drv.c
+++ b/drivers/gpu/drm/tve200/tve200_drv.c
@@ -120,7 +120,7 @@ static int tve200_modeset_init(struct drm_device *dev)
dev_info(dev->dev, "attached to panel %s\n",
dev_name(panel->dev));
- ret = drm_vblank_init(dev, 1);
+ ret = drm_vblank_init(dev);
if (ret) {
dev_err(dev->dev, "failed to init vblank\n");
goto out_bridge;
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 8f08567d28fc6..2c1c479494b12 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -1151,7 +1151,7 @@ int vc4_kms_load(struct drm_device *dev)
/* Set support for vblank irq fast disable, before drm_vblank_init() */
dev->vblank_disable_immediate = true;
- ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ ret = drm_vblank_init(dev);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n");
return ret;
diff --git a/drivers/gpu/drm/verisilicon/vs_drm.c b/drivers/gpu/drm/verisilicon/vs_drm.c
index fd259d53f49f1..3e4944eb745c4 100644
--- a/drivers/gpu/drm/verisilicon/vs_drm.c
+++ b/drivers/gpu/drm/verisilicon/vs_drm.c
@@ -121,7 +121,7 @@ int vs_drm_initialize(struct vs_dc *dc, struct platform_device *pdev)
vdrm->crtcs[i] = crtc;
}
- ret = drm_vblank_init(drm, dc->identity.display_count);
+ ret = drm_vblank_init(drm);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c
index 44ffffec550fd..971c5a7424b37 100644
--- a/drivers/gpu/drm/virtio/virtgpu_display.c
+++ b/drivers/gpu/drm/virtio/virtgpu_display.c
@@ -381,7 +381,7 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev)
for (i = 0 ; i < vgdev->num_scanouts; ++i)
vgdev_output_init(vgdev, i);
- ret = drm_vblank_init(vgdev->ddev, vgdev->num_scanouts);
+ ret = drm_vblank_init(vgdev->ddev);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 5a640b531d88f..5a830cee7fe9b 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -192,8 +192,7 @@ int vkms_create(struct vkms_config *config)
goto out_devres;
}
- ret = drm_vblank_init(&vkms_device->drm,
- vkms_config_get_num_crtcs(config));
+ ret = drm_vblank_init(&vkms_device->drm);
if (ret) {
DRM_ERROR("Failed to vblank\n");
goto out_devres;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
index 7b8163b5e5014..22601060727fb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
@@ -212,7 +212,7 @@ vmw_vkms_init(struct vmw_private *vmw)
ret = kstrtobool(buffer, &vmw->vkms_enabled);
if (!ret && vmw->vkms_enabled) {
- ret = drm_vblank_init(&vmw->drm, VMWGFX_NUM_DISPLAY_UNITS);
+ ret = drm_vblank_init(&vmw->drm);
vmw->vkms_enabled = (ret == 0);
}
diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index d5f9224505655..c5209df46afe5 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -504,7 +504,7 @@ int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
drm->mode_config.max_width = ZYNQMP_DISP_MAX_WIDTH;
drm->mode_config.max_height = ZYNQMP_DISP_MAX_HEIGHT;
- ret = drm_vblank_init(drm, 1);
+ ret = drm_vblank_init(drm);
if (ret)
return ret;
diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
index 2fcef9c0f5b1b..d78f40d3a85be 100644
--- a/include/drm/drm_vblank.h
+++ b/include/drm/drm_vblank.h
@@ -285,7 +285,7 @@ struct drm_vblank_crtc {
};
struct drm_vblank_crtc *drm_crtc_vblank_crtc(struct drm_crtc *crtc);
-int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs);
+int drm_vblank_init(struct drm_device *dev);
bool drm_dev_has_vblank(const struct drm_device *dev);
u64 drm_crtc_vblank_count(struct drm_crtc *crtc);
u64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc,
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/5] drm/vblank: Use drm_for_each_crtc() in drm_vblank_init()
2026-08-14 20:35 [PATCH 0/5] drm/vblank: Enforce all-or-nothing vblank support Lyude Paul
` (2 preceding siblings ...)
2026-08-14 20:35 ` [PATCH 3/5] drm/vblank: Remove num_crtcs argument from drm_vblank_init() Lyude Paul
@ 2026-08-14 20:35 ` Lyude Paul
2026-08-14 20:35 ` [PATCH 5/5] drm/vblank: Require all CRTCs implement vblank support " Lyude Paul
4 siblings, 0 replies; 6+ messages in thread
From: Lyude Paul @ 2026-08-14 20:35 UTC (permalink / raw)
To: dri-devel, linux-kernel, freedreno, linux-arm-kernel, nouveau,
linux-arm-msm, linux-hyperv, linux-sunxi, asahi, linux-stm32,
linux-samsung-soc, linux-amlogic, linux-mediatek, intel-gfx,
linux-aspeed, linux-rockchip, linux-tegra, linux-renesas-soc,
linux-mips, amd-gfx, spice-devel, intel-xe, imx
No functional changes yet, we just should be using this iterator here
instead of manually counting the number of CRTCs anyhow.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
drivers/gpu/drm/drm_vblank.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 17283e8920378..d57405050554f 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -547,19 +547,20 @@ static void drm_vblank_init_release(struct drm_device *dev, void *ptr)
int drm_vblank_init(struct drm_device *dev)
{
int ret;
- unsigned int num_crtcs = dev->mode_config.num_crtc;
- unsigned int i;
+ struct drm_crtc *crtc;
spin_lock_init(&dev->vbl_lock);
spin_lock_init(&dev->vblank_time_lock);
- dev->vblank = drmm_kcalloc(dev, num_crtcs, sizeof(*dev->vblank), GFP_KERNEL);
+ dev->vblank = drmm_kcalloc(dev, dev->mode_config.num_crtc,
+ sizeof(*dev->vblank), GFP_KERNEL);
if (!dev->vblank)
return -ENOMEM;
dev->has_hw_vblank = true;
- for (i = 0; i < num_crtcs; i++) {
+ drm_for_each_crtc(crtc, dev) {
+ unsigned int i = crtc->index;
struct drm_vblank_crtc *vblank = drm_vblank_crtc(dev, i);
vblank->dev = dev;
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 5/5] drm/vblank: Require all CRTCs implement vblank support in drm_vblank_init()
2026-08-14 20:35 [PATCH 0/5] drm/vblank: Enforce all-or-nothing vblank support Lyude Paul
` (3 preceding siblings ...)
2026-08-14 20:35 ` [PATCH 4/5] drm/vblank: Use drm_for_each_crtc() in drm_vblank_init() Lyude Paul
@ 2026-08-14 20:35 ` Lyude Paul
4 siblings, 0 replies; 6+ messages in thread
From: Lyude Paul @ 2026-08-14 20:35 UTC (permalink / raw)
To: dri-devel, linux-kernel, freedreno, linux-arm-kernel, nouveau,
linux-arm-msm, linux-hyperv, linux-sunxi, asahi, linux-stm32,
linux-samsung-soc, linux-amlogic, linux-mediatek, intel-gfx,
linux-aspeed, linux-rockchip, linux-tegra, linux-renesas-soc,
linux-mips, amd-gfx, spice-devel, intel-xe, imx
Due to us previously allowing users to specify the number of CRTCs for
drm_vblank_init() manually, a untested and almost certainly UB edge case
was technically possible for drivers: implementing vblank support for some
of their CRTCs, and not implementing it for others.
I don't think there's any actual situation in the real world where hardware
like this exists, nor do I think supporting such a possibility was ever
actually the original intent here. But in Rust, we need to be able to
prevent such a situation from occurring since we cannot guarantee no UB is
possible otherwise. I think it makes sense here for us to just handle this
safety check in the DRM core though, since it's quite likely such an edge
case would break C drivers in addition to Rust drivers.
So, let's start enforcing this in drm_vblank_init by checking that every
CRTC has an enable_vblank function registered. Throw a warning if we find
that some CRTCs have it and others don't.
In the event that we don't actually find any CRTCs with vblank support,
simply skip init and return -ENODEV. We intentionally don't WARN_ON() this
scenario, as it isn't a fatal error and drivers which do support KMS but
don't end up registering any CRTCs can simply ignore the error. This is
also useful for Rust, since it saves us from having to track whether or not
any CRTCs registered vblank support ourselves.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
drivers/gpu/drm/drm_vblank.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index d57405050554f..17affae23e7a6 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -542,12 +542,31 @@ static void drm_vblank_init_release(struct drm_device *dev, void *ptr)
* drmm_add_action_or_reset().
*
* Returns:
- * Zero on success or a negative error code on failure.
+ * Zero on success or a negative error code on failure. If no CRTCs with vblank
+ * support implemented were found, -ENODEV will be returned.
*/
int drm_vblank_init(struct drm_device *dev)
{
int ret;
struct drm_crtc *crtc;
+ bool found_vbl_crtc = false, found_non_vbl_crtc = false;
+
+ /* Vblank hooks are per-CRTC, not per-device - which is contrary to how
+ * the vblank core was written. Since hardware that only has vblank
+ * support on some CRTCs but not all is non-existent and would likely
+ * lead to UB, ensure that vblank support is all or nothing.
+ */
+ drm_for_each_crtc(crtc, dev) {
+ if (crtc->funcs->enable_vblank)
+ found_vbl_crtc = true;
+ else
+ found_non_vbl_crtc = true;
+
+ if (drm_WARN_ON(dev, found_vbl_crtc && found_non_vbl_crtc))
+ return -EINVAL;
+ }
+ if (!found_vbl_crtc)
+ return -ENODEV;
spin_lock_init(&dev->vbl_lock);
spin_lock_init(&dev->vblank_time_lock);
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-08-14 20:36 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-14 20:35 [PATCH 0/5] drm/vblank: Enforce all-or-nothing vblank support Lyude Paul
2026-08-14 20:35 ` [PATCH 1/5] drm/vblank: Add drm_device.has_hw_vblank Lyude Paul
2026-08-14 20:35 ` [PATCH 2/5] drm/vblank: Remove drm->num_crtcs Lyude Paul
2026-08-14 20:35 ` [PATCH 3/5] drm/vblank: Remove num_crtcs argument from drm_vblank_init() Lyude Paul
2026-08-14 20:35 ` [PATCH 4/5] drm/vblank: Use drm_for_each_crtc() in drm_vblank_init() Lyude Paul
2026-08-14 20:35 ` [PATCH 5/5] drm/vblank: Require all CRTCs implement vblank support " Lyude Paul
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox