[PATCH v9 2/2] drm: Send per-connector hotplug events

From: Nicolas Frattaroli

Date: Wed Apr 22 2026 - 14:25:08 EST


Try to send per-connector hotplug events as often as possible, rather
than connector-less global hotplug events. This does result in more
hotplug events if multiple connectors changed at the same time, but
give userspace more actionable information.

Since the hotplug event needs to be sent outside of the mode_config
mutex to avoid a deadlock, the drm_client_dev_hotplug() call is split
off from the drm_sysfs_(connector_)?hotplug_event calls.

Co-developed-by: Marius Vlad <marius.vlad@xxxxxxxxxxxxx>
Signed-off-by: Marius Vlad <marius.vlad@xxxxxxxxxxxxx>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@xxxxxxxxxxxxx>
---
drivers/gpu/drm/drm_probe_helper.c | 37 ++++++++++++++++---------------------
1 file changed, 16 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index d4dc8cb45bce..2daa4242ce7e 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -760,16 +760,12 @@ static void output_poll_execute(struct work_struct *work)
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
enum drm_connector_status old_status;
- bool repoll = false, changed;
+ bool repoll = false, changed = false;
u64 old_epoch_counter;

if (!dev->mode_config.poll_enabled)
return;

- /* Pick up any changes detected by the probe functions. */
- changed = dev->mode_config.delayed_event;
- dev->mode_config.delayed_event = false;
-
if (!drm_kms_helper_poll) {
if (dev->mode_config.poll_running) {
drm_kms_helper_disable_hpd(dev);
@@ -836,6 +832,7 @@ static void output_poll_execute(struct work_struct *work)
connector->base.id, connector->name,
old_epoch_counter, connector->epoch_counter);

+ drm_sysfs_connector_hotplug_event(connector);
changed = true;
}
}
@@ -844,8 +841,15 @@ static void output_poll_execute(struct work_struct *work)
mutex_unlock(&dev->mode_config.mutex);

out:
+ /* Pick up any changes detected by the probe functions. */
+ if (dev->mode_config.delayed_event) {
+ dev->mode_config.delayed_event = false;
+ changed = true;
+ drm_sysfs_hotplug_event(dev);
+ }
+
if (changed)
- drm_kms_helper_hotplug_event(dev);
+ drm_client_dev_hotplug(dev);

if (repoll)
schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
@@ -1081,9 +1085,9 @@ EXPORT_SYMBOL(drm_connector_helper_hpd_irq_event);
*/
bool drm_helper_hpd_irq_event(struct drm_device *dev)
{
- struct drm_connector *connector, *first_changed_connector = NULL;
struct drm_connector_list_iter conn_iter;
- int changed = 0;
+ struct drm_connector *connector;
+ bool changed = false;

if (!dev->mode_config.poll_enabled)
return false;
@@ -1096,24 +1100,15 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
continue;

if (check_connector_changed(connector)) {
- if (!first_changed_connector) {
- drm_connector_get(connector);
- first_changed_connector = connector;
- }
-
- changed++;
+ changed = true;
+ drm_sysfs_connector_hotplug_event(connector);
}
}
drm_connector_list_iter_end(&conn_iter);
mutex_unlock(&dev->mode_config.mutex);

- if (changed == 1)
- drm_kms_helper_connector_hotplug_event(first_changed_connector);
- else if (changed > 0)
- drm_kms_helper_hotplug_event(dev);
-
- if (first_changed_connector)
- drm_connector_put(first_changed_connector);
+ if (changed)
+ drm_client_dev_hotplug(dev);

return changed;
}

--
2.53.0