Skip to contentSkip to conversation

drm/edid: Add helper to detect whether EDID changed

PATCH In review Paul Kocialkowski 4 participants 12 messages Jul 24, 2017 – Jul 26, 2017

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/2 drm/edid: Add helper to detect whether EDID changed

This adds a common drm helper to detect whether the EDID changed from the last known cached one. This is useful help detect that a monitor was changed during a suspend/resume cycle.

When that happens (a monitor is replaced by another one during suspend), no hotplug event will be triggered so the change will not be caught at resume time. Detecting that the EDID changed allows detecting it.

---
 drivers/gpu/drm/drm_edid.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_edid.h     |  3 +++
 2 files changed, 48 insertions(+)
drivers/gpu/drm/drm_edid.c +45 -0
index 6bb6337be920..f6ce8bc2907a 100644
@@ -5036,3 +5036,48 @@ static void drm_get_displayid(struct drm_connector *connector,
 	}
 	return;
 }
+
+/**
+ * drm_check_edid_changed - Check whether the EDID changed since the last update
+ * @connector: connector we're probing
+ * @adapter: I2C adapter to use for DDC
+ *
+ * Check whether the EDID changed since the last time it was updated in the
+ * drm blob cache.
+ *
+ * Return: A boolean indicating whether a change happened or not.
+ */
+bool drm_check_edid_changed(struct drm_connector *connector,
+			    struct i2c_adapter *adapter)
+{
+	struct drm_property_blob *edid_blob;
+	struct edid *edid_stored;
+	struct edid *edid_read;
+	int ret = 0;
+
+	if (!connector->edid_blob_ptr)
+		return false;
+
+	edid_blob = drm_property_blob_get(connector->edid_blob_ptr);
+	if (!edid_blob)
+		return false;
+
+	if (!edid_blob->data || edid_blob->length != sizeof(struct edid))
+		goto out;
+
+	edid_stored = (struct edid *) edid_blob->data;
+
+	edid_read = drm_get_edid(connector, adapter);
+	if (!edid_read)
+		goto out;
+
+	ret = memcmp(edid_stored, edid_read, sizeof(struct edid));
+
+	kfree(edid_read);
+
+out:
+	drm_property_blob_put(edid_blob);
+
+	return ret != 0;
+}
+EXPORT_SYMBOL_GPL(drm_check_edid_changed);
include/drm/drm_edid.h +3 -0
index 1e1908a6b1d6..593a97b269c3 100644
@@ -485,4 +485,7 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name,
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 					   int hsize, int vsize, int fresh,
 					   bool rb);
+bool drm_check_edid_changed(struct drm_connector *connector,
+			    struct i2c_adapter *adapter);
+
 #endif /* __DRM_EDID_H__ */
Signature · 6 lines
2.13.2

_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
#1 lore raw

PATCH 2/2 drm/i915: Detect monitor change from EDID change after resume

This introduces a dedicated work and related helpers to detect whether a monitor was replaced by another one during suspend. This detection is based on EDID change detection, using the associated generic drm helper.

This requires storing more information to the intel_connector structure, such as the i2c adapter required to get the EDID.

Support for this is introduced for DP, HDMI and VGA.

---
 drivers/gpu/drm/i915/i915_drv.c      |  2 ++
 drivers/gpu/drm/i915/i915_drv.h      |  5 ++++
 drivers/gpu/drm/i915/intel_crt.c     |  3 +++
 drivers/gpu/drm/i915/intel_display.c | 50 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_dp.c      |  3 +++
 drivers/gpu/drm/i915/intel_drv.h     |  6 +++++
 drivers/gpu/drm/i915/intel_hdmi.c    |  3 +++
 7 files changed, 72 insertions(+)
drivers/gpu/drm/i915/i915_drv.c +2 -0
index 3ac8215c0e36..b3cf4112fc65 100644
@@ -1702,6 +1702,8 @@ static int i915_drm_resume(struct drm_device *dev)
 
 	intel_display_resume(dev);
 
+	intel_edid_changes_detect(dev);
+
 	drm_kms_helper_poll_enable(dev);
 
 	/*
drivers/gpu/drm/i915/i915_drv.h +5 -0
index b051122c960b..2c189a5b714e 100644
@@ -3904,6 +3904,11 @@ intel_display_capture_error_state(struct drm_i915_private *dev_priv);
 extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
 					    struct intel_display_error_state *error);
 
+/* edid change */
+void intel_edid_change_init(struct intel_connector *connector,
+			    struct i2c_adapter *adapter);
+void intel_edid_changes_detect(struct drm_device *dev);
+
 int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val);
 int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u32 mbox, u32 val);
 int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request,
drivers/gpu/drm/i915/intel_crt.c +3 -0
index 84a1f5e85153..63e2184a6ea4 100644
@@ -925,6 +925,9 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
 	 */
 	crt->force_hotplug_required = 0;
 
+	intel_edid_change_init(intel_connector,
+			       intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin));
+
 	/*
 	 * TODO: find a proper way to discover whether we need to set the the
 	 * polarity and link reversal bits or not, instead of relying on the
drivers/gpu/drm/i915/intel_display.c +50 -0

53 lines not on this page · raw message

drivers/gpu/drm/i915/intel_dp.c +3 -0
index 2d42d09428c9..bc4dbb076096 100644
@@ -6063,6 +6063,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 		goto fail;
 	}
 
+	if (!is_edp(intel_dp))
+		intel_edid_change_init(intel_connector, &intel_dp->aux.ddc);
+
 	intel_dp_add_properties(intel_dp, connector);
 
 	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
drivers/gpu/drm/i915/intel_drv.h +6 -0
index 021cc5487853..47d350d2f993 100644
@@ -319,6 +319,12 @@ struct intel_connector {
 	struct edid *edid;
 	struct edid *detect_edid;
 
+	/* I2C adapter to retrieve the EDID. */
+	struct i2c_adapter *adapter;
+
+	/* Work to detect EDID change. */
+	struct work_struct edid_change_work;
+
 	/* since POLL and HPD connectors may use the same HPD line keep the native
 	   state of connector->polled in case hotplug storm detection changes it */
 	u8 polled;
drivers/gpu/drm/i915/intel_hdmi.c +3 -0
index 2f831cfdd243..a6ce77f81668 100644
@@ -1909,6 +1909,9 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
 	else
 		intel_connector->get_hw_state = intel_connector_get_hw_state;
 
+	intel_edid_change_init(intel_connector,
+			       intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus));
+
 	intel_hdmi_add_properties(intel_hdmi, connector);
 
 	intel_connector_attach_encoder(intel_connector, intel_encoder);
Signature · 6 lines
2.13.2

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Acked-by on v1 1/2
#2 lore raw
In reply to Paul Kocialkowski
Quoted 8 lines · Paul Kocialkowski

This adds a common drm helper to detect whether the EDID changed from the last known cached one. This is useful help detect that a monitor was changed during a suspend/resume cycle.

When that happens (a monitor is replaced by another one during suspend), no hotplug event will be triggered so the change will not be caught at resume time. Detecting that the EDID changed allows detecting it.

