diff options
-rw-r--r-- | lib/igt_debugfs.c | 111 | ||||
-rw-r--r-- | lib/igt_debugfs.h | 5 | ||||
-rw-r--r-- | tests/chamelium.c | 61 |
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, |