All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] drmtest: introduce kmsg_error functions
@ 2013-11-11 17:06 Paulo Zanoni
  2013-11-11 17:06 ` [PATCH 2/2] tests: add kms_edp_vdd_race Paulo Zanoni
  2013-11-11 18:02 ` [PATCH 1/2] drmtest: introduce kmsg_error functions Daniel Vetter
  0 siblings, 2 replies; 10+ messages in thread
From: Paulo Zanoni @ 2013-11-11 17:06 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

These functions should help you checking for new Kernel error
messages. One of the problems I had while writing the runtime PM test
suite is that when you read the sysfs and debugfs files, the only way
to detect errors is by checking dmesg, so I was always getting SUCCESS
even if the test caught a bug. Also, we have so many debugfs/sysfs
files that it was not easy to discover which file caused the error
messages I was seeing. So this commit adds some infrastructure to
allow us to automatically check for new errors on dmesg.

Use it like this:

int main(int argc, char *argv[]) {
	int fd, i;

	igt_fixture
		fd = kmsg_error_setup();

	igt_subtest("t1") {
		kmsg_error_reset(fd);
		do_something();
		kmsg_error_detect("");
	}

	igt_subtest("t2") {
		for (i = 0; i < 10; i++) {
			char *file_name = get_file(i);
			kmsg_error_reset(fd);
			process_file(file_name);
			kmsg_error_detect(file_name):
		}
	}

	igt_fixture
		kmsg_error_teardown(fd);
}

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 lib/drmtest.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/drmtest.h | 13 ++++++++++
 2 files changed, 92 insertions(+)

diff --git a/lib/drmtest.c b/lib/drmtest.c
index d8fc60f..ebabfd8 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -41,6 +41,7 @@
 #include <linux/kd.h>
 #include <unistd.h>
 #include <sys/wait.h>
+#include <poll.h>
 #include "drm_fourcc.h"
 
 #include "drmtest.h"
@@ -2307,3 +2308,81 @@ void igt_system_suspend_autoresume(void)
 	ret = system("rtcwake -s 30 -m mem");
 	igt_assert(ret == 0);
 }
+
+/* The kmsg error detecting functions allow you to catch new error messages from
+ * the Kernel. The idea is that you have to call kmsg_error_setup() only once at
+ * the beginning, and kmsg_error_teardown() at the end. And for every subtest,
+ * you run kmsg_error_reset() at the begin and kmsg_error_detect() at the end:
+ * this should make sure that kmsg_error_detect() will only catch the error
+ * messages that were introduced after the subtest started. */
+int kmsg_error_setup(void)
+{
+	int fd = open("/dev/kmsg", O_RDONLY);
+
+	igt_assert_f(fd >= 0, "Can't open /dev/kmsg\n");
+	return fd;
+}
+
+void kmsg_error_teardown(int fd)
+{
+	close(fd);
+}
+
+/* You have to call this before running your subtest, so that the next time you
+ * call kmsg_error_detect you'll only look at the new kmsg lines. */
+void kmsg_error_reset(int fd)
+{
+	lseek(fd, 0, SEEK_END);
+}
+
+static void kmsg_error_line_parse(const char *line, const char *error_msg)
+{
+	igt_assert_f(strstr(line, "------------[ cut here ]------------") == 0,
+		     "%s\n", error_msg);
+	igt_assert_f(strstr(line, "*ERROR*") == 0, "%s\n", error_msg);
+	igt_assert_f(strstr(line, "BUG: sleeping function called from invalid context at") == 0,
+		     "%s\n", error_msg);
+}
+
+/* Keep reading the Kernel ring buffer and checking for errors. Stop reading if
+ * there's nothing new on the buffer after the timeout. Notice that every time
+ * you call this function, the time it will take to return will always be >= the
+ * timeout. */
+void kmsg_error_detect(int fd, int timeout_ms, const char *error_msg)
+{
+	int i, rc;
+	int line_size = 128, line_used = 0, buf_size = 128;
+	char buf[buf_size];
+	char *line;
+	struct pollfd pfd;
+	ssize_t readed;
+
+	line = malloc(sizeof(char) * line_size);
+	igt_assert(line);
+
+	pfd.fd = fd;
+	pfd.events = POLLIN | POLLPRI;
+
+	while (1) {
+		pfd.revents = 0;
+		rc = poll(&pfd, 1, timeout_ms);
+		if (!rc)
+			break;
+
+		readed = read(fd, &buf, buf_size - 1);
+		for (i = 0; i < readed; i++) {
+			if (line_used + 1 >= line_size) {
+				line = realloc(line, line_size * 2);
+				line_size *= 2;
+				igt_assert(line);
+			}
+			line[line_used++] = buf[i];
+			if (buf[i] == '\n') {
+				line[line_used] = '\0';
+				kmsg_error_line_parse(line, error_msg);
+				line_used = 0;
+			}
+		}
+	}
+	free(line);
+}
diff --git a/lib/drmtest.h b/lib/drmtest.h
index a9fd0bc..05e3629 100644
--- a/lib/drmtest.h
+++ b/lib/drmtest.h
@@ -413,4 +413,17 @@ void igt_enable_prefault(void);
 /* suspend and auto-resume system */
 void igt_system_suspend_autoresume(void);
 
+/* Returns the fd for the other functions. */
+int kmsg_error_setup(void);
+/* Closes the fd */
+void kmsg_error_teardown(int fd);
+/* Skip to the end of the kmsg fd, so that the next time you call
+ * kmsg_error_detect() you will only parse the new messages. */
+void kmsg_error_reset(int fd);
+/* Reads all the new Kernel messages since the last time you called
+ * kmsg_error_teardown, and also waits for new messages for timeout_ms. In case
+ * we find any error we'll also print error_msg. Uses igt_assert, so no need to
+ * check for return values. */
+void kmsg_error_detect(int fd, int timeout_ms, const char *error_msg);
+
 #endif /* DRMTEST_H */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/2] tests: add kms_edp_vdd_race
  2013-11-11 17:06 [PATCH 1/2] drmtest: introduce kmsg_error functions Paulo Zanoni