This makes sense and could be used by other drivers.

Harry

Quoted 72 lines
---
 drivers/gpu/drm/drm_edid.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_edid.h     |  3 +++
 2 files changed, 48 insertions(+)
drivers/gpu/drm/drm_edid.c +45 -0
index 6bb6337be920..f6ce8bc2907a 100644
@@ -5036,3 +5036,48 @@ static void drm_get_displayid(struct drm_connector *connector,
 	}
 	return;
 }
+
+/**
+ * drm_check_edid_changed - Check whether the EDID changed since the last update
+ * @connector: connector we're probing
+ * @adapter: I2C adapter to use for DDC
+ *
+ * Check whether the EDID changed since the last time it was updated in the
+ * drm blob cache.
+ *
+ * Return: A boolean indicating whether a change happened or not.
+ */
+bool drm_check_edid_changed(struct drm_connector *connector,
+			    struct i2c_adapter *adapter)
+{
+	struct drm_property_blob *edid_blob;
+	struct edid *edid_stored;
+	struct edid *edid_read;
+	int ret = 0;
+
+	if (!connector->edid_blob_ptr)
+		return false;
+
+	edid_blob = drm_property_blob_get(connector->edid_blob_ptr);
+	if (!edid_blob)
+		return false;
+
+	if (!edid_blob->data || edid_blob->length != sizeof(struct edid))
+		goto out;
+
+	edid_stored = (struct edid *) edid_blob->data;
+
+	edid_read = drm_get_edid(connector, adapter);
+	if (!edid_read)
+		goto out;
+
+	ret = memcmp(edid_stored, edid_read, sizeof(struct edid));
+
+	kfree(edid_read);
+
+out:
+	drm_property_blob_put(edid_blob);
+
+	return ret != 0;
+}
+EXPORT_SYMBOL_GPL(drm_check_edid_changed);
include/drm/drm_edid.h +3 -0
index 1e1908a6b1d6..593a97b269c3 100644
@@ -485,4 +485,7 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name,
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 					   int hsize, int vsize, int fresh,
 					   bool rb);
+bool drm_check_edid_changed(struct drm_connector *connector,
+			    struct i2c_adapter *adapter);
+
 #endif /* __DRM_EDID_H__ */
#3 lore raw

✗ Fi.CI.BAT: warning for series starting with [1/2] drm/edid: Add helper to detect whether EDID changed

In reply to Paul Kocialkowski
== Series Details ==

== Series Details ==

Series: series starting with [1/2] drm/edid: Add helper to detect whether EDID changed
URL : https://patchwork.freedesktop.org/series/27807/
State : warning

== Summary ==

Series 27807v1 Series without cover letter
https://patchwork.freedesktop.org/api/1.0/series/27807/revisions/1/mbox/

Test gem_exec_flush:

        Subgroup basic-batch-kernel-default-uc:
                pass       -> FAIL       (fi-snb-2600) fdo#100007
Test gem_exec_suspend:
        Subgroup basic-s3:
                pass       -> DMESG-WARN (fi-blb-e6850)
                pass       -> DMESG-WARN (fi-ilk-650)
                pass       -> DMESG-WARN (fi-snb-2520m)
                pass       -> DMESG-WARN (fi-snb-2600)
                pass       -> DMESG-WARN (fi-ivb-3520m)
                pass       -> DMESG-WARN (fi-ivb-3770)
                pass       -> DMESG-WARN (fi-byt-j1900)
                pass       -> DMESG-WARN (fi-byt-n2820)
                pass       -> DMESG-WARN (fi-hsw-4770)
                pass       -> DMESG-WARN (fi-hsw-4770r)
                pass       -> DMESG-WARN (fi-bdw-5557u) fdo#101891
                pass       -> DMESG-WARN (fi-bdw-gvtdvm)
                pass       -> DMESG-WARN (fi-bsw-n3050)
                pass       -> DMESG-WARN (fi-skl-6260u)
                pass       -> DMESG-WARN (fi-skl-6700hq)
                pass       -> DMESG-WARN (fi-skl-6700k)
                pass       -> DMESG-WARN (fi-skl-6770hq)
                pass       -> DMESG-WARN (fi-skl-gvtdvm)
                pass       -> DMESG-WARN (fi-skl-x1585l)
                pass       -> DMESG-WARN (fi-bxt-j4205)
                pass       -> DMESG-WARN (fi-kbl-7500u)
                pass       -> DMESG-WARN (fi-kbl-7560u)
                pass       -> DMESG-WARN (fi-kbl-r)
                pass       -> DMESG-WARN (fi-glk-2a)
        Subgroup basic-s4-devices:
                pass       -> DMESG-WARN (fi-blb-e6850)
                pass       -> DMESG-WARN (fi-ilk-650)
                pass       -> DMESG-WARN (fi-snb-2520m)
                pass       -> DMESG-WARN (fi-snb-2600)
                pass       -> DMESG-WARN (fi-ivb-3520m)
                pass       -> DMESG-WARN (fi-ivb-3770)
                pass       -> DMESG-WARN (fi-byt-j1900)
                pass       -> DMESG-WARN (fi-byt-n2820)
                pass       -> DMESG-WARN (fi-hsw-4770)
                pass       -> DMESG-WARN (fi-hsw-4770r)
                pass       -> DMESG-WARN (fi-bdw-5557u)
                pass       -> DMESG-WARN (fi-bdw-gvtdvm)
                pass       -> DMESG-WARN (fi-bsw-n3050)
                pass       -> DMESG-WARN (fi-skl-6260u)
                pass       -> DMESG-WARN (fi-skl-6700hq)
                pass       -> DMESG-WARN (fi-skl-6700k)
                pass       -> DMESG-WARN (fi-skl-6770hq)
                pass       -> DMESG-WARN (fi-skl-gvtdvm)
                pass       -> DMESG-WARN (fi-skl-x1585l)
                pass       -> DMESG-WARN (fi-bxt-j4205)
                pass       -> DMESG-WARN (fi-kbl-7500u)
                pass       -> DMESG-WARN (fi-kbl-7560u)
                pass       -> DMESG-WARN (fi-kbl-r)
                pass       -> DMESG-WARN (fi-glk-2a)
Test gem_flink_basic:
        Subgroup bad-flink:
                pass       -> DMESG-WARN (fi-bdw-gvtdvm)
                pass       -> DMESG-WARN (fi-skl-6700hq)
                pass       -> DMESG-WARN (fi-skl-gvtdvm)
                pass       -> DMESG-WARN (fi-kbl-r)
        Subgroup bad-open:
                pass       -> DMESG-WARN (fi-bdw-gvtdvm)
                pass       -> DMESG-WARN (fi-skl-6700hq)
                pass       -> DMESG-WARN (fi-skl-gvtdvm)
                pass       -> DMESG-WARN (fi-kbl-r)
        Subgroup basic:
                pass       -> DMESG-WARN (fi-bdw-gvtdvm)
                pass       -> DMESG-WARN (fi-skl-6700hq)
                pass       -> DMESG-WARN (fi-skl-gvtdvm)
                pass       -> DMESG-WARN (fi-kbl-r)
        Subgroup double-flink:
                pass       -> DMESG-WARN (fi-bdw-gvtdvm)
                pass       -> DMESG-WARN (fi-skl-6700hq)
                pass       -> DMESG-WARN (fi-skl-gvtdvm)
                pass       -> DMESG-WARN (fi-kbl-r)
        Subgroup flink-lifetime:
                pass       -> DMESG-WARN (fi-bdw-gvtdvm)
                pass       -> DMESG-WARN (fi-skl-6700hq)
                pass       -> DMESG-WARN (fi-skl-gvtdvm)
                pass       -> DMESG-WARN (fi-kbl-r)
