When a uevent only updates a single connector, add a CONNECTOR property to the uevent. This allows user-space to ignore other connectors when handling the uevent. This is purely an optimization, drivers can still send a uevent without the CONNECTOR property.
The CONNECTOR property is already set when sending HDCP property update uevents, see drm_sysfs_connector_status_event.
This has been tested with a wlroots patch [1].
amdgpu and the probe-helper has been updated to use these new fine-grained uevents.
Changes in v4: address comments from Ville, Maxime and Sam.
Simon Ser (6): drm/sysfs: introduce drm_sysfs_connector_hotplug_event drm/probe-helper: add drm_kms_helper_connector_hotplug_event drm/connector: use drm_sysfs_connector_hotplug_event amdgpu: use drm_kms_helper_connector_hotplug_event drm/probe-helper: use drm_kms_helper_connector_hotplug_event i915/display/dp: send a more fine-grained link-status uevent
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 ++-- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 4 +- drivers/gpu/drm/drm_connector.c | 2 +- drivers/gpu/drm/drm_probe_helper.c | 48 +++++++++++++++---- drivers/gpu/drm/drm_sysfs.c | 25 ++++++++++ drivers/gpu/drm/i915/display/intel_dp.c | 2 +- include/drm/drm_probe_helper.h | 1 + include/drm/drm_sysfs.h | 1 + 8 files changed, 75 insertions(+), 16 deletions(-)
base-commit: f6632721cd6231e1bf28b5317dcc7543e43359f7
This function sends a hotplug uevent with a CONNECTOR property.
Signed-off-by: Simon Ser contact@emersion.fr Reviewed-by: Sam Ravnborg sam@ravnborg.org Acked-by: Harry Wentland harry.wentland@amd.com --- drivers/gpu/drm/drm_sysfs.c | 25 +++++++++++++++++++++++++ include/drm/drm_sysfs.h | 1 + 2 files changed, 26 insertions(+)
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 76ff6ec3421b..430e00b16eec 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -409,6 +409,31 @@ void drm_sysfs_hotplug_event(struct drm_device *dev) } EXPORT_SYMBOL(drm_sysfs_hotplug_event);
+/** + * drm_sysfs_connector_hotplug_event - generate a DRM uevent for any connector + * change + * @connector: connector which has changed + * + * Send a uevent for the DRM connector specified by @connector. This will send + * a uevent with the properties HOTPLUG=1 and CONNECTOR. + */ +void drm_sysfs_connector_hotplug_event(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + char hotplug_str[] = "HOTPLUG=1", conn_id[21]; + char *envp[] = { hotplug_str, conn_id, NULL }; + + snprintf(conn_id, sizeof(conn_id), + "CONNECTOR=%u", connector->base.id); + + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] generating connector hotplug event\n", + connector->base.id, connector->name); + + kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp); +} +EXPORT_SYMBOL(drm_sysfs_connector_hotplug_event); + /** * drm_sysfs_connector_status_event - generate a DRM uevent for connector * property status change diff --git a/include/drm/drm_sysfs.h b/include/drm/drm_sysfs.h index d454ef617b2c..6273cac44e47 100644 --- a/include/drm/drm_sysfs.h +++ b/include/drm/drm_sysfs.h @@ -11,6 +11,7 @@ int drm_class_device_register(struct device *dev); void drm_class_device_unregister(struct device *dev);
void drm_sysfs_hotplug_event(struct drm_device *dev); +void drm_sysfs_connector_hotplug_event(struct drm_connector *connector); void drm_sysfs_connector_status_event(struct drm_connector *connector, struct drm_property *property); #endif
This function is the same as drm_kms_helper_hotplug_event, but takes a connector instead of a device.
Signed-off-by: Simon Ser contact@emersion.fr Reviewed-by: Sam Ravnborg sam@ravnborg.org Acked-by: Harry Wentland harry.wentland@amd.com --- drivers/gpu/drm/drm_probe_helper.c | 23 +++++++++++++++++++++++ include/drm/drm_probe_helper.h | 1 + 2 files changed, 24 insertions(+)
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 61d5c57f23e1..3aef3b188c99 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -604,6 +604,9 @@ EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); * * This function must be called from process context with no mode * setting locks held. + * + * If only a single connector has changed, consider calling + * drm_kms_helper_connector_hotplug_event() instead. */ void drm_kms_helper_hotplug_event(struct drm_device *dev) { @@ -616,6 +619,26 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev) } EXPORT_SYMBOL(drm_kms_helper_hotplug_event);
+/** + * drm_kms_helper_connector_hotplug_event - fire off a KMS connector hotplug event + * @connector: drm_connector which has changed + * + * This is the same as drm_kms_helper_hotplug_event(), except it fires a more + * fine-grained uevent for a single connector. + */ +void drm_kms_helper_connector_hotplug_event(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + + /* send a uevent + call fbdev */ + drm_sysfs_connector_hotplug_event(connector); + if (dev->mode_config.funcs->output_poll_changed) + dev->mode_config.funcs->output_poll_changed(dev); + + drm_client_dev_hotplug(dev); +} +EXPORT_SYMBOL(drm_kms_helper_connector_hotplug_event); + static void output_poll_execute(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h index 04c57564c397..48300aa6ca71 100644 --- a/include/drm/drm_probe_helper.h +++ b/include/drm/drm_probe_helper.h @@ -20,6 +20,7 @@ void drm_kms_helper_poll_fini(struct drm_device *dev); bool drm_helper_hpd_irq_event(struct drm_device *dev); bool drm_connector_helper_hpd_irq_event(struct drm_connector *connector); void drm_kms_helper_hotplug_event(struct drm_device *dev); +void drm_kms_helper_connector_hotplug_event(struct drm_connector *connector);
void drm_kms_helper_poll_disable(struct drm_device *dev); void drm_kms_helper_poll_enable(struct drm_device *dev);
In drm_connector_register, use drm_sysfs_connector_hotplug_event instead of drm_sysfs_hotplug_event, because the hotplug event only updates a single connector.
Signed-off-by: Simon Ser contact@emersion.fr Reviewed-by: Sam Ravnborg sam@ravnborg.org Acked-by: Harry Wentland harry.wentland@amd.com --- drivers/gpu/drm/drm_connector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index ec3973e8963c..a50c82bc2b2f 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -547,7 +547,7 @@ int drm_connector_register(struct drm_connector *connector) connector->registration_state = DRM_CONNECTOR_REGISTERED;
/* Let userspace know we have a new connector */ - drm_sysfs_hotplug_event(connector->dev); + drm_sysfs_connector_hotplug_event(connector);
if (connector->privacy_screen) drm_privacy_screen_register_notifier(connector->privacy_screen,
When updating a single connector, use drm_kms_helper_connector_hotplug_event instead of drm_kms_helper_hotplug_event.
Signed-off-by: Simon Ser contact@emersion.fr Reviewed-by: Harry Wentland harry.wentland@amd.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 ++++---- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-)
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 9b1fc54555ee..c261e57d9a22 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2652,7 +2652,7 @@ static void handle_hpd_irq(void *param) drm_modeset_unlock_all(dev);
if (aconnector->base.force == DRM_FORCE_UNSPECIFIED) - drm_kms_helper_hotplug_event(dev); + drm_kms_helper_connector_hotplug_event(connector);
} else if (dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD)) { if (new_connection_type == dc_connection_none && @@ -2666,7 +2666,7 @@ static void handle_hpd_irq(void *param) drm_modeset_unlock_all(dev);
if (aconnector->base.force == DRM_FORCE_UNSPECIFIED) - drm_kms_helper_hotplug_event(dev); + drm_kms_helper_connector_hotplug_event(connector); } mutex_unlock(&aconnector->hpd_lock);
@@ -2833,7 +2833,7 @@ static void handle_hpd_rx_irq(void *param) dm_restore_drm_connector_state(dev, connector); drm_modeset_unlock_all(dev);
- drm_kms_helper_hotplug_event(dev); + drm_kms_helper_connector_hotplug_event(connector); } else if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) {
if (aconnector->fake_enable) @@ -2846,7 +2846,7 @@ static void handle_hpd_rx_irq(void *param) dm_restore_drm_connector_state(dev, connector); drm_modeset_unlock_all(dev);
- drm_kms_helper_hotplug_event(dev); + drm_kms_helper_connector_hotplug_event(connector); } } #ifdef CONFIG_DRM_AMD_DC_HDCP diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 87daa78a32b8..23e789855d17 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -1241,7 +1241,7 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf, dm_restore_drm_connector_state(dev, connector); drm_modeset_unlock_all(dev);
- drm_kms_helper_hotplug_event(dev); + drm_kms_helper_connector_hotplug_event(connector); } else if (param[0] == 0) { if (!aconnector->dc_link) goto unlock; @@ -1263,7 +1263,7 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf, dm_restore_drm_connector_state(dev, connector); drm_modeset_unlock_all(dev);
- drm_kms_helper_hotplug_event(dev); + drm_kms_helper_connector_hotplug_event(connector); }
unlock:
If an hotplug event only updates a single connector, use drm_kms_helper_connector_hotplug_event instead of drm_kms_helper_hotplug_event.
Changes in v4: - Simplify loop logic (Ville, Sam) - Update drm_connector_helper_hpd_irq_event (Maxime)
Signed-off-by: Simon Ser contact@emersion.fr Cc: Ville Syrjala ville.syrjala@linux.intel.com Cc: Sam Ravnborg sam@ravnborg.org Cc: Maxime Ripard maxime@cerno.tech --- drivers/gpu/drm/drm_probe_helper.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 3aef3b188c99..682359512996 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -888,7 +888,7 @@ bool drm_connector_helper_hpd_irq_event(struct drm_connector *connector) mutex_unlock(&dev->mode_config.mutex);
if (changed) { - drm_kms_helper_hotplug_event(dev); + drm_kms_helper_connector_hotplug_event(connector); drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Sent hotplug event\n", connector->base.id, connector->name); @@ -927,9 +927,9 @@ EXPORT_SYMBOL(drm_connector_helper_hpd_irq_event); */ bool drm_helper_hpd_irq_event(struct drm_device *dev) { - struct drm_connector *connector; + struct drm_connector *connector, *first_changed_connector = NULL; struct drm_connector_list_iter conn_iter; - bool changed = false; + int changed = 0;
if (!dev->mode_config.poll_enabled) return false; @@ -941,16 +941,25 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) continue;
- if (check_connector_changed(connector)) - changed = true; + if (check_connector_changed(connector)) { + if (!first_changed_connector) { + drm_connector_get(connector); + first_changed_connector = connector; + } + + changed++; + } } drm_connector_list_iter_end(&conn_iter); mutex_unlock(&dev->mode_config.mutex);
- if (changed) { + if (changed == 1) + drm_kms_helper_connector_hotplug_event(first_changed_connector); + else if (changed > 0) drm_kms_helper_hotplug_event(dev); - DRM_DEBUG_KMS("Sent hotplug event\n"); - } + + if (first_changed_connector) + drm_connector_put(first_changed_connector);
return changed; }
On Mon, Oct 18, 2021 at 08:47:30AM +0000, Simon Ser wrote:
If an hotplug event only updates a single connector, use drm_kms_helper_connector_hotplug_event instead of drm_kms_helper_hotplug_event.
Changes in v4:
- Simplify loop logic (Ville, Sam)
- Update drm_connector_helper_hpd_irq_event (Maxime)
Signed-off-by: Simon Ser contact@emersion.fr Cc: Ville Syrjala ville.syrjala@linux.intel.com Cc: Sam Ravnborg sam@ravnborg.org Cc: Maxime Ripard maxime@cerno.tech
Reviewed-by: Maxime Ripard maxime@cerno.tech
Thanks! Maxime
Hi Simon,
On Mon, Oct 18, 2021 at 08:47:30AM +0000, Simon Ser wrote:
If an hotplug event only updates a single connector, use drm_kms_helper_connector_hotplug_event instead of drm_kms_helper_hotplug_event.
Changes in v4:
- Simplify loop logic (Ville, Sam)
- Update drm_connector_helper_hpd_irq_event (Maxime)
Signed-off-by: Simon Ser contact@emersion.fr Cc: Ville Syrjala ville.syrjala@linux.intel.com Cc: Sam Ravnborg sam@ravnborg.org Cc: Maxime Ripard maxime@cerno.tech
Thanks, I like this better. Reviewed-by: Sam Ravnborg sam@ravnborg.org
Maybe I am late and this was already applied...
Sam
When link-status changes, send a hotplug uevent which contains the connector ID. That way, user-space can more easily figure out that only this connector has been updated.
Changes in v4: avoid sending two uevents (Ville)
Signed-off-by: Simon Ser contact@emersion.fr Cc: Ville Syrjala ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 04175f359fd6..8b81a709d33b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5263,7 +5263,7 @@ static void intel_dp_modeset_retry_work_fn(struct work_struct *work) DRM_MODE_LINK_STATUS_BAD); mutex_unlock(&connector->dev->mode_config.mutex); /* Send Hotplug uevent so userspace can reprobe */ - drm_kms_helper_hotplug_event(connector->dev); + drm_kms_helper_connector_hotplug_event(connector); }
bool
On Mon, Oct 18, 2021 at 08:47:31AM +0000, Simon Ser wrote:
When link-status changes, send a hotplug uevent which contains the connector ID. That way, user-space can more easily figure out that only this connector has been updated.
Changes in v4: avoid sending two uevents (Ville)
Signed-off-by: Simon Ser contact@emersion.fr Cc: Ville Syrjala ville.syrjala@linux.intel.com
Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/display/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 04175f359fd6..8b81a709d33b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5263,7 +5263,7 @@ static void intel_dp_modeset_retry_work_fn(struct work_struct *work) DRM_MODE_LINK_STATUS_BAD); mutex_unlock(&connector->dev->mode_config.mutex); /* Send Hotplug uevent so userspace can reprobe */
- drm_kms_helper_hotplug_event(connector->dev);
- drm_kms_helper_connector_hotplug_event(connector);
}
bool
2.33.1
dri-devel@lists.freedesktop.org