@ 2013-11-11 17:06 ` Paulo Zanoni
  2013-11-11 18:15   ` Daniel Vetter
  2013-11-11 18:02 ` [PATCH 1/2] drmtest: introduce kmsg_error functions Daniel Vetter
  1 sibling, 1 reply; 10+ messages in thread
From: Paulo Zanoni @ 2013-11-11 17:06 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

We recently fixed a bug where it was impossible to do I2C transactions
on eDP panels when they were disabled. Now it should be possible to do
these transactions when the panel is disabled, but there's a race
condition that triggers dmesg errors if we try do do the I2C
transactions and set a mode on the panel at the same time. This
program should reproduce this bug and check dmesg for errors.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 tests/.gitignore         |   1 +
 tests/Makefile.am        |   2 +
 tests/kms_edp_vdd_race.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 229 insertions(+)
 create mode 100644 tests/kms_edp_vdd_race.c

diff --git a/tests/.gitignore b/tests/.gitignore
index 09ea074..ddb61f9 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -102,6 +102,7 @@ igt_no_exit_list_only
 igt_no_subtest
 kms_addfb
 kms_cursor_crc
+kms_edp_vdd_race
 kms_flip
 kms_pipe_crc_basic
 kms_render
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0426ec0..955d2a3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -52,6 +52,7 @@ TESTS_progs_M = \
 	gem_write_read_ring_switch \
 	kms_addfb \
 	kms_cursor_crc \
+	kms_edp_vdd_race \
 	kms_flip \
 	kms_pipe_crc_basic \
 	kms_render \
@@ -236,6 +237,7 @@ gem_fence_thrash_LDADD = $(LDADD) -lpthread
 gem_flink_race_LDADD = $(LDADD) -lpthread
 gem_threaded_access_tiled_LDADD = $(LDADD) -lpthread
 prime_self_import_LDADD = $(LDADD) -lpthread
+kms_edp_vdd_race_LDADD = $(LDADD) -lpthread
 
 gem_wait_render_timeout_LDADD = $(LDADD) -lrt
 kms_flip_LDADD = $(LDADD) -lrt
diff --git a/tests/kms_edp_vdd_race.c b/tests/kms_edp_vdd_race.c
new file mode 100644
index 0000000..a6bff65
--- /dev/null
+++ b/tests/kms_edp_vdd_race.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors: Paulo Zanoni <paulo.r.zanoni@intel.com>
+ *
+ */
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "drmtest.h"
+
+int drm_fd, kmsg_fd;
+drmModeResPtr res;
+drmModeConnectorPtr edp_connector;
+bool stop;
+
+static void disable_all_screens(void)
+{
+	int i, rc;
+
+	for (i = 0; i < res->count_crtcs; i++) {
+		rc = drmModeSetCrtc(drm_fd, res->crtcs[i], -1, 0, 0,
+				    NULL, 0, NULL);
+		igt_assert(rc == 0);
+	}
+}
+
+static void find_edp_connector(void)
+{
+	int i;
+	drmModeConnectorPtr c;
+
+	edp_connector = NULL;
+	for (i = 0; i < res->count_connectors; i++) {
+		c = drmModeGetConnector(drm_fd, res->connectors[i]);
+
+		if (c->connector_type == DRM_MODE_CONNECTOR_eDP) {
+			igt_require(c->connection == DRM_MODE_CONNECTED);
+			edp_connector = c;
+			break;
+		}
+
+		drmModeFreeConnector(c);
+	}
+	igt_require(edp_connector);
+}
+
+static void read_edid_ioctl(int fd)
+{
+	unsigned char edid[128] = {};
+	struct i2c_msg msgs[] = {
+		{ /* Start at 0. */
+			.addr = 0x50,
+			.flags = 0,
+			.len = 1,
+			.buf = edid,
+		}, { /* Now read the EDID. */
+			.addr = 0x50,
+			.flags = I2C_M_RD,
+			.len = 128,
+			.buf = edid,
+		}
+	};
+	struct i2c_rdwr_ioctl_data msgset = {
+		.msgs = msgs,
+		.nmsgs = 2,
+	};
+
+	ioctl(fd, I2C_RDWR, &msgset);
+}
+
+/* TODO: We're currently just trying to read all the I2C files. We should try to
+ * find which one is really the eDP I2C file and just read from it. */
+static void read_i2c_edid(void)
+{
+	int fd;
+	DIR *dir;
+
+	struct dirent *dirent;
+	char full_name[32];
+
+	dir = opendir("/dev/");
+	igt_assert(dir);
+
+	while ((dirent = readdir(dir))) {
+		if (strncmp(dirent->d_name, "i2c-", 4) == 0) {
+			snprintf(full_name, 32, "/dev/%s", dirent->d_name);
+			fd = open(full_name, O_RDWR);
+			igt_assert(fd != -1);
+			read_edid_ioctl(fd);
+			close(fd);
+		}
+	}
+
+	closedir(dir);
+}
+
+static void *i2c_thread_func(void *unused)
+{
+	while (!stop)
+		read_i2c_edid();
+
+	pthread_exit(NULL);
+}
+
+static uint32_t create_fb(int width, int height)
+{
+	struct kmstest_fb fb;
+	cairo_t *cr;
+	uint32_t buffer_id;
+
+	buffer_id = kmstest_create_fb(drm_fd, width, height, 32, 24, false,
+				      &fb);
+	cr = kmstest_get_cairo_ctx(drm_fd, &fb);
+	kmstest_paint_test_pattern(cr, width, height);
+	return buffer_id;
+}
+
+static void enable_edp_screen(void)
+{
+	int rc;
+	uint32_t buffer_id = 0, crtc_id, connector_id;
+	drmModeModeInfoPtr mode;
+
+	crtc_id = res->crtcs[0];
+	connector_id = edp_connector->connector_id;
+	mode = &edp_connector->modes[0];
+
+	buffer_id = create_fb(mode->hdisplay, mode->vdisplay);
+
+	rc = drmModeSetCrtc(drm_fd, crtc_id, buffer_id, 0, 0, &connector_id,
+			    1, mode);
+	igt_assert(rc == 0);
+}
+
+static void *modeset_thread_func(void *unused)
+{
+	while (!stop) {
+		disable_all_screens();
+		sleep(1);
+		enable_edp_screen();
+		sleep(1);
+	}
+
+	pthread_exit(NULL);
+}
+
+/* This test exercises a race condition that happens when we're trying to read
+ * the I2C data from an eDP panel at the same time we're trying to set a mode on
+ * the same panel. If we have the bug, we print error messages on dmesg, which
+ * we should catch with the kmsg functions. */
+static void i2c_modeset_vdd_race(void)
+{
+	pthread_t i2c_thread, modeset_thread;
+	void *status;
+
+	kmsg_error_reset(kmsg_fd);
+
+	stop = false;
+	pthread_create(&i2c_thread, NULL, i2c_thread_func, NULL);
+	pthread_create(&modeset_thread, NULL, modeset_thread_func, NULL);
+
+	/* This effectively sleeps for 100 seconds, but kills the program in
+	 * case there's error on dmesg. */
+	kmsg_error_detect(kmsg_fd, 100 * 1000, "");
+
+	stop = true;
+	pthread_join(i2c_thread, &status);
+	pthread_join(modeset_thread, &status);
+
+	/* Make sure we check everything after the threads have actually
+	 * stopped. */
+	kmsg_error_detect(kmsg_fd, 1 * 1000, "");
+}
+
+igt_main
+{
+	igt_fixture {
+		drm_fd = drm_open_any();
+		igt_require(drm_fd >= 0);
+
+		res = drmModeGetResources(drm_fd);
+		igt_assert(res);
+
+		kmsg_fd = kmsg_error_setup();
+
+		find_edp_connector();
+	}
+
+	igt_subtest("i2c-modeset-vdd-race")
+		i2c_modeset_vdd_race();
+
+	igt_fixture {
+		kmsg_error_teardown(kmsg_fd);
+		drmModeFreeConnector(edp_connector);
+		drmModeFreeResources(res);
+		close(drm_fd);
+	}
+}
-- 
1.8.3.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] drmtest: introduce kmsg_error functions
  2013-11-11 17:06 [PATCH 1/2] drmtest: introduce kmsg_error functions Paulo Zanoni
  2013-11-11 17:06 ` [PATCH 2/2] tests: add kms_edp_vdd_race Paulo Zanoni
@ 2013-11-11 18:02 ` Daniel Vetter
  2013-11-11 18:18   ` Paulo Zanoni
  1 sibling, 1 reply; 10+ messages in thread
From: Daniel Vetter @ 2013-11-11 18:02 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: intel-gfx, Paulo Zanoni

On Mon, Nov 11, 2013 at 03:06:09PM -0200, Paulo Zanoni wrote:
> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
> 
> These functions should help you checking for new Kernel error
> messages. One of the problems I had while writing the runtime PM test
> suite is that when you read the sysfs and debugfs files, the only way
> to detect errors is by checking dmesg, so I was always getting SUCCESS
> even if the test caught a bug. Also, we have so many debugfs/sysfs
> files that it was not easy to discover which file caused the error
> messages I was seeing. So this commit adds some infrastructure to
> allow us to automatically check for new errors on dmesg.
> 
> Use it like this:
> 
> int main(int argc, char *argv[]) {
> 	int fd, i;
> 
> 	igt_fixture
> 		fd = kmsg_error_setup();
> 
> 	igt_subtest("t1") {
> 		kmsg_error_reset(fd);
> 		do_something();
> 		kmsg_error_detect("");
> 	}
> 
> 	igt_subtest("t2") {
> 		for (i = 0; i < 10; i++) {
> 			char *file_name = get_file(i);
> 			kmsg_error_reset(fd);
> 			process_file(file_name);
> 			kmsg_error_detect(file_name):
> 		}
> 	}
> 
> 	igt_fixture
> 		kmsg_error_teardown(fd);
> }