Test gem_linear_blits:
        Subgroup basic:
                pass       -> DMESG-WARN (fi-bdw-gvtdvm)
                pass       -> DMESG-WARN (fi-skl-6700hq)
                pass       -> DMESG-WARN (fi-skl-gvtdvm)
                pass       -> DMESG-WARN (fi-kbl-r)
Test gem_mmap:
        Subgroup basic:
                pass       -> DMESG-WARN (fi-bdw-gvtdvm)
                pass       -> DMESG-WARN (fi-skl-6700hq)
                pass       -> DMESG-WARN (fi-skl-gvtdvm)
                pass       -> DMESG-WARN (fi-kbl-r)
        Subgroup basic-small-bo:
                pass       -> DMESG-WARN (fi-bdw-gvtdvm)
                pass       -> DMESG-WARN (fi-skl-6700hq)
                pass       -> DMESG-WARN (fi-skl-gvtdvm)
                pass       -> DMESG-WARN (fi-kbl-r)

WARNING: Long output truncated
fi-pnv-d510 failed to collect. IGT log at Patchwork_5269/fi-pnv-d510/igt.log

30d8319f3f0974c3f116620627b428a7db307e78 drm-tip: 2017y-07m-24d-14h-53m-05s UTC integration manifest 0b2db20 drm/i915: Detect monitor change from EDID change after resume
9626615 drm/edid: Add helper to detect whether EDID changed

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_5269/
_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

#4 lore raw
In reply to Paul Kocialkowski
Quoted 9 lines · Paul Kocialkowski

This adds a common drm helper to detect whether the EDID changed from the last known cached one. This is useful help detect that a monitor was changed during a suspend/resume cycle.

When that happens (a monitor is replaced by another one during suspend), no hotplug event will be triggered so the change will not be caught at resume time. Detecting that the EDID changed allows detecting it.

I can't find the older mails I've typed about this, but the plan we've discussed a while back was:
- Add a generational counter to each connector, maybe even expose it to userspace.

- Increment that counter every time something changed, e.g. connector->status in the propbe helpers, or when attaching a new edid with the set_edid helper.

- Tada, no changes needed to drivers, and easily extensible to other things than edid!

Cheers, Daniel

Quoted 77 lines
---
 drivers/gpu/drm/drm_edid.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_edid.h     |  3 +++
 2 files changed, 48 insertions(+)
drivers/gpu/drm/drm_edid.c +45 -0
index 6bb6337be920..f6ce8bc2907a 100644
@@ -5036,3 +5036,48 @@ static void drm_get_displayid(struct drm_connector *connector,
 	}
 	return;
 }
+
+/**
+ * drm_check_edid_changed - Check whether the EDID changed since the last update
+ * @connector: connector we're probing
+ * @adapter: I2C adapter to use for DDC
+ *
+ * Check whether the EDID changed since the last time it was updated in the
+ * drm blob cache.
+ *
+ * Return: A boolean indicating whether a change happened or not.
+ */
+bool drm_check_edid_changed(struct drm_connector *connector,
+			    struct i2c_adapter *adapter)
+{
+	struct drm_property_blob *edid_blob;
+	struct edid *edid_stored;
+	struct edid *edid_read;
+	int ret = 0;
+
+	if (!connector->edid_blob_ptr)
+		return false;
+
+	edid_blob = drm_property_blob_get(connector->edid_blob_ptr);
+	if (!edid_blob)
+		return false;
+
+	if (!edid_blob->data || edid_blob->length != sizeof(struct edid))
+		goto out;
+
+	edid_stored = (struct edid *) edid_blob->data;
+
+	edid_read = drm_get_edid(connector, adapter);
+	if (!edid_read)
+		goto out;
+
+	ret = memcmp(edid_stored, edid_read, sizeof(struct edid));
+
+	kfree(edid_read);
+
+out:
+	drm_property_blob_put(edid_blob);
+
+	return ret != 0;
+}
+EXPORT_SYMBOL_GPL(drm_check_edid_changed);
include/drm/drm_edid.h +3 -0
index 1e1908a6b1d6..593a97b269c3 100644
@@ -485,4 +485,7 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name,
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 					   int hsize, int vsize, int fresh,
 					   bool rb);
+bool drm_check_edid_changed(struct drm_connector *connector,
+			    struct i2c_adapter *adapter);
+
 #endif /* __DRM_EDID_H__ */
Signature · 6 lines
2.13.2

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#5 lore raw
Quoted 21 lines · Daniel Vetter
Quoted 6 lines · Paul Kocialkowski

This adds a common drm helper to detect whether the EDID changed from
the last known cached one. This is useful help detect that a monitor was
changed during a suspend/resume cycle.

Quoted 7 lines

When that happens (a monitor is replaced by another one during suspend),
no hotplug event will be triggered so the change will not be caught at
resume time. Detecting that the EDID changed allows detecting it.

I can't find the older mails I've typed about this, but the plan we've discussed a while back was:
- Add a generational counter to each connector, maybe even expose it to
userspace.

Quoted 7 lines

- Increment that counter every time something changed, e.g. connector->status in the propbe helpers, or when attaching a new
edid
with the set_edid helper.

- Tada, no changes needed to drivers, and easily extensible to other things than edid!

I don't see how it solves the problem here though. After a suspend/resume cycle, there is simply no indication that anything has changed when a monitor was replaced by another one, so I don't see how adding a counter in the mix would help.

Could you provide more details about the reasoning? I feel like I'm missing something here.

Cheers,

Paul

Quoted 87 lines
Quoted 85 lines
---
 drivers/gpu/drm/drm_edid.c | 45
+++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_edid.h     |  3 +++
 2 files changed, 48 insertions(+)
drivers/gpu/drm/drm_edid.c +3 -0
index 6bb6337be920..f6ce8bc2907a 100644
@@ -5036,3 +5036,48 @@ static void drm_get_displayid(struct
 drm_connector *connector,
 	}
 	return;
 }
+
+/**
+ * drm_check_edid_changed - Check whether the EDID changed since

the last update
+ * @connector: connector we're probing
+ * @adapter: I2C adapter to use for DDC
+ *
+ * Check whether the EDID changed since the last time it was updated in the
+ * drm blob cache.
+ *
+ * Return: A boolean indicating whether a change happened or not.
+ */

