[Intel-gfx] [PATCH i-g-t 1/2] lib/igt_debugfs: Add functions/tests for controlling/testing HPD storm logic

Lyude lyude at redhat.com
Thu Feb 23 03:18:32 UTC 2017


Recently we added i915_hpd_storm_ctl into i915's debugfs directory,
which allows us to control the thresholds i915 uses for detecting
hotplug interrupt storms from userspace, along with the ability to
entirely disable them. This adds some helper functions into IGT to
enable making use of this feature, along with adding some chamelium
tests for it.

Signed-off-by: Lyude <lyude at redhat.com>
---
 lib/igt_debugfs.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_debugfs.h |   5 +++
 tests/chamelium.c |  61 ++++++++++++++++++++++++++++++
 3 files changed, 177 insertions(+)

diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 982573d..e64d001 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -463,6 +463,117 @@ void igt_require_pipe_crc(void)
 	fclose(ctl);
 }
 
+/**
+ * igt_hpd_storm_set_threshold:
+ * @threshold: How many hotplugs per second required to trigger an HPD storm,
+ * or 0 to disable storm detection.
+ *
+ * Convienence helper to configure the HPD storm detection threshold for i915
+ * through debugfs. Useful for hotplugging tests where HPD storm detection
+ * might get in the way and slow things down.
+ *
+ * If the system does not support HPD storm detection, this function does
+ * nothing.
+ *
+ * See: https://01.org/linuxgraphics/gfx-docs/drm/gpu/i915.html#hotplug
+ */
+void igt_hpd_storm_set_threshold(unsigned int threshold)
+{
+	int fd = igt_debugfs_open("i915_hpd_storm_ctl", O_WRONLY);
+	char buf[16];
+
+	if (fd < 0)
+		return;
+
+	igt_debug("Setting HPD storm threshold to %d\n", threshold);
+	snprintf(buf, sizeof(buf), "%d", threshold);
+	igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf));
+
+	close(fd);
+	igt_install_exit_handler((igt_exit_handler_t)igt_hpd_storm_reset);
+}
+
+/**
+ * igt_hpd_storm_reset:
+ *
+ * Convienence helper to reset HPD storm detection to it's default settings.
+ * If hotplug detection was disabled on any ports due to an HPD storm, it will
+ * be immediately re-enabled. Always called on exit if the HPD storm detection
+ * threshold was modified during any tests.
+ *
+ * If the system does not support HPD storm detection, this function does
+ * nothing.
+ *
+ * See: https://01.org/linuxgraphics/gfx-docs/drm/gpu/i915.html#hotplug
+ */
+void igt_hpd_storm_reset(void)
+{
+	int fd = igt_debugfs_open("i915_hpd_storm_ctl", O_WRONLY);
+	const char *buf = "reset";
+
+	if (fd < 0)
+		return;
+
+	igt_debug("Resetting HPD storm threshold\n");
+	igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf));
+
+	close(fd);
+}
+
+/**
+ * igt_hpd_storm_detected:
+ *
+ * Checks whether or not i915 has detected an HPD interrupt storm on any of the
+ * system's ports.
+ *
+ * This function always returns false on systems that do not support HPD storm
+ * detection.
+ *
+ * See: https://01.org/linuxgraphics/gfx-docs/drm/gpu/i915.html#hotplug
+ *
+ * Returns: Whether or not an HPD storm has been detected.
+ */
+bool igt_hpd_storm_detected(void)
+{
+	int fd = igt_debugfs_open("i915_hpd_storm_ctl", O_RDONLY);
+	char *start_loc;
+	char buf[32] = {0}, detected_str[4];
+	bool ret;
+
+	if (fd < 0)
+		return false;
+
+	igt_assert_lt(0, read(fd, buf, sizeof(buf)));
+	igt_assert(start_loc = strstr(buf, "Detected: "));
+	igt_assert_eq(sscanf(start_loc, "Detected: %s\n", detected_str), 1);
+
+	if (strcmp(detected_str, "yes") == 0)
+		ret = true;
+	else if (strcmp(detected_str, "no") == 0)
+		ret = false;
+	else
+		igt_fail_on_f(true, "Unknown hpd storm detection status '%s'\n",
+			      detected_str);
+
+	close(fd);
+	return ret;
+}
+
+/**
+ * igt_require_hpd_storm_ctl:
+ *
+ * Skips the current test if the system does not have HPD storm detection.
+ *
+ * See: https://01.org/linuxgraphics/gfx-docs/drm/gpu/i915.html#hotplug
+ */
+void igt_require_hpd_storm_ctl(void)
+{
+	int fd = igt_debugfs_open("i915_hpd_storm_ctl", O_RDONLY);
+
+	igt_require_f(fd > 0, "No i915_hpd_storm_ctl found in debugfs\n");
+	close(fd);
+}
+
 static igt_pipe_crc_t *
 pipe_crc_new(enum pipe pipe, enum intel_pipe_crc_source source, int flags)
 {
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index 86c25dd..5587ad4 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -129,6 +129,11 @@ int igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
 			  igt_crc_t **out_crcs);
 void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc);
 