Imo that's the wrong approach. _Every_ test should fail if we end up with
errors/backtraces in dmesg. And if you look for very specific stuff (like
gpu hang or missed irq warnings) the approach thus far has been to expose
that information somehow through debugfs files. That way we're independent
from the exact string used in the kernel output.

I think the right approach is to add this to the test runner, i.e. piglit.
There's already very basic support to capture the (new) dmesg output for
each test with the --dmesg option. Have you played around with that and
tried to extend it to your liking?
-Daniel



> 
> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> ---
>  lib/drmtest.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/drmtest.h | 13 ++++++++++
>  2 files changed, 92 insertions(+)
> 
> diff --git a/lib/drmtest.c b/lib/drmtest.c
> index d8fc60f..ebabfd8 100644
> --- a/lib/drmtest.c
> +++ b/lib/drmtest.c
> @@ -41,6 +41,7 @@
>  #include <linux/kd.h>
>  #include <unistd.h>
>  #include <sys/wait.h>
> +#include <poll.h>
>  #include "drm_fourcc.h"
>  
>  #include "drmtest.h"
> @@ -2307,3 +2308,81 @@ void igt_system_suspend_autoresume(void)
>  	ret = system("rtcwake -s 30 -m mem");
>  	igt_assert(ret == 0);
>  }
> +
> +/* The kmsg error detecting functions allow you to catch new error messages from
> + * the Kernel. The idea is that you have to call kmsg_error_setup() only once at
> + * the beginning, and kmsg_error_teardown() at the end. And for every subtest,
> + * you run kmsg_error_reset() at the begin and kmsg_error_detect() at the end:
> + * this should make sure that kmsg_error_detect() will only catch the error
> + * messages that were introduced after the subtest started. */
> +int kmsg_error_setup(void)
> +{
> +	int fd = open("/dev/kmsg", O_RDONLY);
> +
> +	igt_assert_f(fd >= 0, "Can't open /dev/kmsg\n");
> +	return fd;
> +}
> +
> +void kmsg_error_teardown(int fd)
> +{
> +	close(fd);
> +}
> +
> +/* You have to call this before running your subtest, so that the next time you
> + * call kmsg_error_detect you'll only look at the new kmsg lines. */
> +void kmsg_error_reset(int fd)
> +{
> +	lseek(fd, 0, SEEK_END);
> +}
> +
> +static void kmsg_error_line_parse(const char *line, const char *error_msg)
> +{
> +	igt_assert_f(strstr(line, "------------[ cut here ]------------") == 0,
> +		     "%s\n", error_msg);
> +	igt_assert_f(strstr(line, "*ERROR*") == 0, "%s\n", error_msg);
> +	igt_assert_f(strstr(line, "BUG: sleeping function called from invalid context at") == 0,
> +		     "%s\n", error_msg);
> +}
> +
> +/* Keep reading the Kernel ring buffer and checking for errors. Stop reading if
> + * there's nothing new on the buffer after the timeout. Notice that every time
> + * you call this function, the time it will take to return will always be >= the
> + * timeout. */
> +void kmsg_error_detect(int fd, int timeout_ms, const char *error_msg)
> +{
> +	int i, rc;
> +	int line_size = 128, line_used = 0, buf_size = 128;
> +	char buf[buf_size];
> +	char *line;
> +	struct pollfd pfd;
> +	ssize_t readed;
> +
> +	line = malloc(sizeof(char) * line_size);
> +	igt_assert(line);
> +
> +	pfd.fd = fd;
> +	pfd.events = POLLIN | POLLPRI;
> +
> +	while (1) {
> +		pfd.revents = 0;
> +		rc = poll(&pfd, 1, timeout_ms);
> +		if (!rc)
> +			break;
> +
> +		readed = read(fd, &buf, buf_size - 1);
> +		for (i = 0; i < readed; i++) {
> +			if (line_used + 1 >= line_size) {
> +				line = realloc(line, line_size * 2);
> +				line_size *= 2;
> +				igt_assert(line);
> +			}
> +			line[line_used++] = buf[i];
> +			if (buf[i] == '\n') {
> +				line[line_used] = '\0';
> +				kmsg_error_line_parse(line, error_msg);
> +				line_used = 0;
> +			}
> +		}
> +	}
> +	free(line);
> +}
> diff --git a/lib/drmtest.h b/lib/drmtest.h
> index a9fd0bc..05e3629 100644
> --- a/lib/drmtest.h
> +++ b/lib/drmtest.h
> @@ -413,4 +413,17 @@ void igt_enable_prefault(void);
>  /* suspend and auto-resume system */
>  void igt_system_suspend_autoresume(void);
>  
> +/* Returns the fd for the other functions. */
> +int kmsg_error_setup(void);
> +/* Closes the fd */
> +void kmsg_error_teardown(int fd);
> +/* Skip to the end of the kmsg fd, so that the next time you call
> + * kmsg_error_detect() you will only parse the new messages. */
> +void kmsg_error_reset(int fd);
> +/* Reads all the new Kernel messages since the last time you called
> + * kmsg_error_teardown, and also waits for new messages for timeout_ms. In case
> + * we find any error we'll also print error_msg. Uses igt_assert, so no need to
> + * check for return values. */
> +void kmsg_error_detect(int fd, int timeout_ms, const char *error_msg);
> +
>  #endif /* DRMTEST_H */
> -- 
> 1.8.3.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/2] tests: add kms_edp_vdd_race
  2013-11-11 17:06 ` [PATCH 2/2] tests: add kms_edp_vdd_race Paulo Zanoni
@ 2013-11-11 18:15   ` Daniel Vetter
  2013-11-11 18:25     ` Paulo Zanoni
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Vetter @ 2013-11-11 18:15 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: intel-gfx, Paulo Zanoni

On Mon, Nov 11, 2013 at 03:06:10PM -0200, Paulo Zanoni wrote:
> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
> 
> We recently fixed a bug where it was impossible to do I2C transactions
> on eDP panels when they were disabled. Now it should be possible to do
> these transactions when the panel is disabled, but there's a race
> condition that triggers dmesg errors if we try do do the I2C
> transactions and set a mode on the panel at the same time. This
> program should reproduce this bug and check dmesg for errors.
> 
> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

Like I've said in the previous mail I think the generic dmesg error
checking should be somewhere generic (and probably in piglit). Otherwise
the test looks good. And the naming also matches the new convention ;-)
-Daniel

> ---
>  tests/.gitignore         |   1 +
>  tests/Makefile.am        |   2 +
>  tests/kms_edp_vdd_race.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 229 insertions(+)
>  create mode 100644 tests/kms_edp_vdd_race.c
> 
> diff --git a/tests/.gitignore b/tests/.gitignore
> index 09ea074..ddb61f9 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -102,6 +102,7 @@ igt_no_exit_list_only
>  igt_no_subtest
>  kms_addfb
>  kms_cursor_crc
> +kms_edp_vdd_race
>  kms_flip
>  kms_pipe_crc_basic
>  kms_render
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index 0426ec0..955d2a3 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -52,6 +52,7 @@ TESTS_progs_M = \
>  	gem_write_read_ring_switch \
>  	kms_addfb \
>  	kms_cursor_crc \
> +	kms_edp_vdd_race \
>  	kms_flip \
>  	kms_pipe_crc_basic \
>  	kms_render \
> @@ -236,6 +237,7 @@ gem_fence_thrash_LDADD = $(LDADD) -lpthread
>  gem_flink_race_LDADD = $(LDADD) -lpthread
>  gem_threaded_access_tiled_LDADD = $(LDADD) -lpthread
>  prime_self_import_LDADD = $(LDADD) -lpthread
> +kms_edp_vdd_race_LDADD = $(LDADD) -lpthread
>  
>  gem_wait_render_timeout_LDADD = $(LDADD) -lrt
>  kms_flip_LDADD = $(LDADD) -lrt
> diff --git a/tests/kms_edp_vdd_race.c b/tests/kms_edp_vdd_race.c
> new file mode 100644
> index 0000000..a6bff65
> --- /dev/null
> +++ b/tests/kms_edp_vdd_race.c
> @@ -0,0 +1,226 @@
> +/*
> + * Copyright © 2013 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors: Paulo Zanoni <paulo.r.zanoni@intel.com>
> + *
> + */
> +
> +#include <dirent.h>
> +#include <fcntl.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-dev.h>
> +#include <pthread.h>
> +#include <string.h>
> +#include <sys/ioctl.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +
> +#include "drmtest.h"
> +
> +int drm_fd, kmsg_fd;
> +drmModeResPtr res;
> +drmModeConnectorPtr edp_connector;
> +bool stop;
> +
> +static void disable_all_screens(void)
> +{
> +	int i, rc;
> +
> +	for (i = 0; i < res->count_crtcs; i++) {
> +		rc = drmModeSetCrtc(drm_fd, res->crtcs[i], -1, 0, 0,
> +				    NULL, 0, NULL);
> +		igt_assert(rc == 0);
> +	}
> +}
> +
> +static void find_edp_connector(void)
> +{
> +	int i;
> +	drmModeConnectorPtr c;
> +
> +	edp_connector = NULL;
> +	for (i = 0; i < res->count_connectors; i++) {
> +		c = drmModeGetConnector(drm_fd, res->connectors[i]);
> +
> +		if (c->connector_type == DRM_MODE_CONNECTOR_eDP) {
> +			igt_require(c->connection == DRM_MODE_CONNECTED);
> +			edp_connector = c;
> +			break;
> +		}
> +
> +		drmModeFreeConnector(c);
> +	}
> +	igt_require(edp_connector);
> +}
> +
> +static void read_edid_ioctl(int fd)
> +{
> +	unsigned char edid[128] = {};
> +	struct i2c_msg msgs[] = {
> +		{ /* Start at 0. */
> +			.addr = 0x50,
> +			.flags = 0,
> +			.len = 1,
> +			.buf = edid,
> +		}, { /* Now read the EDID. */
> +			.addr = 0x50,
> +			.flags = I2C_M_RD,
> +			.len = 128,
> +			.buf = edid,
> +		}
> +	};
> +	struct i2c_rdwr_ioctl_data msgset = {
> +		.msgs = msgs,
> +		.nmsgs = 2,
> +	};
> +
> +	ioctl(fd, I2C_RDWR, &msgset);
> +}
> +
> +/* TODO: We're currently just trying to read all the I2C files. We should try to
> + * find which one is really the eDP I2C file and just read from it. */
> +static void read_i2c_edid(void)
> +{
> +	int fd;
> +	DIR *dir;
> +
> +	struct dirent *dirent;
> +	char full_name[32];
> +
> +	dir = opendir("/dev/");
> +	igt_assert(dir);
> +
> +	while ((dirent = readdir(dir))) {
> +		if (strncmp(dirent->d_name, "i2c-", 4) == 0) {
> +			snprintf(full_name, 32, "/dev/%s", dirent->d_name);
> +			fd = open(full_name, O_RDWR);
> +			igt_assert(fd != -1);
> +			read_edid_ioctl(fd);
> +			close(fd);
> +		}
> +	}
> +
> +	closedir(dir);
> +}
> +
> +static void *i2c_thread_func(void *unused)
> +{
> +	while (!stop)
> +		read_i2c_edid();
> +
> +	pthread_exit(NULL);
> +}
> +
> +static uint32_t create_fb(int width, int height)
> +{
> +	struct kmstest_fb fb;
> +	cairo_t *cr;
> +	uint32_t buffer_id;
> +
> +	buffer_id = kmstest_create_fb(drm_fd, width, height, 32, 24, false,
> +				      &fb);
> +	cr = kmstest_get_cairo_ctx(drm_fd, &fb);
> +	kmstest_paint_test_pattern(cr, width, height);
> +	return buffer_id;
> +}
> +
> +static void enable_edp_screen(void)
> +{
> +	int rc;
> +	uint32_t buffer_id = 0, crtc_id, connector_id;
> +	drmModeModeInfoPtr mode;
> +
> +	crtc_id = res->crtcs[0];
> +	connector_id = edp_connector->connector_id;
> +	mode = &edp_connector->modes[0];
> +
> +	buffer_id = create_fb(mode->hdisplay, mode->vdisplay);
> +
> +	rc = drmModeSetCrtc(drm_fd, crtc_id, buffer_id, 0, 0, &connector_id,
> +			    1, mode);
> +	igt_assert(rc == 0);
> +}
> +
> +static void *modeset_thread_func(void *unused)
> +{
> +	while (!stop) {
> +		disable_all_screens();
> +		sleep(1);
> +		enable_edp_screen();
> +		sleep(1);
> +	}
> +
> +	pthread_exit(NULL);
> +}
> +
> +/* This test exercises a race condition that happens when we're trying to read
> + * the I2C data from an eDP panel at the same time we're trying to set a mode on
> + * the same panel. If we have the bug, we print error messages on dmesg, which
> + * we should catch with the kmsg functions. */
> +static void i2c_modeset_vdd_race(void)
> +{
> +	pthread_t i2c_thread, modeset_thread;
> +	void *status;
> +
> +	kmsg_error_reset(kmsg_fd);
> +
> +	stop = false;
> +	pthread_create(&i2c_thread, NULL, i2c_thread_func, NULL);
> +	pthread_create(&modeset_thread, NULL, modeset_thread_func, NULL);
> +
> +	/* This effectively sleeps for 100 seconds, but kills the program in
> +	 * case there's error on dmesg. */
> +	kmsg_error_detect(kmsg_fd, 100 * 1000, "");
> +
> +	stop = true;
> +	pthread_join(i2c_thread, &status);
> +	pthread_join(modeset_thread, &status);
> +
> +	/* Make sure we check everything after the threads have actually
> +	 * stopped. */
> +	kmsg_error_detect(kmsg_fd, 1 * 1000, "");
> +}
> +
> +igt_main
> +{
> +	igt_fixture {
> +		drm_fd = drm_open_any();
> +		igt_require(drm_fd >= 0);
> +
> +		res = drmModeGetResources(drm_fd);
> +		igt_assert(res);
> +
> +		kmsg_fd = kmsg_error_setup();
> +
> +		find_edp_connector();
> +	}
> +
> +	igt_subtest("i2c-modeset-vdd-race")
> +		i2c_modeset_vdd_race();
> +
> +	igt_fixture {
> +		kmsg_error_teardown(kmsg_fd);
> +		drmModeFreeConnector(edp_connector);
> +		drmModeFreeResources(res);
> +		close(drm_fd);
> +	}
> +}
> -- 
> 1.8.3.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] drmtest: introduce kmsg_error functions
  2013-11-11 18:02 ` [PATCH 1/2] drmtest: introduce kmsg_error functions Daniel Vetter