drivers/gpu/drm/drm_edid.c +12 -0
+bool drm_check_edid_changed(struct drm_connector *connector,
+			    struct i2c_adapter *adapter)
+{
+	struct drm_property_blob *edid_blob;
+	struct edid *edid_stored;
+	struct edid *edid_read;
+	int ret = 0;
+
+	if (!connector->edid_blob_ptr)
+		return false;
+
+	edid_blob = drm_property_blob_get(connector-
Quoted 1 line

edid_blob_ptr);

drivers/gpu/drm/drm_edid.c +4 -0
+	if (!edid_blob)
+		return false;
+
+	if (!edid_blob->data || edid_blob->length != sizeof(struct

edid))

drivers/gpu/drm/drm_edid.c +18 -0
+		goto out;
+
+	edid_stored = (struct edid *) edid_blob->data;
+
+	edid_read = drm_get_edid(connector, adapter);
+	if (!edid_read)
+		goto out;
+
+	ret = memcmp(edid_stored, edid_read, sizeof(struct edid));
+
+	kfree(edid_read);
+
+out:
+	drm_property_blob_put(edid_blob);
+
+	return ret != 0;
+}
+EXPORT_SYMBOL_GPL(drm_check_edid_changed);
include/drm/drm_edid.h +3 -0
index 1e1908a6b1d6..593a97b269c3 100644
@@ -485,4 +485,7 @@ void drm_edid_get_monitor_name(struct edid
 *edid, char *name,
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 					   int hsize, int vsize,
 int fresh,
 					   bool rb);
+bool drm_check_edid_changed(struct drm_connector *connector,
+			    struct i2c_adapter *adapter);
+
 #endif /* __DRM_EDID_H__ */
Signature · 6 lines
2.13.2

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 2 lines
Paul Kocialkowski <[email protected]>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
#6 lore raw
Quoted 30 lines · Paul Kocialkowski
Quoted 21 lines · Daniel Vetter
Quoted 6 lines · Paul Kocialkowski

This adds a common drm helper to detect whether the EDID changed from
the last known cached one. This is useful help detect that a monitor was
changed during a suspend/resume cycle.

Quoted 7 lines

When that happens (a monitor is replaced by another one during suspend),
no hotplug event will be triggered so the change will not be caught at
resume time. Detecting that the EDID changed allows detecting it.

I can't find the older mails I've typed about this, but the plan we've discussed a while back was:
- Add a generational counter to each connector, maybe even expose it to
userspace.

Quoted 7 lines

- Increment that counter every time something changed, e.g. connector->status in the propbe helpers, or when attaching a new
edid
with the set_edid helper.

- Tada, no changes needed to drivers, and easily extensible to other things than edid!

Quoted 7 lines

I don't see how it solves the problem here though. After a suspend/resume cycle, there is simply no indication that anything has changed when a monitor was replaced by another one, so I don't see how adding a counter in the mix would help.

Could you provide more details about the reasoning? I feel like I'm missing something here.

Your bug doesn't just exist over s/r, it's just much easier to observe in s/r since users can take however long they want to with plugging in a different monitor. But the same issue exists e.g. when we go from hpd to polling because too much noise on the line.

Wrt the suspend/resume issue: What we need to do on resume is do a full reprobe of all outputs, in an async worker. Telling userspace to do this by sending an uevent was the cheapest way, but it'd be better if the kernel could do that asynchronously and inform userspace about the exact changes. And there's more to reprobe than just the edid, and we don't want to re-invent a separate reprobe path just for resume like you start in your patch series. So yeah my plan was missing:

- force a full async reprobe after resume (maybe we could reuse the poll worker for that as a one-shot).

Cheers, Daniel

Quoted 95 lines

Cheers,

Paul

Quoted 81 lines
Quoted 81 lines
---
 drivers/gpu/drm/drm_edid.c | 45
+++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_edid.h     |  3 +++
 2 files changed, 48 insertions(+)
drivers/gpu/drm/drm_edid.c +3 -0
index 6bb6337be920..f6ce8bc2907a 100644
@@ -5036,3 +5036,48 @@ static void drm_get_displayid(struct
 drm_connector *connector,
    }
    return;
 }
+
+/**
+ * drm_check_edid_changed - Check whether the EDID changed since

the last update
+ * @connector: connector we're probing
+ * @adapter: I2C adapter to use for DDC
+ *
+ * Check whether the EDID changed since the last time it was updated in the
+ * drm blob cache.
+ *
+ * Return: A boolean indicating whether a change happened or not.
+ */

drivers/gpu/drm/drm_edid.c +12 -0
+bool drm_check_edid_changed(struct drm_connector *connector,
+                       struct i2c_adapter *adapter)
+{
+   struct drm_property_blob *edid_blob;
+   struct edid *edid_stored;
+   struct edid *edid_read;
+   int ret = 0;
+
+   if (!connector->edid_blob_ptr)
+           return false;
+
+   edid_blob = drm_property_blob_get(connector-
Quoted 1 line

edid_blob_ptr);

drivers/gpu/drm/drm_edid.c +4 -0
+   if (!edid_blob)
+           return false;
+
+   if (!edid_blob->data || edid_blob->length != sizeof(struct

edid))

drivers/gpu/drm/drm_edid.c +18 -0
+           goto out;
+
+   edid_stored = (struct edid *) edid_blob->data;
+
+   edid_read = drm_get_edid(connector, adapter);
+   if (!edid_read)
+           goto out;
+
+   ret = memcmp(edid_stored, edid_read, sizeof(struct edid));
+
+   kfree(edid_read);
+
+out:
+   drm_property_blob_put(edid_blob);
+
+   return ret != 0;
+}
+EXPORT_SYMBOL_GPL(drm_check_edid_changed);
include/drm/drm_edid.h +3 -1
index 1e1908a6b1d6..593a97b269c3 100644
@@ -485,4 +485,7 @@ void drm_edid_get_monitor_name(struct edid
 *edid, char *name,
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
                                       int hsize, int vsize,
 int fresh,
                                       bool rb);
+bool drm_check_edid_changed(struct drm_connector *connector,
+                       struct i2c_adapter *adapter);
+
 #endif /* __DRM_EDID_H__ */
--

2.13.2

Quoted 6 lines
Quoted 4 lines

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

--
Paul Kocialkowski <[email protected]>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland

Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
#7 lore raw
Quoted 62 lines · Daniel Vetter
Quoted 44 lines · Paul Kocialkowski
Quoted 27 lines · Daniel Vetter
Quoted 15 lines · Paul Kocialkowski

This adds a common drm helper to detect whether the EDID changed from
the last known cached one. This is useful help detect that a monitor
was
changed during a suspend/resume cycle.

When that happens (a monitor is replaced by another one during suspend),
no hotplug event will be triggered so the change will not be caught
at
resume time. Detecting that the EDID changed allows detecting it.

Quoted 2 lines

com>

I can't find the older mails I've typed about this, but the plan we've
discussed a while back was:
- Add a generational counter to each connector, maybe even expose it
to
userspace.

Quoted 8 lines