+void igt_hpd_storm_set_threshold(unsigned int threshold);
+void igt_hpd_storm_reset(void);
+bool igt_hpd_storm_detected(void);
+void igt_require_hpd_storm_ctl(void);
+
 /*
  * Drop caches
  */
diff --git a/tests/chamelium.c b/tests/chamelium.c
index f340279..849e1ac 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -44,6 +44,9 @@ typedef struct {
 #define HOTPLUG_TIMEOUT 20 /* seconds */
 #define SUSPEND_RESUME_DELAY 20 /* seconds */
 
+#define HPD_STORM_PULSE_INTERVAL_DP 100 /* ms */
+#define HPD_STORM_PULSE_INTERVAL_HDMI 200 /* ms */
+
 /* Pre-calculated CRCs for the pattern fb, for all the modes in the default
  * chamelium edid
  */
@@ -528,6 +531,48 @@ test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
 	igt_cleanup_hotplug(mon);
 }
 
+static void
+test_hpd_storm_detect(data_t *data, struct chamelium_port *port, int width)
+{
+	struct udev_monitor *mon;
+	int count = 0;
+
+	igt_require_hpd_storm_ctl();
+	reset_state(data, port);
+
+	igt_hpd_storm_set_threshold(1);
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+	igt_assert(igt_hpd_storm_detected());
+
+	mon = igt_watch_hotplug();
+	chamelium_fire_hpd_pulses(data->chamelium, port, width, 10);
+
+	/*
+	 * Polling should have been enabled by the HPD storm at this point,
+	 * so we should only get at most 1 hotplug event
+	 */
+	igt_until_timeout(5)
+		count += igt_hotplug_detected(mon, 1);
+	igt_assert_lt(count, 2);
+
+	igt_cleanup_hotplug(mon);
+	igt_hpd_storm_reset();
+}
+
+static void
+test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
+{
+	igt_require_hpd_storm_ctl();
+	reset_state(data, port);
+
+	igt_hpd_storm_set_threshold(0);
+	chamelium_fire_hpd_pulses(data->chamelium, port,
+				  width, 10);
+	igt_assert(!igt_hpd_storm_detected());
+
+	igt_hpd_storm_reset();
+}
+
 #define for_each_port(p, port)            \
 	for (p = 0, port = data.ports[p]; \
 	     p < data.port_count;         \
@@ -593,6 +638,14 @@ igt_main
 						SUSPEND_STATE_DISK,
 						SUSPEND_TEST_DEVICES);
 
+		connector_subtest("dp-hpd-storm", DisplayPort)
+			test_hpd_storm_detect(&data, port,
+					      HPD_STORM_PULSE_INTERVAL_DP);
+
+		connector_subtest("dp-hpd-storm-disable", DisplayPort)
+			test_hpd_storm_disable(&data, port,
+					       HPD_STORM_PULSE_INTERVAL_DP);
+
 		connector_subtest("dp-edid-change-during-suspend", DisplayPort)
 			test_suspend_resume_edid_change(&data, port,
 							SUSPEND_STATE_MEM,
@@ -641,6 +694,14 @@ igt_main
 						SUSPEND_STATE_DISK,
 						SUSPEND_TEST_DEVICES);
 
+		connector_subtest("hdmi-hpd-storm", HDMIA)
+			test_hpd_storm_detect(&data, port,
+					      HPD_STORM_PULSE_INTERVAL_HDMI);
+
+		connector_subtest("hdmi-hpd-storm-disable", HDMIA)
+			test_hpd_storm_disable(&data, port,
+					       HPD_STORM_PULSE_INTERVAL_HDMI);
+
 		connector_subtest("hdmi-edid-change-during-suspend", HDMIA)
 			test_suspend_resume_edid_change(&data, port,
 							SUSPEND_STATE_MEM,
-- 
2.9.3



More information about the Intel-gfx mailing list