summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/igt_debugfs.c111
-rw-r--r--lib/igt_debugfs.h5
-rw-r--r--tests/chamelium.c61
3 files changed, 177 insertions, 0 deletions
diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 982573d7..e64d001b 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 86c25dd3..5587ad40 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 f3402790..849e1ac5 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,