- Increment that counter every time something changed, e.g. connector->status in the propbe helpers, or when attaching a new
edid
with the set_edid helper.

- Tada, no changes needed to drivers, and easily extensible to other
things than edid!

I don't see how it solves the problem here though. After a suspend/resume cycle, there is simply no indication that anything has
changed when a monitor was replaced by another one, so I don't see how
adding a counter in the mix would help.

Quoted 2 lines

Could you provide more details about the reasoning? I feel like I'm missing something here.

Your bug doesn't just exist over s/r, it's just much easier to observe in s/r since users can take however long they want to with plugging in a different monitor. But the same issue exists e.g. when we go from hpd to polling because too much noise on the line.

Wrt the suspend/resume issue: What we need to do on resume is do a full reprobe of all outputs, in an async worker. Telling userspace to do this by sending an uevent was the cheapest way, but it'd be better if the kernel could do that asynchronously and inform userspace about the exact changes. And there's more to reprobe than just the edid, and we don't want to re-invent a separate reprobe path just for resume like you start in your patch series. So yeah my plan was missing:

Quoted 2 lines

- force a full async reprobe after resume (maybe we could reuse the poll worker for that as a one-shot).

First off, I definitely agree we need a way to tell userspace exactly what has happened. I wanted to start a discussion about that in i-g-t patch "Unrelated hotplug uevent masking out actual test result" but it didn't get much traction. For testing purposes, it is unacceptable that userspace only gets notified that "something happened".

Still, as far as I know, userspace is expected to ask for a full reprobe when something has changed, and that is apparently part of the DRM spec, so we can't expect that it could query for an update on "only the things that changed".

However, one way to mitigate this is to make sure that the driver knows what changed and only updates these things when a full reprobe is requested. Is this the approach that you have in mind?

The methodology behind my series follows what is currently done: detect change in whatever way necessary, inform userspace and let it trigger full reprobe. If I'm understanding correctly, what you're suggesting is instead to reprobe what is needed on the kernel side when an associated change occurs instead of having userspace trigger it, and then let userspace aware that something changed and return the "cached" updated status when userspace asks for the subsequent reprobe. Is that correct?

Cheers,

Paul

Quoted 100 lines
Quoted 97 lines
Quoted 86 lines
Quoted 86 lines
---
 drivers/gpu/drm/drm_edid.c | 45
+++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_edid.h     |  3 +++
 2 files changed, 48 insertions(+)
drivers/gpu/drm/drm_edid.c +3 -0
index 6bb6337be920..f6ce8bc2907a 100644
@@ -5036,3 +5036,48 @@ static void drm_get_displayid(struct
 drm_connector *connector,
    }
    return;
 }
+
+/**
+ * drm_check_edid_changed - Check whether the EDID changed

since
the last update
+ * @connector: connector we're probing
+ * @adapter: I2C adapter to use for DDC
+ *
+ * Check whether the EDID changed since the last time it was updated in the
+ * drm blob cache.
+ *
+ * Return: A boolean indicating whether a change happened or not.
+ */

drivers/gpu/drm/drm_edid.c +12 -0
+bool drm_check_edid_changed(struct drm_connector *connector,
+                       struct i2c_adapter *adapter)
+{
+   struct drm_property_blob *edid_blob;
+   struct edid *edid_stored;
+   struct edid *edid_read;
+   int ret = 0;
+
+   if (!connector->edid_blob_ptr)
+           return false;
+
+   edid_blob = drm_property_blob_get(connector-
Quoted 1 line

edid_blob_ptr);

drivers/gpu/drm/drm_edid.c +4 -0
+   if (!edid_blob)
+           return false;
+
+   if (!edid_blob->data || edid_blob->length != sizeof(struct

edid))

drivers/gpu/drm/drm_edid.c +18 -0
+           goto out;
+
+   edid_stored = (struct edid *) edid_blob->data;
+
+   edid_read = drm_get_edid(connector, adapter);
+   if (!edid_read)
+           goto out;
+
+   ret = memcmp(edid_stored, edid_read, sizeof(struct edid));
+
+   kfree(edid_read);
+
+out:
+   drm_property_blob_put(edid_blob);
+
+   return ret != 0;
+}
+EXPORT_SYMBOL_GPL(drm_check_edid_changed);
include/drm/drm_edid.h +0 -0
index 1e1908a6b1d6..593a97b269c3 100644
@@ -485,4 +485,7 @@ void drm_edid_get_monitor_name(struct edid
 *edid, char *name,
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device
 *dev,
                                       int hsize, int vsize,

int fresh,

                                       bool rb);
include/drm/drm_edid.h +3 -1
+bool drm_check_edid_changed(struct drm_connector *connector,
+                       struct i2c_adapter *adapter);
+
 #endif /* __DRM_EDID_H__ */
--

2.13.2

Quoted 6 lines
Quoted 4 lines

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

--
Paul Kocialkowski <[email protected]> Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland

Signature · 6 lines
Paul Kocialkowski <[email protected]>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
#8 lore raw
Quoted 72 lines · Paul Kocialkowski
Quoted 62 lines · Daniel Vetter
Quoted 44 lines · Paul Kocialkowski
Quoted 27 lines · Daniel Vetter
Quoted 15 lines · Paul Kocialkowski

This adds a common drm helper to detect whether the EDID changed from
the last known cached one. This is useful help detect that a monitor
was
changed during a suspend/resume cycle.

When that happens (a monitor is replaced by another one during suspend),
no hotplug event will be triggered so the change will not be caught
at
resume time. Detecting that the EDID changed allows detecting it.

Quoted 2 lines

com>

I can't find the older mails I've typed about this, but the plan we've
discussed a while back was:
- Add a generational counter to each connector, maybe even expose it
to
userspace.

Quoted 8 lines

- Increment that counter every time something changed, e.g. connector->status in the propbe helpers, or when attaching a new
edid
with the set_edid helper.

- Tada, no changes needed to drivers, and easily extensible to other
things than edid!

I don't see how it solves the problem here though. After a suspend/resume cycle, there is simply no indication that anything has
changed when a monitor was replaced by another one, so I don't see how
adding a counter in the mix would help.

Quoted 2 lines

Could you provide more details about the reasoning? I feel like I'm missing something here.

Your bug doesn't just exist over s/r, it's just much easier to observe in s/r since users can take however long they want to with plugging in a different monitor. But the same issue exists e.g. when we go from hpd to polling because too much noise on the line.

Wrt the suspend/resume issue: What we need to do on resume is do a full reprobe of all outputs, in an async worker. Telling userspace to do this by sending an uevent was the cheapest way, but it'd be better if the kernel could do that asynchronously and inform userspace about the exact changes. And there's more to reprobe than just the edid, and we don't want to re-invent a separate reprobe path just for resume like you start in your patch series. So yeah my plan was missing:

Quoted 2 lines

- force a full async reprobe after resume (maybe we could reuse the poll worker for that as a one-shot).