@ 2013-11-11 18:18   ` Paulo Zanoni
  2013-11-11 18:48     ` Daniel Vetter
  0 siblings, 1 reply; 10+ messages in thread
From: Paulo Zanoni @ 2013-11-11 18:18 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, Paulo Zanoni

2013/11/11 Daniel Vetter <daniel@ffwll.ch>:
> On Mon, Nov 11, 2013 at 03:06:09PM -0200, Paulo Zanoni wrote:
>> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
>>
>> These functions should help you checking for new Kernel error
>> messages. One of the problems I had while writing the runtime PM test
>> suite is that when you read the sysfs and debugfs files, the only way
>> to detect errors is by checking dmesg, so I was always getting SUCCESS
>> even if the test caught a bug. Also, we have so many debugfs/sysfs
>> files that it was not easy to discover which file caused the error
>> messages I was seeing. So this commit adds some infrastructure to
>> allow us to automatically check for new errors on dmesg.
>>
>> Use it like this:
>>
>> int main(int argc, char *argv[]) {
>>       int fd, i;
>>
>>       igt_fixture
>>               fd = kmsg_error_setup();
>>
>>       igt_subtest("t1") {
>>               kmsg_error_reset(fd);
>>               do_something();
>>               kmsg_error_detect("");
>>       }
>>
>>       igt_subtest("t2") {
>>               for (i = 0; i < 10; i++) {
>>                       char *file_name = get_file(i);
>>                       kmsg_error_reset(fd);
>>                       process_file(file_name);
>>                       kmsg_error_detect(file_name):
>>               }
>>       }
>>
>>       igt_fixture
>>               kmsg_error_teardown(fd);
>> }
>
> Imo that's the wrong approach. _Every_ test should fail if we end up with
> errors/backtraces in dmesg.