First off, I definitely agree we need a way to tell userspace exactly what has happened. I wanted to start a discussion about that in i-g-t patch "Unrelated hotplug uevent masking out actual test result" but it didn't get much traction. For testing purposes, it is unacceptable that userspace only gets notified that "something happened".

Quoted 4 lines

Still, as far as I know, userspace is expected to ask for a full reprobe when something has changed, and that is apparently part of the DRM spec, so we can't expect that it could query for an update on "only the things that changed".

We can update that spec in a backwards compatible way. E.g. we can ask for the current properties without forcing a reprobe (won't even call down into the driver), and userspace could use that to check which connector has an incremented epoche counter since the last time it sampled things. Then it can reprobe just that one.

Old userspace wouldn't know about this, and would keep working as-is.

Quoted 11 lines

However, one way to mitigate this is to make sure that the driver knows what changed and only updates these things when a full reprobe is requested. Is this the approach that you have in mind?

The methodology behind my series follows what is currently done: detect change in whatever way necessary, inform userspace and let it trigger full reprobe. If I'm understanding correctly, what you're suggesting is instead to reprobe what is needed on the kernel side when an associated change occurs instead of having userspace trigger it, and then let userspace aware that something changed and return the "cached" updated status when userspace asks for the subsequent reprobe. Is that correct?

There's two things: the uapi discussion and the internal implementation, imo their separate (but somewhat connected) topics.

- For the internal implementation of detecting edid changes I don't like your approach of rolling a completely new detect path just for resume. I think we can very well integrate that into the existing probe code using the approach I've laid out.

- There's more than just edid (e.g. hdcp status, various stuff that's handled in dp aux for DP sinks), and I think a general mechanism for tracking that something changed will be useful for the internal implementation. The other plan would be that we have to wire a bool changed through the entire probe stack, and make sure it's handled correctly everywhere, which is a) a lot more work b) more fragile. Doing a connector->status_epoch++ everywhere we detect a change is _much_ simpler.

- For the uapi change: We already support returning the cached stuff, the only bit that's missing is the epoch counter to let userspace know where it might need to do a full reprobe. Or maybe we'll just spec that a full reprobe isn't necessary after a hpd event (but that's unlikely to work out given how many bugs we'd need to fix first).

Cheers, Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
#9 lore raw
Quoted 113 lines · Daniel Vetter
Quoted 95 lines · Paul Kocialkowski
Quoted 80 lines · Daniel Vetter
Quoted 54 lines · Paul Kocialkowski
Quoted 40 lines · Daniel Vetter
Quoted 18 lines · Paul Kocialkowski

This adds a common drm helper to detect whether the EDID changed
from
the last known cached one. This is useful help detect that a monitor
was
changed during a suspend/resume cycle.

When that happens (a monitor is replaced by another one during
suspend),
no hotplug event will be triggered so the change will not be caught
at
resume time. Detecting that the EDID changed allows detecting
it.

Quoted 3 lines

tel.
com>

I can't find the older mails I've typed about this, but the plan
we've
discussed a while back was:
- Add a generational counter to each connector, maybe even expose
it
to
userspace.

- Increment that counter every time something changed, e.g. connector->status in the propbe helpers, or when attaching a
new
edid
with the set_edid helper.

Quoted 3 lines

- Tada, no changes needed to drivers, and easily extensible to other
things than edid!

I don't see how it solves the problem here though. After a suspend/resume cycle, there is simply no indication that anything
has
changed when a monitor was replaced by another one, so I don't see
how
adding a counter in the mix would help.

Quoted 3 lines

Could you provide more details about the reasoning? I feel like I'm
missing something here.

Your bug doesn't just exist over s/r, it's just much easier to observe
in s/r since users can take however long they want to with plugging in
a different monitor. But the same issue exists e.g. when we go from
hpd to polling because too much noise on the line.

Wrt the suspend/resume issue: What we need to do on resume is do a full reprobe of all outputs, in an async worker. Telling userspace to
do this by sending an uevent was the cheapest way, but it'd be better
if the kernel could do that asynchronously and inform userspace about
the exact changes. And there's more to reprobe than just the edid, and
we don't want to re-invent a separate reprobe path just for resume like you start in your patch series. So yeah my plan was missing:

Quoted 3 lines

- force a full async reprobe after resume (maybe we could reuse the
poll worker for that as a one-shot).

First off, I definitely agree we need a way to tell userspace exactly
what has happened. I wanted to start a discussion about that in i-g- t
patch "Unrelated hotplug uevent masking out actual test result" but it
didn't get much traction. For testing purposes, it is unacceptable that
userspace only gets notified that "something happened".

Quoted 7 lines

Still, as far as I know, userspace is expected to ask for a full reprobe
when something has changed, and that is apparently part of the DRM spec,
so we can't expect that it could query for an update on "only the things
that changed".

We can update that spec in a backwards compatible way. E.g. we can ask for
the current properties without forcing a reprobe (won't even call down into the driver), and userspace could use that to check which connector
has an incremented epoche counter since the last time it sampled things.
Then it can reprobe just that one.

Quoted 1 line

Old userspace wouldn't know about this, and would keep working as-is.

So the level of detail you're aiming at providing userspace is "connector foo changed" then? I agree it is better than the current "some connector(s) changed", but what I'd like to see for proper testing is a way to find out "bar for connector foo changed".

Quoted 30 lines
Quoted 5 lines

However, one way to mitigate this is to make sure that the driver knows
what changed and only updates these things when a full reprobe is requested. Is this the approach that you have in mind?

Quoted 13 lines

The methodology behind my series follows what is currently done:
detect
change in whatever way necessary, inform userspace and let it trigger
full reprobe. If I'm understanding correctly, what you're suggesting is
instead to reprobe what is needed on the kernel side when an associated
change occurs instead of having userspace trigger it, and then let userspace aware that something changed and return the "cached" updated
status when userspace asks for the subsequent reprobe. Is that correct?

There's two things: the uapi discussion and the internal implementation,
imo their separate (but somewhat connected) topics.

- For the internal implementation of detecting edid changes I don't like
your approach of rolling a completely new detect path just for
resume.
I think we can very well integrate that into the existing probe code using the approach I've laid out.

Quoted 9 lines

- There's more than just edid (e.g. hdcp status, various stuff that's handled in dp aux for DP sinks), and I think a general mechanism for tracking that something changed will be useful for the internal implementation. The other plan would be that we have to wire a bool changed through the entire probe stack, and make sure it's handled correctly everywhere, which is a) a lot more work b) more fragile.
Doing
a connector->status_epoch++ everywhere we detect a change is _much_ simpler.

So to summarize, the following would happen: an async worker would detect whether something changed, then increase the counter for that connector and notify userspace, which would trigger full reprobe of that connector only. Legacy userspace would just trigger full reprobe for all connectors.

I am still under the impression that you'd like the full reprobe to be done on the kernel's async worker, to detect that e.g. EDID changed. But then userspace is going to fully reprobe again, so it will be duplicated. Unless the kernel also keeps a reference of the last time the counter was read from userspace, to determine when to skip full reprobe when it is asked from userspace? That feels pretty similar to having a bool indicating change.

My approach here was to look specifically for the thing that can change in the async worker (only EDID with this change, but it could be extended for the other things you mentioned) as to reduce the duplication as much as possible.

Quoted 9 lines

- For the uapi change: We already support returning the cached stuff, the
only bit that's missing is the epoch counter to let userspace know
where
it might need to do a full reprobe. Or maybe we'll just spec that a
full
reprobe isn't necessary after a hpd event (but that's unlikely to
work
out given how many bugs we'd need to fix first).

Okay, thanks for the additional explanation. I think I'm getting a better grasp on your idea.

Signature · 2 lines
Paul Kocialkowski <[email protected]>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
#10 lore raw
Quoted 114 lines · Paul Kocialkowski
Quoted 113 lines · Daniel Vetter
Quoted 95 lines · Paul Kocialkowski
Quoted 80 lines · Daniel Vetter
Quoted 54 lines · Paul Kocialkowski
Quoted 40 lines · Daniel Vetter
Quoted 18 lines · Paul Kocialkowski

This adds a common drm helper to detect whether the EDID changed
from
the last known cached one. This is useful help detect that a monitor
was
changed during a suspend/resume cycle.

When that happens (a monitor is replaced by another one during
suspend),
no hotplug event will be triggered so the change will not be caught
at
resume time. Detecting that the EDID changed allows detecting
it.

Quoted 3 lines

tel.
com>

I can't find the older mails I've typed about this, but the plan
we've
discussed a while back was:
- Add a generational counter to each connector, maybe even expose
it
to
userspace.

- Increment that counter every time something changed, e.g. connector->status in the propbe helpers, or when attaching a
new
edid
with the set_edid helper.

Quoted 3 lines

- Tada, no changes needed to drivers, and easily extensible to other
things than edid!

I don't see how it solves the problem here though. After a suspend/resume cycle, there is simply no indication that anything
has
changed when a monitor was replaced by another one, so I don't see
how
adding a counter in the mix would help.

Quoted 3 lines

Could you provide more details about the reasoning? I feel like I'm
missing something here.

Your bug doesn't just exist over s/r, it's just much easier to observe
in s/r since users can take however long they want to with plugging in
a different monitor. But the same issue exists e.g. when we go from
hpd to polling because too much noise on the line.

Wrt the suspend/resume issue: What we need to do on resume is do a full reprobe of all outputs, in an async worker. Telling userspace to
do this by sending an uevent was the cheapest way, but it'd be better
if the kernel could do that asynchronously and inform userspace about
the exact changes. And there's more to reprobe than just the edid, and
we don't want to re-invent a separate reprobe path just for resume like you start in your patch series. So yeah my plan was missing:

Quoted 3 lines

- force a full async reprobe after resume (maybe we could reuse the
poll worker for that as a one-shot).

First off, I definitely agree we need a way to tell userspace exactly
what has happened. I wanted to start a discussion about that in i-g- t
patch "Unrelated hotplug uevent masking out actual test result" but it
didn't get much traction. For testing purposes, it is unacceptable that
userspace only gets notified that "something happened".

Quoted 7 lines

Still, as far as I know, userspace is expected to ask for a full reprobe
when something has changed, and that is apparently part of the DRM spec,
so we can't expect that it could query for an update on "only the things
that changed".

We can update that spec in a backwards compatible way. E.g. we can ask for
the current properties without forcing a reprobe (won't even call down into the driver), and userspace could use that to check which connector
has an incremented epoche counter since the last time it sampled things.
Then it can reprobe just that one.

Quoted 6 lines
Quoted 1 line

Old userspace wouldn't know about this, and would keep working as-is.

So the level of detail you're aiming at providing userspace is "connector foo changed" then? I agree it is better than the current "some connector(s) changed", but what I'd like to see for proper testing is a way to find out "bar for connector foo changed".

If you want taht level of detail you need introspection in a in-kernel selftest I think. We'd need to rather massively change/extend the uapi to support that level of testing through the uapi, and thus far no one else is asking for it with a real use-case.

Quoted 69 lines
Quoted 30 lines
Quoted 5 lines

However, one way to mitigate this is to make sure that the driver knows
what changed and only updates these things when a full reprobe is requested. Is this the approach that you have in mind?

Quoted 13 lines

The methodology behind my series follows what is currently done:
detect
change in whatever way necessary, inform userspace and let it trigger
full reprobe. If I'm understanding correctly, what you're suggesting is
instead to reprobe what is needed on the kernel side when an associated
change occurs instead of having userspace trigger it, and then let userspace aware that something changed and return the "cached" updated
status when userspace asks for the subsequent reprobe. Is that correct?

There's two things: the uapi discussion and the internal implementation,
imo their separate (but somewhat connected) topics.

- For the internal implementation of detecting edid changes I don't like
your approach of rolling a completely new detect path just for
resume.
I think we can very well integrate that into the existing probe code using the approach I've laid out.

Quoted 9 lines

- There's more than just edid (e.g. hdcp status, various stuff that's handled in dp aux for DP sinks), and I think a general mechanism for tracking that something changed will be useful for the internal implementation. The other plan would be that we have to wire a bool changed through the entire probe stack, and make sure it's handled correctly everywhere, which is a) a lot more work b) more fragile.
Doing
a connector->status_epoch++ everywhere we detect a change is _much_ simpler.

So to summarize, the following would happen: an async worker would detect whether something changed, then increase the counter for that connector and notify userspace, which would trigger full reprobe of that connector only. Legacy userspace would just trigger full reprobe for all connectors.

I am still under the impression that you'd like the full reprobe to be done on the kernel's async worker, to detect that e.g. EDID changed. But then userspace is going to fully reprobe again, so it will be duplicated. Unless the kernel also keeps a reference of the last time the counter was read from userspace, to determine when to skip full reprobe when it is asked from userspace? That feels pretty similar to having a bool indicating change.

My approach here was to look specifically for the thing that can change in the async worker (only EDID with this change, but it could be extended for the other things you mentioned) as to reduce the duplication as much as possible.

Quoted 9 lines

- For the uapi change: We already support returning the cached stuff, the
only bit that's missing is the epoch counter to let userspace know
where
it might need to do a full reprobe. Or maybe we'll just spec that a
full
reprobe isn't necessary after a hpd event (but that's unlikely to
work
out given how many bugs we'd need to fix first).

Quoted 2 lines

Okay, thanks for the additional explanation. I think I'm getting a better grasp on your idea.

Yeah, the full reprobe isn't needed if you we spec that as the new fancy behaviour. We already support getting the cached values through drmModeGetConnectorCurrent(), without forcing a full reprobe.

Note that really the only thing the hpd handling doesn't do is fill and filter the mode list. I guess as part of this work we should fix that, that should take care of most of the needs for full reprobing. -Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
#11 lore raw
Quoted 148 lines · Daniel Vetter
Quoted 138 lines · Paul Kocialkowski
Quoted 137 lines · Daniel Vetter
Quoted 115 lines · Paul Kocialkowski
Quoted 96 lines · Daniel Vetter
Quoted 63 lines · Paul Kocialkowski
Quoted 47 lines · Daniel Vetter
Quoted 20 lines · Paul Kocialkowski