That's exactly why I wrote code to check dmesg! We could, in the
future, make the igt_subtest macros call this code automatically.


> And if you look for very specific stuff (like
> gpu hang or missed irq warnings) the approach thus far has been to expose
> that information somehow through debugfs files.

So you're suggesting I should create some sort of debugfs interface to
expose every single WARN our driver does? Doesn't really sound like a
good idea, unless we invent our our I915_WARN, I915_ERROR, etc.. And
we still won't catch the WARNs and ERRORs spit by drm.ko or anything
outside i915.ko.


> That way we're independent
> from the exact string used in the kernel output.

ZZ_check_dmesg already parses dmesg strings, I just copied it. Also,
the whole IGT already relies way too much on being ran against
very-recent libdrm/Kernels, we're just adding one more dependency. And
we can also add the newer strings if somebody ever changes the WARN or
DRM_ERROR output: it's not like our code will completely break, it
just won't be as good. And we always require everybody to use IGT git
master anyway. I don't see the problem.


>
> I think the right approach is to add this to the test runner, i.e. piglit.
> There's already very basic support to capture the (new) dmesg output for
> each test with the --dmesg option. Have you played around with that and
> tried to extend it to your liking?

My goal is that I want to know, inside a test program, which line of
code introduced the dmesg error, and if we use some sort of external
approach like what you're suggesting this won't be possible. I have
code that opens hundreds of sysfs and debugfs files, and I want to
check dmesg after I open/close every single file, to be able to detect
which one exactly causes the problem. I'm already using this locally
and it *really* saved a lot of time for me. If we don 't accept this
code inside drmtest.c, I'm gonna ask if I can push it directly to
pm_pc8.c.


> -Daniel
>
>
>
>>
>> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
>> ---
>>  lib/drmtest.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  lib/drmtest.h | 13 ++++++++++
>>  2 files changed, 92 insertions(+)
>>
>> diff --git a/lib/drmtest.c b/lib/drmtest.c
>> index d8fc60f..ebabfd8 100644
>> --- a/lib/drmtest.c
>> +++ b/lib/drmtest.c
>> @@ -41,6 +41,7 @@
>>  #include <linux/kd.h>
>>  #include <unistd.h>
>>  #include <sys/wait.h>
>> +#include <poll.h>
>>  #include "drm_fourcc.h"
>>
>>  #include "drmtest.h"
>> @@ -2307,3 +2308,81 @@ void igt_system_suspend_autoresume(void)
>>       ret = system("rtcwake -s 30 -m mem");
>>       igt_assert(ret == 0);
>>  }
>> +
>> +/* The kmsg error detecting functions allow you to catch new error messages from
>> + * the Kernel. The idea is that you have to call kmsg_error_setup() only once at
>> + * the beginning, and kmsg_error_teardown() at the end. And for every subtest,
>> + * you run kmsg_error_reset() at the begin and kmsg_error_detect() at the end:
>> + * this should make sure that kmsg_error_detect() will only catch the error
>> + * messages that were introduced after the subtest started. */
>> +int kmsg_error_setup(void)
>> +{
>> +     int fd = open("/dev/kmsg", O_RDONLY);
>> +
>> +     igt_assert_f(fd >= 0, "Can't open /dev/kmsg\n");
>> +     return fd;
>> +}
>> +
>> +void kmsg_error_teardown(int fd)
>> +{
>> +     close(fd);
>> +}
>> +
>> +/* You have to call this before running your subtest, so that the next time you
>> + * call kmsg_error_detect you'll only look at the new kmsg lines. */
>> +void kmsg_error_reset(int fd)
>> +{
>> +     lseek(fd, 0, SEEK_END);
>> +}
>> +
>> +static void kmsg_error_line_parse(const char *line, const char *error_msg)
>> +{
>> +     igt_assert_f(strstr(line, "------------[ cut here ]------------") == 0,
>> +                  "%s\n", error_msg);
>> +     igt_assert_f(strstr(line, "*ERROR*") == 0, "%s\n", error_msg);
>> +     igt_assert_f(strstr(line, "BUG: sleeping function called from invalid context at") == 0,
>> +                  "%s\n", error_msg);
>> +}
>> +
>> +/* Keep reading the Kernel ring buffer and checking for errors. Stop reading if
>> + * there's nothing new on the buffer after the timeout. Notice that every time
>> + * you call this function, the time it will take to return will always be >= the
>> + * timeout. */
>> +void kmsg_error_detect(int fd, int timeout_ms, const char *error_msg)
>> +{
>> +     int i, rc;
>> +     int line_size = 128, line_used = 0, buf_size = 128;
>> +     char buf[buf_size];
>> +     char *line;
>> +     struct pollfd pfd;
>> +     ssize_t readed;
>> +
>> +     line = malloc(sizeof(char) * line_size);
>> +     igt_assert(line);
>> +
>> +     pfd.fd = fd;
>> +     pfd.events = POLLIN | POLLPRI;
>> +
>> +     while (1) {
>> +             pfd.revents = 0;
>> +             rc = poll(&pfd, 1, timeout_ms);
>> +             if (!rc)
>> +                     break;
>> +
>> +             readed = read(fd, &buf, buf_size - 1);
>> +             for (i = 0; i < readed; i++) {
>> +                     if (line_used + 1 >= line_size) {
>> +                             line = realloc(line, line_size * 2);
>> +                             line_size *= 2;
>> +                             igt_assert(line);
>> +                     }
>> +                     line[line_used++] = buf[i];
>> +                     if (buf[i] == '\n') {
>> +                             line[line_used] = '\0';
>> +                             kmsg_error_line_parse(line, error_msg);
>> +                             line_used = 0;
>> +                     }
>> +             }
>> +     }
>> +     free(line);
>> +}
>> diff --git a/lib/drmtest.h b/lib/drmtest.h
>> index a9fd0bc..05e3629 100644
>> --- a/lib/drmtest.h
>> +++ b/lib/drmtest.h
>> @@ -413,4 +413,17 @@ void igt_enable_prefault(void);
>>  /* suspend and auto-resume system */
>>  void igt_system_suspend_autoresume(void);
>>
>> +/* Returns the fd for the other functions. */
>> +int kmsg_error_setup(void);
>> +/* Closes the fd */
>> +void kmsg_error_teardown(int fd);
>> +/* Skip to the end of the kmsg fd, so that the next time you call
>> + * kmsg_error_detect() you will only parse the new messages. */
>> +void kmsg_error_reset(int fd);
>> +/* Reads all the new Kernel messages since the last time you called
>> + * kmsg_error_teardown, and also waits for new messages for timeout_ms. In case
>> + * we find any error we'll also print error_msg. Uses igt_assert, so no need to
>> + * check for return values. */
>> +void kmsg_error_detect(int fd, int timeout_ms, const char *error_msg);
>> +
>>  #endif /* DRMTEST_H */
>> --
>> 1.8.3.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/2] tests: add kms_edp_vdd_race
  2013-11-11 18:15   ` Daniel Vetter
@ 2013-11-11 18:25     ` Paulo Zanoni
  2013-11-11 18:41       ` Daniel Vetter
  0 siblings, 1 reply; 10+ messages in thread
From: Paulo Zanoni @ 2013-11-11 18:25 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, Paulo Zanoni

2013/11/11 Daniel Vetter <daniel@ffwll.ch>:
> On Mon, Nov 11, 2013 at 03:06:10PM -0200, Paulo Zanoni wrote:
>> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
>>
>> We recently fixed a bug where it was impossible to do I2C transactions
>> on eDP panels when they were disabled. Now it should be possible to do
>> these transactions when the panel is disabled, but there's a race
>> condition that triggers dmesg errors if we try do do the I2C
>> transactions and set a mode on the panel at the same time. This
>> program should reproduce this bug and check dmesg for errors.
>>
>> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
>
> Like I've said in the previous mail I think the generic dmesg error
> checking should be somewhere generic (and probably in piglit). Otherwise
> the test looks good. And the naming also matches the new convention ;-)

Then this test will always give a SUCCESS. Not really what I wanted :(

> -Daniel
>
>> ---
>>  tests/.gitignore         |   1 +
>>  tests/Makefile.am        |   2 +
>>  tests/kms_edp_vdd_race.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 229 insertions(+)
>>  create mode 100644 tests/kms_edp_vdd_race.c
>>
>> diff --git a/tests/.gitignore b/tests/.gitignore
>> index 09ea074..ddb61f9 100644
>> --- a/tests/.gitignore
>> +++ b/tests/.gitignore
>> @@ -102,6 +102,7 @@ igt_no_exit_list_only
>>  igt_no_subtest
>>  kms_addfb
>>  kms_cursor_crc
>> +kms_edp_vdd_race
>>  kms_flip
>>  kms_pipe_crc_basic
>>  kms_render
>> diff --git a/tests/Makefile.am b/tests/Makefile.am
>> index 0426ec0..955d2a3 100644
>> --- a/tests/Makefile.am
>> +++ b/tests/Makefile.am
>> @@ -52,6 +52,7 @@ TESTS_progs_M = \
>>       gem_write_read_ring_switch \
>>       kms_addfb \
>>       kms_cursor_crc \
>> +     kms_edp_vdd_race \
>>       kms_flip \
>>       kms_pipe_crc_basic \
>>       kms_render \
>> @@ -236,6 +237,7 @@ gem_fence_thrash_LDADD = $(LDADD) -lpthread
>>  gem_flink_race_LDADD = $(LDADD) -lpthread
>>  gem_threaded_access_tiled_LDADD = $(LDADD) -lpthread
>>  prime_self_import_LDADD = $(LDADD) -lpthread
>> +kms_edp_vdd_race_LDADD = $(LDADD) -lpthread
>>
>>  gem_wait_render_timeout_LDADD = $(LDADD) -lrt
>>  kms_flip_LDADD = $(LDADD) -lrt
>> diff --git a/tests/kms_edp_vdd_race.c b/tests/kms_edp_vdd_race.c
>> new file mode 100644
>> index 0000000..a6bff65
>> --- /dev/null
>> +++ b/tests/kms_edp_vdd_race.c
>> @@ -0,0 +1,226 @@
>> +/*
>> + * Copyright © 2013 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> + * IN THE SOFTWARE.
>> + *
>> + * Authors: Paulo Zanoni <paulo.r.zanoni@intel.com>
>> + *
>> + */
>> +
>> +#include <dirent.h>
>> +#include <fcntl.h>
>> +#include <linux/i2c.h>
>> +#include <linux/i2c-dev.h>
>> +#include <pthread.h>
>> +#include <string.h>
>> +#include <sys/ioctl.h>
>> +#include <sys/stat.h>
>> +#include <sys/types.h>
>> +
>> +#include "drmtest.h"
>> +
>> +int drm_fd, kmsg_fd;
>> +drmModeResPtr res;
>> +drmModeConnectorPtr edp_connector;
>> +bool stop;
>> +
>> +static void disable_all_screens(void)
>> +{
>> +     int i, rc;
>> +
>> +     for (i = 0; i < res->count_crtcs; i++) {
>> +             rc = drmModeSetCrtc(drm_fd, res->crtcs[i], -1, 0, 0,
>> +                                 NULL, 0, NULL);
>> +             igt_assert(rc == 0);
>> +     }
>> +}
>> +
>> +static void find_edp_connector(void)
>> +{
>> +     int i;
>> +     drmModeConnectorPtr c;
>> +
>> +     edp_connector = NULL;
>> +     for (i = 0; i < res->count_connectors; i++) {
>> +             c = drmModeGetConnector(drm_fd, res->connectors[i]);
>> +
>> +             if (c->connector_type == DRM_MODE_CONNECTOR_eDP) {
>> +                     igt_require(c->connection == DRM_MODE_CONNECTED);
>> +                     edp_connector = c;
>> +                     break;
>> +             }
>> +
>> +             drmModeFreeConnector(c);
>> +     }
>> +     igt_require(edp_connector);
>> +}
>> +
>> +static void read_edid_ioctl(int fd)
>> +{
>> +     unsigned char edid[128] = {};
>> +     struct i2c_msg msgs[] = {
>> +             { /* Start at 0. */
>> +                     .addr = 0x50,
>> +                     .flags = 0,
>> +                     .len = 1,
>> +                     .buf = edid,
>> +             }, { /* Now read the EDID. */
>> +                     .addr = 0x50,
>> +                     .flags = I2C_M_RD,
>> +                     .len = 128,
>> +                     .buf = edid,
>> +             }
>> +     };
>> +     struct i2c_rdwr_ioctl_data msgset = {
>> +             .msgs = msgs,
>> +             .nmsgs = 2,
>> +     };
>> +
>> +     ioctl(fd, I2C_RDWR, &msgset);
>> +}
>> +
>> +/* TODO: We're currently just trying to read all the I2C files. We should try to
>> + * find which one is really the eDP I2C file and just read from it. */
>> +static void read_i2c_edid(void)
>> +{
>> +     int fd;
>> +     DIR *dir;
>> +
>> +     struct dirent *dirent;
>> +     char full_name[32];
>> +
>> +     dir = opendir("/dev/");
>> +     igt_assert(dir);
>> +
>> +     while ((dirent = readdir(dir))) {
>> +             if (strncmp(dirent->d_name, "i2c-", 4) == 0) {
>> +                     snprintf(full_name, 32, "/dev/%s", dirent->d_name);
>> +                     fd = open(full_name, O_RDWR);
>> +                     igt_assert(fd != -1);
>> +                     read_edid_ioctl(fd);
>> +                     close(fd);
>> +             }
>> +     }
>> +
>> +     closedir(dir);
>> +}
>> +
>> +static void *i2c_thread_func(void *unused)
>> +{
>> +     while (!stop)
>> +             read_i2c_edid();
>> +
>> +     pthread_exit(NULL);
>> +}
>> +
>> +static uint32_t create_fb(int width, int height)
>> +{
>> +     struct kmstest_fb fb;
>> +     cairo_t *cr;
>> +     uint32_t buffer_id;
>> +
>> +     buffer_id = kmstest_create_fb(drm_fd, width, height, 32, 24, false,
>> +                                   &fb);
>> +     cr = kmstest_get_cairo_ctx(drm_fd, &fb);
>> +     kmstest_paint_test_pattern(cr, width, height);
>> +     return buffer_id;
>> +}
>> +
>> +static void enable_edp_screen(void)
>> +{
>> +     int rc;
>> +     uint32_t buffer_id = 0, crtc_id, connector_id;
>> +     drmModeModeInfoPtr mode;
>> +
>> +     crtc_id = res->crtcs[0];
>> +     connector_id = edp_connector->connector_id;
>> +     mode = &edp_connector->modes[0];
>> +
>> +     buffer_id = create_fb(mode->hdisplay, mode->vdisplay);
>> +
>> +     rc = drmModeSetCrtc(drm_fd, crtc_id, buffer_id, 0, 0, &connector_id,
>> +                         1, mode);
>> +     igt_assert(rc == 0);
>> +}
>> +
>> +static void *modeset_thread_func(void *unused)
>> +{
>> +     while (!stop) {
>> +             disable_all_screens();
>> +             sleep(1);
>> +             enable_edp_screen();
>> +             sleep(1);
>> +     }
>> +
>> +     pthread_exit(NULL);
>> +}
>> +
>> +/* This test exercises a race condition that happens when we're trying to read
>> + * the I2C data from an eDP panel at the same time we're trying to set a mode on
>> + * the same panel. If we have the bug, we print error messages on dmesg, which
>> + * we should catch with the kmsg functions. */
>> +static void i2c_modeset_vdd_race(void)
>> +{
>> +     pthread_t i2c_thread, modeset_thread;
>> +     void *status;
>> +
>> +     kmsg_error_reset(kmsg_fd);
>> +
>> +     stop = false;
>> +     pthread_create(&i2c_thread, NULL, i2c_thread_func, NULL);
>> +     pthread_create(&modeset_thread, NULL, modeset_thread_func, NULL);
>> +
>> +     /* This effectively sleeps for 100 seconds, but kills the program in
>> +      * case there's error on dmesg. */
>> +     kmsg_error_detect(kmsg_fd, 100 * 1000, "");
>> +
>> +     stop = true;
>> +     pthread_join(i2c_thread, &status);
>> +     pthread_join(modeset_thread, &status);
>> +
>> +     /* Make sure we check everything after the threads have actually
>> +      * stopped. */
>> +     kmsg_error_detect(kmsg_fd, 1 * 1000, "");
>> +}
>> +
>> +igt_main
>> +{
>> +     igt_fixture {
>> +             drm_fd = drm_open_any();
>> +             igt_require(drm_fd >= 0);
>> +
>> +             res = drmModeGetResources(drm_fd);
>> +             igt_assert(res);
>> +
>> +             kmsg_fd = kmsg_error_setup();
>> +
>> +             find_edp_connector();
>> +     }
>> +
>> +     igt_subtest("i2c-modeset-vdd-race")
>> +             i2c_modeset_vdd_race();
>> +
>> +     igt_fixture {
>> +             kmsg_error_teardown(kmsg_fd);
>> +             drmModeFreeConnector(edp_connector);
>> +             drmModeFreeResources(res);
>> +             close(drm_fd);
>> +     }
>> +}
>> --
>> 1.8.3.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/2] tests: add kms_edp_vdd_race
  2013-11-11 18:25     ` Paulo Zanoni
@ 2013-11-11 18:41       ` Daniel Vetter
  2013-11-11 18:54         ` Paulo Zanoni
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Vetter @ 2013-11-11 18:41 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development, Paulo Zanoni

On Mon, Nov 11, 2013 at 04:25:36PM -0200, Paulo Zanoni wrote:
> 2013/11/11 Daniel Vetter <daniel@ffwll.ch>:
> > On Mon, Nov 11, 2013 at 03:06:10PM -0200, Paulo Zanoni wrote:
> >> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
> >>
> >> We recently fixed a bug where it was impossible to do I2C transactions
> >> on eDP panels when they were disabled. Now it should be possible to do
> >> these transactions when the panel is disabled, but there's a race
> >> condition that triggers dmesg errors if we try do do the I2C
> >> transactions and set a mode on the panel at the same time. This
> >> program should reproduce this bug and check dmesg for errors.
> >>
> >> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> >
> > Like I've said in the previous mail I think the generic dmesg error
> > checking should be somewhere generic (and probably in piglit). Otherwise
> > the test looks good. And the naming also matches the new convention ;-)
> 
> Then this test will always give a SUCCESS. Not really what I wanted :(

It's not the only one. We have tests that only annoy the in-kernel debug
features like lockdep, object use-after-free and other stuff. Or all the
WARN backtraces from testdisplay. And very often they all "succeed".

Checking dmesg in individual tests really doesn't make much sense imo and
needs to be somewhere where it's done for _all_ testcases. QA already has
that in their own testrunner infrastructure, unfortunately that's not
shared with developers so we get to invent a new wheel.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] drmtest: introduce kmsg_error functions
  2013-11-11 18:18   ` Paulo Zanoni
@ 2013-11-11 18:48     ` Daniel Vetter
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Vetter @ 2013-11-11 18:48 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development, Paulo Zanoni

On Mon, Nov 11, 2013 at 04:18:04PM -0200, Paulo Zanoni wrote:
> 2013/11/11 Daniel Vetter <daniel@ffwll.ch>:
> > On Mon, Nov 11, 2013 at 03:06:09PM -0200, Paulo Zanoni wrote:
> >> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
> >>
> >> These functions should help you checking for new Kernel error
> >> messages. One of the problems I had while writing the runtime PM test
> >> suite is that when you read the sysfs and debugfs files, the only way
> >> to detect errors is by checking dmesg, so I was always getting SUCCESS
> >> even if the test caught a bug. Also, we have so many debugfs/sysfs
> >> files that it was not easy to discover which file caused the error
> >> messages I was seeing. So this commit adds some infrastructure to
> >> allow us to automatically check for new errors on dmesg.
> >>
> >> Use it like this:
> >>
> >> int main(int argc, char *argv[]) {
> >>       int fd, i;
> >>
> >>       igt_fixture
> >>               fd = kmsg_error_setup();
> >>
> >>       igt_subtest("t1") {
> >>               kmsg_error_reset(fd);
> >>               do_something();
> >>               kmsg_error_detect("");
> >>       }
> >>
> >>       igt_subtest("t2") {
> >>               for (i = 0; i < 10; i++) {
> >>                       char *file_name = get_file(i);
> >>                       kmsg_error_reset(fd);
> >>                       process_file(file_name);
> >>                       kmsg_error_detect(file_name):
> >>               }
> >>       }
> >>
> >>       igt_fixture
> >>               kmsg_error_teardown(fd);
> >> }
> >
> > Imo that's the wrong approach. _Every_ test should fail if we end up with
> > errors/backtraces in dmesg.
> 
> That's exactly why I wrote code to check dmesg! We could, in the
> future, make the igt_subtest macros call this code automatically.

That leaves out tests that aren't yet converted over to subtests ...
> 
> 
> > And if you look for very specific stuff (like
> > gpu hang or missed irq warnings) the approach thus far has been to expose
> > that information somehow through debugfs files.
> 
> So you're suggesting I should create some sort of debugfs interface to
> expose every single WARN our driver does? Doesn't really sound like a
> good idea, unless we invent our our I915_WARN, I915_ERROR, etc.. And
> we still won't catch the WARNs and ERRORs spit by drm.ko or anything
> outside i915.ko.

Nope. I'm suggesting to do this in the piglit runner instead so that all
tests profit automatically. Since as you say, we can't patch lockdep.

> > That way we're independent
> > from the exact string used in the kernel output.
> 
> ZZ_check_dmesg already parses dmesg strings, I just copied it. Also,
> the whole IGT already relies way too much on being ran against
> very-recent libdrm/Kernels, we're just adding one more dependency. And
> we can also add the newer strings if somebody ever changes the WARN or
> DRM_ERROR output: it's not like our code will completely break, it
> just won't be as good. And we always require everybody to use IGT git
> master anyway. I don't see the problem.

ZZ_check_dmesg was a quick hack done two years ago that should have been
ported to something sane a long time ago. With piglit's non-deterministic
test ordering it's pretty useless nowadays.

> > I think the right approach is to add this to the test runner, i.e. piglit.
> > There's already very basic support to capture the (new) dmesg output for
> > each test with the --dmesg option. Have you played around with that and
> > tried to extend it to your liking?
> 
> My goal is that I want to know, inside a test program, which line of
> code introduced the dmesg error, and if we use some sort of external
> approach like what you're suggesting this won't be possible. I have
> code that opens hundreds of sysfs and debugfs files, and I want to
> check dmesg after I open/close every single file, to be able to detect
> which one exactly causes the problem. I'm already using this locally
> and it *really* saved a lot of time for me. If we don 't accept this
> code inside drmtest.c, I'm gonna ask if I can push it directly to
> pm_pc8.c.

Hm, thus far I've just looked at the functions in the backtrace. Can you
give an example of which kinds of bugs your hunting that need this?

But in general I certainly don't want this in pc8.c. If it's indeed useful
to check dmesg after each step in some tests then having some helpers in
igt/lib makes sense. Just doing it for the overall test though just
duplicates functionality which already exists in piglit.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/2] tests: add kms_edp_vdd_race
  2013-11-11 18:41       ` Daniel Vetter
@ 2013-11-11 18:54         ` Paulo Zanoni
  2013-11-11 21:10           ` Daniel Vetter
  0 siblings, 1 reply; 10+ messages in thread
From: Paulo Zanoni @ 2013-11-11 18:54 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, Paulo Zanoni

2013/11/11 Daniel Vetter <daniel@ffwll.ch>:
> On Mon, Nov 11, 2013 at 04:25:36PM -0200, Paulo Zanoni wrote:
>> 2013/11/11 Daniel Vetter <daniel@ffwll.ch>:
>> > On Mon, Nov 11, 2013 at 03:06:10PM -0200, Paulo Zanoni wrote:
>> >> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
>> >>
>> >> We recently fixed a bug where it was impossible to do I2C transactions
>> >> on eDP panels when they were disabled. Now it should be possible to do
>> >> these transactions when the panel is disabled, but there's a race
>> >> condition that triggers dmesg errors if we try do do the I2C
>> >> transactions and set a mode on the panel at the same time. This
>> >> program should reproduce this bug and check dmesg for errors.
>> >>
>> >> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
>> >
>> > Like I've said in the previous mail I think the generic dmesg error
>> > checking should be somewhere generic (and probably in piglit). Otherwise
>> > the test looks good. And the naming also matches the new convention ;-)
>>
>> Then this test will always give a SUCCESS. Not really what I wanted :(
>
> It's not the only one. We have tests that only annoy the in-kernel debug
> features like lockdep, object use-after-free and other stuff. Or all the
> WARN backtraces from testdisplay. And very often they all "succeed".

And that's the problem I'm trying to solve. We have a solution, it's
useful not just for me - you just gave examples of where it would be
useful too -, yet, IMHO, you still didn't give a good technical reason
on why you're rejecting it.

>
> Checking dmesg in individual tests really doesn't make much sense imo

Well, IMHO it makes a lot of sense. It's even helping me write code,
as I already explained.


> and
> needs to be somewhere where it's done for _all_ testcases.

My code is not preventing that. In fact, I think it's helping us get
to that point.


> QA already has
> that in their own testrunner infrastructure, unfortunately that's not
> shared with developers so we get to invent a new wheel.

I just proposed these new wheels...


> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch



-- 
Paulo Zanoni

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/2] tests: add kms_edp_vdd_race
  2013-11-11 18:54         ` Paulo Zanoni
@ 2013-11-11 21:10           ` Daniel Vetter
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Vetter @ 2013-11-11 21:10 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development, Paulo Zanoni

On Mon, Nov 11, 2013 at 04:54:32PM -0200, Paulo Zanoni wrote:
> 2013/11/11 Daniel Vetter <daniel@ffwll.ch>:
> > On Mon, Nov 11, 2013 at 04:25:36PM -0200, Paulo Zanoni wrote:
> >> 2013/11/11 Daniel Vetter <daniel@ffwll.ch>:
> >> > On Mon, Nov 11, 2013 at 03:06:10PM -0200, Paulo Zanoni wrote:
> >> >> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
> >> >>
> >> >> We recently fixed a bug where it was impossible to do I2C transactions
> >> >> on eDP panels when they were disabled. Now it should be possible to do
> >> >> these transactions when the panel is disabled, but there's a race
> >> >> condition that triggers dmesg errors if we try do do the I2C
> >> >> transactions and set a mode on the panel at the same time. This
> >> >> program should reproduce this bug and check dmesg for errors.
> >> >>
> >> >> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> >> >
> >> > Like I've said in the previous mail I think the generic dmesg error
> >> > checking should be somewhere generic (and probably in piglit). Otherwise
> >> > the test looks good. And the naming also matches the new convention ;-)
> >>
> >> Then this test will always give a SUCCESS. Not really what I wanted :(
> >
> > It's not the only one. We have tests that only annoy the in-kernel debug
> > features like lockdep, object use-after-free and other stuff. Or all the
> > WARN backtraces from testdisplay. And very often they all "succeed".
> 
> And that's the problem I'm trying to solve. We have a solution, it's
> useful not just for me - you just gave examples of where it would be
> useful too -, yet, IMHO, you still didn't give a good technical reason
> on why you're rejecting it.
> 
> >
> > Checking dmesg in individual tests really doesn't make much sense imo
> 
> Well, IMHO it makes a lot of sense. It's even helping me write code,
> as I already explained.
> 
> 
> > and
> > needs to be somewhere where it's done for _all_ testcases.
> 
> My code is not preventing that. In fact, I think it's helping us get
> to that point.
> 
> 
> > QA already has
> > that in their own testrunner infrastructure, unfortunately that's not
> > shared with developers so we get to invent a new wheel.
> 
> I just proposed these new wheels...

Ok, lazy me finally got around to just doing it. I've sent 2 patches to
the piglit mailing list which enable dmesg checking for igt runs by
default in less than 5 lines of code. For all tests, at the subtest
granularity.

Imo this simplicity a technical reason to do it in piglit ;-)

That leaves us with your use-case of very fine-grained checking of dmesg
errors within a testcase. tbh I'm not really sold on this being that
useful, but I'd be ok with merging the helper code if you convinced it's a
great idea. One thing though which could be improved is the cleanup - imo
it's much simpler to just have an atexit handler for such helpers.

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2013-11-11 21:10 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-11 17:06 [PATCH 1/2] drmtest: introduce kmsg_error functions Paulo Zanoni
2013-11-11 17:06 ` [PATCH 2/2] tests: add kms_edp_vdd_race Paulo Zanoni
2013-11-11 18:15   ` Daniel Vetter
2013-11-11 18:25     ` Paulo Zanoni
2013-11-11 18:41       ` Daniel Vetter
2013-11-11 18:54         ` Paulo Zanoni
2013-11-11 21:10           ` Daniel Vetter
2013-11-11 18:02 ` [PATCH 1/2] drmtest: introduce kmsg_error functions Daniel Vetter
2013-11-11 18:18   ` Paulo Zanoni
2013-11-11 18:48     ` Daniel Vetter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.