This adds a common drm helper to detect whether the EDID changed
from
the last known cached one. This is useful help detect that a
monitor
was
changed during a suspend/resume cycle.

When that happens (a monitor is replaced by another one during
suspend),
no hotplug event will be triggered so the change will not be
caught
at
resume time. Detecting that the EDID changed allows detecting
it.

Quoted 4 lines

x.in
tel.
com>

I can't find the older mails I've typed about this, but the
plan
we've
discussed a while back was:
- Add a generational counter to each connector, maybe even expose
it
to
userspace.

- Increment that counter every time something changed, e.g.
connector->status in the propbe helpers, or when
attaching a
new
edid
with the set_edid helper.

Quoted 4 lines

- Tada, no changes needed to drivers, and easily
extensible to
other
things than edid!

I don't see how it solves the problem here though. After a suspend/resume cycle, there is simply no indication that anything
has
changed when a monitor was replaced by another one, so I don't
see
how
adding a counter in the mix would help.

Quoted 4 lines

Could you provide more details about the reasoning? I feel like
I'm
missing something here.

Your bug doesn't just exist over s/r, it's just much easier to observe
in s/r since users can take however long they want to with plugging in
a different monitor. But the same issue exists e.g. when we go from
hpd to polling because too much noise on the line.

Wrt the suspend/resume issue: What we need to do on resume is do a
full reprobe of all outputs, in an async worker. Telling userspace
to
do this by sending an uevent was the cheapest way, but it'd be better
if the kernel could do that asynchronously and inform userspace
about
the exact changes. And there's more to reprobe than just the edid,
and
we don't want to re-invent a separate reprobe path just for resume
like you start in your patch series. So yeah my plan was missing:

Quoted 4 lines

- force a full async reprobe after resume (maybe we could reuse
the
poll worker for that as a one-shot).

First off, I definitely agree we need a way to tell userspace exactly
what has happened. I wanted to start a discussion about that in i-g-
t
patch "Unrelated hotplug uevent masking out actual test result" but
it
didn't get much traction. For testing purposes, it is unacceptable
that
userspace only gets notified that "something happened".

Quoted 9 lines

Still, as far as I know, userspace is expected to ask for a full reprobe
when something has changed, and that is apparently part of the DRM
spec,
so we can't expect that it could query for an update on "only the
things
that changed".

We can update that spec in a backwards compatible way. E.g. we can ask
for
the current properties without forcing a reprobe (won't even call down
into the driver), and userspace could use that to check which connector
has an incremented epoche counter since the last time it sampled things.
Then it can reprobe just that one.

Quoted 8 lines
Quoted 2 lines

Old userspace wouldn't know about this, and would keep working as- is.

So the level of detail you're aiming at providing userspace is "connector foo changed" then? I agree it is better than the current "some connector(s) changed", but what I'd like to see for proper testing
is a way to find out "bar for connector foo changed".

Quoted 6 lines

If you want taht level of detail you need introspection in a in-kernel selftest I think. We'd need to rather massively change/extend the uapi to
support that level of testing through the uapi, and thus far no one else
is asking for it with a real use-case.

I'm frankly surprised that no one has complained about this yet!

The current level of (lack of) detail about what is happening when a hotplug event is triggered makes testing for various things really hard. But I suppose it makes sense with the "reprobe everything all the time" approach ;)

For instance, it wouldn't hurt to add a REASON=foo field to the uevent, in addition to HOTPLUG=1, which would most certainly maintain compatibility with current userspace. I'm not sure that would work out too well if uevents are to be stacked together though.

Quoted 92 lines
Quoted 92 lines
Quoted 36 lines
Quoted 7 lines

However, one way to mitigate this is to make sure that the driver
knows
what changed and only updates these things when a full reprobe is
requested. Is this the approach that you have in mind?

Quoted 15 lines

The methodology behind my series follows what is currently done:
detect
change in whatever way necessary, inform userspace and let it trigger
full reprobe. If I'm understanding correctly, what you're suggesting
is
instead to reprobe what is needed on the kernel side when an associated
change occurs instead of having userspace trigger it, and then let
userspace aware that something changed and return the "cached" updated
status when userspace asks for the subsequent reprobe. Is that correct?

There's two things: the uapi discussion and the internal implementation,
imo their separate (but somewhat connected) topics.

- For the internal implementation of detecting edid changes I don't
like
your approach of rolling a completely new detect path just for
resume.
I think we can very well integrate that into the existing probe
code
using the approach I've laid out.

Quoted 15 lines

- There's more than just edid (e.g. hdcp status, various stuff that's
handled in dp aux for DP sinks), and I think a general mechanism
for
tracking that something changed will be useful for the internal implementation. The other plan would be that we have to wire a
bool
changed through the entire probe stack, and make sure it's
handled
correctly everywhere, which is a) a lot more work b) more
fragile.
Doing
a connector->status_epoch++ everywhere we detect a change is
_much_
simpler.

So to summarize, the following would happen: an async worker would detect whether something changed, then increase the counter for that connector and notify userspace, which would trigger full reprobe of that
connector only. Legacy userspace would just trigger full reprobe for all
connectors.

I am still under the impression that you'd like the full reprobe to be
done on the kernel's async worker, to detect that e.g. EDID changed. But
then userspace is going to fully reprobe again, so it will be duplicated. Unless the kernel also keeps a reference of the last time
the counter was read from userspace, to determine when to skip full reprobe when it is asked from userspace? That feels pretty similar to
having a bool indicating change.

My approach here was to look specifically for the thing that can change
in the async worker (only EDID with this change, but it could be extended for the other things you mentioned) as to reduce the duplication as much as possible.

Quoted 13 lines

- For the uapi change: We already support returning the cached stuff,
the
only bit that's missing is the epoch counter to let userspace
know
where
it might need to do a full reprobe. Or maybe we'll just spec
that a
full
reprobe isn't necessary after a hpd event (but that's unlikely
to
work
out given how many bugs we'd need to fix first).

Quoted 7 lines
Quoted 2 lines

Okay, thanks for the additional explanation. I think I'm getting a better grasp on your idea.

Yeah, the full reprobe isn't needed if you we spec that as the new fancy
behaviour. We already support getting the cached values through drmModeGetConnectorCurrent(), without forcing a full reprobe.

So then userspace gets the cached values and considers them as "already updated" if the counter has increased, and then stops there and doesn't trigger a full reprobe (which was already done by the kernel's worker)?

So all in all, the win here is reprobing only 1 connector instead of reprobing them all. The same could be achieved via a more detail hotplug notification that also mentions which connector was concerned by the event.

Quoted 4 lines

Note that really the only thing the hpd handling doesn't do is fill and
filter the mode list. I guess as part of this work we should fix that, that should take care of most of the needs for full reprobing.

Either way, I do not have enough time left in my internship to start working on something as big as this change, but I think it's a step in the right direction.

Signature · 6 lines
Paul Kocialkowski <[email protected]>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx