All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH i-g-t 0/7] igt: Add support for testing writeback connectors
@ 2017-07-06 16:14 Liviu Dudau
  2017-07-06 16:14 ` [PATCH i-g-t 1/7] igt: lib/igt_crc: Split out CRC functionality Liviu Dudau
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Liviu Dudau @ 2017-07-06 16:14 UTC (permalink / raw)
  To: Intel GFX discussion

We're trying to introduce support for writeback connectors, a way to
expose in DRM the hardware functionality from display engines that
allows to write back into memory the result of the DE's composition
of supported planes.

Generic DRM support is available here [1] and will be merged once
this patchset gets approved for inclusion into igt. VC4 support
for writeback is added here [2] and for mali-dp is added here [3].

[1] https://lists.freedesktop.org/archives/dri-devel/2017-May/141796.html
[2] https://lists.freedesktop.org/archives/dri-devel/2017-June/143337.html
[3] https://lists.freedesktop.org/archives/dri-devel/2017-May/141799.html

Many thanks,
Liviu

Brian Starkey (7):
  igt: lib/igt_crc: Split out CRC functionality
  lib/igt_kms: Add writeback support in lib/
  kms_writeback: Add initial writeback tests
  lib: Add function to hash a framebuffer
  kms_writeback: Add writeback-check-output
  lib/igt_kms: Add igt_output_clone_pipe for cloning
  kms_writeback: Add tests using a cloned output

 lib/Makefile.sources              |   2 +
 lib/igt_aux.c                     |   1 +
 lib/igt_chamelium.h               |   1 +
 lib/igt_crc.c                     | 563 ++++++++++++++++++++++++++++++++++++++
 lib/igt_crc.h                     | 125 +++++++++
 lib/igt_debugfs.c                 | 547 ------------------------------------
 lib/igt_debugfs.h                 |  81 ------
 lib/igt_fb.c                      |  65 +++++
 lib/igt_fb.h                      |   5 +
 lib/igt_kms.c                     | 172 +++++++++---
 lib/igt_kms.h                     |  26 ++
 tests/Makefile.sources            |   1 +
 tests/chamelium.c                 |   1 +
 tests/kms_atomic_transition.c     |   1 +
 tests/kms_ccs.c                   |   1 +
 tests/kms_chv_cursor_fail.c       |   1 +
 tests/kms_crtc_background_color.c |   1 +
 tests/kms_cursor_crc.c            |   1 +
 tests/kms_cursor_legacy.c         |   1 +
 tests/kms_draw_crc.c              |   1 +
 tests/kms_fbc_crc.c               |   1 +
 tests/kms_flip_tiling.c           |   1 +
 tests/kms_frontbuffer_tracking.c  |   1 +
 tests/kms_mmap_write_crc.c        |   1 +
 tests/kms_mmio_vs_cs_flip.c       |   1 +
 tests/kms_pipe_color.c            |   1 +
 tests/kms_pipe_crc_basic.c        |   1 +
 tests/kms_plane.c                 |   1 +
 tests/kms_plane_lowres.c          |   1 +
 tests/kms_plane_multiple.c        |   1 +
 tests/kms_plane_scaling.c         |   1 +
 tests/kms_pwrite_crc.c            |   1 +
 tests/kms_rotation_crc.c          |   1 +
 tests/kms_universal_plane.c       |   1 +
 tests/kms_writeback.c             | 541 ++++++++++++++++++++++++++++++++++++
 tools/intel_display_crc.c         |   1 +
 36 files changed, 1487 insertions(+), 666 deletions(-)
 create mode 100644 lib/igt_crc.c
 create mode 100644 lib/igt_crc.h
 create mode 100644 tests/kms_writeback.c

-- 
2.13.1

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

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

* [PATCH i-g-t 1/7] igt: lib/igt_crc: Split out CRC functionality
  2017-07-06 16:14 [PATCH i-g-t 0/7] igt: Add support for testing writeback connectors Liviu Dudau
@ 2017-07-06 16:14 ` Liviu Dudau
  2017-07-17 13:50   ` Arkadiusz Hiler
  2017-07-06 16:14 ` [PATCH i-g-t 2/7] lib/igt_kms: Add writeback support in lib/ Liviu Dudau
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Liviu Dudau @ 2017-07-06 16:14 UTC (permalink / raw)
  To: Intel GFX discussion

From: Brian Starkey <brian.starkey@arm.com>

Separate out the CRC code for better compartmentalisation. Should ease
the addition of more/different CRC sources in the future.

Signed-off-by: Brian Starkey <brian.starkey@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>

---
 lib/Makefile.sources              |   2 +
 lib/igt_chamelium.h               |   1 +
 lib/igt_crc.c                     | 563 ++++++++++++++++++++++++++++++++++++++
 lib/igt_crc.h                     | 125 +++++++++
 lib/igt_debugfs.c                 | 547 ------------------------------------
 lib/igt_debugfs.h                 |  81 ------
 tests/chamelium.c                 |   1 +
 tests/kms_atomic_transition.c     |   1 +
 tests/kms_ccs.c                   |   1 +
 tests/kms_chv_cursor_fail.c       |   1 +
 tests/kms_crtc_background_color.c |   1 +
 tests/kms_cursor_crc.c            |   1 +
 tests/kms_cursor_legacy.c         |   1 +
 tests/kms_draw_crc.c              |   1 +
 tests/kms_fbc_crc.c               |   1 +
 tests/kms_flip_tiling.c           |   1 +
 tests/kms_frontbuffer_tracking.c  |   1 +
 tests/kms_mmap_write_crc.c        |   1 +
 tests/kms_mmio_vs_cs_flip.c       |   1 +
 tests/kms_pipe_color.c            |   1 +
 tests/kms_pipe_crc_basic.c        |   1 +
 tests/kms_plane.c                 |   1 +
 tests/kms_plane_lowres.c          |   1 +
 tests/kms_plane_multiple.c        |   1 +
 tests/kms_plane_scaling.c         |   1 +
 tests/kms_pwrite_crc.c            |   1 +
 tests/kms_rotation_crc.c          |   1 +
 tests/kms_universal_plane.c       |   1 +
 tools/intel_display_crc.c         |   1 +
 29 files changed, 714 insertions(+), 628 deletions(-)
 create mode 100644 lib/igt_crc.c
 create mode 100644 lib/igt_crc.h

diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index 53fdb54c..cfba15c9 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -11,6 +11,8 @@ lib_source_list =	 	\
 	igt_debugfs.h		\
 	igt_aux.c		\
 	igt_aux.h		\
+	igt_crc.c		\
+	igt_crc.h		\
 	igt_edid_template.h	\
 	igt_gt.c		\
 	igt_gt.h		\
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 81322ad2..ea5abc2e 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -31,6 +31,7 @@
 #endif
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <stdbool.h>
 
 struct chamelium;
diff --git a/lib/igt_crc.c b/lib/igt_crc.c
new file mode 100644
index 00000000..91a0b5a8
--- /dev/null
+++ b/lib/igt_crc.c
@@ -0,0 +1,563 @@
+/*
+ * 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.
+ *
+ */
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "igt_aux.h"
+#include "igt_crc.h"
+#include "igt_core.h"
+#include "igt_debugfs.h"
+#include "igt_kms.h"
+
+/**
+ * igt_assert_crc_equal:
+ * @a: first pipe CRC value
+ * @b: second pipe CRC value
+ *
+ * Compares two CRC values and fails the testcase if they don't match with
+ * igt_fail(). Note that due to CRC collisions CRC based testcase can only
+ * assert that CRCs match, never that they are different. Otherwise there might
+ * be random testcase failures when different screen contents end up with the
+ * same CRC by chance.
+ */
+void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
+{
+	int i;
+
+	for (i = 0; i < a->n_words; i++)
+		igt_assert_eq_u32(a->crc[i], b->crc[i]);
+}
+
+/**
+ * igt_crc_to_string:
+ * @crc: pipe CRC value to print
+ *
+ * This formats @crc into a string buffer which is owned by igt_crc_to_string().
+ * The next call will override the buffer again, which makes this multithreading
+ * unsafe.
+ *
+ * This should only ever be used for diagnostic debug output.
+ */
+char *igt_crc_to_string(igt_crc_t *crc)
+{
+	int i;
+	char buf[128] = { 0 };
+
+	for (i = 0; i < crc->n_words; i++)
+		sprintf(buf + strlen(buf), "%08x ", crc->crc[i]);
+
+	return strdup(buf);
+}
+
+#define MAX_CRC_ENTRIES 10
+#define MAX_LINE_LEN (10 + 11 * MAX_CRC_ENTRIES + 1)
+
+/* (6 fields, 8 chars each, space separated (5) + '\n') */
+#define LEGACY_LINE_LEN       (6 * 8 + 5 + 1)
+
+struct _igt_pipe_crc {
+	int fd;
+	int dir;
+	int ctl_fd;
+	int crc_fd;
+	int flags;
+	bool is_legacy;
+
+	enum pipe pipe;
+	enum intel_pipe_crc_source source;
+};
+
+static const char *pipe_crc_sources[] = {
+	"none",
+	"plane1",
+	"plane2",
+	"pf",
+	"pipe",
+	"TV",
+	"DP-B",
+	"DP-C",
+	"DP-D",
+	"auto"
+};
+
+static const char *pipe_crc_source_name(enum intel_pipe_crc_source source)
+{
+        return pipe_crc_sources[source];
+}
+
+static bool igt_pipe_crc_do_start(igt_pipe_crc_t *pipe_crc)
+{
+	char buf[64];
+
+	/* Stop first just to make sure we don't have lingering state left. */
+	igt_pipe_crc_stop(pipe_crc);
+
+	if (pipe_crc->is_legacy)
+		sprintf(buf, "pipe %s %s", kmstest_pipe_name(pipe_crc->pipe),
+			pipe_crc_source_name(pipe_crc->source));
+	else
+		sprintf(buf, "%s", pipe_crc_source_name(pipe_crc->source));
+
+	igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), strlen(buf));
+
+	if (!pipe_crc->is_legacy) {
+		int err;
+
+		sprintf(buf, "crtc-%d/crc/data", pipe_crc->pipe);
+		err = 0;
+
+		pipe_crc->crc_fd = openat(pipe_crc->dir, buf, pipe_crc->flags);
+		if (pipe_crc->crc_fd < 0)
+			err = -errno;
+
+		if (err == -EINVAL)
+			return false;
+
+		igt_assert_eq(err, 0);
+	}
+
+	errno = 0;
+	return true;
+}
+
+static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe)
+{
+	char buf[32];
+
+	sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe));
+	igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf));
+}
+
+static void igt_pipe_crc_reset(int drm_fd)
+{
+	struct dirent *dirent;
+	const char *cmd = "none";
+	bool done = false;
+	DIR *dir;
+	int fdir;
+	int fd;
+
+	fdir = igt_debugfs_dir(drm_fd);
+	if (fdir < 0)
+		return;
+
+	dir = fdopendir(fdir);
+	if (!dir) {
+		close(fdir);
+		return;
+	}
+
+	while ((dirent = readdir(dir))) {
+		char buf[128];
+
+		if (strcmp(dirent->d_name, "crtc-") != 0)
+			continue;
+
+		sprintf(buf, "%s/crc/control", dirent->d_name);
+		fd = openat(fdir, buf, O_WRONLY);
+		if (fd < 0)
+			continue;
+
+		igt_assert_eq(write(fd, cmd, strlen(cmd)), strlen(cmd));
+		close(fd);
+
+		done = true;
+	}
+	closedir(dir);
+
+	if (!done) {
+		fd = openat(fdir, "i915_display_crtc_ctl", O_WRONLY);
+		if (fd != -1) {
+			igt_pipe_crc_pipe_off(fd, PIPE_A);
+			igt_pipe_crc_pipe_off(fd, PIPE_B);
+			igt_pipe_crc_pipe_off(fd, PIPE_C);
+
+			close(fd);
+		}
+	}
+
+	close(fdir);
+}
+
+static void pipe_crc_exit_handler(int sig)
+{
+	struct dirent *dirent;
+	char buf[128];
+	DIR *dir;
+	int fd;
+
+	dir = opendir("/dev/dri");
+	if (!dir)
+		return;
+
+	/*
+	 * Try to reset CRC capture for all DRM devices, this is only needed
+	 * for the legacy CRC ABI and can be completely removed once the
+	 * legacy codepaths are removed.
+	 */
+	while ((dirent = readdir(dir))) {
+		if (strncmp(dirent->d_name, "card", 4) != 0)
+			continue;
+
+		sprintf(buf, "/dev/dri/%s", dirent->d_name);
+		fd = open(buf, O_WRONLY);
+
+		igt_pipe_crc_reset(fd);
+
+		close(fd);
+	}
+	closedir(dir);
+}
+
+/**
+ * igt_require_pipe_crc:
+ *
+ * Convenience helper to check whether pipe CRC capturing is supported by the
+ * kernel. Uses igt_skip to automatically skip the test/subtest if this isn't
+ * the case.
+ */
+void igt_require_pipe_crc(int fd)
+{
+	const char *cmd = "pipe A none";
+	int ctl, written;
+
+	ctl = igt_debugfs_open(fd, "crtc-0/crc/control", O_RDONLY);
+	if (ctl < 0) {
+		ctl = igt_debugfs_open(fd, "i915_display_crc_ctl", O_WRONLY);
+		igt_require_f(ctl,
+			      "No display_crc_ctl found, kernel too old\n");
+
+		written = write(ctl, cmd, strlen(cmd));
+		igt_require_f(written < 0,
+			      "CRCs not supported on this platform\n");
+	}
+	close(ctl);
+}
+
+static igt_pipe_crc_t *
+pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source, int flags)
+{
+	igt_pipe_crc_t *pipe_crc;
+	char buf[128];
+	int debugfs;
+
+	debugfs = igt_debugfs_dir(fd);
+	igt_assert(debugfs != -1);
+
+	igt_install_exit_handler(pipe_crc_exit_handler);
+
+	pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc));
+
+	sprintf(buf, "crtc-%d/crc/control", pipe);
+	pipe_crc->ctl_fd = openat(debugfs, buf, O_WRONLY);
+	if (pipe_crc->ctl_fd == -1) {
+		pipe_crc->ctl_fd = openat(debugfs,
+					  "i915_display_crc_ctl", O_WRONLY);
+		igt_assert(pipe_crc->ctl_fd != -1);
+		pipe_crc->is_legacy = true;
+	}
+
+	if (pipe_crc->is_legacy) {
+		sprintf(buf, "i915_pipe_%s_crc", kmstest_pipe_name(pipe));
+		pipe_crc->crc_fd = openat(debugfs, buf, flags);
+		igt_assert(pipe_crc->crc_fd != -1);
+		igt_debug("Using legacy frame CRC ABI\n");
+	} else {
+		pipe_crc->crc_fd = -1;
+		igt_debug("Using generic frame CRC ABI\n");
+	}
+
+	pipe_crc->fd = fd;
+	pipe_crc->dir = debugfs;
+	pipe_crc->pipe = pipe;
+	pipe_crc->source = source;
+	pipe_crc->flags = flags;
+
+	return pipe_crc;
+}
+
+/**
+ * igt_pipe_crc_new:
+ * @pipe: display pipe to use as source
+ * @source: CRC tap point to use as source
+ *
+ * This sets up a new pipe CRC capture object for the given @pipe and @source
+ * in blocking mode.
+ *
+ * Returns: A pipe CRC object for the given @pipe and @source. The library
+ * assumes that the source is always available since recent kernels support at
+ * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
+ */
+igt_pipe_crc_t *
+igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
+{
+	return pipe_crc_new(fd, pipe, source, O_RDONLY);
+}
+
+/**
+ * igt_pipe_crc_new_nonblock:
+ * @pipe: display pipe to use as source
+ * @source: CRC tap point to use as source
+ *
+ * This sets up a new pipe CRC capture object for the given @pipe and @source
+ * in nonblocking mode.
+ *
+ * Returns: A pipe CRC object for the given @pipe and @source. The library
+ * assumes that the source is always available since recent kernels support at
+ * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
+ */
+igt_pipe_crc_t *
+igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
+{
+	return pipe_crc_new(fd, pipe, source, O_RDONLY | O_NONBLOCK);
+}
+
+/**
+ * igt_pipe_crc_free:
+ * @pipe_crc: pipe CRC object
+ *
+ * Frees all resources associated with @pipe_crc.
+ */
+void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc)
+{
+	if (!pipe_crc)
+		return;
+
+	close(pipe_crc->ctl_fd);
+	close(pipe_crc->crc_fd);
+	close(pipe_crc->dir);
+	free(pipe_crc);
+}
+
+static bool pipe_crc_init_from_string(igt_pipe_crc_t *pipe_crc, igt_crc_t *crc,
+				      const char *line)
+{
+	int n, i;
+	const char *buf;
+
+	if (pipe_crc->is_legacy) {
+		crc->has_valid_frame = true;
+		crc->n_words = 5;
+		n = sscanf(line, "%8u %8x %8x %8x %8x %8x", &crc->frame,
+			   &crc->crc[0], &crc->crc[1], &crc->crc[2],
+			   &crc->crc[3], &crc->crc[4]);
+		return n == 6;
+	}
+
+	if (strncmp(line, "XXXXXXXXXX", 10) == 0)
+		crc->has_valid_frame = false;
+	else {
+		crc->has_valid_frame = true;
+		crc->frame = strtoul(line, NULL, 16);
+	}
+
+	buf = line + 10;
+	for (i = 0; *buf != '\n'; i++, buf += 11)
+		crc->crc[i] = strtoul(buf, NULL, 16);
+
+	crc->n_words = i;
+
+	return true;
+}
+
+static int read_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
+{
+	ssize_t bytes_read;
+	char buf[MAX_LINE_LEN + 1];
+	size_t read_len;
+
+	if (pipe_crc->is_legacy)
+		read_len = LEGACY_LINE_LEN;
+	else
+		read_len = MAX_LINE_LEN;
+
+	igt_set_timeout(5, "CRC reading");
+	bytes_read = read(pipe_crc->crc_fd, &buf, read_len);
+	igt_reset_timeout();
+
+	if (bytes_read < 0 && errno == EAGAIN)
+		igt_assert(pipe_crc->flags & O_NONBLOCK);
+
+	if (bytes_read < 0)
+		bytes_read = 0;
+
+	buf[bytes_read] = '\0';
+
+	if (bytes_read && !pipe_crc_init_from_string(pipe_crc, out, buf))
+		return -EINVAL;
+
+	return bytes_read;
+}
+
+static void read_one_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
+{
+	while (read_crc(pipe_crc, out) == 0)
+		usleep(1000);
+}
+
+/**
+ * igt_pipe_crc_start:
+ * @pipe_crc: pipe CRC object
+ *
+ * Starts the CRC capture process on @pipe_crc.
+ */
+void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc)
+{
+	igt_crc_t crc;
+
+	igt_assert(igt_pipe_crc_do_start(pipe_crc));
+
+	if (pipe_crc->is_legacy) {
+		/*
+		 * For some no yet identified reason, the first CRC is
+		 * bonkers. So let's just wait for the next vblank and read
+		 * out the buggy result.
+		 *
+		 * On CHV sometimes the second CRC is bonkers as well, so
+		 * don't trust that one either.
+		 */
+		read_one_crc(pipe_crc, &crc);
+		read_one_crc(pipe_crc, &crc);
+	}
+}
+
+/**
+ * igt_pipe_crc_stop:
+ * @pipe_crc: pipe CRC object
+ *
+ * Stops the CRC capture process on @pipe_crc.
+ */
+void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc)
+{
+	char buf[32];
+
+	if (pipe_crc->is_legacy) {
+		sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe_crc->pipe));
+		igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)),
+			      strlen(buf));
+	} else {
+		close(pipe_crc->crc_fd);
+		pipe_crc->crc_fd = -1;
+	}
+}
+
+/**
+ * igt_pipe_crc_get_crcs:
+ * @pipe_crc: pipe CRC object
+ * @n_crcs: number of CRCs to capture
+ * @out_crcs: buffer pointer for the captured CRC values
+ *
+ * Read up to @n_crcs from @pipe_crc. This function does not block, and will
+ * return early if not enough CRCs can be captured, if @pipe_crc has been
+ * opened using igt_pipe_crc_new_nonblock(). It will block until @n_crcs are
+ * retrieved if @pipe_crc has been opened using igt_pipe_crc_new(). @out_crcs is
+ * alloced by this function and must be released with free() by the caller.
+ *
+ * Callers must start and stop the capturing themselves by calling
+ * igt_pipe_crc_start() and igt_pipe_crc_stop(). For one-shot CRC collecting
+ * look at igt_pipe_crc_collect_crc().
+ *
+ * Returns:
+ * The number of CRCs captured. Should be equal to @n_crcs in blocking mode, but
+ * can be less (even zero) in non-blocking mode.
+ */
+int
+igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
+		      igt_crc_t **out_crcs)
+{
+	igt_crc_t *crcs;
+	int n = 0;
+
+	crcs = calloc(n_crcs, sizeof(igt_crc_t));
+
+	do {
+		igt_crc_t *crc = &crcs[n];
+		int ret;
+
+		ret = read_crc(pipe_crc, crc);
+		if (ret < 0)
+			continue;
+		if (ret == 0)
+			break;
+
+		n++;
+	} while (n < n_crcs);
+
+	*out_crcs = crcs;
+	return n;
+}
+
+static void crc_sanity_checks(igt_crc_t *crc)
+{
+	int i;
+	bool all_zero = true;
+
+	for (i = 0; i < crc->n_words; i++) {
+		igt_warn_on_f(crc->crc[i] == 0xffffffff,
+			      "Suspicious CRC: it looks like the CRC "
+			      "read back was from a register in a powered "
+			      "down well\n");
+		if (crc->crc[i])
+			all_zero = false;
+	}
+
+	igt_warn_on_f(all_zero, "Suspicious CRC: All values are 0.\n");
+}
+
+/**
+ * igt_pipe_crc_collect_crc:
+ * @pipe_crc: pipe CRC object
+ * @out_crc: buffer for the captured CRC values
+ *
+ * Read a single CRC from @pipe_crc. This function blocks until the CRC is
+ * retrieved, irrespective of whether @pipe_crc has been opened with
+ * igt_pipe_crc_new() or igt_pipe_crc_new_nonblock().  @out_crc must be
+ * allocated by the caller.
+ *
+ * This function takes care of the pipe_crc book-keeping, it will start/stop
+ * the collection of the CRC.
+ *
+ * This function also calls the interactive debug with the "crc" domain, so you
+ * can make use of this feature to actually see the screen that is being CRC'd.
+ *
+ * For continuous CRC collection look at igt_pipe_crc_start(),
+ * igt_pipe_crc_get_crcs() and igt_pipe_crc_stop().
+ */
+void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc)
+{
+	igt_debug_wait_for_keypress("crc");
+
+	igt_pipe_crc_start(pipe_crc);
+	read_one_crc(pipe_crc, out_crc);
+	igt_pipe_crc_stop(pipe_crc);
+
+	crc_sanity_checks(out_crc);
+}
+
diff --git a/lib/igt_crc.h b/lib/igt_crc.h
new file mode 100644
index 00000000..b0623baf
--- /dev/null
+++ b/lib/igt_crc.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ *
+ * # Pipe CRC Support
+ *
+ * This library wraps up the kernel's support for capturing pipe CRCs into a
+ * neat and tidy package. For the detailed usage see all the functions which
+ * work on #igt_pipe_crc_t. This is supported on all platforms and outputs.
+ *
+ * Actually using pipe CRCs to write modeset tests is a bit tricky though, so
+ * there is no way to directly check a CRC: Both the details of the plane
+ * blending, color correction and other hardware and how exactly the CRC is
+ * computed at each tap point vary by hardware generation and are not disclosed.
+ *
+ * The only way to use #igt_crc_t CRCs therefore is to compare CRCs among each
+ * another either for equality or difference. Otherwise CRCs must be treated as
+ * completely opaque values. Note that not even CRCs from different pipes or tap
+ * points on the same platform can be compared. Hence only use
+ * igt_assert_crc_equal() to inspect CRC values captured by the same
+ * #igt_pipe_crc_t object.
+ */
+
+#ifndef __IGT_CRC_H__
+#define __IGT_CRC_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+enum pipe;
+
+/**
+ * igt_pipe_crc_t:
+ *
+ * Pipe CRC support structure. Needs to be allocated and set up with
+ * igt_pipe_crc_new() for a specific pipe and pipe CRC source value.
+ */
+typedef struct _igt_pipe_crc igt_pipe_crc_t;
+
+#define DRM_MAX_CRC_NR 10
+/**
+ * igt_crc_t:
+ * @frame: frame number of the capture CRC
+ * @n_words: internal field, don't access
+ * @crc: internal field, don't access
+ *
+ * Pipe CRC value. All other members than @frame are private and should not be
+ * inspected by testcases.
+ */
+typedef struct {
+	uint32_t frame;
+	bool has_valid_frame;
+	int n_words;
+	uint32_t crc[DRM_MAX_CRC_NR];
+} igt_crc_t;
+
+/**
+ * intel_pipe_crc_source:
+ * @INTEL_PIPE_CRC_SOURCE_NONE: No source
+ * @INTEL_PIPE_CRC_SOURCE_PLANE1: Plane 1
+ * @INTEL_PIPE_CRC_SOURCE_PLANE2: Plane 2
+ * @INTEL_PIPE_CRC_SOURCE_PF: Panel Filter
+ * @INTEL_PIPE_CRC_SOURCE_PIPE: Pipe
+ * @INTEL_PIPE_CRC_SOURCE_TV: TV
+ * @INTEL_PIPE_CRC_SOURCE_DP_B: DisplayPort B
+ * @INTEL_PIPE_CRC_SOURCE_DP_C: DisplayPort C
+ * @INTEL_PIPE_CRC_SOURCE_DP_D: DisplayPort D
+ * @INTEL_PIPE_CRC_SOURCE_AUTO: Automatic source selection
+ * @INTEL_PIPE_CRC_SOURCE_MAX: Number of available sources
+ *
+ * Enumeration of all supported pipe CRC sources. Not all platforms and all
+ * outputs support all of them. Generic tests should just use
+ * INTEL_PIPE_CRC_SOURCE_AUTO. It should always map to an end-of-pipe CRC
+ * suitable for checking planes, cursor, color correction and any other
+ * output-agnostic features.
+ */
+enum intel_pipe_crc_source {
+        INTEL_PIPE_CRC_SOURCE_NONE,
+        INTEL_PIPE_CRC_SOURCE_PLANE1,
+        INTEL_PIPE_CRC_SOURCE_PLANE2,
+        INTEL_PIPE_CRC_SOURCE_PF,
+        INTEL_PIPE_CRC_SOURCE_PIPE,
+        INTEL_PIPE_CRC_SOURCE_TV,
+        INTEL_PIPE_CRC_SOURCE_DP_B,
+        INTEL_PIPE_CRC_SOURCE_DP_C,
+        INTEL_PIPE_CRC_SOURCE_DP_D,
+        INTEL_PIPE_CRC_SOURCE_AUTO,
+        INTEL_PIPE_CRC_SOURCE_MAX,
+};
+
+void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
+char *igt_crc_to_string(igt_crc_t *crc);
+
+void igt_require_pipe_crc(int fd);
+igt_pipe_crc_t *
+igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
+igt_pipe_crc_t *
+igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
+void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc);
+void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc);
+void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc);
+__attribute__((warn_unused_result))
+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);
+
+#endif /* __IGT_CRC_H__ */
diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 80f25c61..e08b7ae8 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -51,24 +51,6 @@
  * basic functions to access debugfs files with e.g. igt_debugfs_open() it also
  * provides higher-level wrappers for some debugfs features.
  *
- * # Pipe CRC Support
- *
- * This library wraps up the kernel's support for capturing pipe CRCs into a
- * neat and tidy package. For the detailed usage see all the functions which
- * work on #igt_pipe_crc_t. This is supported on all platforms and outputs.
- *
- * Actually using pipe CRCs to write modeset tests is a bit tricky though, so
- * there is no way to directly check a CRC: Both the details of the plane
- * blending, color correction and other hardware and how exactly the CRC is
- * computed at each tap point vary by hardware generation and are not disclosed.
- *
- * The only way to use #igt_crc_t CRCs therefore is to compare CRCs among each
- * another either for equality or difference. Otherwise CRCs must be treated as
- * completely opaque values. Note that not even CRCs from different pipes or tap
- * points on the same platform can be compared. Hence only use
- * igt_assert_crc_equal() to inspect CRC values captured by the same
- * #igt_pipe_crc_t object.
- *
  * # Other debugfs interface wrappers
  *
  * This covers the miscellaneous debugfs interface wrappers:
@@ -277,235 +259,6 @@ bool igt_debugfs_search(int device, const char *filename, const char *substring)
 	return matched;
 }
 
-/*
- * Pipe CRC
- */
-
-/**
- * igt_assert_crc_equal:
- * @a: first pipe CRC value
- * @b: second pipe CRC value
- *
- * Compares two CRC values and fails the testcase if they don't match with
- * igt_fail(). Note that due to CRC collisions CRC based testcase can only
- * assert that CRCs match, never that they are different. Otherwise there might
- * be random testcase failures when different screen contents end up with the
- * same CRC by chance.
- */
-void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
-{
-	int i;
-
-	for (i = 0; i < a->n_words; i++)
-		igt_assert_eq_u32(a->crc[i], b->crc[i]);
-}
-
-/**
- * igt_crc_to_string:
- * @crc: pipe CRC value to print
- *
- * This formats @crc into a string buffer which is owned by igt_crc_to_string().
- * The next call will override the buffer again, which makes this multithreading
- * unsafe.
- *
- * This should only ever be used for diagnostic debug output.
- */
-char *igt_crc_to_string(igt_crc_t *crc)
-{
-	int i;
-	char buf[128] = { 0 };
-
-	for (i = 0; i < crc->n_words; i++)
-		sprintf(buf + strlen(buf), "%08x ", crc->crc[i]);
-
-	return strdup(buf);
-}
-
-#define MAX_CRC_ENTRIES 10
-#define MAX_LINE_LEN (10 + 11 * MAX_CRC_ENTRIES + 1)
-
-/* (6 fields, 8 chars each, space separated (5) + '\n') */
-#define LEGACY_LINE_LEN       (6 * 8 + 5 + 1)
-
-struct _igt_pipe_crc {
-	int fd;
-	int dir;
-	int ctl_fd;
-	int crc_fd;
-	int flags;
-	bool is_legacy;
-
-	enum pipe pipe;
-	enum intel_pipe_crc_source source;
-};
-
-static const char *pipe_crc_sources[] = {
-	"none",
-	"plane1",
-	"plane2",
-	"pf",
-	"pipe",
-	"TV",
-	"DP-B",
-	"DP-C",
-	"DP-D",
-	"auto"
-};
-
-static const char *pipe_crc_source_name(enum intel_pipe_crc_source source)
-{
-        return pipe_crc_sources[source];
-}
-
-static bool igt_pipe_crc_do_start(igt_pipe_crc_t *pipe_crc)
-{
-	char buf[64];
-
-	/* Stop first just to make sure we don't have lingering state left. */
-	igt_pipe_crc_stop(pipe_crc);
-
-	if (pipe_crc->is_legacy)
-		sprintf(buf, "pipe %s %s", kmstest_pipe_name(pipe_crc->pipe),
-			pipe_crc_source_name(pipe_crc->source));
-	else
-		sprintf(buf, "%s", pipe_crc_source_name(pipe_crc->source));
-
-	igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), strlen(buf));
-
-	if (!pipe_crc->is_legacy) {
-		int err;
-
-		sprintf(buf, "crtc-%d/crc/data", pipe_crc->pipe);
-		err = 0;
-
-		pipe_crc->crc_fd = openat(pipe_crc->dir, buf, pipe_crc->flags);
-		if (pipe_crc->crc_fd < 0)
-			err = -errno;
-
-		if (err == -EINVAL)
-			return false;
-
-		igt_assert_eq(err, 0);
-	}
-
-	errno = 0;
-	return true;
-}
-
-static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe)
-{
-	char buf[32];
-
-	sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe));
-	igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf));
-}
-
-static void igt_pipe_crc_reset(int drm_fd)
-{
-	struct dirent *dirent;
-	const char *cmd = "none";
-	bool done = false;
-	DIR *dir;
-	int fdir;
-	int fd;
-
-	fdir = igt_debugfs_dir(drm_fd);
-	if (fdir < 0)
-		return;
-
-	dir = fdopendir(fdir);
-	if (!dir) {
-		close(fdir);
-		return;
-	}
-
-	while ((dirent = readdir(dir))) {
-		char buf[128];
-
-		if (strcmp(dirent->d_name, "crtc-") != 0)
-			continue;
-
-		sprintf(buf, "%s/crc/control", dirent->d_name);
-		fd = openat(fdir, buf, O_WRONLY);
-		if (fd < 0)
-			continue;
-
-		igt_assert_eq(write(fd, cmd, strlen(cmd)), strlen(cmd));
-		close(fd);
-
-		done = true;
-	}
-	closedir(dir);
-
-	if (!done) {
-		fd = openat(fdir, "i915_display_crtc_ctl", O_WRONLY);
-		if (fd != -1) {
-			igt_pipe_crc_pipe_off(fd, PIPE_A);
-			igt_pipe_crc_pipe_off(fd, PIPE_B);
-			igt_pipe_crc_pipe_off(fd, PIPE_C);
-
-			close(fd);
-		}
-	}
-
-	close(fdir);
-}
-
-static void pipe_crc_exit_handler(int sig)
-{
-	struct dirent *dirent;
-	char buf[128];
-	DIR *dir;
-	int fd;
-
-	dir = opendir("/dev/dri");
-	if (!dir)
-		return;
-
-	/*
-	 * Try to reset CRC capture for all DRM devices, this is only needed
-	 * for the legacy CRC ABI and can be completely removed once the
-	 * legacy codepaths are removed.
-	 */
-	while ((dirent = readdir(dir))) {
-		if (strncmp(dirent->d_name, "card", 4) != 0)
-			continue;
-
-		sprintf(buf, "/dev/dri/%s", dirent->d_name);
-		fd = open(buf, O_WRONLY);
-
-		igt_pipe_crc_reset(fd);
-
-		close(fd);
-	}
-	closedir(dir);
-}
-
-/**
- * igt_require_pipe_crc:
- *
- * Convenience helper to check whether pipe CRC capturing is supported by the
- * kernel. Uses igt_skip to automatically skip the test/subtest if this isn't
- * the case.
- */
-void igt_require_pipe_crc(int fd)
-{
-	const char *cmd = "pipe A none";
-	int ctl, written;
-
-	ctl = igt_debugfs_open(fd, "crtc-0/crc/control", O_RDONLY);
-	if (ctl < 0) {
-		ctl = igt_debugfs_open(fd, "i915_display_crc_ctl", O_WRONLY);
-		igt_require_f(ctl,
-			      "No display_crc_ctl found, kernel too old\n");
-
-		written = write(ctl, cmd, strlen(cmd));
-		igt_require_f(written < 0,
-			      "CRCs not supported on this platform\n");
-	}
-	close(ctl);
-}
-
 static void igt_hpd_storm_exit_handler(int sig)
 {
 	int fd = drm_open_driver_master(DRIVER_INTEL);
@@ -627,306 +380,6 @@ void igt_require_hpd_storm_ctl(int drm_fd)
 	close(fd);
 }
 
-static igt_pipe_crc_t *
-pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source, int flags)
-{
-	igt_pipe_crc_t *pipe_crc;
-	char buf[128];
-	int debugfs;
-
-	debugfs = igt_debugfs_dir(fd);
-	igt_assert(debugfs != -1);
-
-	igt_install_exit_handler(pipe_crc_exit_handler);
-
-	pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc));
-
-	sprintf(buf, "crtc-%d/crc/control", pipe);
-	pipe_crc->ctl_fd = openat(debugfs, buf, O_WRONLY);
-	if (pipe_crc->ctl_fd == -1) {
-		pipe_crc->ctl_fd = openat(debugfs,
-					  "i915_display_crc_ctl", O_WRONLY);
-		igt_assert(pipe_crc->ctl_fd != -1);
-		pipe_crc->is_legacy = true;
-	}
-
-	if (pipe_crc->is_legacy) {
-		sprintf(buf, "i915_pipe_%s_crc", kmstest_pipe_name(pipe));
-		pipe_crc->crc_fd = openat(debugfs, buf, flags);
-		igt_assert(pipe_crc->crc_fd != -1);
-		igt_debug("Using legacy frame CRC ABI\n");
-	} else {
-		pipe_crc->crc_fd = -1;
-		igt_debug("Using generic frame CRC ABI\n");
-	}
-
-	pipe_crc->fd = fd;
-	pipe_crc->dir = debugfs;
-	pipe_crc->pipe = pipe;
-	pipe_crc->source = source;
-	pipe_crc->flags = flags;
-
-	return pipe_crc;
-}
-
-/**
- * igt_pipe_crc_new:
- * @pipe: display pipe to use as source
- * @source: CRC tap point to use as source
- *
- * This sets up a new pipe CRC capture object for the given @pipe and @source
- * in blocking mode.
- *
- * Returns: A pipe CRC object for the given @pipe and @source. The library
- * assumes that the source is always available since recent kernels support at
- * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
- */
-igt_pipe_crc_t *
-igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
-{
-	return pipe_crc_new(fd, pipe, source, O_RDONLY);
-}
-
-/**
- * igt_pipe_crc_new_nonblock:
- * @pipe: display pipe to use as source
- * @source: CRC tap point to use as source
- *
- * This sets up a new pipe CRC capture object for the given @pipe and @source
- * in nonblocking mode.
- *
- * Returns: A pipe CRC object for the given @pipe and @source. The library
- * assumes that the source is always available since recent kernels support at
- * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
- */
-igt_pipe_crc_t *
-igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
-{
-	return pipe_crc_new(fd, pipe, source, O_RDONLY | O_NONBLOCK);
-}
-
-/**
- * igt_pipe_crc_free:
- * @pipe_crc: pipe CRC object
- *
- * Frees all resources associated with @pipe_crc.
- */
-void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc)
-{
-	if (!pipe_crc)
-		return;
-
-	close(pipe_crc->ctl_fd);
-	close(pipe_crc->crc_fd);
-	close(pipe_crc->dir);
-	free(pipe_crc);
-}
-
-static bool pipe_crc_init_from_string(igt_pipe_crc_t *pipe_crc, igt_crc_t *crc,
-				      const char *line)
-{
-	int n, i;
-	const char *buf;
-
-	if (pipe_crc->is_legacy) {
-		crc->has_valid_frame = true;
-		crc->n_words = 5;
-		n = sscanf(line, "%8u %8x %8x %8x %8x %8x", &crc->frame,
-			   &crc->crc[0], &crc->crc[1], &crc->crc[2],
-			   &crc->crc[3], &crc->crc[4]);
-		return n == 6;
-	}
-
-	if (strncmp(line, "XXXXXXXXXX", 10) == 0)
-		crc->has_valid_frame = false;
-	else {
-		crc->has_valid_frame = true;
-		crc->frame = strtoul(line, NULL, 16);
-	}
-
-	buf = line + 10;
-	for (i = 0; *buf != '\n'; i++, buf += 11)
-		crc->crc[i] = strtoul(buf, NULL, 16);
-
-	crc->n_words = i;
-
-	return true;
-}
-
-static int read_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
-{
-	ssize_t bytes_read;
-	char buf[MAX_LINE_LEN + 1];
-	size_t read_len;
-
-	if (pipe_crc->is_legacy)
-		read_len = LEGACY_LINE_LEN;
-	else
-		read_len = MAX_LINE_LEN;
-
-	igt_set_timeout(5, "CRC reading");
-	bytes_read = read(pipe_crc->crc_fd, &buf, read_len);
-	igt_reset_timeout();
-
-	if (bytes_read < 0 && errno == EAGAIN)
-		igt_assert(pipe_crc->flags & O_NONBLOCK);
-
-	if (bytes_read < 0)
-		bytes_read = 0;
-
-	buf[bytes_read] = '\0';
-
-	if (bytes_read && !pipe_crc_init_from_string(pipe_crc, out, buf))
-		return -EINVAL;
-
-	return bytes_read;
-}
-
-static void read_one_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
-{
-	while (read_crc(pipe_crc, out) == 0)
-		usleep(1000);
-}
-
-/**
- * igt_pipe_crc_start:
- * @pipe_crc: pipe CRC object
- *
- * Starts the CRC capture process on @pipe_crc.
- */
-void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc)
-{
-	igt_crc_t crc;
-
-	igt_assert(igt_pipe_crc_do_start(pipe_crc));
-
-	if (pipe_crc->is_legacy) {
-		/*
-		 * For some no yet identified reason, the first CRC is
-		 * bonkers. So let's just wait for the next vblank and read
-		 * out the buggy result.
-		 *
-		 * On CHV sometimes the second CRC is bonkers as well, so
-		 * don't trust that one either.
-		 */
-		read_one_crc(pipe_crc, &crc);
-		read_one_crc(pipe_crc, &crc);
-	}
-}
-
-/**
- * igt_pipe_crc_stop:
- * @pipe_crc: pipe CRC object
- *
- * Stops the CRC capture process on @pipe_crc.
- */
-void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc)
-{
-	char buf[32];
-
-	if (pipe_crc->is_legacy) {
-		sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe_crc->pipe));
-		igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)),
-			      strlen(buf));
-	} else {
-		close(pipe_crc->crc_fd);
-		pipe_crc->crc_fd = -1;
-	}
-}
-
-/**
- * igt_pipe_crc_get_crcs:
- * @pipe_crc: pipe CRC object
- * @n_crcs: number of CRCs to capture
- * @out_crcs: buffer pointer for the captured CRC values
- *
- * Read up to @n_crcs from @pipe_crc. This function does not block, and will
- * return early if not enough CRCs can be captured, if @pipe_crc has been
- * opened using igt_pipe_crc_new_nonblock(). It will block until @n_crcs are
- * retrieved if @pipe_crc has been opened using igt_pipe_crc_new(). @out_crcs is
- * alloced by this function and must be released with free() by the caller.
- *
- * Callers must start and stop the capturing themselves by calling
- * igt_pipe_crc_start() and igt_pipe_crc_stop(). For one-shot CRC collecting
- * look at igt_pipe_crc_collect_crc().
- *
- * Returns:
- * The number of CRCs captured. Should be equal to @n_crcs in blocking mode, but
- * can be less (even zero) in non-blocking mode.
- */
-int
-igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
-		      igt_crc_t **out_crcs)
-{
-	igt_crc_t *crcs;
-	int n = 0;
-
-	crcs = calloc(n_crcs, sizeof(igt_crc_t));
-
-	do {
-		igt_crc_t *crc = &crcs[n];
-		int ret;
-
-		ret = read_crc(pipe_crc, crc);
-		if (ret < 0)
-			continue;
-		if (ret == 0)
-			break;
-
-		n++;
-	} while (n < n_crcs);
-
-	*out_crcs = crcs;
-	return n;
-}
-
-static void crc_sanity_checks(igt_crc_t *crc)
-{
-	int i;
-	bool all_zero = true;
-
-	for (i = 0; i < crc->n_words; i++) {
-		igt_warn_on_f(crc->crc[i] == 0xffffffff,
-			      "Suspicious CRC: it looks like the CRC "
-			      "read back was from a register in a powered "
-			      "down well\n");
-		if (crc->crc[i])
-			all_zero = false;
-	}
-
-	igt_warn_on_f(all_zero, "Suspicious CRC: All values are 0.\n");
-}
-
-/**
- * igt_pipe_crc_collect_crc:
- * @pipe_crc: pipe CRC object
- * @out_crc: buffer for the captured CRC values
- *
- * Read a single CRC from @pipe_crc. This function blocks until the CRC is
- * retrieved, irrespective of whether @pipe_crc has been opened with
- * igt_pipe_crc_new() or igt_pipe_crc_new_nonblock().  @out_crc must be
- * allocated by the caller.
- *
- * This function takes care of the pipe_crc book-keeping, it will start/stop
- * the collection of the CRC.
- *
- * This function also calls the interactive debug with the "crc" domain, so you
- * can make use of this feature to actually see the screen that is being CRC'd.
- *
- * For continuous CRC collection look at igt_pipe_crc_start(),
- * igt_pipe_crc_get_crcs() and igt_pipe_crc_stop().
- */
-void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc)
-{
-	igt_debug_wait_for_keypress("crc");
-
-	igt_pipe_crc_start(pipe_crc);
-	read_one_crc(pipe_crc, out_crc);
-	igt_pipe_crc_stop(pipe_crc);
-
-	crc_sanity_checks(out_crc);
-}
-
 /*
  * Drop caches
  */
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index 7b846a83..01a5ee07 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -29,8 +29,6 @@
 #include <stdint.h>
 #include <stdio.h>
 
-enum pipe;
-
 const char *igt_debugfs_mount(void);
 
 int igt_debugfs_dir(int device);
@@ -50,85 +48,6 @@ bool igt_debugfs_search(int fd, const char *filename, const char *substring);
 #define igt_debugfs_read(fd, filename, buf) \
 		__igt_debugfs_read(fd, (filename), (buf), sizeof(buf))
 
-/*
- * Pipe CRC
- */
-
-/**
- * igt_pipe_crc_t:
- *
- * Pipe CRC support structure. Needs to be allocated and set up with
- * igt_pipe_crc_new() for a specific pipe and pipe CRC source value.
- */
-typedef struct _igt_pipe_crc igt_pipe_crc_t;
-
-#define DRM_MAX_CRC_NR 10
-/**
- * igt_crc_t:
- * @frame: frame number of the capture CRC
- * @n_words: internal field, don't access
- * @crc: internal field, don't access
- *
- * Pipe CRC value. All other members than @frame are private and should not be
- * inspected by testcases.
- */
-typedef struct {
-	uint32_t frame;
-	bool has_valid_frame;
-	int n_words;
-	uint32_t crc[DRM_MAX_CRC_NR];
-} igt_crc_t;
-
-/**
- * intel_pipe_crc_source:
- * @INTEL_PIPE_CRC_SOURCE_NONE: No source
- * @INTEL_PIPE_CRC_SOURCE_PLANE1: Plane 1
- * @INTEL_PIPE_CRC_SOURCE_PLANE2: Plane 2
- * @INTEL_PIPE_CRC_SOURCE_PF: Panel Filter
- * @INTEL_PIPE_CRC_SOURCE_PIPE: Pipe
- * @INTEL_PIPE_CRC_SOURCE_TV: TV
- * @INTEL_PIPE_CRC_SOURCE_DP_B: DisplayPort B
- * @INTEL_PIPE_CRC_SOURCE_DP_C: DisplayPort C
- * @INTEL_PIPE_CRC_SOURCE_DP_D: DisplayPort D
- * @INTEL_PIPE_CRC_SOURCE_AUTO: Automatic source selection
- * @INTEL_PIPE_CRC_SOURCE_MAX: Number of available sources
- *
- * Enumeration of all supported pipe CRC sources. Not all platforms and all
- * outputs support all of them. Generic tests should just use
- * INTEL_PIPE_CRC_SOURCE_AUTO. It should always map to an end-of-pipe CRC
- * suitable for checking planes, cursor, color correction and any other
- * output-agnostic features.
- */
-enum intel_pipe_crc_source {
-        INTEL_PIPE_CRC_SOURCE_NONE,
-        INTEL_PIPE_CRC_SOURCE_PLANE1,
-        INTEL_PIPE_CRC_SOURCE_PLANE2,
-        INTEL_PIPE_CRC_SOURCE_PF,
-        INTEL_PIPE_CRC_SOURCE_PIPE,
-        INTEL_PIPE_CRC_SOURCE_TV,
-        INTEL_PIPE_CRC_SOURCE_DP_B,
-        INTEL_PIPE_CRC_SOURCE_DP_C,
-        INTEL_PIPE_CRC_SOURCE_DP_D,
-        INTEL_PIPE_CRC_SOURCE_AUTO,
-        INTEL_PIPE_CRC_SOURCE_MAX,
-};
-
-void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
-char *igt_crc_to_string(igt_crc_t *crc);
-
-void igt_require_pipe_crc(int fd);
-igt_pipe_crc_t *
-igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
-igt_pipe_crc_t *
-igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
-void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc);
-void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc);
-void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc);
-__attribute__((warn_unused_result))
-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(int fd, unsigned int threshold);
 void igt_hpd_storm_reset(int fd);
 bool igt_hpd_storm_detected(int fd);
diff --git a/tests/chamelium.c b/tests/chamelium.c
index b412c6a7..9b0424d1 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -26,6 +26,7 @@
 
 #include "config.h"
 #include "igt.h"
+#include "igt_crc.h"
 
 #include <fcntl.h>
 #include <string.h>
diff --git a/tests/kms_atomic_transition.c b/tests/kms_atomic_transition.c
index ba5cd4d6..37de838f 100644
--- a/tests/kms_atomic_transition.c
+++ b/tests/kms_atomic_transition.c
@@ -22,6 +22,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include "drmtest.h"
 #include "sw_sync.h"
 #include <errno.h>
diff --git a/tests/kms_ccs.c b/tests/kms_ccs.c
index 29d676af..66bd0f29 100644
--- a/tests/kms_ccs.c
+++ b/tests/kms_ccs.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 
 IGT_TEST_DESCRIPTION("Test render compression (RC), in which the main surface "
 		     "is complemented by a color control surface (CCS) that "
diff --git a/tests/kms_chv_cursor_fail.c b/tests/kms_chv_cursor_fail.c
index 3e74df11..b02958bd 100644
--- a/tests/kms_chv_cursor_fail.c
+++ b/tests/kms_chv_cursor_fail.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <errno.h>
 #include <limits.h>
 #include <stdbool.h>
diff --git a/tests/kms_crtc_background_color.c b/tests/kms_crtc_background_color.c
index e12e1634..3bcabcac 100644
--- a/tests/kms_crtc_background_color.c
+++ b/tests/kms_crtc_background_color.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <math.h>
 
 
diff --git a/tests/kms_cursor_crc.c b/tests/kms_cursor_crc.c
index 4c5e00c0..4693e9f4 100644
--- a/tests/kms_cursor_crc.c
+++ b/tests/kms_cursor_crc.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <errno.h>
 #include <limits.h>
 #include <stdbool.h>
diff --git a/tests/kms_cursor_legacy.c b/tests/kms_cursor_legacy.c
index 8180b043..505e3f9d 100644
--- a/tests/kms_cursor_legacy.c
+++ b/tests/kms_cursor_legacy.c
@@ -27,6 +27,7 @@
 #include <sys/poll.h>
 
 #include "igt.h"
+#include "igt_crc.h"
 #include "igt_rand.h"
 #include "igt_stats.h"
 
diff --git a/tests/kms_draw_crc.c b/tests/kms_draw_crc.c
index c57d3a35..8cb4e147 100644
--- a/tests/kms_draw_crc.c
+++ b/tests/kms_draw_crc.c
@@ -25,6 +25,7 @@
 /* This program tests whether the igt_draw library actually works. */
 
 #include "igt.h"
+#include "igt_crc.h"
 
 #define MAX_CONNECTORS 32
 
diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c
index 7964e052..10656b89 100644
--- a/tests/kms_fbc_crc.c
+++ b/tests/kms_fbc_crc.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
diff --git a/tests/kms_flip_tiling.c b/tests/kms_flip_tiling.c
index 5aae29a8..8e1a2fb4 100644
--- a/tests/kms_flip_tiling.c
+++ b/tests/kms_flip_tiling.c
@@ -25,6 +25,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
diff --git a/tests/kms_frontbuffer_tracking.c b/tests/kms_frontbuffer_tracking.c
index c24e4a81..4af5e006 100644
--- a/tests/kms_frontbuffer_tracking.c
+++ b/tests/kms_frontbuffer_tracking.c
@@ -25,6 +25,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include "igt_sysfs.h"
 #include <sys/types.h>
 #include <sys/stat.h>
diff --git a/tests/kms_mmap_write_crc.c b/tests/kms_mmap_write_crc.c
index e5f089f6..79efa792 100644
--- a/tests/kms_mmap_write_crc.c
+++ b/tests/kms_mmap_write_crc.c
@@ -31,6 +31,7 @@
 #include <string.h>
 
 #include "drmtest.h"
+#include "igt_crc.h"
 #include "igt_debugfs.h"
 #include "igt_kms.h"
 #include "intel_chipset.h"
diff --git a/tests/kms_mmio_vs_cs_flip.c b/tests/kms_mmio_vs_cs_flip.c
index fa947d9c..ee1d202a 100644
--- a/tests/kms_mmio_vs_cs_flip.c
+++ b/tests/kms_mmio_vs_cs_flip.c
@@ -22,6 +22,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
diff --git a/tests/kms_pipe_color.c b/tests/kms_pipe_color.c
index a3100fae..389fb3de 100644
--- a/tests/kms_pipe_color.c
+++ b/tests/kms_pipe_color.c
@@ -28,6 +28,7 @@
 #include "drm.h"
 #include "drmtest.h"
 #include "igt.h"
+#include "igt_crc.h"
 
 IGT_TEST_DESCRIPTION("Test Color Features at Pipe level");
 
diff --git a/tests/kms_pipe_crc_basic.c b/tests/kms_pipe_crc_basic.c
index 35adddba..38da3a42 100644
--- a/tests/kms_pipe_crc_basic.c
+++ b/tests/kms_pipe_crc_basic.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include "igt_sysfs.h"
 #include <errno.h>
 #include <stdbool.h>
diff --git a/tests/kms_plane.c b/tests/kms_plane.c
index 1d92a62b..2fa58e8f 100644
--- a/tests/kms_plane.c
+++ b/tests/kms_plane.c
@@ -25,6 +25,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
diff --git a/tests/kms_plane_lowres.c b/tests/kms_plane_lowres.c
index ee39759c..a4e37275 100644
--- a/tests/kms_plane_lowres.c
+++ b/tests/kms_plane_lowres.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include "drmtest.h"
 #include <errno.h>
 #include <stdbool.h>
diff --git a/tests/kms_plane_multiple.c b/tests/kms_plane_multiple.c
index f6c62235..1b60a067 100644
--- a/tests/kms_plane_multiple.c
+++ b/tests/kms_plane_multiple.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include "drmtest.h"
 #include <errno.h>
 #include <stdbool.h>
diff --git a/tests/kms_plane_scaling.c b/tests/kms_plane_scaling.c
index 1457894a..d554f27f 100644
--- a/tests/kms_plane_scaling.c
+++ b/tests/kms_plane_scaling.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <math.h>
 
 
diff --git a/tests/kms_pwrite_crc.c b/tests/kms_pwrite_crc.c
index ee895db6..f1e6f023 100644
--- a/tests/kms_pwrite_crc.c
+++ b/tests/kms_pwrite_crc.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <errno.h>
 #include <limits.h>
 #include <stdbool.h>
diff --git a/tests/kms_rotation_crc.c b/tests/kms_rotation_crc.c
index 83e37f12..fa361100 100644
--- a/tests/kms_rotation_crc.c
+++ b/tests/kms_rotation_crc.c
@@ -23,6 +23,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <math.h>
 
 #define MAX_FENCES 32
diff --git a/tests/kms_universal_plane.c b/tests/kms_universal_plane.c
index 31f07804..14300b7a 100644
--- a/tests/kms_universal_plane.c
+++ b/tests/kms_universal_plane.c
@@ -22,6 +22,7 @@
  */
 
 #include "igt.h"
+#include "igt_crc.h"
 #include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
diff --git a/tools/intel_display_crc.c b/tools/intel_display_crc.c
index d1b28ea7..104f432f 100644
--- a/tools/intel_display_crc.c
+++ b/tools/intel_display_crc.c
@@ -30,6 +30,7 @@
 #include <unistd.h>
 
 #include "igt_core.h"
+#include "igt_crc.h"
 #include "igt_debugfs.h"
 #include "igt_kms.h"
 
-- 
2.13.1

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

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

* [PATCH i-g-t 2/7] lib/igt_kms: Add writeback support in lib/
  2017-07-06 16:14 [PATCH i-g-t 0/7] igt: Add support for testing writeback connectors Liviu Dudau
  2017-07-06 16:14 ` [PATCH i-g-t 1/7] igt: lib/igt_crc: Split out CRC functionality Liviu Dudau
@ 2017-07-06 16:14 ` Liviu Dudau
  2017-07-06 16:14 ` [PATCH i-g-t 3/7] kms_writeback: Add initial writeback tests Liviu Dudau
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Liviu Dudau @ 2017-07-06 16:14 UTC (permalink / raw)
  To: Intel GFX discussion

From: Brian Starkey <brian.starkey@arm.com>

Add support in igt_kms for Writeback connectors, with the ability to
attach framebuffers and retrieve fences.

Signed-off-by: Brian Starkey <brian.starkey@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>

---
 lib/igt_aux.c |  1 +
 lib/igt_kms.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 lib/igt_kms.h | 16 +++++++++++++
 3 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index 882dba06..945c1248 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -1087,6 +1087,7 @@ static const struct type_name connector_type_names[] = {
 	{ DRM_MODE_CONNECTOR_eDP, "eDP" },
 	{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
 	{ DRM_MODE_CONNECTOR_DSI, "DSI" },
+	{ DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" },
 	{}
 };
 
diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index faf9df2f..c86a2a63 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -186,7 +186,10 @@ const char *igt_crtc_prop_names[IGT_NUM_CRTC_PROPS] = {
 
 const char *igt_connector_prop_names[IGT_NUM_CONNECTOR_PROPS] = {
 	"scaling mode",
-	"CRTC_ID"
+	"CRTC_ID",
+	"WRITEBACK_PIXEL_FORMATS",
+	"WRITEBACK_FB_ID",
+	"WRITEBACK_OUT_FENCE_PTR"
 };
 
 /*
@@ -1831,6 +1834,7 @@ void igt_display_init(igt_display_t *display, int drm_fd)
 		output->pending_crtc_idx_mask = 0;
 		output->id = resources->connectors[i];
 		output->display = display;
+		output->writeback_out_fence_fd = -1;
 
 		igt_output_refresh(output);
 
@@ -1898,6 +1902,42 @@ igt_output_t *igt_output_from_connector(igt_display_t *display,
 	return found;
 }
 
+void igt_output_set_writeback_fb(igt_output_t *output, struct igt_fb *fb)
+{
+	igt_display_t *display = output->display;
+	struct kmstest_connector_config *config = &output->config;
+
+	if (config->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
+		return;
+
+	LOG(display, "%s: output_set_writeback_fb(%d)\n", output->name,
+	    fb ? fb->fb_id : 0);
+
+	output->writeback_fb = fb;
+}
+
+static void igt_output_reset_writeback_out_fence(igt_output_t *output)
+{
+	if (output->writeback_out_fence_fd >= 0) {
+		close(output->writeback_out_fence_fd);
+		output->writeback_out_fence_fd = -1;
+	}
+}
+
+void igt_output_request_writeback_out_fence(igt_output_t *output)
+{
+	igt_output_reset_writeback_out_fence(output);
+	output->writeback_out_fence_requested = true;
+}
+
+int igt_output_get_last_writeback_out_fence(igt_output_t *output)
+{
+	int fd = output->writeback_out_fence_fd;
+	output->writeback_out_fence_fd = -1;
+
+	return fd;
+}
+
 static void igt_pipe_fini(igt_pipe_t *pipe)
 {
 	int i;
@@ -1918,6 +1958,8 @@ static void igt_pipe_fini(igt_pipe_t *pipe)
 static void igt_output_fini(igt_output_t *output)
 {
 	kmstest_free_connector_config(&output->config);
+	if (output->writeback_out_fence_fd >= 0)
+		close(output->writeback_out_fence_fd);
 	free(output->name);
 	output->name = NULL;
 }
@@ -2534,10 +2576,41 @@ static void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAto
 
 		igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_CRTC_ID, crtc_id);
 	}
+
+	if (output->writeback_fb) {
+		igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_WRITEBACK_FB_ID, output->writeback_fb->fb_id);
+		output->writeback_fb = NULL;
+	}
+
+	igt_output_reset_writeback_out_fence(output);
+	if (output->writeback_out_fence_requested) {
+		igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_WRITEBACK_OUT_FENCE_PTR,
+						  (uint64_t)(uintptr_t)&output->writeback_out_fence_fd);
+	}
+
 	/*
 	 *	TODO: Add all other connector level properties here
 	 */
+}
+
+static void handle_writeback_out_fences(igt_display_t *display, uint32_t flags, int ret)
+{
+	int i;
 
+	for (i = 0; i < display->n_outputs; i++) {
+		igt_output_t *output = &display->outputs[i];
+
+		if (!output->config.connector)
+			continue;
+
+		if (!output->writeback_out_fence_requested)
+			continue;
+
+		output->writeback_out_fence_requested = false;
+
+		if (ret || (flags & DRM_MODE_ATOMIC_TEST_ONLY))
+			igt_assert(output->writeback_out_fence_fd == -1);
+	}
 }
 
 /*
@@ -2586,6 +2659,7 @@ static int igt_atomic_commit(igt_display_t *display, uint32_t flags, void *user_
 	}
 
 	ret = drmModeAtomicCommit(display->drm_fd, req, flags, user_data);
+	handle_writeback_out_fences(display, flags, ret);
 	if (!ret) {
 
 		for_each_pipe(display, pipe) {
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
index 35428f3e..ce9a35ef 100644
--- a/lib/igt_kms.h
+++ b/lib/igt_kms.h
@@ -37,6 +37,10 @@
 #include "igt_fb.h"
 #include "ioctl_wrappers.h"
 
+#ifndef DRM_MODE_CONNECTOR_WRITEBACK
+#define DRM_MODE_CONNECTOR_WRITEBACK   18
+#endif
+
 /* Low-level helpers with kmstest_ prefix */
 
 /**
@@ -113,6 +117,9 @@ extern const char *igt_crtc_prop_names[];
 enum igt_atomic_connector_properties {
        IGT_CONNECTOR_SCALING_MODE = 0,
        IGT_CONNECTOR_CRTC_ID,
+       IGT_CONNECTOR_WRITEBACK_PIXEL_FORMATS,
+       IGT_CONNECTOR_WRITEBACK_FB_ID,
+       IGT_CONNECTOR_WRITEBACK_OUT_FENCE_PTR,
        IGT_NUM_CONNECTOR_PROPS
 };
 
@@ -363,6 +370,10 @@ typedef struct {
 	unsigned long pending_crtc_idx_mask;
 	bool use_override_mode;
 	drmModeModeInfo override_mode;
+
+	struct igt_fb *writeback_fb;
+	int32_t writeback_out_fence_fd;
+	bool writeback_out_fence_requested;
 } igt_output_t;
 
 struct igt_display {
@@ -392,10 +403,15 @@ drmModeModeInfo *igt_output_get_mode(igt_output_t *output);
 void igt_output_override_mode(igt_output_t *output, drmModeModeInfo *mode);
 void igt_output_set_pipe(igt_output_t *output, enum pipe pipe);
 void igt_output_set_scaling_mode(igt_output_t *output, uint64_t scaling_mode);
+
 igt_plane_t *igt_output_get_plane(igt_output_t *output, int plane_idx);
 igt_plane_t *igt_output_get_plane_type(igt_output_t *output, int plane_type);
 igt_output_t *igt_output_from_connector(igt_display_t *display,
     drmModeConnector *connector);
+void igt_output_set_writeback_fb(igt_output_t *output, struct igt_fb *fb);
+void igt_output_request_writeback_out_fence(igt_output_t *output);
+int igt_output_get_last_writeback_out_fence(igt_output_t *output);
+
 igt_plane_t *igt_pipe_get_plane_type(igt_pipe_t *pipe, int plane_type);
 bool igt_pipe_get_property(igt_pipe_t *pipe, const char *name,
 			   uint32_t *prop_id, uint64_t *value,
-- 
2.13.1

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

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

* [PATCH i-g-t 3/7] kms_writeback: Add initial writeback tests
  2017-07-06 16:14 [PATCH i-g-t 0/7] igt: Add support for testing writeback connectors Liviu Dudau
  2017-07-06 16:14 ` [PATCH i-g-t 1/7] igt: lib/igt_crc: Split out CRC functionality Liviu Dudau
  2017-07-06 16:14 ` [PATCH i-g-t 2/7] lib/igt_kms: Add writeback support in lib/ Liviu Dudau
@ 2017-07-06 16:14 ` Liviu Dudau
  2017-07-06 16:14 ` [PATCH i-g-t 4/7] lib: Add function to hash a framebuffer Liviu Dudau
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Liviu Dudau @ 2017-07-06 16:14 UTC (permalink / raw)
  To: Intel GFX discussion

From: Brian Starkey <brian.starkey@arm.com>

Add tests for the WRITEBACK_PIXEL_FORMATS, WRITEBACK_OUT_FENCE_PTR and
WRITEBACK_FB_ID properties on writeback connectors, ensuring their
behaviour is correct.

Signed-off-by: Brian Starkey <brian.starkey@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>

---
 lib/igt_kms.c          |   6 +-
 lib/igt_kms.h          |   7 +
 tests/Makefile.sources |   1 +
 tests/kms_writeback.c  | 371 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 382 insertions(+), 3 deletions(-)
 create mode 100644 tests/kms_writeback.c

diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index c86a2a63..de50d421 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -2133,7 +2133,7 @@ static uint32_t igt_plane_get_fb_gem_handle(igt_plane_t *plane)
 /*
  * Add position and fb changes of a plane to the atomic property set
  */
-static void
+void
 igt_atomic_prepare_plane_commit(igt_plane_t *plane, igt_pipe_t *pipe,
 	drmModeAtomicReq *req)
 {
@@ -2511,7 +2511,7 @@ igt_pipe_replace_blob(igt_pipe_t *pipe, uint64_t *blob, void *ptr, size_t length
 /*
  * Add crtc property changes to the atomic property set
  */
-static void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req)
+void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req)
 {
 	if (pipe_obj->background_changed)
 		igt_atomic_populate_crtc_req(req, pipe_obj, IGT_CRTC_BACKGROUND, pipe_obj->background);
@@ -2560,7 +2560,7 @@ static void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicRe
 /*
  * Add connector property changes to the atomic property set
  */
-static void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req)
+void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req)
 {
 
 	struct kmstest_connector_config *config = &output->config;
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
index ce9a35ef..ab8ec764 100644
--- a/lib/igt_kms.h
+++ b/lib/igt_kms.h
@@ -533,6 +533,8 @@ static inline bool igt_output_is_connected(igt_output_t *output)
 #define igt_atomic_populate_plane_req(req, plane, prop, value) \
 	igt_assert_lt(0, drmModeAtomicAddProperty(req, plane->drm_plane->plane_id,\
 						  plane->atomic_props_plane[prop], value))
+void igt_atomic_prepare_plane_commit(igt_plane_t *plane, igt_pipe_t *pipe,
+	drmModeAtomicReq *req);
 
 /**
  * igt_atomic_populate_crtc_req:
@@ -544,6 +546,9 @@ static inline bool igt_output_is_connected(igt_output_t *output)
 #define igt_atomic_populate_crtc_req(req, pipe, prop, value) \
 	igt_assert_lt(0, drmModeAtomicAddProperty(req, pipe->crtc_id,\
 						  pipe->atomic_props_crtc[prop], value))
+
+void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req);
+
 /**
  * igt_atomic_populate_connector_req:
  * @req: A pointer to drmModeAtomicReq
@@ -555,6 +560,8 @@ static inline bool igt_output_is_connected(igt_output_t *output)
 	igt_assert_lt(0, drmModeAtomicAddProperty(req, output->config.connector->connector_id,\
 						  output->config.atomic_props_connector[prop], value))
 
+void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req);
+
 void igt_enable_connectors(void);
 void igt_reset_connectors(void);
 
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 5b98a5a3..7318855d 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -213,6 +213,7 @@ TESTS_progs = \
 	kms_tv_load_detect \
 	kms_universal_plane \
 	kms_vblank \
+	kms_writeback \
 	meta_test \
 	perf \
 	pm_backlight \
diff --git a/tests/kms_writeback.c b/tests/kms_writeback.c
new file mode 100644
index 00000000..d2066482
--- /dev/null
+++ b/tests/kms_writeback.c
@@ -0,0 +1,371 @@
+/*
+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "igt.h"
+#include "igt_fb.h"
+
+/* We need to define these ourselves until we get an updated libdrm */
+#ifndef DRM_MODE_CONNECTOR_WRITEBACK
+#define DRM_MODE_CONNECTOR_WRITEBACK   18
+#endif
+
+static drmModePropertyBlobRes *get_writeback_formats_blob(igt_output_t *output)
+{
+	drmModePropertyBlobRes *blob = NULL;
+	uint64_t blob_id;
+	int ret;
+
+	ret = kmstest_get_property(output->display->drm_fd,
+				   output->config.connector->connector_id,
+				   DRM_MODE_OBJECT_CONNECTOR,
+				   igt_connector_prop_names[IGT_CONNECTOR_WRITEBACK_PIXEL_FORMATS],
+				   NULL, &blob_id, NULL);
+	if (ret)
+		blob = drmModeGetPropertyBlob(output->display->drm_fd, blob_id);
+
+	igt_assert(blob);
+
+	return blob;
+}
+
+static uint32_t pick_writeback_format(igt_output_t *output)
+{
+	drmModePropertyBlobRes *wb_formats_blob = get_writeback_formats_blob(output);
+	const uint32_t *wb_formats, *cairo_formats;
+	uint32_t format = 0;
+	int n_cairo_formats, n_wb_formats, i, j;
+
+	igt_get_all_cairo_formats(&cairo_formats, &n_cairo_formats);
+
+	wb_formats = wb_formats_blob->data;
+	n_wb_formats = wb_formats_blob->length / sizeof(*wb_formats);
+	for (i = 0; (i < n_wb_formats) && !format; i++) {
+		for (j = 0; j < n_cairo_formats; j++) {
+			if (wb_formats[i] == cairo_formats[j]) {
+				format = wb_formats[i];
+				break;
+			}
+		}
+	}
+
+	drmModeFreePropertyBlob(wb_formats_blob);
+
+	igt_assert(format);
+	return format;
+}
+
+static bool check_writeback_config(igt_display_t *display, igt_output_t *output)
+{
+	igt_fb_t input_fb, output_fb;
+	igt_plane_t *plane;
+	uint32_t writeback_format = pick_writeback_format(output);
+	uint64_t tiling = igt_fb_mod_to_tiling(0);
+	int width, height, ret;
+	drmModeModeInfo override_mode = {
+		.clock = 25175,
+		.hdisplay = 640,
+		.hsync_start = 656,
+		.hsync_end = 752,
+		.htotal = 800,
+		.hskew = 0,
+		.vdisplay = 480,
+		.vsync_start = 490,
+		.vsync_end = 492,
+		.vtotal = 525,
+		.vscan = 0,
+		.vrefresh = 60,
+		.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+		.name = {"640x480-60"},
+	};
+	igt_output_override_mode(output, &override_mode);
+
+	width = override_mode.hdisplay;
+	height = override_mode.vdisplay;
+
+	ret = igt_create_fb(display->drm_fd, width, height, DRM_FORMAT_XRGB8888,
+			    tiling, &input_fb);
+	igt_assert(ret >= 0);
+
+	ret = igt_create_fb(display->drm_fd, width, height, writeback_format,
+			    tiling, &output_fb);
+	igt_assert(ret >= 0);
+
+	plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+	igt_plane_set_fb(plane, &input_fb);
+	igt_output_set_writeback_fb(output, &output_fb);
+
+	ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
+					    DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	igt_plane_set_fb(plane, NULL);
+	igt_remove_fb(display->drm_fd, &input_fb);
+	igt_remove_fb(display->drm_fd, &output_fb);
+
+	return !ret;
+}
+
+static igt_output_t *kms_writeback_get_output(igt_display_t *display)
+{
+	int i;
+
+	for (i = 0; i < display->n_outputs; i++) {
+		igt_output_t *output = &display->outputs[i];
+		int j;
+
+		if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
+			continue;
+
+		kmstest_force_connector(display->drm_fd, output->config.connector, FORCE_CONNECTOR_ON);
+
+		for (j = 0; j < igt_display_get_n_pipes(display); j++) {
+			igt_output_set_pipe(output, j);
+
+			if (check_writeback_config(display, output)) {
+				igt_debug("Using connector %u:%s on pipe %d\n",
+					  output->config.connector->connector_id,
+					  output->name, j);
+				return output;
+			}
+		}
+
+		/* Restore any connectors we don't use, so we don't trip on them later */
+		kmstest_force_connector(display->drm_fd, output->config.connector, FORCE_CONNECTOR_UNSPECIFIED);
+	}
+
+	return NULL;
+}
+
+static void check_writeback_fb_id(igt_output_t *output)
+{
+	bool found;
+	uint64_t check_fb_id;
+
+	found = kmstest_get_property(output->display->drm_fd, output->id,
+				     DRM_MODE_OBJECT_CONNECTOR,
+				     igt_connector_prop_names[IGT_CONNECTOR_WRITEBACK_FB_ID],
+				     NULL, &check_fb_id, NULL);
+	igt_assert(found && (check_fb_id == 0));
+}
+
+static int do_writeback_test(igt_output_t *output, uint32_t flags,
+			      uint32_t fb_id, int32_t *out_fence_ptr,
+			      bool ptr_valid)
+{
+	int ret;
+	enum pipe pipe;
+	drmModeAtomicReq *req;
+	igt_display_t *display = output->display;
+	struct kmstest_connector_config *config = &output->config;
+
+	req = drmModeAtomicAlloc();
+	drmModeAtomicSetCursor(req, 0);
+
+	for_each_pipe(display, pipe) {
+		igt_pipe_t *pipe_obj = &display->pipes[pipe];
+		igt_plane_t *plane;
+
+		/*
+		 * Add CRTC Properties to the property set
+		 */
+		igt_atomic_prepare_crtc_commit(pipe_obj, req);
+
+		for_each_plane_on_pipe(display, pipe, plane) {
+			igt_atomic_prepare_plane_commit(plane, pipe_obj, req);
+		}
+	}
+
+	igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_CRTC_ID, config->crtc->crtc_id);
+	igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_WRITEBACK_FB_ID, fb_id);
+	igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_WRITEBACK_OUT_FENCE_PTR, (uint64_t)out_fence_ptr);
+
+	if (ptr_valid)
+		*out_fence_ptr = 0;
+
+	ret = drmModeAtomicCommit(display->drm_fd, req, flags, NULL);
+
+	if (ptr_valid && (ret || (flags & DRM_MODE_ATOMIC_TEST_ONLY)))
+		igt_assert(*out_fence_ptr == -1);
+
+	drmModeAtomicFree(req);
+
+	/* WRITEBACK_FB_ID must always read as zero */
+	check_writeback_fb_id(output);
+
+	return ret;
+}
+
+static void invalid_out_fence(igt_output_t *output, igt_fb_t *valid_fb, igt_fb_t *invalid_fb)
+{
+	int i, ret;
+	int32_t out_fence;
+	struct {
+		uint32_t fb_id;
+		bool ptr_valid;
+		int32_t *out_fence_ptr;
+	} invalid_tests[] = {
+		{
+			/* No output buffer, but the WRITEBACK_OUT_FENCE_PTR set. */
+			.fb_id = 0,
+			.ptr_valid = true,
+			.out_fence_ptr = &out_fence,
+		},
+		{
+			/* Invalid output buffer. */
+			.fb_id = invalid_fb->fb_id,
+			.ptr_valid = true,
+			.out_fence_ptr = &out_fence,
+		},
+		{
+			/* Invalid WRITEBACK_OUT_FENCE_PTR. */
+			.fb_id = valid_fb->fb_id,
+			.ptr_valid = false,
+			.out_fence_ptr = (int32_t *)0x8,
+		},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(invalid_tests); i++) {
+		ret = do_writeback_test(output, DRM_MODE_ATOMIC_ALLOW_MODESET,
+					invalid_tests[i].fb_id,
+					invalid_tests[i].out_fence_ptr,
+					invalid_tests[i].ptr_valid);
+		igt_assert(ret != 0);
+	}
+}
+
+static void writeback_fb_id(igt_output_t *output, igt_fb_t *valid_fb, igt_fb_t *invalid_fb)
+{
+
+	int ret;
+
+	/* Valid output buffer */
+	ret = do_writeback_test(output, DRM_MODE_ATOMIC_ALLOW_MODESET,
+				valid_fb->fb_id, NULL, false);
+	igt_assert(ret == 0);
+
+	/* Invalid object for WRITEBACK_FB_ID */
+	ret = do_writeback_test(output, DRM_MODE_ATOMIC_ALLOW_MODESET,
+				output->id, NULL, false);
+	igt_assert(ret == -EINVAL);
+
+	/* Zero WRITEBACK_FB_ID */
+	ret = do_writeback_test(output, DRM_MODE_ATOMIC_ALLOW_MODESET,
+				0, NULL, false);
+	igt_assert(ret == 0);
+}
+
+igt_main
+{
+	igt_display_t display;
+	igt_output_t *output;
+	igt_plane_t *plane;
+	igt_fb_t input_fb;
+	drmModeModeInfo mode;
+	int ret;
+
+	memset(&display, 0, sizeof(display));
+
+	igt_fixture {
+		display.drm_fd = drm_open_driver_master(DRIVER_ANY);
+		igt_assert_fd(display.drm_fd);
+
+		kmstest_set_vt_graphics_mode();
+
+		igt_display_init(&display, display.drm_fd);
+
+		igt_require(display.is_atomic);
+
+		output = kms_writeback_get_output(&display);
+		igt_require(output);
+
+		if (output->use_override_mode)
+			memcpy(&mode, &output->override_mode, sizeof(mode));
+		else
+			memcpy(&mode, &output->config.default_mode, sizeof(mode));
+
+		plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+		igt_require(plane);
+
+		ret = igt_create_fb(display.drm_fd, mode.hdisplay,
+				    mode.vdisplay,
+				    DRM_FORMAT_XRGB8888,
+				    igt_fb_mod_to_tiling(0),
+				    &input_fb);
+		igt_assert(ret >= 0);
+		igt_plane_set_fb(plane, &input_fb);
+	}
+
+	igt_subtest("writeback-pixel-formats") {
+		drmModePropertyBlobRes *formats_blob = get_writeback_formats_blob(output);
+		const char *valid_chars = "0123456 ABCGNRUXY";
+		unsigned int i;
+		char *c;
+
+		/*
+		 * We don't have a comprehensive list of formats, so just check
+		 * that the blob length is sensible and that it doesn't contain
+		 * any outlandish characters
+		 */
+		igt_assert(!(formats_blob->length % 4));
+		c = formats_blob->data;
+		for (i = 0; i < formats_blob->length; i++)
+			igt_assert_f(strchr(valid_chars, c[i]),
+				     "Unexpected character %c\n", c[i]);
+	}
+
+	igt_subtest("writeback-invalid-out-fence") {
+		igt_fb_t invalid_fb;
+		ret = igt_create_fb(display.drm_fd, mode.hdisplay / 2,
+				    mode.vdisplay / 2,
+				    DRM_FORMAT_XRGB8888,
+				    igt_fb_mod_to_tiling(0),
+				    &invalid_fb);
+		igt_require(ret > 0);
+
+		invalid_out_fence(output, &input_fb, &invalid_fb);
+
+		igt_remove_fb(display.drm_fd, &invalid_fb);
+	}
+
+	igt_subtest("writeback-fb-id") {
+		igt_fb_t output_fb;
+		ret = igt_create_fb(display.drm_fd, mode.hdisplay, mode.vdisplay,
+				    DRM_FORMAT_XRGB8888,
+				    igt_fb_mod_to_tiling(0),
+				    &output_fb);
+		igt_require(ret > 0);
+
+		writeback_fb_id(output, &input_fb, &output_fb);
+
+		igt_remove_fb(display.drm_fd, &output_fb);
+	}
+
+	igt_fixture {
+		igt_remove_fb(display.drm_fd, &input_fb);
+		igt_display_fini(&display);
+	}
+}
-- 
2.13.1

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

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

* [PATCH i-g-t 4/7] lib: Add function to hash a framebuffer
  2017-07-06 16:14 [PATCH i-g-t 0/7] igt: Add support for testing writeback connectors Liviu Dudau
                   ` (2 preceding siblings ...)
  2017-07-06 16:14 ` [PATCH i-g-t 3/7] kms_writeback: Add initial writeback tests Liviu Dudau
@ 2017-07-06 16:14 ` Liviu Dudau
  2017-07-06 16:14 ` [PATCH i-g-t 5/7] kms_writeback: Add writeback-check-output Liviu Dudau
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Liviu Dudau @ 2017-07-06 16:14 UTC (permalink / raw)
  To: Intel GFX discussion

From: Brian Starkey <brian.starkey@arm.com>

To use writeback buffers as a CRC source, we need to be able to hash
them. Implement a simple FVA-1a hashing routine for this purpose.

Doing a bytewise hash on the framebuffer directly can be very slow if
the memory is noncached. By making a copy of each line in the FB first
(which can take advantage of word-access speedup), we can do the hash
on a cached copy, which is much faster (10x speedup on my platform).

Signed-off-by: Brian Starkey <brian.starkey@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>

---
 lib/igt_fb.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_fb.h |  5 +++++
 2 files changed, 70 insertions(+)

diff --git a/lib/igt_fb.c b/lib/igt_fb.c
index d2b7e9e3..f613bb2e 100644
--- a/lib/igt_fb.c
+++ b/lib/igt_fb.c
@@ -1302,3 +1302,68 @@ void igt_get_all_cairo_formats(const uint32_t **formats, int *format_count)
 	*formats = drm_formats;
 	*format_count = n_formats;
 }
+
+/*
+ * This implements the FNV-1a hashing algorithm instead of CRC, for
+ * simplicity
+ * http://www.isthe.com/chongo/tech/comp/fnv/index.html
+ *
+ * hash = offset_basis
+ * for each octet_of_data to be hashed
+ *         hash = hash xor octet_of_data
+ *         hash = hash * FNV_prime
+ * return hash
+ *
+ * 32 bit offset_basis = 2166136261
+ * 32 bit FNV_prime = 224 + 28 + 0x93 = 16777619
+ */
+int igt_fb_get_crc(struct igt_fb *fb, igt_crc_t *crc)
+{
+#define FNV1a_OFFSET_BIAS 2166136261
+#define FNV1a_PRIME 16777619
+	uint32_t hash;
+	void *map;
+	char *ptr, *line = NULL;
+	int x, y, cpp = igt_drm_format_to_bpp(fb->drm_format) / 8;
+
+	if (fb->is_dumb)
+		map = kmstest_dumb_map_buffer(fb->fd, fb->gem_handle, fb->size,
+					      PROT_READ);
+	else
+		map = gem_mmap__gtt(fb->fd, fb->gem_handle, fb->size,
+				    PROT_READ);
+	ptr = map;
+
+	/*
+	 * Framebuffers are often uncached, which can make byte-wise accesses
+	 * very slow. We copy each line of the FB into a local buffer to speed
+	 * up the hashing.
+	 */
+	line = malloc(fb->stride);
+	if (!line) {
+		munmap(map, fb->size);
+		return -ENOMEM;
+	}
+
+	hash = FNV1a_OFFSET_BIAS;
+
+	for (y = 0; y < fb->height; y++, ptr += fb->stride) {
+
+		memcpy(line, ptr, fb->stride);
+
+		for (x = 0; x < fb->width * cpp; x++) {
+			hash ^= line[x];
+			hash *= FNV1a_PRIME;
+		}
+	}
+
+	crc->n_words = 1;
+	crc->crc[0] = hash;
+
+	free(line);
+	munmap(map, fb->size);
+
+	return 0;
+#undef FNV1a_OFFSET_BIAS
+#undef FNV1a_PRIME
+}
diff --git a/lib/igt_fb.h b/lib/igt_fb.h
index 4a680cef..04430e9d 100644
--- a/lib/igt_fb.h
+++ b/lib/igt_fb.h
@@ -43,6 +43,8 @@ typedef struct _cairo cairo_t;
 
 #include <i915_drm.h>
 
+#include "igt_crc.h"
+
 /**
  * igt_fb_t:
  * @fb_id: KMS ID of the framebuffer
@@ -156,5 +158,8 @@ uint32_t igt_drm_format_to_bpp(uint32_t drm_format);
 const char *igt_format_str(uint32_t drm_format);
 void igt_get_all_cairo_formats(const uint32_t **formats, int *format_count);
 
+/* Get a hash for a framebuffer */
+int igt_fb_get_crc(struct igt_fb *fb, igt_crc_t *crc);
+
 #endif /* __IGT_FB_H__ */
 
-- 
2.13.1

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

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

* [PATCH i-g-t 5/7] kms_writeback: Add writeback-check-output
  2017-07-06 16:14 [PATCH i-g-t 0/7] igt: Add support for testing writeback connectors Liviu Dudau
                   ` (3 preceding siblings ...)
  2017-07-06 16:14 ` [PATCH i-g-t 4/7] lib: Add function to hash a framebuffer Liviu Dudau
@ 2017-07-06 16:14 ` Liviu Dudau
  2017-07-06 16:14 ` [PATCH i-g-t 6/7] lib/igt_kms: Add igt_output_clone_pipe for cloning Liviu Dudau
  2017-07-06 16:14 ` [PATCH i-g-t 7/7] kms_writeback: Add tests using a cloned output Liviu Dudau
  6 siblings, 0 replies; 10+ messages in thread
From: Liviu Dudau @ 2017-07-06 16:14 UTC (permalink / raw)
  To: Intel GFX discussion

From: Brian Starkey <brian.starkey@arm.com>

Add a test which makes commits using the writeback connector, and
checks the output buffer hash to make sure it is/isn't written as
appropriate.

Signed-off-by: Brian Starkey <brian.starkey@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>

---
 tests/kms_writeback.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 123 insertions(+)

diff --git a/tests/kms_writeback.c b/tests/kms_writeback.c
index d2066482..8201a81c 100644
--- a/tests/kms_writeback.c
+++ b/tests/kms_writeback.c
@@ -29,6 +29,7 @@
 
 #include "igt.h"
 #include "igt_fb.h"
+#include "sw_sync.h"
 
 /* We need to define these ourselves until we get an updated libdrm */
 #ifndef DRM_MODE_CONNECTOR_WRITEBACK
@@ -278,6 +279,115 @@ static void writeback_fb_id(igt_output_t *output, igt_fb_t *valid_fb, igt_fb_t *
 	igt_assert(ret == 0);
 }
 
+static void fill_fb(igt_fb_t *fb, double color[3])
+{
+	cairo_t *cr = igt_get_cairo_ctx(fb->fd, fb);
+	igt_assert(cr);
+
+	igt_paint_color(cr, 0, 0, fb->width, fb->height,
+			color[0], color[1], color[2]);
+}
+
+static void get_and_wait_out_fence(igt_output_t *output)
+{
+	int ret, out_fence = out_fence = igt_output_get_last_writeback_out_fence(output);
+	igt_assert(out_fence >= 0);
+
+	ret = sync_fence_wait(out_fence, 1000);
+	igt_assert(ret == 0);
+	close(out_fence);
+}
+
+static void writeback_seqence(igt_output_t *output, igt_plane_t *plane,
+			      igt_fb_t *in_fb, igt_fb_t *out_fbs[], int n_commits)
+{
+	int i, color_idx = 0;
+	double in_fb_colors[2][3] = {
+		{ 1.0, 0.0, 0.0 },
+		{ 0.0, 1.0, 0.0 },
+	};
+	double clear_color[3] = { 1.0, 1.0, 1.0 };
+	igt_crc_t cleared_crc, out_expected;
+
+	for (i = 0; i < n_commits; i++, color_idx++) {
+		/* Change the input color each time */
+		fill_fb(in_fb, in_fb_colors[color_idx % 2]);
+
+		if (out_fbs[i]) {
+			igt_crc_t out_before;
+
+			/* Get the expected CRC */
+			fill_fb(out_fbs[i], in_fb_colors[color_idx % 2]);
+			igt_fb_get_crc(out_fbs[i], &out_expected);
+
+			fill_fb(out_fbs[i], clear_color);
+			if (i == 0)
+				igt_fb_get_crc(out_fbs[i], &cleared_crc);
+			igt_fb_get_crc(out_fbs[i], &out_before);
+			igt_assert_crc_equal(&cleared_crc, &out_before);
+		}
+
+		/* Commit */
+		igt_plane_set_fb(plane, in_fb);
+		igt_output_set_writeback_fb(output, out_fbs[i]);
+		if (out_fbs[i])
+			igt_output_request_writeback_out_fence(output);
+		igt_display_commit_atomic(output->display,
+					  DRM_MODE_ATOMIC_ALLOW_MODESET,
+					  NULL);
+		if (out_fbs[i])
+			get_and_wait_out_fence(output);
+
+		/* Make sure the old output buffer is untouched */
+		if (i > 0 && out_fbs[i - 1] && (out_fbs[i] != out_fbs[i - 1])) {
+			igt_crc_t out_prev;
+			igt_fb_get_crc(out_fbs[i - 1], &out_prev);
+			igt_assert_crc_equal(&cleared_crc, &out_prev);
+		}
+
+		/* Make sure this output buffer is written */
+		if (out_fbs[i]) {
+			igt_crc_t out_after;
+			igt_fb_get_crc(out_fbs[i], &out_after);
+			igt_assert_crc_equal(&out_expected, &out_after);
+
+			/* And clear it, for the next time */
+			fill_fb(out_fbs[i], clear_color);
+		}
+	}
+}
+
+static void writeback_check_output(igt_output_t *output, igt_plane_t *plane,
+				   igt_fb_t *input_fb, igt_fb_t *output_fb)
+{
+	igt_fb_t *out_fbs[2] = { 0 };
+	igt_fb_t second_out_fb;
+	int ret;
+
+	/* One commit, with a writeback. */
+	writeback_seqence(output, plane, input_fb, &output_fb, 1);
+
+	/* Two commits, the second with no writeback */
+	out_fbs[0] = output_fb;
+	writeback_seqence(output, plane, input_fb, out_fbs, 2);
+
+	/* Two commits, both with writeback */
+	out_fbs[1] = output_fb;
+	writeback_seqence(output, plane, input_fb, out_fbs, 2);
+
+	ret = igt_create_fb(output_fb->fd, output_fb->width, output_fb->height,
+			    DRM_FORMAT_XRGB8888,
+			    igt_fb_mod_to_tiling(0),
+			    &second_out_fb);
+	igt_require(ret > 0);
+
+	/* Two commits, with different writeback buffers */
+	out_fbs[1] = &second_out_fb;
+	writeback_seqence(output, plane, input_fb, out_fbs, 2);
+
+	igt_remove_fb(output_fb->fd, &second_out_fb);
+}
+
 igt_main
 {
 	igt_display_t display;
@@ -364,6 +474,19 @@ igt_main
 		igt_remove_fb(display.drm_fd, &output_fb);
 	}
 
+	igt_subtest("writeback-check-output") {
+		igt_fb_t output_fb;
+		ret = igt_create_fb(display.drm_fd, mode.hdisplay, mode.vdisplay,
+				    DRM_FORMAT_XRGB8888,
+				    igt_fb_mod_to_tiling(0),
+				    &output_fb);
+		igt_require(ret > 0);
+
+		writeback_check_output(output, plane, &input_fb, &output_fb);
+
+		igt_remove_fb(display.drm_fd, &output_fb);
+	}
+
 	igt_fixture {
 		igt_remove_fb(display.drm_fd, &input_fb);
 		igt_display_fini(&display);
-- 
2.13.1

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

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

* [PATCH i-g-t 6/7] lib/igt_kms: Add igt_output_clone_pipe for cloning
  2017-07-06 16:14 [PATCH i-g-t 0/7] igt: Add support for testing writeback connectors Liviu Dudau
                   ` (4 preceding siblings ...)
  2017-07-06 16:14 ` [PATCH i-g-t 5/7] kms_writeback: Add writeback-check-output Liviu Dudau
@ 2017-07-06 16:14 ` Liviu Dudau
  2017-07-06 16:14 ` [PATCH i-g-t 7/7] kms_writeback: Add tests using a cloned output Liviu Dudau
  6 siblings, 0 replies; 10+ messages in thread
From: Liviu Dudau @ 2017-07-06 16:14 UTC (permalink / raw)
  To: Intel GFX discussion

From: Brian Starkey <brian.starkey@arm.com>

An output can be added as a clone of any other output(s) attached to a
pipe using igt_output_clone_pipe()

Signed-off-by: Brian Starkey <brian.starkey@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>

---
 lib/igt_kms.c | 90 +++++++++++++++++++++++++++++++++++++----------------------
 lib/igt_kms.h |  3 ++
 2 files changed, 59 insertions(+), 34 deletions(-)

diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index de50d421..57274591 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -1560,6 +1560,17 @@ static void igt_display_log_shift(igt_display_t *display, int shift)
 	igt_assert(display->log_shift >= 0);
 }
 
+static int igt_output_idx(igt_output_t *output)
+{
+	int i;
+
+	for (i = 0; i < output->display->n_outputs; i++)
+		if (&output->display->outputs[i] == output)
+			return i;
+
+	return -1;
+}
+
 static void igt_output_refresh(igt_output_t *output)
 {
 	igt_display_t *display = output->display;
@@ -1986,40 +1997,6 @@ void igt_display_fini(igt_display_t *display)
 	display->pipes = NULL;
 }
 
-static void igt_display_refresh(igt_display_t *display)
-{
-	igt_output_t *output;
-	int i;
-
-	unsigned long pipes_in_use = 0;
-
-       /* Check that two outputs aren't trying to use the same pipe */
-	for (i = 0; i < display->n_outputs; i++) {
-		output = &display->outputs[i];
-
-		if (pipes_in_use & output->pending_crtc_idx_mask)
-			goto report_dup;
-
-		pipes_in_use |= output->pending_crtc_idx_mask;
-
-		if (output->force_reprobe)
-			igt_output_refresh(output);
-	}
-
-	return;
-
-report_dup:
-	for (; i > 0; i--) {
-		igt_output_t *b = &display->outputs[i - 1];
-
-		igt_assert_f(output->pending_crtc_idx_mask !=
-			     b->pending_crtc_idx_mask,
-			     "%s and %s are both trying to use pipe %s\n",
-			     igt_output_name(output), igt_output_name(b),
-			     kmstest_pipe_name(ffs(b->pending_crtc_idx_mask) - 1));
-	}
-}
-
 static igt_pipe_t *igt_output_get_driving_pipe(igt_output_t *output)
 {
 	igt_display_t *display = output->display;
@@ -2043,6 +2020,38 @@ static igt_pipe_t *igt_output_get_driving_pipe(igt_output_t *output)
 	return &display->pipes[pipe];
 }
 
+static void igt_display_refresh(igt_display_t *display)
+{
+	igt_output_t *output;
+	igt_pipe_t *pipe;
+	int i;
+
+	unsigned long pipes_in_use = 0;
+
+	/* Check that outputs and pipes agree wrt. cloning */
+	for (i = 0; i < display->n_outputs; i++) {
+		output = &display->outputs[i];
+
+		pipe = igt_output_get_driving_pipe(output);
+		if (pipe) {
+			igt_assert_f(pipe->outputs & (1 << igt_output_idx(output)),
+				     "Output %s not expected to be using pipe %s\n",
+				     igt_output_name(output),
+				     kmstest_pipe_name(pipe->pipe));
+
+			if (pipes_in_use & output->pending_crtc_idx_mask)
+				LOG(display, "Output %s clones pipe %s\n",
+				    igt_output_name(output),
+				    kmstest_pipe_name(pipe->pipe));
+		}
+
+		pipes_in_use |= output->pending_crtc_idx_mask;
+
+		if (output->force_reprobe)
+			igt_output_refresh(output);
+	}
+}
+
 static igt_plane_t *igt_pipe_get_plane(igt_pipe_t *pipe, int plane_idx)
 {
 	igt_assert_f(plane_idx >= 0 && plane_idx < pipe->n_planes,
@@ -2946,6 +2955,16 @@ void igt_output_override_mode(igt_output_t *output, drmModeModeInfo *mode)
 		pipe->mode_changed = true;
 }
 
+void igt_output_clone_pipe(igt_output_t *output, enum pipe pipe)
+{
+	igt_display_t *display = output->display;
+	uint32_t current_clones = display->pipes[pipe].outputs;
+
+	igt_output_set_pipe(output, pipe);
+
+	display->pipes[pipe].outputs |= current_clones;
+}
+
 void igt_output_set_pipe(igt_output_t *output, enum pipe pipe)
 {
 	igt_display_t *display = output->display;
@@ -2957,6 +2976,7 @@ void igt_output_set_pipe(igt_output_t *output, enum pipe pipe)
 		old_pipe = igt_output_get_driving_pipe(output);
 
 		old_pipe->mode_changed = true;
+		old_pipe->outputs &= ~(1 << igt_output_idx(output));
 	}
 
 	if (pipe == PIPE_NONE) {
@@ -2968,6 +2988,8 @@ void igt_output_set_pipe(igt_output_t *output, enum pipe pipe)
 		output->pending_crtc_idx_mask = 1 << pipe;
 
 		display->pipes[pipe].mode_changed = true;
+
+		display->pipes[pipe].outputs = (1 << igt_output_idx(output));
 	}
 
 	output->config.pipe_changed = true;
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
index ab8ec764..9ddcfade 100644
--- a/lib/igt_kms.h
+++ b/lib/igt_kms.h
@@ -358,6 +358,8 @@ struct igt_pipe {
 
 	int32_t out_fence_fd;
 	bool out_fence_requested;
+
+	uint32_t outputs;
 };
 
 typedef struct {
@@ -402,6 +404,7 @@ const char *igt_output_name(igt_output_t *output);
 drmModeModeInfo *igt_output_get_mode(igt_output_t *output);
 void igt_output_override_mode(igt_output_t *output, drmModeModeInfo *mode);
 void igt_output_set_pipe(igt_output_t *output, enum pipe pipe);
+void igt_output_clone_pipe(igt_output_t *output, enum pipe pipe);
 void igt_output_set_scaling_mode(igt_output_t *output, uint64_t scaling_mode);
 
 igt_plane_t *igt_output_get_plane(igt_output_t *output, int plane_idx);
-- 
2.13.1

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

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

* [PATCH i-g-t 7/7] kms_writeback: Add tests using a cloned output
  2017-07-06 16:14 [PATCH i-g-t 0/7] igt: Add support for testing writeback connectors Liviu Dudau
                   ` (5 preceding siblings ...)
  2017-07-06 16:14 ` [PATCH i-g-t 6/7] lib/igt_kms: Add igt_output_clone_pipe for cloning Liviu Dudau
@ 2017-07-06 16:14 ` Liviu Dudau
  6 siblings, 0 replies; 10+ messages in thread
From: Liviu Dudau @ 2017-07-06 16:14 UTC (permalink / raw)
  To: Intel GFX discussion

From: Brian Starkey <brian.starkey@arm.com>

Update the connector search to also optionally attempt to find a
non-writeback connector to clone to.

Add a subtest which is the same as writeback-check-output, but also
clones to the second connector.

Signed-off-by: Brian Starkey <brian.starkey@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>

---
 tests/kms_writeback.c | 63 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/tests/kms_writeback.c b/tests/kms_writeback.c
index 8201a81c..9a34bca0 100644
--- a/tests/kms_writeback.c
+++ b/tests/kms_writeback.c
@@ -81,7 +81,8 @@ static uint32_t pick_writeback_format(igt_output_t *output)
 	return format;
 }
 
-static bool check_writeback_config(igt_display_t *display, igt_output_t *output)
+static bool check_writeback_config(igt_display_t *display, igt_output_t *output,
+				   int pipe, igt_output_t **clone)
 {
 	igt_fb_t input_fb, output_fb;
 	igt_plane_t *plane;
@@ -123,6 +124,27 @@ static bool check_writeback_config(igt_display_t *display, igt_output_t *output)
 
 	ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
 					    DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+	if (!ret && clone) {
+		/* Try and find a clone */
+		int i, newret;
+		*clone = NULL;
+
+		for (i = 0; i < display->n_outputs; i++) {
+			igt_output_t *second_output = &display->outputs[i];
+			if (output != second_output &&
+			    igt_pipe_connector_valid(pipe, second_output)) {
+
+				igt_output_clone_pipe(second_output, pipe);
+				newret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
+								    DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+				igt_output_set_pipe(second_output, PIPE_NONE);
+				if (!newret) {
+					*clone = second_output;
+					break;
+				}
+			}
+		}
+	}
 	igt_plane_set_fb(plane, NULL);
 	igt_remove_fb(display->drm_fd, &input_fb);
 	igt_remove_fb(display->drm_fd, &output_fb);
@@ -130,7 +152,8 @@ static bool check_writeback_config(igt_display_t *display, igt_output_t *output)
 	return !ret;
 }
 
-static igt_output_t *kms_writeback_get_output(igt_display_t *display)
+static igt_output_t *kms_writeback_get_output(igt_display_t *display, enum pipe *pipe,
+					      igt_output_t **clone)
 {
 	int i;
 
@@ -146,10 +169,16 @@ static igt_output_t *kms_writeback_get_output(igt_display_t *display)
 		for (j = 0; j < igt_display_get_n_pipes(display); j++) {
 			igt_output_set_pipe(output, j);
 
-			if (check_writeback_config(display, output)) {
+			if (check_writeback_config(display, output, j, clone)) {
 				igt_debug("Using connector %u:%s on pipe %d\n",
 					  output->config.connector->connector_id,
 					  output->name, j);
+				if (clone && *clone)
+					igt_debug("Cloning to connector %u:%s\n",
+						  (*clone)->config.connector->connector_id,
+						  (*clone)->name);
+				if (pipe)
+					*pipe = j;
 				return output;
 			}
 		}
@@ -190,9 +219,6 @@ static int do_writeback_test(igt_output_t *output, uint32_t flags,
 		igt_pipe_t *pipe_obj = &display->pipes[pipe];
 		igt_plane_t *plane;
 
-		/*
-		 * Add CRTC Properties to the property set
-		 */
 		igt_atomic_prepare_crtc_commit(pipe_obj, req);
 
 		for_each_plane_on_pipe(display, pipe, plane) {
@@ -391,10 +417,11 @@ static void writeback_check_output(igt_output_t *output, igt_plane_t *plane,
 igt_main
 {
 	igt_display_t display;
-	igt_output_t *output;
+	igt_output_t *output, *clone;
 	igt_plane_t *plane;
 	igt_fb_t input_fb;
 	drmModeModeInfo mode;
+	enum pipe pipe;
 	int ret;
 
 	memset(&display, 0, sizeof(display));
@@ -409,7 +436,7 @@ igt_main
 
 		igt_require(display.is_atomic);
 
-		output = kms_writeback_get_output(&display);
+		output = kms_writeback_get_output(&display, &pipe, &clone);
 		igt_require(output);
 
 		if (output->use_override_mode)
@@ -487,6 +514,26 @@ igt_main
 		igt_remove_fb(display.drm_fd, &output_fb);
 	}
 
+	igt_subtest("writeback-check-output-clone") {
+		igt_fb_t output_fb;
+
+		igt_require(clone);
+
+		ret = igt_create_fb(display.drm_fd, mode.hdisplay, mode.vdisplay,
+				    DRM_FORMAT_XRGB8888,
+				    igt_fb_mod_to_tiling(0),
+				    &output_fb);
+		igt_require(ret > 0);
+
+		igt_output_clone_pipe(clone, pipe);
+
+		writeback_check_output(output, plane, &input_fb, &output_fb);
+
+		igt_output_set_pipe(clone, PIPE_NONE);
+
+		igt_remove_fb(display.drm_fd, &output_fb);
+	}
+
 	igt_fixture {
 		igt_remove_fb(display.drm_fd, &input_fb);
 		igt_display_fini(&display);
-- 
2.13.1

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

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

* Re: [PATCH i-g-t 1/7] igt: lib/igt_crc: Split out CRC functionality
  2017-07-06 16:14 ` [PATCH i-g-t 1/7] igt: lib/igt_crc: Split out CRC functionality Liviu Dudau
@ 2017-07-17 13:50   ` Arkadiusz Hiler
  2017-07-17 15:06     ` Liviu Dudau
  0 siblings, 1 reply; 10+ messages in thread
From: Arkadiusz Hiler @ 2017-07-17 13:50 UTC (permalink / raw)
  To: Liviu Dudau; +Cc: Intel GFX discussion

On Thu, Jul 06, 2017 at 05:14:18PM +0100, Liviu Dudau wrote:
> From: Brian Starkey <brian.starkey@arm.com>
> 
> Separate out the CRC code for better compartmentalisation. Should ease
> the addition of more/different CRC sources in the future.
> 
> Signed-off-by: Brian Starkey <brian.starkey@arm.com>
> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
> 
> ---
>  lib/Makefile.sources              |   2 +
>  lib/igt_chamelium.h               |   1 +
>  lib/igt_crc.c                     | 563 ++++++++++++++++++++++++++++++++++++++
>  lib/igt_crc.h                     | 125 +++++++++
>  lib/igt_debugfs.c                 | 547 ------------------------------------
>  lib/igt_debugfs.h                 |  81 ------
>  tests/chamelium.c                 |   1 +
>  tests/kms_atomic_transition.c     |   1 +
>  tests/kms_ccs.c                   |   1 +
>  tests/kms_chv_cursor_fail.c       |   1 +
>  tests/kms_crtc_background_color.c |   1 +
>  tests/kms_cursor_crc.c            |   1 +
>  tests/kms_cursor_legacy.c         |   1 +
>  tests/kms_draw_crc.c              |   1 +
>  tests/kms_fbc_crc.c               |   1 +
>  tests/kms_flip_tiling.c           |   1 +
>  tests/kms_frontbuffer_tracking.c  |   1 +
>  tests/kms_mmap_write_crc.c        |   1 +
>  tests/kms_mmio_vs_cs_flip.c       |   1 +
>  tests/kms_pipe_color.c            |   1 +
>  tests/kms_pipe_crc_basic.c        |   1 +
>  tests/kms_plane.c                 |   1 +
>  tests/kms_plane_lowres.c          |   1 +
>  tests/kms_plane_multiple.c        |   1 +
>  tests/kms_plane_scaling.c         |   1 +
>  tests/kms_pwrite_crc.c            |   1 +
>  tests/kms_rotation_crc.c          |   1 +
>  tests/kms_universal_plane.c       |   1 +
>  tools/intel_display_crc.c         |   1 +
>  29 files changed, 714 insertions(+), 628 deletions(-)
>  create mode 100644 lib/igt_crc.c
>  create mode 100644 lib/igt_crc.h
> 
> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> index 53fdb54c..cfba15c9 100644
> --- a/lib/Makefile.sources
> +++ b/lib/Makefile.sources
> @@ -11,6 +11,8 @@ lib_source_list =	 	\
>  	igt_debugfs.h		\
>  	igt_aux.c		\
>  	igt_aux.h		\
> +	igt_crc.c		\
> +	igt_crc.h		\
>  	igt_edid_template.h	\
>  	igt_gt.c		\
>  	igt_gt.h		\
> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> index 81322ad2..ea5abc2e 100644
> --- a/lib/igt_chamelium.h
> +++ b/lib/igt_chamelium.h
> @@ -31,6 +31,7 @@
>  #endif
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <stdbool.h>
>  
>  struct chamelium;
> diff --git a/lib/igt_crc.c b/lib/igt_crc.c
> new file mode 100644
> index 00000000..91a0b5a8
> --- /dev/null
> +++ b/lib/igt_crc.c
> @@ -0,0 +1,563 @@
> +/*
> + * 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.
> + *
> + */
> +#include <dirent.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +
> +#include "igt_aux.h"
> +#include "igt_crc.h"
> +#include "igt_core.h"
> +#include "igt_debugfs.h"
> +#include "igt_kms.h"
> +
> +/**
> + * igt_assert_crc_equal:
> + * @a: first pipe CRC value
> + * @b: second pipe CRC value
> + *
> + * Compares two CRC values and fails the testcase if they don't match with
> + * igt_fail(). Note that due to CRC collisions CRC based testcase can only
> + * assert that CRCs match, never that they are different. Otherwise there might
> + * be random testcase failures when different screen contents end up with the
> + * same CRC by chance.
> + */
> +void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
> +{
> +	int i;
> +
> +	for (i = 0; i < a->n_words; i++)
> +		igt_assert_eq_u32(a->crc[i], b->crc[i]);
> +}
> +
> +/**
> + * igt_crc_to_string:
> + * @crc: pipe CRC value to print
> + *
> + * This formats @crc into a string buffer which is owned by igt_crc_to_string().
> + * The next call will override the buffer again, which makes this multithreading
> + * unsafe.
> + *
> + * This should only ever be used for diagnostic debug output.
> + */
> +char *igt_crc_to_string(igt_crc_t *crc)

Noticed that the doc is out of sync with how the function actually
works. Sending a patch to fix that.

Other than that LGTM.

-- 
Cheers,
Arek

> +{
> +	int i;
> +	char buf[128] = { 0 };
> +
> +	for (i = 0; i < crc->n_words; i++)
> +		sprintf(buf + strlen(buf), "%08x ", crc->crc[i]);
> +
> +	return strdup(buf);
> +}
> +
> +#define MAX_CRC_ENTRIES 10
> +#define MAX_LINE_LEN (10 + 11 * MAX_CRC_ENTRIES + 1)
> +
> +/* (6 fields, 8 chars each, space separated (5) + '\n') */
> +#define LEGACY_LINE_LEN       (6 * 8 + 5 + 1)
> +
> +struct _igt_pipe_crc {
> +	int fd;
> +	int dir;
> +	int ctl_fd;
> +	int crc_fd;
> +	int flags;
> +	bool is_legacy;
> +
> +	enum pipe pipe;
> +	enum intel_pipe_crc_source source;
> +};
> +
> +static const char *pipe_crc_sources[] = {
> +	"none",
> +	"plane1",
> +	"plane2",
> +	"pf",
> +	"pipe",
> +	"TV",
> +	"DP-B",
> +	"DP-C",
> +	"DP-D",
> +	"auto"
> +};
> +
> +static const char *pipe_crc_source_name(enum intel_pipe_crc_source source)
> +{
> +        return pipe_crc_sources[source];
> +}
> +
> +static bool igt_pipe_crc_do_start(igt_pipe_crc_t *pipe_crc)
> +{
> +	char buf[64];
> +
> +	/* Stop first just to make sure we don't have lingering state left. */
> +	igt_pipe_crc_stop(pipe_crc);
> +
> +	if (pipe_crc->is_legacy)
> +		sprintf(buf, "pipe %s %s", kmstest_pipe_name(pipe_crc->pipe),
> +			pipe_crc_source_name(pipe_crc->source));
> +	else
> +		sprintf(buf, "%s", pipe_crc_source_name(pipe_crc->source));
> +
> +	igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), strlen(buf));
> +
> +	if (!pipe_crc->is_legacy) {
> +		int err;
> +
> +		sprintf(buf, "crtc-%d/crc/data", pipe_crc->pipe);
> +		err = 0;
> +
> +		pipe_crc->crc_fd = openat(pipe_crc->dir, buf, pipe_crc->flags);
> +		if (pipe_crc->crc_fd < 0)
> +			err = -errno;
> +
> +		if (err == -EINVAL)
> +			return false;
> +
> +		igt_assert_eq(err, 0);
> +	}
> +
> +	errno = 0;
> +	return true;
> +}
> +
> +static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe)
> +{
> +	char buf[32];
> +
> +	sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe));
> +	igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf));
> +}
> +
> +static void igt_pipe_crc_reset(int drm_fd)
> +{
> +	struct dirent *dirent;
> +	const char *cmd = "none";
> +	bool done = false;
> +	DIR *dir;
> +	int fdir;
> +	int fd;
> +
> +	fdir = igt_debugfs_dir(drm_fd);
> +	if (fdir < 0)
> +		return;
> +
> +	dir = fdopendir(fdir);
> +	if (!dir) {
> +		close(fdir);
> +		return;
> +	}
> +
> +	while ((dirent = readdir(dir))) {
> +		char buf[128];
> +
> +		if (strcmp(dirent->d_name, "crtc-") != 0)
> +			continue;
> +
> +		sprintf(buf, "%s/crc/control", dirent->d_name);
> +		fd = openat(fdir, buf, O_WRONLY);
> +		if (fd < 0)
> +			continue;
> +
> +		igt_assert_eq(write(fd, cmd, strlen(cmd)), strlen(cmd));
> +		close(fd);
> +
> +		done = true;
> +	}
> +	closedir(dir);
> +
> +	if (!done) {
> +		fd = openat(fdir, "i915_display_crtc_ctl", O_WRONLY);
> +		if (fd != -1) {
> +			igt_pipe_crc_pipe_off(fd, PIPE_A);
> +			igt_pipe_crc_pipe_off(fd, PIPE_B);
> +			igt_pipe_crc_pipe_off(fd, PIPE_C);
> +
> +			close(fd);
> +		}
> +	}
> +
> +	close(fdir);
> +}
> +
> +static void pipe_crc_exit_handler(int sig)
> +{
> +	struct dirent *dirent;
> +	char buf[128];
> +	DIR *dir;
> +	int fd;
> +
> +	dir = opendir("/dev/dri");
> +	if (!dir)
> +		return;
> +
> +	/*
> +	 * Try to reset CRC capture for all DRM devices, this is only needed
> +	 * for the legacy CRC ABI and can be completely removed once the
> +	 * legacy codepaths are removed.
> +	 */
> +	while ((dirent = readdir(dir))) {
> +		if (strncmp(dirent->d_name, "card", 4) != 0)
> +			continue;
> +
> +		sprintf(buf, "/dev/dri/%s", dirent->d_name);
> +		fd = open(buf, O_WRONLY);
> +
> +		igt_pipe_crc_reset(fd);
> +
> +		close(fd);
> +	}
> +	closedir(dir);
> +}
> +
> +/**
> + * igt_require_pipe_crc:
> + *
> + * Convenience helper to check whether pipe CRC capturing is supported by the
> + * kernel. Uses igt_skip to automatically skip the test/subtest if this isn't
> + * the case.
> + */
> +void igt_require_pipe_crc(int fd)
> +{
> +	const char *cmd = "pipe A none";
> +	int ctl, written;
> +
> +	ctl = igt_debugfs_open(fd, "crtc-0/crc/control", O_RDONLY);
> +	if (ctl < 0) {
> +		ctl = igt_debugfs_open(fd, "i915_display_crc_ctl", O_WRONLY);
> +		igt_require_f(ctl,
> +			      "No display_crc_ctl found, kernel too old\n");
> +
> +		written = write(ctl, cmd, strlen(cmd));
> +		igt_require_f(written < 0,
> +			      "CRCs not supported on this platform\n");
> +	}
> +	close(ctl);
> +}
> +
> +static igt_pipe_crc_t *
> +pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source, int flags)
> +{
> +	igt_pipe_crc_t *pipe_crc;
> +	char buf[128];
> +	int debugfs;
> +
> +	debugfs = igt_debugfs_dir(fd);
> +	igt_assert(debugfs != -1);
> +
> +	igt_install_exit_handler(pipe_crc_exit_handler);
> +
> +	pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc));
> +
> +	sprintf(buf, "crtc-%d/crc/control", pipe);
> +	pipe_crc->ctl_fd = openat(debugfs, buf, O_WRONLY);
> +	if (pipe_crc->ctl_fd == -1) {
> +		pipe_crc->ctl_fd = openat(debugfs,
> +					  "i915_display_crc_ctl", O_WRONLY);
> +		igt_assert(pipe_crc->ctl_fd != -1);
> +		pipe_crc->is_legacy = true;
> +	}
> +
> +	if (pipe_crc->is_legacy) {
> +		sprintf(buf, "i915_pipe_%s_crc", kmstest_pipe_name(pipe));
> +		pipe_crc->crc_fd = openat(debugfs, buf, flags);
> +		igt_assert(pipe_crc->crc_fd != -1);
> +		igt_debug("Using legacy frame CRC ABI\n");
> +	} else {
> +		pipe_crc->crc_fd = -1;
> +		igt_debug("Using generic frame CRC ABI\n");
> +	}
> +
> +	pipe_crc->fd = fd;
> +	pipe_crc->dir = debugfs;
> +	pipe_crc->pipe = pipe;
> +	pipe_crc->source = source;
> +	pipe_crc->flags = flags;
> +
> +	return pipe_crc;
> +}
> +
> +/**
> + * igt_pipe_crc_new:
> + * @pipe: display pipe to use as source
> + * @source: CRC tap point to use as source
> + *
> + * This sets up a new pipe CRC capture object for the given @pipe and @source
> + * in blocking mode.
> + *
> + * Returns: A pipe CRC object for the given @pipe and @source. The library
> + * assumes that the source is always available since recent kernels support at
> + * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
> + */
> +igt_pipe_crc_t *
> +igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
> +{
> +	return pipe_crc_new(fd, pipe, source, O_RDONLY);
> +}
> +
> +/**
> + * igt_pipe_crc_new_nonblock:
> + * @pipe: display pipe to use as source
> + * @source: CRC tap point to use as source
> + *
> + * This sets up a new pipe CRC capture object for the given @pipe and @source
> + * in nonblocking mode.
> + *
> + * Returns: A pipe CRC object for the given @pipe and @source. The library
> + * assumes that the source is always available since recent kernels support at
> + * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
> + */
> +igt_pipe_crc_t *
> +igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
> +{
> +	return pipe_crc_new(fd, pipe, source, O_RDONLY | O_NONBLOCK);
> +}
> +
> +/**
> + * igt_pipe_crc_free:
> + * @pipe_crc: pipe CRC object
> + *
> + * Frees all resources associated with @pipe_crc.
> + */
> +void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc)
> +{
> +	if (!pipe_crc)
> +		return;
> +
> +	close(pipe_crc->ctl_fd);
> +	close(pipe_crc->crc_fd);
> +	close(pipe_crc->dir);
> +	free(pipe_crc);
> +}
> +
> +static bool pipe_crc_init_from_string(igt_pipe_crc_t *pipe_crc, igt_crc_t *crc,
> +				      const char *line)
> +{
> +	int n, i;
> +	const char *buf;
> +
> +	if (pipe_crc->is_legacy) {
> +		crc->has_valid_frame = true;
> +		crc->n_words = 5;
> +		n = sscanf(line, "%8u %8x %8x %8x %8x %8x", &crc->frame,
> +			   &crc->crc[0], &crc->crc[1], &crc->crc[2],
> +			   &crc->crc[3], &crc->crc[4]);
> +		return n == 6;
> +	}
> +
> +	if (strncmp(line, "XXXXXXXXXX", 10) == 0)
> +		crc->has_valid_frame = false;
> +	else {
> +		crc->has_valid_frame = true;
> +		crc->frame = strtoul(line, NULL, 16);
> +	}
> +
> +	buf = line + 10;
> +	for (i = 0; *buf != '\n'; i++, buf += 11)
> +		crc->crc[i] = strtoul(buf, NULL, 16);
> +
> +	crc->n_words = i;
> +
> +	return true;
> +}
> +
> +static int read_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
> +{
> +	ssize_t bytes_read;
> +	char buf[MAX_LINE_LEN + 1];
> +	size_t read_len;
> +
> +	if (pipe_crc->is_legacy)
> +		read_len = LEGACY_LINE_LEN;
> +	else
> +		read_len = MAX_LINE_LEN;
> +
> +	igt_set_timeout(5, "CRC reading");
> +	bytes_read = read(pipe_crc->crc_fd, &buf, read_len);
> +	igt_reset_timeout();
> +
> +	if (bytes_read < 0 && errno == EAGAIN)
> +		igt_assert(pipe_crc->flags & O_NONBLOCK);
> +
> +	if (bytes_read < 0)
> +		bytes_read = 0;
> +
> +	buf[bytes_read] = '\0';
> +
> +	if (bytes_read && !pipe_crc_init_from_string(pipe_crc, out, buf))
> +		return -EINVAL;
> +
> +	return bytes_read;
> +}
> +
> +static void read_one_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
> +{
> +	while (read_crc(pipe_crc, out) == 0)
> +		usleep(1000);
> +}
> +
> +/**
> + * igt_pipe_crc_start:
> + * @pipe_crc: pipe CRC object
> + *
> + * Starts the CRC capture process on @pipe_crc.
> + */
> +void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc)
> +{
> +	igt_crc_t crc;
> +
> +	igt_assert(igt_pipe_crc_do_start(pipe_crc));
> +
> +	if (pipe_crc->is_legacy) {
> +		/*
> +		 * For some no yet identified reason, the first CRC is
> +		 * bonkers. So let's just wait for the next vblank and read
> +		 * out the buggy result.
> +		 *
> +		 * On CHV sometimes the second CRC is bonkers as well, so
> +		 * don't trust that one either.
> +		 */
> +		read_one_crc(pipe_crc, &crc);
> +		read_one_crc(pipe_crc, &crc);
> +	}
> +}
> +
> +/**
> + * igt_pipe_crc_stop:
> + * @pipe_crc: pipe CRC object
> + *
> + * Stops the CRC capture process on @pipe_crc.
> + */
> +void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc)
> +{
> +	char buf[32];
> +
> +	if (pipe_crc->is_legacy) {
> +		sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe_crc->pipe));
> +		igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)),
> +			      strlen(buf));
> +	} else {
> +		close(pipe_crc->crc_fd);
> +		pipe_crc->crc_fd = -1;
> +	}
> +}
> +
> +/**
> + * igt_pipe_crc_get_crcs:
> + * @pipe_crc: pipe CRC object
> + * @n_crcs: number of CRCs to capture
> + * @out_crcs: buffer pointer for the captured CRC values
> + *
> + * Read up to @n_crcs from @pipe_crc. This function does not block, and will
> + * return early if not enough CRCs can be captured, if @pipe_crc has been
> + * opened using igt_pipe_crc_new_nonblock(). It will block until @n_crcs are
> + * retrieved if @pipe_crc has been opened using igt_pipe_crc_new(). @out_crcs is
> + * alloced by this function and must be released with free() by the caller.
> + *
> + * Callers must start and stop the capturing themselves by calling
> + * igt_pipe_crc_start() and igt_pipe_crc_stop(). For one-shot CRC collecting
> + * look at igt_pipe_crc_collect_crc().
> + *
> + * Returns:
> + * The number of CRCs captured. Should be equal to @n_crcs in blocking mode, but
> + * can be less (even zero) in non-blocking mode.
> + */
> +int
> +igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
> +		      igt_crc_t **out_crcs)
> +{
> +	igt_crc_t *crcs;
> +	int n = 0;
> +
> +	crcs = calloc(n_crcs, sizeof(igt_crc_t));
> +
> +	do {
> +		igt_crc_t *crc = &crcs[n];
> +		int ret;
> +
> +		ret = read_crc(pipe_crc, crc);
> +		if (ret < 0)
> +			continue;
> +		if (ret == 0)
> +			break;
> +
> +		n++;
> +	} while (n < n_crcs);
> +
> +	*out_crcs = crcs;
> +	return n;
> +}
> +
> +static void crc_sanity_checks(igt_crc_t *crc)
> +{
> +	int i;
> +	bool all_zero = true;
> +
> +	for (i = 0; i < crc->n_words; i++) {
> +		igt_warn_on_f(crc->crc[i] == 0xffffffff,
> +			      "Suspicious CRC: it looks like the CRC "
> +			      "read back was from a register in a powered "
> +			      "down well\n");
> +		if (crc->crc[i])
> +			all_zero = false;
> +	}
> +
> +	igt_warn_on_f(all_zero, "Suspicious CRC: All values are 0.\n");
> +}
> +
> +/**
> + * igt_pipe_crc_collect_crc:
> + * @pipe_crc: pipe CRC object
> + * @out_crc: buffer for the captured CRC values
> + *
> + * Read a single CRC from @pipe_crc. This function blocks until the CRC is
> + * retrieved, irrespective of whether @pipe_crc has been opened with
> + * igt_pipe_crc_new() or igt_pipe_crc_new_nonblock().  @out_crc must be
> + * allocated by the caller.
> + *
> + * This function takes care of the pipe_crc book-keeping, it will start/stop
> + * the collection of the CRC.
> + *
> + * This function also calls the interactive debug with the "crc" domain, so you
> + * can make use of this feature to actually see the screen that is being CRC'd.
> + *
> + * For continuous CRC collection look at igt_pipe_crc_start(),
> + * igt_pipe_crc_get_crcs() and igt_pipe_crc_stop().
> + */
> +void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc)
> +{
> +	igt_debug_wait_for_keypress("crc");
> +
> +	igt_pipe_crc_start(pipe_crc);
> +	read_one_crc(pipe_crc, out_crc);
> +	igt_pipe_crc_stop(pipe_crc);
> +
> +	crc_sanity_checks(out_crc);
> +}
> +
> diff --git a/lib/igt_crc.h b/lib/igt_crc.h
> new file mode 100644
> index 00000000..b0623baf
> --- /dev/null
> +++ b/lib/igt_crc.h
> @@ -0,0 +1,125 @@
> +/*
> + * 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.
> + *
> + * # Pipe CRC Support
> + *
> + * This library wraps up the kernel's support for capturing pipe CRCs into a
> + * neat and tidy package. For the detailed usage see all the functions which
> + * work on #igt_pipe_crc_t. This is supported on all platforms and outputs.
> + *
> + * Actually using pipe CRCs to write modeset tests is a bit tricky though, so
> + * there is no way to directly check a CRC: Both the details of the plane
> + * blending, color correction and other hardware and how exactly the CRC is
> + * computed at each tap point vary by hardware generation and are not disclosed.
> + *
> + * The only way to use #igt_crc_t CRCs therefore is to compare CRCs among each
> + * another either for equality or difference. Otherwise CRCs must be treated as
> + * completely opaque values. Note that not even CRCs from different pipes or tap
> + * points on the same platform can be compared. Hence only use
> + * igt_assert_crc_equal() to inspect CRC values captured by the same
> + * #igt_pipe_crc_t object.
> + */
> +
> +#ifndef __IGT_CRC_H__
> +#define __IGT_CRC_H__
> +
> +#include <stdbool.h>
> +#include <stdint.h>
> +
> +enum pipe;
> +
> +/**
> + * igt_pipe_crc_t:
> + *
> + * Pipe CRC support structure. Needs to be allocated and set up with
> + * igt_pipe_crc_new() for a specific pipe and pipe CRC source value.
> + */
> +typedef struct _igt_pipe_crc igt_pipe_crc_t;
> +
> +#define DRM_MAX_CRC_NR 10
> +/**
> + * igt_crc_t:
> + * @frame: frame number of the capture CRC
> + * @n_words: internal field, don't access
> + * @crc: internal field, don't access
> + *
> + * Pipe CRC value. All other members than @frame are private and should not be
> + * inspected by testcases.
> + */
> +typedef struct {
> +	uint32_t frame;
> +	bool has_valid_frame;
> +	int n_words;
> +	uint32_t crc[DRM_MAX_CRC_NR];
> +} igt_crc_t;
> +
> +/**
> + * intel_pipe_crc_source:
> + * @INTEL_PIPE_CRC_SOURCE_NONE: No source
> + * @INTEL_PIPE_CRC_SOURCE_PLANE1: Plane 1
> + * @INTEL_PIPE_CRC_SOURCE_PLANE2: Plane 2
> + * @INTEL_PIPE_CRC_SOURCE_PF: Panel Filter
> + * @INTEL_PIPE_CRC_SOURCE_PIPE: Pipe
> + * @INTEL_PIPE_CRC_SOURCE_TV: TV
> + * @INTEL_PIPE_CRC_SOURCE_DP_B: DisplayPort B
> + * @INTEL_PIPE_CRC_SOURCE_DP_C: DisplayPort C
> + * @INTEL_PIPE_CRC_SOURCE_DP_D: DisplayPort D
> + * @INTEL_PIPE_CRC_SOURCE_AUTO: Automatic source selection
> + * @INTEL_PIPE_CRC_SOURCE_MAX: Number of available sources
> + *
> + * Enumeration of all supported pipe CRC sources. Not all platforms and all
> + * outputs support all of them. Generic tests should just use
> + * INTEL_PIPE_CRC_SOURCE_AUTO. It should always map to an end-of-pipe CRC
> + * suitable for checking planes, cursor, color correction and any other
> + * output-agnostic features.
> + */
> +enum intel_pipe_crc_source {
> +        INTEL_PIPE_CRC_SOURCE_NONE,
> +        INTEL_PIPE_CRC_SOURCE_PLANE1,
> +        INTEL_PIPE_CRC_SOURCE_PLANE2,
> +        INTEL_PIPE_CRC_SOURCE_PF,
> +        INTEL_PIPE_CRC_SOURCE_PIPE,
> +        INTEL_PIPE_CRC_SOURCE_TV,
> +        INTEL_PIPE_CRC_SOURCE_DP_B,
> +        INTEL_PIPE_CRC_SOURCE_DP_C,
> +        INTEL_PIPE_CRC_SOURCE_DP_D,
> +        INTEL_PIPE_CRC_SOURCE_AUTO,
> +        INTEL_PIPE_CRC_SOURCE_MAX,
> +};
> +
> +void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
> +char *igt_crc_to_string(igt_crc_t *crc);
> +
> +void igt_require_pipe_crc(int fd);
> +igt_pipe_crc_t *
> +igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
> +igt_pipe_crc_t *
> +igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
> +void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc);
> +void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc);
> +void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc);
> +__attribute__((warn_unused_result))
> +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);
> +
> +#endif /* __IGT_CRC_H__ */
> diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
> index 80f25c61..e08b7ae8 100644
> --- a/lib/igt_debugfs.c
> +++ b/lib/igt_debugfs.c
> @@ -51,24 +51,6 @@
>   * basic functions to access debugfs files with e.g. igt_debugfs_open() it also
>   * provides higher-level wrappers for some debugfs features.
>   *
> - * # Pipe CRC Support
> - *
> - * This library wraps up the kernel's support for capturing pipe CRCs into a
> - * neat and tidy package. For the detailed usage see all the functions which
> - * work on #igt_pipe_crc_t. This is supported on all platforms and outputs.
> - *
> - * Actually using pipe CRCs to write modeset tests is a bit tricky though, so
> - * there is no way to directly check a CRC: Both the details of the plane
> - * blending, color correction and other hardware and how exactly the CRC is
> - * computed at each tap point vary by hardware generation and are not disclosed.
> - *
> - * The only way to use #igt_crc_t CRCs therefore is to compare CRCs among each
> - * another either for equality or difference. Otherwise CRCs must be treated as
> - * completely opaque values. Note that not even CRCs from different pipes or tap
> - * points on the same platform can be compared. Hence only use
> - * igt_assert_crc_equal() to inspect CRC values captured by the same
> - * #igt_pipe_crc_t object.
> - *
>   * # Other debugfs interface wrappers
>   *
>   * This covers the miscellaneous debugfs interface wrappers:
> @@ -277,235 +259,6 @@ bool igt_debugfs_search(int device, const char *filename, const char *substring)
>  	return matched;
>  }
>  
> -/*
> - * Pipe CRC
> - */
> -
> -/**
> - * igt_assert_crc_equal:
> - * @a: first pipe CRC value
> - * @b: second pipe CRC value
> - *
> - * Compares two CRC values and fails the testcase if they don't match with
> - * igt_fail(). Note that due to CRC collisions CRC based testcase can only
> - * assert that CRCs match, never that they are different. Otherwise there might
> - * be random testcase failures when different screen contents end up with the
> - * same CRC by chance.
> - */
> -void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
> -{
> -	int i;
> -
> -	for (i = 0; i < a->n_words; i++)
> -		igt_assert_eq_u32(a->crc[i], b->crc[i]);
> -}
> -
> -/**
> - * igt_crc_to_string:
> - * @crc: pipe CRC value to print
> - *
> - * This formats @crc into a string buffer which is owned by igt_crc_to_string().
> - * The next call will override the buffer again, which makes this multithreading
> - * unsafe.
> - *
> - * This should only ever be used for diagnostic debug output.
> - */
> -char *igt_crc_to_string(igt_crc_t *crc)
> -{
> -	int i;
> -	char buf[128] = { 0 };
> -
> -	for (i = 0; i < crc->n_words; i++)
> -		sprintf(buf + strlen(buf), "%08x ", crc->crc[i]);
> -
> -	return strdup(buf);
> -}
> -
> -#define MAX_CRC_ENTRIES 10
> -#define MAX_LINE_LEN (10 + 11 * MAX_CRC_ENTRIES + 1)
> -
> -/* (6 fields, 8 chars each, space separated (5) + '\n') */
> -#define LEGACY_LINE_LEN       (6 * 8 + 5 + 1)
> -
> -struct _igt_pipe_crc {
> -	int fd;
> -	int dir;
> -	int ctl_fd;
> -	int crc_fd;
> -	int flags;
> -	bool is_legacy;
> -
> -	enum pipe pipe;
> -	enum intel_pipe_crc_source source;
> -};
> -
> -static const char *pipe_crc_sources[] = {
> -	"none",
> -	"plane1",
> -	"plane2",
> -	"pf",
> -	"pipe",
> -	"TV",
> -	"DP-B",
> -	"DP-C",
> -	"DP-D",
> -	"auto"
> -};
> -
> -static const char *pipe_crc_source_name(enum intel_pipe_crc_source source)
> -{
> -        return pipe_crc_sources[source];
> -}
> -
> -static bool igt_pipe_crc_do_start(igt_pipe_crc_t *pipe_crc)
> -{
> -	char buf[64];
> -
> -	/* Stop first just to make sure we don't have lingering state left. */
> -	igt_pipe_crc_stop(pipe_crc);
> -
> -	if (pipe_crc->is_legacy)
> -		sprintf(buf, "pipe %s %s", kmstest_pipe_name(pipe_crc->pipe),
> -			pipe_crc_source_name(pipe_crc->source));
> -	else
> -		sprintf(buf, "%s", pipe_crc_source_name(pipe_crc->source));
> -
> -	igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), strlen(buf));
> -
> -	if (!pipe_crc->is_legacy) {
> -		int err;
> -
> -		sprintf(buf, "crtc-%d/crc/data", pipe_crc->pipe);
> -		err = 0;
> -
> -		pipe_crc->crc_fd = openat(pipe_crc->dir, buf, pipe_crc->flags);
> -		if (pipe_crc->crc_fd < 0)
> -			err = -errno;
> -
> -		if (err == -EINVAL)
> -			return false;
> -
> -		igt_assert_eq(err, 0);
> -	}
> -
> -	errno = 0;
> -	return true;
> -}
> -
> -static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe)
> -{
> -	char buf[32];
> -
> -	sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe));
> -	igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf));
> -}
> -
> -static void igt_pipe_crc_reset(int drm_fd)
> -{
> -	struct dirent *dirent;
> -	const char *cmd = "none";
> -	bool done = false;
> -	DIR *dir;
> -	int fdir;
> -	int fd;
> -
> -	fdir = igt_debugfs_dir(drm_fd);
> -	if (fdir < 0)
> -		return;
> -
> -	dir = fdopendir(fdir);
> -	if (!dir) {
> -		close(fdir);
> -		return;
> -	}
> -
> -	while ((dirent = readdir(dir))) {
> -		char buf[128];
> -
> -		if (strcmp(dirent->d_name, "crtc-") != 0)
> -			continue;
> -
> -		sprintf(buf, "%s/crc/control", dirent->d_name);
> -		fd = openat(fdir, buf, O_WRONLY);
> -		if (fd < 0)
> -			continue;
> -
> -		igt_assert_eq(write(fd, cmd, strlen(cmd)), strlen(cmd));
> -		close(fd);
> -
> -		done = true;
> -	}
> -	closedir(dir);
> -
> -	if (!done) {
> -		fd = openat(fdir, "i915_display_crtc_ctl", O_WRONLY);
> -		if (fd != -1) {
> -			igt_pipe_crc_pipe_off(fd, PIPE_A);
> -			igt_pipe_crc_pipe_off(fd, PIPE_B);
> -			igt_pipe_crc_pipe_off(fd, PIPE_C);
> -
> -			close(fd);
> -		}
> -	}
> -
> -	close(fdir);
> -}
> -
> -static void pipe_crc_exit_handler(int sig)
> -{
> -	struct dirent *dirent;
> -	char buf[128];
> -	DIR *dir;
> -	int fd;
> -
> -	dir = opendir("/dev/dri");
> -	if (!dir)
> -		return;
> -
> -	/*
> -	 * Try to reset CRC capture for all DRM devices, this is only needed
> -	 * for the legacy CRC ABI and can be completely removed once the
> -	 * legacy codepaths are removed.
> -	 */
> -	while ((dirent = readdir(dir))) {
> -		if (strncmp(dirent->d_name, "card", 4) != 0)
> -			continue;
> -
> -		sprintf(buf, "/dev/dri/%s", dirent->d_name);
> -		fd = open(buf, O_WRONLY);
> -
> -		igt_pipe_crc_reset(fd);
> -
> -		close(fd);
> -	}
> -	closedir(dir);
> -}
> -
> -/**
> - * igt_require_pipe_crc:
> - *
> - * Convenience helper to check whether pipe CRC capturing is supported by the
> - * kernel. Uses igt_skip to automatically skip the test/subtest if this isn't
> - * the case.
> - */
> -void igt_require_pipe_crc(int fd)
> -{
> -	const char *cmd = "pipe A none";
> -	int ctl, written;
> -
> -	ctl = igt_debugfs_open(fd, "crtc-0/crc/control", O_RDONLY);
> -	if (ctl < 0) {
> -		ctl = igt_debugfs_open(fd, "i915_display_crc_ctl", O_WRONLY);
> -		igt_require_f(ctl,
> -			      "No display_crc_ctl found, kernel too old\n");
> -
> -		written = write(ctl, cmd, strlen(cmd));
> -		igt_require_f(written < 0,
> -			      "CRCs not supported on this platform\n");
> -	}
> -	close(ctl);
> -}
> -
>  static void igt_hpd_storm_exit_handler(int sig)
>  {
>  	int fd = drm_open_driver_master(DRIVER_INTEL);
> @@ -627,306 +380,6 @@ void igt_require_hpd_storm_ctl(int drm_fd)
>  	close(fd);
>  }
>  
> -static igt_pipe_crc_t *
> -pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source, int flags)
> -{
> -	igt_pipe_crc_t *pipe_crc;
> -	char buf[128];
> -	int debugfs;
> -
> -	debugfs = igt_debugfs_dir(fd);
> -	igt_assert(debugfs != -1);
> -
> -	igt_install_exit_handler(pipe_crc_exit_handler);
> -
> -	pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc));
> -
> -	sprintf(buf, "crtc-%d/crc/control", pipe);
> -	pipe_crc->ctl_fd = openat(debugfs, buf, O_WRONLY);
> -	if (pipe_crc->ctl_fd == -1) {
> -		pipe_crc->ctl_fd = openat(debugfs,
> -					  "i915_display_crc_ctl", O_WRONLY);
> -		igt_assert(pipe_crc->ctl_fd != -1);
> -		pipe_crc->is_legacy = true;
> -	}
> -
> -	if (pipe_crc->is_legacy) {
> -		sprintf(buf, "i915_pipe_%s_crc", kmstest_pipe_name(pipe));
> -		pipe_crc->crc_fd = openat(debugfs, buf, flags);
> -		igt_assert(pipe_crc->crc_fd != -1);
> -		igt_debug("Using legacy frame CRC ABI\n");
> -	} else {
> -		pipe_crc->crc_fd = -1;
> -		igt_debug("Using generic frame CRC ABI\n");
> -	}
> -
> -	pipe_crc->fd = fd;
> -	pipe_crc->dir = debugfs;
> -	pipe_crc->pipe = pipe;
> -	pipe_crc->source = source;
> -	pipe_crc->flags = flags;
> -
> -	return pipe_crc;
> -}
> -
> -/**
> - * igt_pipe_crc_new:
> - * @pipe: display pipe to use as source
> - * @source: CRC tap point to use as source
> - *
> - * This sets up a new pipe CRC capture object for the given @pipe and @source
> - * in blocking mode.
> - *
> - * Returns: A pipe CRC object for the given @pipe and @source. The library
> - * assumes that the source is always available since recent kernels support at
> - * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
> - */
> -igt_pipe_crc_t *
> -igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
> -{
> -	return pipe_crc_new(fd, pipe, source, O_RDONLY);
> -}
> -
> -/**
> - * igt_pipe_crc_new_nonblock:
> - * @pipe: display pipe to use as source
> - * @source: CRC tap point to use as source
> - *
> - * This sets up a new pipe CRC capture object for the given @pipe and @source
> - * in nonblocking mode.
> - *
> - * Returns: A pipe CRC object for the given @pipe and @source. The library
> - * assumes that the source is always available since recent kernels support at
> - * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
> - */
> -igt_pipe_crc_t *
> -igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
> -{
> -	return pipe_crc_new(fd, pipe, source, O_RDONLY | O_NONBLOCK);
> -}
> -
> -/**
> - * igt_pipe_crc_free:
> - * @pipe_crc: pipe CRC object
> - *
> - * Frees all resources associated with @pipe_crc.
> - */
> -void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc)
> -{
> -	if (!pipe_crc)
> -		return;
> -
> -	close(pipe_crc->ctl_fd);
> -	close(pipe_crc->crc_fd);
> -	close(pipe_crc->dir);
> -	free(pipe_crc);
> -}
> -
> -static bool pipe_crc_init_from_string(igt_pipe_crc_t *pipe_crc, igt_crc_t *crc,
> -				      const char *line)
> -{
> -	int n, i;
> -	const char *buf;
> -
> -	if (pipe_crc->is_legacy) {
> -		crc->has_valid_frame = true;
> -		crc->n_words = 5;
> -		n = sscanf(line, "%8u %8x %8x %8x %8x %8x", &crc->frame,
> -			   &crc->crc[0], &crc->crc[1], &crc->crc[2],
> -			   &crc->crc[3], &crc->crc[4]);
> -		return n == 6;
> -	}
> -
> -	if (strncmp(line, "XXXXXXXXXX", 10) == 0)
> -		crc->has_valid_frame = false;
> -	else {
> -		crc->has_valid_frame = true;
> -		crc->frame = strtoul(line, NULL, 16);
> -	}
> -
> -	buf = line + 10;
> -	for (i = 0; *buf != '\n'; i++, buf += 11)
> -		crc->crc[i] = strtoul(buf, NULL, 16);
> -
> -	crc->n_words = i;
> -
> -	return true;
> -}
> -
> -static int read_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
> -{
> -	ssize_t bytes_read;
> -	char buf[MAX_LINE_LEN + 1];
> -	size_t read_len;
> -
> -	if (pipe_crc->is_legacy)
> -		read_len = LEGACY_LINE_LEN;
> -	else
> -		read_len = MAX_LINE_LEN;
> -
> -	igt_set_timeout(5, "CRC reading");
> -	bytes_read = read(pipe_crc->crc_fd, &buf, read_len);
> -	igt_reset_timeout();
> -
> -	if (bytes_read < 0 && errno == EAGAIN)
> -		igt_assert(pipe_crc->flags & O_NONBLOCK);
> -
> -	if (bytes_read < 0)
> -		bytes_read = 0;
> -
> -	buf[bytes_read] = '\0';
> -
> -	if (bytes_read && !pipe_crc_init_from_string(pipe_crc, out, buf))
> -		return -EINVAL;
> -
> -	return bytes_read;
> -}
> -
> -static void read_one_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
> -{
> -	while (read_crc(pipe_crc, out) == 0)
> -		usleep(1000);
> -}
> -
> -/**
> - * igt_pipe_crc_start:
> - * @pipe_crc: pipe CRC object
> - *
> - * Starts the CRC capture process on @pipe_crc.
> - */
> -void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc)
> -{
> -	igt_crc_t crc;
> -
> -	igt_assert(igt_pipe_crc_do_start(pipe_crc));
> -
> -	if (pipe_crc->is_legacy) {
> -		/*
> -		 * For some no yet identified reason, the first CRC is
> -		 * bonkers. So let's just wait for the next vblank and read
> -		 * out the buggy result.
> -		 *
> -		 * On CHV sometimes the second CRC is bonkers as well, so
> -		 * don't trust that one either.
> -		 */
> -		read_one_crc(pipe_crc, &crc);
> -		read_one_crc(pipe_crc, &crc);
> -	}
> -}
> -
> -/**
> - * igt_pipe_crc_stop:
> - * @pipe_crc: pipe CRC object
> - *
> - * Stops the CRC capture process on @pipe_crc.
> - */
> -void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc)
> -{
> -	char buf[32];
> -
> -	if (pipe_crc->is_legacy) {
> -		sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe_crc->pipe));
> -		igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)),
> -			      strlen(buf));
> -	} else {
> -		close(pipe_crc->crc_fd);
> -		pipe_crc->crc_fd = -1;
> -	}
> -}
> -
> -/**
> - * igt_pipe_crc_get_crcs:
> - * @pipe_crc: pipe CRC object
> - * @n_crcs: number of CRCs to capture
> - * @out_crcs: buffer pointer for the captured CRC values
> - *
> - * Read up to @n_crcs from @pipe_crc. This function does not block, and will
> - * return early if not enough CRCs can be captured, if @pipe_crc has been
> - * opened using igt_pipe_crc_new_nonblock(). It will block until @n_crcs are
> - * retrieved if @pipe_crc has been opened using igt_pipe_crc_new(). @out_crcs is
> - * alloced by this function and must be released with free() by the caller.
> - *
> - * Callers must start and stop the capturing themselves by calling
> - * igt_pipe_crc_start() and igt_pipe_crc_stop(). For one-shot CRC collecting
> - * look at igt_pipe_crc_collect_crc().
> - *
> - * Returns:
> - * The number of CRCs captured. Should be equal to @n_crcs in blocking mode, but
> - * can be less (even zero) in non-blocking mode.
> - */
> -int
> -igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
> -		      igt_crc_t **out_crcs)
> -{
> -	igt_crc_t *crcs;
> -	int n = 0;
> -
> -	crcs = calloc(n_crcs, sizeof(igt_crc_t));
> -
> -	do {
> -		igt_crc_t *crc = &crcs[n];
> -		int ret;
> -
> -		ret = read_crc(pipe_crc, crc);
> -		if (ret < 0)
> -			continue;
> -		if (ret == 0)
> -			break;
> -
> -		n++;
> -	} while (n < n_crcs);
> -
> -	*out_crcs = crcs;
> -	return n;
> -}
> -
> -static void crc_sanity_checks(igt_crc_t *crc)
> -{
> -	int i;
> -	bool all_zero = true;
> -
> -	for (i = 0; i < crc->n_words; i++) {
> -		igt_warn_on_f(crc->crc[i] == 0xffffffff,
> -			      "Suspicious CRC: it looks like the CRC "
> -			      "read back was from a register in a powered "
> -			      "down well\n");
> -		if (crc->crc[i])
> -			all_zero = false;
> -	}
> -
> -	igt_warn_on_f(all_zero, "Suspicious CRC: All values are 0.\n");
> -}
> -
> -/**
> - * igt_pipe_crc_collect_crc:
> - * @pipe_crc: pipe CRC object
> - * @out_crc: buffer for the captured CRC values
> - *
> - * Read a single CRC from @pipe_crc. This function blocks until the CRC is
> - * retrieved, irrespective of whether @pipe_crc has been opened with
> - * igt_pipe_crc_new() or igt_pipe_crc_new_nonblock().  @out_crc must be
> - * allocated by the caller.
> - *
> - * This function takes care of the pipe_crc book-keeping, it will start/stop
> - * the collection of the CRC.
> - *
> - * This function also calls the interactive debug with the "crc" domain, so you
> - * can make use of this feature to actually see the screen that is being CRC'd.
> - *
> - * For continuous CRC collection look at igt_pipe_crc_start(),
> - * igt_pipe_crc_get_crcs() and igt_pipe_crc_stop().
> - */
> -void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc)
> -{
> -	igt_debug_wait_for_keypress("crc");
> -
> -	igt_pipe_crc_start(pipe_crc);
> -	read_one_crc(pipe_crc, out_crc);
> -	igt_pipe_crc_stop(pipe_crc);
> -
> -	crc_sanity_checks(out_crc);
> -}
> -
>  /*
>   * Drop caches
>   */
> diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
> index 7b846a83..01a5ee07 100644
> --- a/lib/igt_debugfs.h
> +++ b/lib/igt_debugfs.h
> @@ -29,8 +29,6 @@
>  #include <stdint.h>
>  #include <stdio.h>
>  
> -enum pipe;
> -
>  const char *igt_debugfs_mount(void);
>  
>  int igt_debugfs_dir(int device);
> @@ -50,85 +48,6 @@ bool igt_debugfs_search(int fd, const char *filename, const char *substring);
>  #define igt_debugfs_read(fd, filename, buf) \
>  		__igt_debugfs_read(fd, (filename), (buf), sizeof(buf))
>  
> -/*
> - * Pipe CRC
> - */
> -
> -/**
> - * igt_pipe_crc_t:
> - *
> - * Pipe CRC support structure. Needs to be allocated and set up with
> - * igt_pipe_crc_new() for a specific pipe and pipe CRC source value.
> - */
> -typedef struct _igt_pipe_crc igt_pipe_crc_t;
> -
> -#define DRM_MAX_CRC_NR 10
> -/**
> - * igt_crc_t:
> - * @frame: frame number of the capture CRC
> - * @n_words: internal field, don't access
> - * @crc: internal field, don't access
> - *
> - * Pipe CRC value. All other members than @frame are private and should not be
> - * inspected by testcases.
> - */
> -typedef struct {
> -	uint32_t frame;
> -	bool has_valid_frame;
> -	int n_words;
> -	uint32_t crc[DRM_MAX_CRC_NR];
> -} igt_crc_t;
> -
> -/**
> - * intel_pipe_crc_source:
> - * @INTEL_PIPE_CRC_SOURCE_NONE: No source
> - * @INTEL_PIPE_CRC_SOURCE_PLANE1: Plane 1
> - * @INTEL_PIPE_CRC_SOURCE_PLANE2: Plane 2
> - * @INTEL_PIPE_CRC_SOURCE_PF: Panel Filter
> - * @INTEL_PIPE_CRC_SOURCE_PIPE: Pipe
> - * @INTEL_PIPE_CRC_SOURCE_TV: TV
> - * @INTEL_PIPE_CRC_SOURCE_DP_B: DisplayPort B
> - * @INTEL_PIPE_CRC_SOURCE_DP_C: DisplayPort C
> - * @INTEL_PIPE_CRC_SOURCE_DP_D: DisplayPort D
> - * @INTEL_PIPE_CRC_SOURCE_AUTO: Automatic source selection
> - * @INTEL_PIPE_CRC_SOURCE_MAX: Number of available sources
> - *
> - * Enumeration of all supported pipe CRC sources. Not all platforms and all
> - * outputs support all of them. Generic tests should just use
> - * INTEL_PIPE_CRC_SOURCE_AUTO. It should always map to an end-of-pipe CRC
> - * suitable for checking planes, cursor, color correction and any other
> - * output-agnostic features.
> - */
> -enum intel_pipe_crc_source {
> -        INTEL_PIPE_CRC_SOURCE_NONE,
> -        INTEL_PIPE_CRC_SOURCE_PLANE1,
> -        INTEL_PIPE_CRC_SOURCE_PLANE2,
> -        INTEL_PIPE_CRC_SOURCE_PF,
> -        INTEL_PIPE_CRC_SOURCE_PIPE,
> -        INTEL_PIPE_CRC_SOURCE_TV,
> -        INTEL_PIPE_CRC_SOURCE_DP_B,
> -        INTEL_PIPE_CRC_SOURCE_DP_C,
> -        INTEL_PIPE_CRC_SOURCE_DP_D,
> -        INTEL_PIPE_CRC_SOURCE_AUTO,
> -        INTEL_PIPE_CRC_SOURCE_MAX,
> -};
> -
> -void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
> -char *igt_crc_to_string(igt_crc_t *crc);
> -
> -void igt_require_pipe_crc(int fd);
> -igt_pipe_crc_t *
> -igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
> -igt_pipe_crc_t *
> -igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
> -void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc);
> -void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc);
> -void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc);
> -__attribute__((warn_unused_result))
> -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(int fd, unsigned int threshold);
>  void igt_hpd_storm_reset(int fd);
>  bool igt_hpd_storm_detected(int fd);
> diff --git a/tests/chamelium.c b/tests/chamelium.c
> index b412c6a7..9b0424d1 100644
> --- a/tests/chamelium.c
> +++ b/tests/chamelium.c
> @@ -26,6 +26,7 @@
>  
>  #include "config.h"
>  #include "igt.h"
> +#include "igt_crc.h"
>  
>  #include <fcntl.h>
>  #include <string.h>
> diff --git a/tests/kms_atomic_transition.c b/tests/kms_atomic_transition.c
> index ba5cd4d6..37de838f 100644
> --- a/tests/kms_atomic_transition.c
> +++ b/tests/kms_atomic_transition.c
> @@ -22,6 +22,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include "drmtest.h"
>  #include "sw_sync.h"
>  #include <errno.h>
> diff --git a/tests/kms_ccs.c b/tests/kms_ccs.c
> index 29d676af..66bd0f29 100644
> --- a/tests/kms_ccs.c
> +++ b/tests/kms_ccs.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  
>  IGT_TEST_DESCRIPTION("Test render compression (RC), in which the main surface "
>  		     "is complemented by a color control surface (CCS) that "
> diff --git a/tests/kms_chv_cursor_fail.c b/tests/kms_chv_cursor_fail.c
> index 3e74df11..b02958bd 100644
> --- a/tests/kms_chv_cursor_fail.c
> +++ b/tests/kms_chv_cursor_fail.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <errno.h>
>  #include <limits.h>
>  #include <stdbool.h>
> diff --git a/tests/kms_crtc_background_color.c b/tests/kms_crtc_background_color.c
> index e12e1634..3bcabcac 100644
> --- a/tests/kms_crtc_background_color.c
> +++ b/tests/kms_crtc_background_color.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <math.h>
>  
>  
> diff --git a/tests/kms_cursor_crc.c b/tests/kms_cursor_crc.c
> index 4c5e00c0..4693e9f4 100644
> --- a/tests/kms_cursor_crc.c
> +++ b/tests/kms_cursor_crc.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <errno.h>
>  #include <limits.h>
>  #include <stdbool.h>
> diff --git a/tests/kms_cursor_legacy.c b/tests/kms_cursor_legacy.c
> index 8180b043..505e3f9d 100644
> --- a/tests/kms_cursor_legacy.c
> +++ b/tests/kms_cursor_legacy.c
> @@ -27,6 +27,7 @@
>  #include <sys/poll.h>
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include "igt_rand.h"
>  #include "igt_stats.h"
>  
> diff --git a/tests/kms_draw_crc.c b/tests/kms_draw_crc.c
> index c57d3a35..8cb4e147 100644
> --- a/tests/kms_draw_crc.c
> +++ b/tests/kms_draw_crc.c
> @@ -25,6 +25,7 @@
>  /* This program tests whether the igt_draw library actually works. */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  
>  #define MAX_CONNECTORS 32
>  
> diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c
> index 7964e052..10656b89 100644
> --- a/tests/kms_fbc_crc.c
> +++ b/tests/kms_fbc_crc.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <errno.h>
>  #include <stdbool.h>
>  #include <stdio.h>
> diff --git a/tests/kms_flip_tiling.c b/tests/kms_flip_tiling.c
> index 5aae29a8..8e1a2fb4 100644
> --- a/tests/kms_flip_tiling.c
> +++ b/tests/kms_flip_tiling.c
> @@ -25,6 +25,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <errno.h>
>  #include <stdbool.h>
>  #include <stdio.h>
> diff --git a/tests/kms_frontbuffer_tracking.c b/tests/kms_frontbuffer_tracking.c
> index c24e4a81..4af5e006 100644
> --- a/tests/kms_frontbuffer_tracking.c
> +++ b/tests/kms_frontbuffer_tracking.c
> @@ -25,6 +25,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include "igt_sysfs.h"
>  #include <sys/types.h>
>  #include <sys/stat.h>
> diff --git a/tests/kms_mmap_write_crc.c b/tests/kms_mmap_write_crc.c
> index e5f089f6..79efa792 100644
> --- a/tests/kms_mmap_write_crc.c
> +++ b/tests/kms_mmap_write_crc.c
> @@ -31,6 +31,7 @@
>  #include <string.h>
>  
>  #include "drmtest.h"
> +#include "igt_crc.h"
>  #include "igt_debugfs.h"
>  #include "igt_kms.h"
>  #include "intel_chipset.h"
> diff --git a/tests/kms_mmio_vs_cs_flip.c b/tests/kms_mmio_vs_cs_flip.c
> index fa947d9c..ee1d202a 100644
> --- a/tests/kms_mmio_vs_cs_flip.c
> +++ b/tests/kms_mmio_vs_cs_flip.c
> @@ -22,6 +22,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <errno.h>
>  #include <stdbool.h>
>  #include <stdio.h>
> diff --git a/tests/kms_pipe_color.c b/tests/kms_pipe_color.c
> index a3100fae..389fb3de 100644
> --- a/tests/kms_pipe_color.c
> +++ b/tests/kms_pipe_color.c
> @@ -28,6 +28,7 @@
>  #include "drm.h"
>  #include "drmtest.h"
>  #include "igt.h"
> +#include "igt_crc.h"
>  
>  IGT_TEST_DESCRIPTION("Test Color Features at Pipe level");
>  
> diff --git a/tests/kms_pipe_crc_basic.c b/tests/kms_pipe_crc_basic.c
> index 35adddba..38da3a42 100644
> --- a/tests/kms_pipe_crc_basic.c
> +++ b/tests/kms_pipe_crc_basic.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include "igt_sysfs.h"
>  #include <errno.h>
>  #include <stdbool.h>
> diff --git a/tests/kms_plane.c b/tests/kms_plane.c
> index 1d92a62b..2fa58e8f 100644
> --- a/tests/kms_plane.c
> +++ b/tests/kms_plane.c
> @@ -25,6 +25,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <errno.h>
>  #include <stdbool.h>
>  #include <stdio.h>
> diff --git a/tests/kms_plane_lowres.c b/tests/kms_plane_lowres.c
> index ee39759c..a4e37275 100644
> --- a/tests/kms_plane_lowres.c
> +++ b/tests/kms_plane_lowres.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include "drmtest.h"
>  #include <errno.h>
>  #include <stdbool.h>
> diff --git a/tests/kms_plane_multiple.c b/tests/kms_plane_multiple.c
> index f6c62235..1b60a067 100644
> --- a/tests/kms_plane_multiple.c
> +++ b/tests/kms_plane_multiple.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include "drmtest.h"
>  #include <errno.h>
>  #include <stdbool.h>
> diff --git a/tests/kms_plane_scaling.c b/tests/kms_plane_scaling.c
> index 1457894a..d554f27f 100644
> --- a/tests/kms_plane_scaling.c
> +++ b/tests/kms_plane_scaling.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <math.h>
>  
>  
> diff --git a/tests/kms_pwrite_crc.c b/tests/kms_pwrite_crc.c
> index ee895db6..f1e6f023 100644
> --- a/tests/kms_pwrite_crc.c
> +++ b/tests/kms_pwrite_crc.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <errno.h>
>  #include <limits.h>
>  #include <stdbool.h>
> diff --git a/tests/kms_rotation_crc.c b/tests/kms_rotation_crc.c
> index 83e37f12..fa361100 100644
> --- a/tests/kms_rotation_crc.c
> +++ b/tests/kms_rotation_crc.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <math.h>
>  
>  #define MAX_FENCES 32
> diff --git a/tests/kms_universal_plane.c b/tests/kms_universal_plane.c
> index 31f07804..14300b7a 100644
> --- a/tests/kms_universal_plane.c
> +++ b/tests/kms_universal_plane.c
> @@ -22,6 +22,7 @@
>   */
>  
>  #include "igt.h"
> +#include "igt_crc.h"
>  #include <errno.h>
>  #include <stdbool.h>
>  #include <stdio.h>
> diff --git a/tools/intel_display_crc.c b/tools/intel_display_crc.c
> index d1b28ea7..104f432f 100644
> --- a/tools/intel_display_crc.c
> +++ b/tools/intel_display_crc.c
> @@ -30,6 +30,7 @@
>  #include <unistd.h>
>  
>  #include "igt_core.h"
> +#include "igt_crc.h"
>  #include "igt_debugfs.h"
>  #include "igt_kms.h"
>  
> -- 
> 2.13.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH i-g-t 1/7] igt: lib/igt_crc: Split out CRC functionality
  2017-07-17 13:50   ` Arkadiusz Hiler
@ 2017-07-17 15:06     ` Liviu Dudau
  0 siblings, 0 replies; 10+ messages in thread
From: Liviu Dudau @ 2017-07-17 15:06 UTC (permalink / raw)
  To: Arkadiusz Hiler; +Cc: Intel GFX discussion

On Mon, Jul 17, 2017 at 04:50:27PM +0300, Arkadiusz Hiler wrote:
> On Thu, Jul 06, 2017 at 05:14:18PM +0100, Liviu Dudau wrote:
> > From: Brian Starkey <brian.starkey@arm.com>
> > 
> > Separate out the CRC code for better compartmentalisation. Should ease
> > the addition of more/different CRC sources in the future.
> > 
> > Signed-off-by: Brian Starkey <brian.starkey@arm.com>
> > Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
> > 
> > ---
> >  lib/Makefile.sources              |   2 +
> >  lib/igt_chamelium.h               |   1 +
> >  lib/igt_crc.c                     | 563 ++++++++++++++++++++++++++++++++++++++
> >  lib/igt_crc.h                     | 125 +++++++++
> >  lib/igt_debugfs.c                 | 547 ------------------------------------
> >  lib/igt_debugfs.h                 |  81 ------
> >  tests/chamelium.c                 |   1 +
> >  tests/kms_atomic_transition.c     |   1 +
> >  tests/kms_ccs.c                   |   1 +
> >  tests/kms_chv_cursor_fail.c       |   1 +
> >  tests/kms_crtc_background_color.c |   1 +
> >  tests/kms_cursor_crc.c            |   1 +
> >  tests/kms_cursor_legacy.c         |   1 +
> >  tests/kms_draw_crc.c              |   1 +
> >  tests/kms_fbc_crc.c               |   1 +
> >  tests/kms_flip_tiling.c           |   1 +
> >  tests/kms_frontbuffer_tracking.c  |   1 +
> >  tests/kms_mmap_write_crc.c        |   1 +
> >  tests/kms_mmio_vs_cs_flip.c       |   1 +
> >  tests/kms_pipe_color.c            |   1 +
> >  tests/kms_pipe_crc_basic.c        |   1 +
> >  tests/kms_plane.c                 |   1 +
> >  tests/kms_plane_lowres.c          |   1 +
> >  tests/kms_plane_multiple.c        |   1 +
> >  tests/kms_plane_scaling.c         |   1 +
> >  tests/kms_pwrite_crc.c            |   1 +
> >  tests/kms_rotation_crc.c          |   1 +
> >  tests/kms_universal_plane.c       |   1 +
> >  tools/intel_display_crc.c         |   1 +
> >  29 files changed, 714 insertions(+), 628 deletions(-)
> >  create mode 100644 lib/igt_crc.c
> >  create mode 100644 lib/igt_crc.h
> > 
> > diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> > index 53fdb54c..cfba15c9 100644
> > --- a/lib/Makefile.sources
> > +++ b/lib/Makefile.sources
> > @@ -11,6 +11,8 @@ lib_source_list =	 	\
> >  	igt_debugfs.h		\
> >  	igt_aux.c		\
> >  	igt_aux.h		\
> > +	igt_crc.c		\
> > +	igt_crc.h		\
> >  	igt_edid_template.h	\
> >  	igt_gt.c		\
> >  	igt_gt.h		\
> > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > index 81322ad2..ea5abc2e 100644
> > --- a/lib/igt_chamelium.h
> > +++ b/lib/igt_chamelium.h
> > @@ -31,6 +31,7 @@
> >  #endif
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <stdbool.h>
> >  
> >  struct chamelium;
> > diff --git a/lib/igt_crc.c b/lib/igt_crc.c
> > new file mode 100644
> > index 00000000..91a0b5a8
> > --- /dev/null
> > +++ b/lib/igt_crc.c
> > @@ -0,0 +1,563 @@
> > +/*
> > + * 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.
> > + *
> > + */
> > +#include <dirent.h>
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <sys/stat.h>
> > +#include <sys/types.h>
> > +
> > +#include "igt_aux.h"
> > +#include "igt_crc.h"
> > +#include "igt_core.h"
> > +#include "igt_debugfs.h"
> > +#include "igt_kms.h"
> > +
> > +/**
> > + * igt_assert_crc_equal:
> > + * @a: first pipe CRC value
> > + * @b: second pipe CRC value
> > + *
> > + * Compares two CRC values and fails the testcase if they don't match with
> > + * igt_fail(). Note that due to CRC collisions CRC based testcase can only
> > + * assert that CRCs match, never that they are different. Otherwise there might
> > + * be random testcase failures when different screen contents end up with the
> > + * same CRC by chance.
> > + */
> > +void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < a->n_words; i++)
> > +		igt_assert_eq_u32(a->crc[i], b->crc[i]);
> > +}
> > +
> > +/**
> > + * igt_crc_to_string:
> > + * @crc: pipe CRC value to print
> > + *
> > + * This formats @crc into a string buffer which is owned by igt_crc_to_string().
> > + * The next call will override the buffer again, which makes this multithreading
> > + * unsafe.
> > + *
> > + * This should only ever be used for diagnostic debug output.
> > + */
> > +char *igt_crc_to_string(igt_crc_t *crc)
> 
> Noticed that the doc is out of sync with how the function actually
> works. Sending a patch to fix that.
> 
> Other than that LGTM.

Thanks for reviewing this.

Best regards,
Liviu

> 
> -- 
> Cheers,
> Arek
> 
> > +{
> > +	int i;
> > +	char buf[128] = { 0 };
> > +
> > +	for (i = 0; i < crc->n_words; i++)
> > +		sprintf(buf + strlen(buf), "%08x ", crc->crc[i]);
> > +
> > +	return strdup(buf);
> > +}
> > +
> > +#define MAX_CRC_ENTRIES 10
> > +#define MAX_LINE_LEN (10 + 11 * MAX_CRC_ENTRIES + 1)
> > +
> > +/* (6 fields, 8 chars each, space separated (5) + '\n') */
> > +#define LEGACY_LINE_LEN       (6 * 8 + 5 + 1)
> > +
> > +struct _igt_pipe_crc {
> > +	int fd;
> > +	int dir;
> > +	int ctl_fd;
> > +	int crc_fd;
> > +	int flags;
> > +	bool is_legacy;
> > +
> > +	enum pipe pipe;
> > +	enum intel_pipe_crc_source source;
> > +};
> > +
> > +static const char *pipe_crc_sources[] = {
> > +	"none",
> > +	"plane1",
> > +	"plane2",
> > +	"pf",
> > +	"pipe",
> > +	"TV",
> > +	"DP-B",
> > +	"DP-C",
> > +	"DP-D",
> > +	"auto"
> > +};
> > +
> > +static const char *pipe_crc_source_name(enum intel_pipe_crc_source source)
> > +{
> > +        return pipe_crc_sources[source];
> > +}
> > +
> > +static bool igt_pipe_crc_do_start(igt_pipe_crc_t *pipe_crc)
> > +{
> > +	char buf[64];
> > +
> > +	/* Stop first just to make sure we don't have lingering state left. */
> > +	igt_pipe_crc_stop(pipe_crc);
> > +
> > +	if (pipe_crc->is_legacy)
> > +		sprintf(buf, "pipe %s %s", kmstest_pipe_name(pipe_crc->pipe),
> > +			pipe_crc_source_name(pipe_crc->source));
> > +	else
> > +		sprintf(buf, "%s", pipe_crc_source_name(pipe_crc->source));
> > +
> > +	igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), strlen(buf));
> > +
> > +	if (!pipe_crc->is_legacy) {
> > +		int err;
> > +
> > +		sprintf(buf, "crtc-%d/crc/data", pipe_crc->pipe);
> > +		err = 0;
> > +
> > +		pipe_crc->crc_fd = openat(pipe_crc->dir, buf, pipe_crc->flags);
> > +		if (pipe_crc->crc_fd < 0)
> > +			err = -errno;
> > +
> > +		if (err == -EINVAL)
> > +			return false;
> > +
> > +		igt_assert_eq(err, 0);
> > +	}
> > +
> > +	errno = 0;
> > +	return true;
> > +}
> > +
> > +static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe)
> > +{
> > +	char buf[32];
> > +
> > +	sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe));
> > +	igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf));
> > +}
> > +
> > +static void igt_pipe_crc_reset(int drm_fd)
> > +{
> > +	struct dirent *dirent;
> > +	const char *cmd = "none";
> > +	bool done = false;
> > +	DIR *dir;
> > +	int fdir;
> > +	int fd;
> > +
> > +	fdir = igt_debugfs_dir(drm_fd);
> > +	if (fdir < 0)
> > +		return;
> > +
> > +	dir = fdopendir(fdir);
> > +	if (!dir) {
> > +		close(fdir);
> > +		return;
> > +	}
> > +
> > +	while ((dirent = readdir(dir))) {
> > +		char buf[128];
> > +
> > +		if (strcmp(dirent->d_name, "crtc-") != 0)
> > +			continue;
> > +
> > +		sprintf(buf, "%s/crc/control", dirent->d_name);
> > +		fd = openat(fdir, buf, O_WRONLY);
> > +		if (fd < 0)
> > +			continue;
> > +
> > +		igt_assert_eq(write(fd, cmd, strlen(cmd)), strlen(cmd));
> > +		close(fd);
> > +
> > +		done = true;
> > +	}
> > +	closedir(dir);
> > +
> > +	if (!done) {
> > +		fd = openat(fdir, "i915_display_crtc_ctl", O_WRONLY);
> > +		if (fd != -1) {
> > +			igt_pipe_crc_pipe_off(fd, PIPE_A);
> > +			igt_pipe_crc_pipe_off(fd, PIPE_B);
> > +			igt_pipe_crc_pipe_off(fd, PIPE_C);
> > +
> > +			close(fd);
> > +		}
> > +	}
> > +
> > +	close(fdir);
> > +}
> > +
> > +static void pipe_crc_exit_handler(int sig)
> > +{
> > +	struct dirent *dirent;
> > +	char buf[128];
> > +	DIR *dir;
> > +	int fd;
> > +
> > +	dir = opendir("/dev/dri");
> > +	if (!dir)
> > +		return;
> > +
> > +	/*
> > +	 * Try to reset CRC capture for all DRM devices, this is only needed
> > +	 * for the legacy CRC ABI and can be completely removed once the
> > +	 * legacy codepaths are removed.
> > +	 */
> > +	while ((dirent = readdir(dir))) {
> > +		if (strncmp(dirent->d_name, "card", 4) != 0)
> > +			continue;
> > +
> > +		sprintf(buf, "/dev/dri/%s", dirent->d_name);
> > +		fd = open(buf, O_WRONLY);
> > +
> > +		igt_pipe_crc_reset(fd);
> > +
> > +		close(fd);
> > +	}
> > +	closedir(dir);
> > +}
> > +
> > +/**
> > + * igt_require_pipe_crc:
> > + *
> > + * Convenience helper to check whether pipe CRC capturing is supported by the
> > + * kernel. Uses igt_skip to automatically skip the test/subtest if this isn't
> > + * the case.
> > + */
> > +void igt_require_pipe_crc(int fd)
> > +{
> > +	const char *cmd = "pipe A none";
> > +	int ctl, written;
> > +
> > +	ctl = igt_debugfs_open(fd, "crtc-0/crc/control", O_RDONLY);
> > +	if (ctl < 0) {
> > +		ctl = igt_debugfs_open(fd, "i915_display_crc_ctl", O_WRONLY);
> > +		igt_require_f(ctl,
> > +			      "No display_crc_ctl found, kernel too old\n");
> > +
> > +		written = write(ctl, cmd, strlen(cmd));
> > +		igt_require_f(written < 0,
> > +			      "CRCs not supported on this platform\n");
> > +	}
> > +	close(ctl);
> > +}
> > +
> > +static igt_pipe_crc_t *
> > +pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source, int flags)
> > +{
> > +	igt_pipe_crc_t *pipe_crc;
> > +	char buf[128];
> > +	int debugfs;
> > +
> > +	debugfs = igt_debugfs_dir(fd);
> > +	igt_assert(debugfs != -1);
> > +
> > +	igt_install_exit_handler(pipe_crc_exit_handler);
> > +
> > +	pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc));
> > +
> > +	sprintf(buf, "crtc-%d/crc/control", pipe);
> > +	pipe_crc->ctl_fd = openat(debugfs, buf, O_WRONLY);
> > +	if (pipe_crc->ctl_fd == -1) {
> > +		pipe_crc->ctl_fd = openat(debugfs,
> > +					  "i915_display_crc_ctl", O_WRONLY);
> > +		igt_assert(pipe_crc->ctl_fd != -1);
> > +		pipe_crc->is_legacy = true;
> > +	}
> > +
> > +	if (pipe_crc->is_legacy) {
> > +		sprintf(buf, "i915_pipe_%s_crc", kmstest_pipe_name(pipe));
> > +		pipe_crc->crc_fd = openat(debugfs, buf, flags);
> > +		igt_assert(pipe_crc->crc_fd != -1);
> > +		igt_debug("Using legacy frame CRC ABI\n");
> > +	} else {
> > +		pipe_crc->crc_fd = -1;
> > +		igt_debug("Using generic frame CRC ABI\n");
> > +	}
> > +
> > +	pipe_crc->fd = fd;
> > +	pipe_crc->dir = debugfs;
> > +	pipe_crc->pipe = pipe;
> > +	pipe_crc->source = source;
> > +	pipe_crc->flags = flags;
> > +
> > +	return pipe_crc;
> > +}
> > +
> > +/**
> > + * igt_pipe_crc_new:
> > + * @pipe: display pipe to use as source
> > + * @source: CRC tap point to use as source
> > + *
> > + * This sets up a new pipe CRC capture object for the given @pipe and @source
> > + * in blocking mode.
> > + *
> > + * Returns: A pipe CRC object for the given @pipe and @source. The library
> > + * assumes that the source is always available since recent kernels support at
> > + * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
> > + */
> > +igt_pipe_crc_t *
> > +igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
> > +{
> > +	return pipe_crc_new(fd, pipe, source, O_RDONLY);
> > +}
> > +
> > +/**
> > + * igt_pipe_crc_new_nonblock:
> > + * @pipe: display pipe to use as source
> > + * @source: CRC tap point to use as source
> > + *
> > + * This sets up a new pipe CRC capture object for the given @pipe and @source
> > + * in nonblocking mode.
> > + *
> > + * Returns: A pipe CRC object for the given @pipe and @source. The library
> > + * assumes that the source is always available since recent kernels support at
> > + * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
> > + */
> > +igt_pipe_crc_t *
> > +igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
> > +{
> > +	return pipe_crc_new(fd, pipe, source, O_RDONLY | O_NONBLOCK);
> > +}
> > +
> > +/**
> > + * igt_pipe_crc_free:
> > + * @pipe_crc: pipe CRC object
> > + *
> > + * Frees all resources associated with @pipe_crc.
> > + */
> > +void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc)
> > +{
> > +	if (!pipe_crc)
> > +		return;
> > +
> > +	close(pipe_crc->ctl_fd);
> > +	close(pipe_crc->crc_fd);
> > +	close(pipe_crc->dir);
> > +	free(pipe_crc);
> > +}
> > +
> > +static bool pipe_crc_init_from_string(igt_pipe_crc_t *pipe_crc, igt_crc_t *crc,
> > +				      const char *line)
> > +{
> > +	int n, i;
> > +	const char *buf;
> > +
> > +	if (pipe_crc->is_legacy) {
> > +		crc->has_valid_frame = true;
> > +		crc->n_words = 5;
> > +		n = sscanf(line, "%8u %8x %8x %8x %8x %8x", &crc->frame,
> > +			   &crc->crc[0], &crc->crc[1], &crc->crc[2],
> > +			   &crc->crc[3], &crc->crc[4]);
> > +		return n == 6;
> > +	}
> > +
> > +	if (strncmp(line, "XXXXXXXXXX", 10) == 0)
> > +		crc->has_valid_frame = false;
> > +	else {
> > +		crc->has_valid_frame = true;
> > +		crc->frame = strtoul(line, NULL, 16);
> > +	}
> > +
> > +	buf = line + 10;
> > +	for (i = 0; *buf != '\n'; i++, buf += 11)
> > +		crc->crc[i] = strtoul(buf, NULL, 16);
> > +
> > +	crc->n_words = i;
> > +
> > +	return true;
> > +}
> > +
> > +static int read_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
> > +{
> > +	ssize_t bytes_read;
> > +	char buf[MAX_LINE_LEN + 1];
> > +	size_t read_len;
> > +
> > +	if (pipe_crc->is_legacy)
> > +		read_len = LEGACY_LINE_LEN;
> > +	else
> > +		read_len = MAX_LINE_LEN;
> > +
> > +	igt_set_timeout(5, "CRC reading");
> > +	bytes_read = read(pipe_crc->crc_fd, &buf, read_len);
> > +	igt_reset_timeout();
> > +
> > +	if (bytes_read < 0 && errno == EAGAIN)
> > +		igt_assert(pipe_crc->flags & O_NONBLOCK);
> > +
> > +	if (bytes_read < 0)
> > +		bytes_read = 0;
> > +
> > +	buf[bytes_read] = '\0';
> > +
> > +	if (bytes_read && !pipe_crc_init_from_string(pipe_crc, out, buf))
> > +		return -EINVAL;
> > +
> > +	return bytes_read;
> > +}
> > +
> > +static void read_one_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
> > +{
> > +	while (read_crc(pipe_crc, out) == 0)
> > +		usleep(1000);
> > +}
> > +
> > +/**
> > + * igt_pipe_crc_start:
> > + * @pipe_crc: pipe CRC object
> > + *
> > + * Starts the CRC capture process on @pipe_crc.
> > + */
> > +void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc)
> > +{
> > +	igt_crc_t crc;
> > +
> > +	igt_assert(igt_pipe_crc_do_start(pipe_crc));
> > +
> > +	if (pipe_crc->is_legacy) {
> > +		/*
> > +		 * For some no yet identified reason, the first CRC is
> > +		 * bonkers. So let's just wait for the next vblank and read
> > +		 * out the buggy result.
> > +		 *
> > +		 * On CHV sometimes the second CRC is bonkers as well, so
> > +		 * don't trust that one either.
> > +		 */
> > +		read_one_crc(pipe_crc, &crc);
> > +		read_one_crc(pipe_crc, &crc);
> > +	}
> > +}
> > +
> > +/**
> > + * igt_pipe_crc_stop:
> > + * @pipe_crc: pipe CRC object
> > + *
> > + * Stops the CRC capture process on @pipe_crc.
> > + */
> > +void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc)
> > +{
> > +	char buf[32];
> > +
> > +	if (pipe_crc->is_legacy) {
> > +		sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe_crc->pipe));
> > +		igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)),
> > +			      strlen(buf));
> > +	} else {
> > +		close(pipe_crc->crc_fd);
> > +		pipe_crc->crc_fd = -1;
> > +	}
> > +}
> > +
> > +/**
> > + * igt_pipe_crc_get_crcs:
> > + * @pipe_crc: pipe CRC object
> > + * @n_crcs: number of CRCs to capture
> > + * @out_crcs: buffer pointer for the captured CRC values
> > + *
> > + * Read up to @n_crcs from @pipe_crc. This function does not block, and will
> > + * return early if not enough CRCs can be captured, if @pipe_crc has been
> > + * opened using igt_pipe_crc_new_nonblock(). It will block until @n_crcs are
> > + * retrieved if @pipe_crc has been opened using igt_pipe_crc_new(). @out_crcs is
> > + * alloced by this function and must be released with free() by the caller.
> > + *
> > + * Callers must start and stop the capturing themselves by calling
> > + * igt_pipe_crc_start() and igt_pipe_crc_stop(). For one-shot CRC collecting
> > + * look at igt_pipe_crc_collect_crc().
> > + *
> > + * Returns:
> > + * The number of CRCs captured. Should be equal to @n_crcs in blocking mode, but
> > + * can be less (even zero) in non-blocking mode.
> > + */
> > +int
> > +igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
> > +		      igt_crc_t **out_crcs)
> > +{
> > +	igt_crc_t *crcs;
> > +	int n = 0;
> > +
> > +	crcs = calloc(n_crcs, sizeof(igt_crc_t));
> > +
> > +	do {
> > +		igt_crc_t *crc = &crcs[n];
> > +		int ret;
> > +
> > +		ret = read_crc(pipe_crc, crc);
> > +		if (ret < 0)
> > +			continue;
> > +		if (ret == 0)
> > +			break;
> > +
> > +		n++;
> > +	} while (n < n_crcs);
> > +
> > +	*out_crcs = crcs;
> > +	return n;
> > +}
> > +
> > +static void crc_sanity_checks(igt_crc_t *crc)
> > +{
> > +	int i;
> > +	bool all_zero = true;
> > +
> > +	for (i = 0; i < crc->n_words; i++) {
> > +		igt_warn_on_f(crc->crc[i] == 0xffffffff,
> > +			      "Suspicious CRC: it looks like the CRC "
> > +			      "read back was from a register in a powered "
> > +			      "down well\n");
> > +		if (crc->crc[i])
> > +			all_zero = false;
> > +	}
> > +
> > +	igt_warn_on_f(all_zero, "Suspicious CRC: All values are 0.\n");
> > +}
> > +
> > +/**
> > + * igt_pipe_crc_collect_crc:
> > + * @pipe_crc: pipe CRC object
> > + * @out_crc: buffer for the captured CRC values
> > + *
> > + * Read a single CRC from @pipe_crc. This function blocks until the CRC is
> > + * retrieved, irrespective of whether @pipe_crc has been opened with
> > + * igt_pipe_crc_new() or igt_pipe_crc_new_nonblock().  @out_crc must be
> > + * allocated by the caller.
> > + *
> > + * This function takes care of the pipe_crc book-keeping, it will start/stop
> > + * the collection of the CRC.
> > + *
> > + * This function also calls the interactive debug with the "crc" domain, so you
> > + * can make use of this feature to actually see the screen that is being CRC'd.
> > + *
> > + * For continuous CRC collection look at igt_pipe_crc_start(),
> > + * igt_pipe_crc_get_crcs() and igt_pipe_crc_stop().
> > + */
> > +void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc)
> > +{
> > +	igt_debug_wait_for_keypress("crc");
> > +
> > +	igt_pipe_crc_start(pipe_crc);
> > +	read_one_crc(pipe_crc, out_crc);
> > +	igt_pipe_crc_stop(pipe_crc);
> > +
> > +	crc_sanity_checks(out_crc);
> > +}
> > +
> > diff --git a/lib/igt_crc.h b/lib/igt_crc.h
> > new file mode 100644
> > index 00000000..b0623baf
> > --- /dev/null
> > +++ b/lib/igt_crc.h
> > @@ -0,0 +1,125 @@
> > +/*
> > + * 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.
> > + *
> > + * # Pipe CRC Support
> > + *
> > + * This library wraps up the kernel's support for capturing pipe CRCs into a
> > + * neat and tidy package. For the detailed usage see all the functions which
> > + * work on #igt_pipe_crc_t. This is supported on all platforms and outputs.
> > + *
> > + * Actually using pipe CRCs to write modeset tests is a bit tricky though, so
> > + * there is no way to directly check a CRC: Both the details of the plane
> > + * blending, color correction and other hardware and how exactly the CRC is
> > + * computed at each tap point vary by hardware generation and are not disclosed.
> > + *
> > + * The only way to use #igt_crc_t CRCs therefore is to compare CRCs among each
> > + * another either for equality or difference. Otherwise CRCs must be treated as
> > + * completely opaque values. Note that not even CRCs from different pipes or tap
> > + * points on the same platform can be compared. Hence only use
> > + * igt_assert_crc_equal() to inspect CRC values captured by the same
> > + * #igt_pipe_crc_t object.
> > + */
> > +
> > +#ifndef __IGT_CRC_H__
> > +#define __IGT_CRC_H__
> > +
> > +#include <stdbool.h>
> > +#include <stdint.h>
> > +
> > +enum pipe;
> > +
> > +/**
> > + * igt_pipe_crc_t:
> > + *
> > + * Pipe CRC support structure. Needs to be allocated and set up with
> > + * igt_pipe_crc_new() for a specific pipe and pipe CRC source value.
> > + */
> > +typedef struct _igt_pipe_crc igt_pipe_crc_t;
> > +
> > +#define DRM_MAX_CRC_NR 10
> > +/**
> > + * igt_crc_t:
> > + * @frame: frame number of the capture CRC
> > + * @n_words: internal field, don't access
> > + * @crc: internal field, don't access
> > + *
> > + * Pipe CRC value. All other members than @frame are private and should not be
> > + * inspected by testcases.
> > + */
> > +typedef struct {
> > +	uint32_t frame;
> > +	bool has_valid_frame;
> > +	int n_words;
> > +	uint32_t crc[DRM_MAX_CRC_NR];
> > +} igt_crc_t;
> > +
> > +/**
> > + * intel_pipe_crc_source:
> > + * @INTEL_PIPE_CRC_SOURCE_NONE: No source
> > + * @INTEL_PIPE_CRC_SOURCE_PLANE1: Plane 1
> > + * @INTEL_PIPE_CRC_SOURCE_PLANE2: Plane 2
> > + * @INTEL_PIPE_CRC_SOURCE_PF: Panel Filter
> > + * @INTEL_PIPE_CRC_SOURCE_PIPE: Pipe
> > + * @INTEL_PIPE_CRC_SOURCE_TV: TV
> > + * @INTEL_PIPE_CRC_SOURCE_DP_B: DisplayPort B
> > + * @INTEL_PIPE_CRC_SOURCE_DP_C: DisplayPort C
> > + * @INTEL_PIPE_CRC_SOURCE_DP_D: DisplayPort D
> > + * @INTEL_PIPE_CRC_SOURCE_AUTO: Automatic source selection
> > + * @INTEL_PIPE_CRC_SOURCE_MAX: Number of available sources
> > + *
> > + * Enumeration of all supported pipe CRC sources. Not all platforms and all
> > + * outputs support all of them. Generic tests should just use
> > + * INTEL_PIPE_CRC_SOURCE_AUTO. It should always map to an end-of-pipe CRC
> > + * suitable for checking planes, cursor, color correction and any other
> > + * output-agnostic features.
> > + */
> > +enum intel_pipe_crc_source {
> > +        INTEL_PIPE_CRC_SOURCE_NONE,
> > +        INTEL_PIPE_CRC_SOURCE_PLANE1,
> > +        INTEL_PIPE_CRC_SOURCE_PLANE2,
> > +        INTEL_PIPE_CRC_SOURCE_PF,
> > +        INTEL_PIPE_CRC_SOURCE_PIPE,
> > +        INTEL_PIPE_CRC_SOURCE_TV,
> > +        INTEL_PIPE_CRC_SOURCE_DP_B,
> > +        INTEL_PIPE_CRC_SOURCE_DP_C,
> > +        INTEL_PIPE_CRC_SOURCE_DP_D,
> > +        INTEL_PIPE_CRC_SOURCE_AUTO,
> > +        INTEL_PIPE_CRC_SOURCE_MAX,
> > +};
> > +
> > +void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
> > +char *igt_crc_to_string(igt_crc_t *crc);
> > +
> > +void igt_require_pipe_crc(int fd);
> > +igt_pipe_crc_t *
> > +igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
> > +igt_pipe_crc_t *
> > +igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
> > +void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc);
> > +void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc);
> > +void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc);
> > +__attribute__((warn_unused_result))
> > +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);
> > +
> > +#endif /* __IGT_CRC_H__ */
> > diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
> > index 80f25c61..e08b7ae8 100644
> > --- a/lib/igt_debugfs.c
> > +++ b/lib/igt_debugfs.c
> > @@ -51,24 +51,6 @@
> >   * basic functions to access debugfs files with e.g. igt_debugfs_open() it also
> >   * provides higher-level wrappers for some debugfs features.
> >   *
> > - * # Pipe CRC Support
> > - *
> > - * This library wraps up the kernel's support for capturing pipe CRCs into a
> > - * neat and tidy package. For the detailed usage see all the functions which
> > - * work on #igt_pipe_crc_t. This is supported on all platforms and outputs.
> > - *
> > - * Actually using pipe CRCs to write modeset tests is a bit tricky though, so
> > - * there is no way to directly check a CRC: Both the details of the plane
> > - * blending, color correction and other hardware and how exactly the CRC is
> > - * computed at each tap point vary by hardware generation and are not disclosed.
> > - *
> > - * The only way to use #igt_crc_t CRCs therefore is to compare CRCs among each
> > - * another either for equality or difference. Otherwise CRCs must be treated as
> > - * completely opaque values. Note that not even CRCs from different pipes or tap
> > - * points on the same platform can be compared. Hence only use
> > - * igt_assert_crc_equal() to inspect CRC values captured by the same
> > - * #igt_pipe_crc_t object.
> > - *
> >   * # Other debugfs interface wrappers
> >   *
> >   * This covers the miscellaneous debugfs interface wrappers:
> > @@ -277,235 +259,6 @@ bool igt_debugfs_search(int device, const char *filename, const char *substring)
> >  	return matched;
> >  }
> >  
> > -/*
> > - * Pipe CRC
> > - */
> > -
> > -/**
> > - * igt_assert_crc_equal:
> > - * @a: first pipe CRC value
> > - * @b: second pipe CRC value
> > - *
> > - * Compares two CRC values and fails the testcase if they don't match with
> > - * igt_fail(). Note that due to CRC collisions CRC based testcase can only
> > - * assert that CRCs match, never that they are different. Otherwise there might
> > - * be random testcase failures when different screen contents end up with the
> > - * same CRC by chance.
> > - */
> > -void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
> > -{
> > -	int i;
> > -
> > -	for (i = 0; i < a->n_words; i++)
> > -		igt_assert_eq_u32(a->crc[i], b->crc[i]);
> > -}
> > -
> > -/**
> > - * igt_crc_to_string:
> > - * @crc: pipe CRC value to print
> > - *
> > - * This formats @crc into a string buffer which is owned by igt_crc_to_string().
> > - * The next call will override the buffer again, which makes this multithreading
> > - * unsafe.
> > - *
> > - * This should only ever be used for diagnostic debug output.
> > - */
> > -char *igt_crc_to_string(igt_crc_t *crc)
> > -{
> > -	int i;
> > -	char buf[128] = { 0 };
> > -
> > -	for (i = 0; i < crc->n_words; i++)
> > -		sprintf(buf + strlen(buf), "%08x ", crc->crc[i]);
> > -
> > -	return strdup(buf);
> > -}
> > -
> > -#define MAX_CRC_ENTRIES 10
> > -#define MAX_LINE_LEN (10 + 11 * MAX_CRC_ENTRIES + 1)
> > -
> > -/* (6 fields, 8 chars each, space separated (5) + '\n') */
> > -#define LEGACY_LINE_LEN       (6 * 8 + 5 + 1)
> > -
> > -struct _igt_pipe_crc {
> > -	int fd;
> > -	int dir;
> > -	int ctl_fd;
> > -	int crc_fd;
> > -	int flags;
> > -	bool is_legacy;
> > -
> > -	enum pipe pipe;
> > -	enum intel_pipe_crc_source source;
> > -};
> > -
> > -static const char *pipe_crc_sources[] = {
> > -	"none",
> > -	"plane1",
> > -	"plane2",
> > -	"pf",
> > -	"pipe",
> > -	"TV",
> > -	"DP-B",
> > -	"DP-C",
> > -	"DP-D",
> > -	"auto"
> > -};
> > -
> > -static const char *pipe_crc_source_name(enum intel_pipe_crc_source source)
> > -{
> > -        return pipe_crc_sources[source];
> > -}
> > -
> > -static bool igt_pipe_crc_do_start(igt_pipe_crc_t *pipe_crc)
> > -{
> > -	char buf[64];
> > -
> > -	/* Stop first just to make sure we don't have lingering state left. */
> > -	igt_pipe_crc_stop(pipe_crc);
> > -
> > -	if (pipe_crc->is_legacy)
> > -		sprintf(buf, "pipe %s %s", kmstest_pipe_name(pipe_crc->pipe),
> > -			pipe_crc_source_name(pipe_crc->source));
> > -	else
> > -		sprintf(buf, "%s", pipe_crc_source_name(pipe_crc->source));
> > -
> > -	igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), strlen(buf));
> > -
> > -	if (!pipe_crc->is_legacy) {
> > -		int err;
> > -
> > -		sprintf(buf, "crtc-%d/crc/data", pipe_crc->pipe);
> > -		err = 0;
> > -
> > -		pipe_crc->crc_fd = openat(pipe_crc->dir, buf, pipe_crc->flags);
> > -		if (pipe_crc->crc_fd < 0)
> > -			err = -errno;
> > -
> > -		if (err == -EINVAL)
> > -			return false;
> > -
> > -		igt_assert_eq(err, 0);
> > -	}
> > -
> > -	errno = 0;
> > -	return true;
> > -}
> > -
> > -static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe)
> > -{
> > -	char buf[32];
> > -
> > -	sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe));
> > -	igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf));
> > -}
> > -
> > -static void igt_pipe_crc_reset(int drm_fd)
> > -{
> > -	struct dirent *dirent;
> > -	const char *cmd = "none";
> > -	bool done = false;
> > -	DIR *dir;
> > -	int fdir;
> > -	int fd;
> > -
> > -	fdir = igt_debugfs_dir(drm_fd);
> > -	if (fdir < 0)
> > -		return;
> > -
> > -	dir = fdopendir(fdir);
> > -	if (!dir) {
> > -		close(fdir);
> > -		return;
> > -	}
> > -
> > -	while ((dirent = readdir(dir))) {
> > -		char buf[128];
> > -
> > -		if (strcmp(dirent->d_name, "crtc-") != 0)
> > -			continue;
> > -
> > -		sprintf(buf, "%s/crc/control", dirent->d_name);
> > -		fd = openat(fdir, buf, O_WRONLY);
> > -		if (fd < 0)
> > -			continue;
> > -
> > -		igt_assert_eq(write(fd, cmd, strlen(cmd)), strlen(cmd));
> > -		close(fd);
> > -
> > -		done = true;
> > -	}
> > -	closedir(dir);
> > -
> > -	if (!done) {
> > -		fd = openat(fdir, "i915_display_crtc_ctl", O_WRONLY);
> > -		if (fd != -1) {
> > -			igt_pipe_crc_pipe_off(fd, PIPE_A);
> > -			igt_pipe_crc_pipe_off(fd, PIPE_B);
> > -			igt_pipe_crc_pipe_off(fd, PIPE_C);
> > -
> > -			close(fd);
> > -		}
> > -	}
> > -
> > -	close(fdir);
> > -}
> > -
> > -static void pipe_crc_exit_handler(int sig)
> > -{
> > -	struct dirent *dirent;
> > -	char buf[128];
> > -	DIR *dir;
> > -	int fd;
> > -
> > -	dir = opendir("/dev/dri");
> > -	if (!dir)
> > -		return;
> > -
> > -	/*
> > -	 * Try to reset CRC capture for all DRM devices, this is only needed
> > -	 * for the legacy CRC ABI and can be completely removed once the
> > -	 * legacy codepaths are removed.
> > -	 */
> > -	while ((dirent = readdir(dir))) {
> > -		if (strncmp(dirent->d_name, "card", 4) != 0)
> > -			continue;
> > -
> > -		sprintf(buf, "/dev/dri/%s", dirent->d_name);
> > -		fd = open(buf, O_WRONLY);
> > -
> > -		igt_pipe_crc_reset(fd);
> > -
> > -		close(fd);
> > -	}
> > -	closedir(dir);
> > -}
> > -
> > -/**
> > - * igt_require_pipe_crc:
> > - *
> > - * Convenience helper to check whether pipe CRC capturing is supported by the
> > - * kernel. Uses igt_skip to automatically skip the test/subtest if this isn't
> > - * the case.
> > - */
> > -void igt_require_pipe_crc(int fd)
> > -{
> > -	const char *cmd = "pipe A none";
> > -	int ctl, written;
> > -
> > -	ctl = igt_debugfs_open(fd, "crtc-0/crc/control", O_RDONLY);
> > -	if (ctl < 0) {
> > -		ctl = igt_debugfs_open(fd, "i915_display_crc_ctl", O_WRONLY);
> > -		igt_require_f(ctl,
> > -			      "No display_crc_ctl found, kernel too old\n");
> > -
> > -		written = write(ctl, cmd, strlen(cmd));
> > -		igt_require_f(written < 0,
> > -			      "CRCs not supported on this platform\n");
> > -	}
> > -	close(ctl);
> > -}
> > -
> >  static void igt_hpd_storm_exit_handler(int sig)
> >  {
> >  	int fd = drm_open_driver_master(DRIVER_INTEL);
> > @@ -627,306 +380,6 @@ void igt_require_hpd_storm_ctl(int drm_fd)
> >  	close(fd);
> >  }
> >  
> > -static igt_pipe_crc_t *
> > -pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source, int flags)
> > -{
> > -	igt_pipe_crc_t *pipe_crc;
> > -	char buf[128];
> > -	int debugfs;
> > -
> > -	debugfs = igt_debugfs_dir(fd);
> > -	igt_assert(debugfs != -1);
> > -
> > -	igt_install_exit_handler(pipe_crc_exit_handler);
> > -
> > -	pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc));
> > -
> > -	sprintf(buf, "crtc-%d/crc/control", pipe);
> > -	pipe_crc->ctl_fd = openat(debugfs, buf, O_WRONLY);
> > -	if (pipe_crc->ctl_fd == -1) {
> > -		pipe_crc->ctl_fd = openat(debugfs,
> > -					  "i915_display_crc_ctl", O_WRONLY);
> > -		igt_assert(pipe_crc->ctl_fd != -1);
> > -		pipe_crc->is_legacy = true;
> > -	}
> > -
> > -	if (pipe_crc->is_legacy) {
> > -		sprintf(buf, "i915_pipe_%s_crc", kmstest_pipe_name(pipe));
> > -		pipe_crc->crc_fd = openat(debugfs, buf, flags);
> > -		igt_assert(pipe_crc->crc_fd != -1);
> > -		igt_debug("Using legacy frame CRC ABI\n");
> > -	} else {
> > -		pipe_crc->crc_fd = -1;
> > -		igt_debug("Using generic frame CRC ABI\n");
> > -	}
> > -
> > -	pipe_crc->fd = fd;
> > -	pipe_crc->dir = debugfs;
> > -	pipe_crc->pipe = pipe;
> > -	pipe_crc->source = source;
> > -	pipe_crc->flags = flags;
> > -
> > -	return pipe_crc;
> > -}
> > -
> > -/**
> > - * igt_pipe_crc_new:
> > - * @pipe: display pipe to use as source
> > - * @source: CRC tap point to use as source
> > - *
> > - * This sets up a new pipe CRC capture object for the given @pipe and @source
> > - * in blocking mode.
> > - *
> > - * Returns: A pipe CRC object for the given @pipe and @source. The library
> > - * assumes that the source is always available since recent kernels support at
> > - * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
> > - */
> > -igt_pipe_crc_t *
> > -igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
> > -{
> > -	return pipe_crc_new(fd, pipe, source, O_RDONLY);
> > -}
> > -
> > -/**
> > - * igt_pipe_crc_new_nonblock:
> > - * @pipe: display pipe to use as source
> > - * @source: CRC tap point to use as source
> > - *
> > - * This sets up a new pipe CRC capture object for the given @pipe and @source
> > - * in nonblocking mode.
> > - *
> > - * Returns: A pipe CRC object for the given @pipe and @source. The library
> > - * assumes that the source is always available since recent kernels support at
> > - * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere.
> > - */
> > -igt_pipe_crc_t *
> > -igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source)
> > -{
> > -	return pipe_crc_new(fd, pipe, source, O_RDONLY | O_NONBLOCK);
> > -}
> > -
> > -/**
> > - * igt_pipe_crc_free:
> > - * @pipe_crc: pipe CRC object
> > - *
> > - * Frees all resources associated with @pipe_crc.
> > - */
> > -void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc)
> > -{
> > -	if (!pipe_crc)
> > -		return;
> > -
> > -	close(pipe_crc->ctl_fd);
> > -	close(pipe_crc->crc_fd);
> > -	close(pipe_crc->dir);
> > -	free(pipe_crc);
> > -}
> > -
> > -static bool pipe_crc_init_from_string(igt_pipe_crc_t *pipe_crc, igt_crc_t *crc,
> > -				      const char *line)
> > -{
> > -	int n, i;
> > -	const char *buf;
> > -
> > -	if (pipe_crc->is_legacy) {
> > -		crc->has_valid_frame = true;
> > -		crc->n_words = 5;
> > -		n = sscanf(line, "%8u %8x %8x %8x %8x %8x", &crc->frame,
> > -			   &crc->crc[0], &crc->crc[1], &crc->crc[2],
> > -			   &crc->crc[3], &crc->crc[4]);
> > -		return n == 6;
> > -	}
> > -
> > -	if (strncmp(line, "XXXXXXXXXX", 10) == 0)
> > -		crc->has_valid_frame = false;
> > -	else {
> > -		crc->has_valid_frame = true;
> > -		crc->frame = strtoul(line, NULL, 16);
> > -	}
> > -
> > -	buf = line + 10;
> > -	for (i = 0; *buf != '\n'; i++, buf += 11)
> > -		crc->crc[i] = strtoul(buf, NULL, 16);
> > -
> > -	crc->n_words = i;
> > -
> > -	return true;
> > -}
> > -
> > -static int read_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
> > -{
> > -	ssize_t bytes_read;
> > -	char buf[MAX_LINE_LEN + 1];
> > -	size_t read_len;
> > -
> > -	if (pipe_crc->is_legacy)
> > -		read_len = LEGACY_LINE_LEN;
> > -	else
> > -		read_len = MAX_LINE_LEN;
> > -
> > -	igt_set_timeout(5, "CRC reading");
> > -	bytes_read = read(pipe_crc->crc_fd, &buf, read_len);
> > -	igt_reset_timeout();
> > -
> > -	if (bytes_read < 0 && errno == EAGAIN)
> > -		igt_assert(pipe_crc->flags & O_NONBLOCK);
> > -
> > -	if (bytes_read < 0)
> > -		bytes_read = 0;
> > -
> > -	buf[bytes_read] = '\0';
> > -
> > -	if (bytes_read && !pipe_crc_init_from_string(pipe_crc, out, buf))
> > -		return -EINVAL;
> > -
> > -	return bytes_read;
> > -}
> > -
> > -static void read_one_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out)
> > -{
> > -	while (read_crc(pipe_crc, out) == 0)
> > -		usleep(1000);
> > -}
> > -
> > -/**
> > - * igt_pipe_crc_start:
> > - * @pipe_crc: pipe CRC object
> > - *
> > - * Starts the CRC capture process on @pipe_crc.
> > - */
> > -void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc)
> > -{
> > -	igt_crc_t crc;
> > -
> > -	igt_assert(igt_pipe_crc_do_start(pipe_crc));
> > -
> > -	if (pipe_crc->is_legacy) {
> > -		/*
> > -		 * For some no yet identified reason, the first CRC is
> > -		 * bonkers. So let's just wait for the next vblank and read
> > -		 * out the buggy result.
> > -		 *
> > -		 * On CHV sometimes the second CRC is bonkers as well, so
> > -		 * don't trust that one either.
> > -		 */
> > -		read_one_crc(pipe_crc, &crc);
> > -		read_one_crc(pipe_crc, &crc);
> > -	}
> > -}
> > -
> > -/**
> > - * igt_pipe_crc_stop:
> > - * @pipe_crc: pipe CRC object
> > - *
> > - * Stops the CRC capture process on @pipe_crc.
> > - */
> > -void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc)
> > -{
> > -	char buf[32];
> > -
> > -	if (pipe_crc->is_legacy) {
> > -		sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe_crc->pipe));
> > -		igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)),
> > -			      strlen(buf));
> > -	} else {
> > -		close(pipe_crc->crc_fd);
> > -		pipe_crc->crc_fd = -1;
> > -	}
> > -}
> > -
> > -/**
> > - * igt_pipe_crc_get_crcs:
> > - * @pipe_crc: pipe CRC object
> > - * @n_crcs: number of CRCs to capture
> > - * @out_crcs: buffer pointer for the captured CRC values
> > - *
> > - * Read up to @n_crcs from @pipe_crc. This function does not block, and will
> > - * return early if not enough CRCs can be captured, if @pipe_crc has been
> > - * opened using igt_pipe_crc_new_nonblock(). It will block until @n_crcs are
> > - * retrieved if @pipe_crc has been opened using igt_pipe_crc_new(). @out_crcs is
> > - * alloced by this function and must be released with free() by the caller.
> > - *
> > - * Callers must start and stop the capturing themselves by calling
> > - * igt_pipe_crc_start() and igt_pipe_crc_stop(). For one-shot CRC collecting
> > - * look at igt_pipe_crc_collect_crc().
> > - *
> > - * Returns:
> > - * The number of CRCs captured. Should be equal to @n_crcs in blocking mode, but
> > - * can be less (even zero) in non-blocking mode.
> > - */
> > -int
> > -igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
> > -		      igt_crc_t **out_crcs)
> > -{
> > -	igt_crc_t *crcs;
> > -	int n = 0;
> > -
> > -	crcs = calloc(n_crcs, sizeof(igt_crc_t));
> > -
> > -	do {
> > -		igt_crc_t *crc = &crcs[n];
> > -		int ret;
> > -
> > -		ret = read_crc(pipe_crc, crc);
> > -		if (ret < 0)
> > -			continue;
> > -		if (ret == 0)
> > -			break;
> > -
> > -		n++;
> > -	} while (n < n_crcs);
> > -
> > -	*out_crcs = crcs;
> > -	return n;
> > -}
> > -
> > -static void crc_sanity_checks(igt_crc_t *crc)
> > -{
> > -	int i;
> > -	bool all_zero = true;
> > -
> > -	for (i = 0; i < crc->n_words; i++) {
> > -		igt_warn_on_f(crc->crc[i] == 0xffffffff,
> > -			      "Suspicious CRC: it looks like the CRC "
> > -			      "read back was from a register in a powered "
> > -			      "down well\n");
> > -		if (crc->crc[i])
> > -			all_zero = false;
> > -	}
> > -
> > -	igt_warn_on_f(all_zero, "Suspicious CRC: All values are 0.\n");
> > -}
> > -
> > -/**
> > - * igt_pipe_crc_collect_crc:
> > - * @pipe_crc: pipe CRC object
> > - * @out_crc: buffer for the captured CRC values
> > - *
> > - * Read a single CRC from @pipe_crc. This function blocks until the CRC is
> > - * retrieved, irrespective of whether @pipe_crc has been opened with
> > - * igt_pipe_crc_new() or igt_pipe_crc_new_nonblock().  @out_crc must be
> > - * allocated by the caller.
> > - *
> > - * This function takes care of the pipe_crc book-keeping, it will start/stop
> > - * the collection of the CRC.
> > - *
> > - * This function also calls the interactive debug with the "crc" domain, so you
> > - * can make use of this feature to actually see the screen that is being CRC'd.
> > - *
> > - * For continuous CRC collection look at igt_pipe_crc_start(),
> > - * igt_pipe_crc_get_crcs() and igt_pipe_crc_stop().
> > - */
> > -void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc)
> > -{
> > -	igt_debug_wait_for_keypress("crc");
> > -
> > -	igt_pipe_crc_start(pipe_crc);
> > -	read_one_crc(pipe_crc, out_crc);
> > -	igt_pipe_crc_stop(pipe_crc);
> > -
> > -	crc_sanity_checks(out_crc);
> > -}
> > -
> >  /*
> >   * Drop caches
> >   */
> > diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
> > index 7b846a83..01a5ee07 100644
> > --- a/lib/igt_debugfs.h
> > +++ b/lib/igt_debugfs.h
> > @@ -29,8 +29,6 @@
> >  #include <stdint.h>
> >  #include <stdio.h>
> >  
> > -enum pipe;
> > -
> >  const char *igt_debugfs_mount(void);
> >  
> >  int igt_debugfs_dir(int device);
> > @@ -50,85 +48,6 @@ bool igt_debugfs_search(int fd, const char *filename, const char *substring);
> >  #define igt_debugfs_read(fd, filename, buf) \
> >  		__igt_debugfs_read(fd, (filename), (buf), sizeof(buf))
> >  
> > -/*
> > - * Pipe CRC
> > - */
> > -
> > -/**
> > - * igt_pipe_crc_t:
> > - *
> > - * Pipe CRC support structure. Needs to be allocated and set up with
> > - * igt_pipe_crc_new() for a specific pipe and pipe CRC source value.
> > - */
> > -typedef struct _igt_pipe_crc igt_pipe_crc_t;
> > -
> > -#define DRM_MAX_CRC_NR 10
> > -/**
> > - * igt_crc_t:
> > - * @frame: frame number of the capture CRC
> > - * @n_words: internal field, don't access
> > - * @crc: internal field, don't access
> > - *
> > - * Pipe CRC value. All other members than @frame are private and should not be
> > - * inspected by testcases.
> > - */
> > -typedef struct {
> > -	uint32_t frame;
> > -	bool has_valid_frame;
> > -	int n_words;
> > -	uint32_t crc[DRM_MAX_CRC_NR];
> > -} igt_crc_t;
> > -
> > -/**
> > - * intel_pipe_crc_source:
> > - * @INTEL_PIPE_CRC_SOURCE_NONE: No source
> > - * @INTEL_PIPE_CRC_SOURCE_PLANE1: Plane 1
> > - * @INTEL_PIPE_CRC_SOURCE_PLANE2: Plane 2
> > - * @INTEL_PIPE_CRC_SOURCE_PF: Panel Filter
> > - * @INTEL_PIPE_CRC_SOURCE_PIPE: Pipe
> > - * @INTEL_PIPE_CRC_SOURCE_TV: TV
> > - * @INTEL_PIPE_CRC_SOURCE_DP_B: DisplayPort B
> > - * @INTEL_PIPE_CRC_SOURCE_DP_C: DisplayPort C
> > - * @INTEL_PIPE_CRC_SOURCE_DP_D: DisplayPort D
> > - * @INTEL_PIPE_CRC_SOURCE_AUTO: Automatic source selection
> > - * @INTEL_PIPE_CRC_SOURCE_MAX: Number of available sources
> > - *
> > - * Enumeration of all supported pipe CRC sources. Not all platforms and all
> > - * outputs support all of them. Generic tests should just use
> > - * INTEL_PIPE_CRC_SOURCE_AUTO. It should always map to an end-of-pipe CRC
> > - * suitable for checking planes, cursor, color correction and any other
> > - * output-agnostic features.
> > - */
> > -enum intel_pipe_crc_source {
> > -        INTEL_PIPE_CRC_SOURCE_NONE,
> > -        INTEL_PIPE_CRC_SOURCE_PLANE1,
> > -        INTEL_PIPE_CRC_SOURCE_PLANE2,
> > -        INTEL_PIPE_CRC_SOURCE_PF,
> > -        INTEL_PIPE_CRC_SOURCE_PIPE,
> > -        INTEL_PIPE_CRC_SOURCE_TV,
> > -        INTEL_PIPE_CRC_SOURCE_DP_B,
> > -        INTEL_PIPE_CRC_SOURCE_DP_C,
> > -        INTEL_PIPE_CRC_SOURCE_DP_D,
> > -        INTEL_PIPE_CRC_SOURCE_AUTO,
> > -        INTEL_PIPE_CRC_SOURCE_MAX,
> > -};
> > -
> > -void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
> > -char *igt_crc_to_string(igt_crc_t *crc);
> > -
> > -void igt_require_pipe_crc(int fd);
> > -igt_pipe_crc_t *
> > -igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
> > -igt_pipe_crc_t *
> > -igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source);
> > -void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc);
> > -void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc);
> > -void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc);
> > -__attribute__((warn_unused_result))
> > -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(int fd, unsigned int threshold);
> >  void igt_hpd_storm_reset(int fd);
> >  bool igt_hpd_storm_detected(int fd);
> > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > index b412c6a7..9b0424d1 100644
> > --- a/tests/chamelium.c
> > +++ b/tests/chamelium.c
> > @@ -26,6 +26,7 @@
> >  
> >  #include "config.h"
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  
> >  #include <fcntl.h>
> >  #include <string.h>
> > diff --git a/tests/kms_atomic_transition.c b/tests/kms_atomic_transition.c
> > index ba5cd4d6..37de838f 100644
> > --- a/tests/kms_atomic_transition.c
> > +++ b/tests/kms_atomic_transition.c
> > @@ -22,6 +22,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include "drmtest.h"
> >  #include "sw_sync.h"
> >  #include <errno.h>
> > diff --git a/tests/kms_ccs.c b/tests/kms_ccs.c
> > index 29d676af..66bd0f29 100644
> > --- a/tests/kms_ccs.c
> > +++ b/tests/kms_ccs.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  
> >  IGT_TEST_DESCRIPTION("Test render compression (RC), in which the main surface "
> >  		     "is complemented by a color control surface (CCS) that "
> > diff --git a/tests/kms_chv_cursor_fail.c b/tests/kms_chv_cursor_fail.c
> > index 3e74df11..b02958bd 100644
> > --- a/tests/kms_chv_cursor_fail.c
> > +++ b/tests/kms_chv_cursor_fail.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <errno.h>
> >  #include <limits.h>
> >  #include <stdbool.h>
> > diff --git a/tests/kms_crtc_background_color.c b/tests/kms_crtc_background_color.c
> > index e12e1634..3bcabcac 100644
> > --- a/tests/kms_crtc_background_color.c
> > +++ b/tests/kms_crtc_background_color.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <math.h>
> >  
> >  
> > diff --git a/tests/kms_cursor_crc.c b/tests/kms_cursor_crc.c
> > index 4c5e00c0..4693e9f4 100644
> > --- a/tests/kms_cursor_crc.c
> > +++ b/tests/kms_cursor_crc.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <errno.h>
> >  #include <limits.h>
> >  #include <stdbool.h>
> > diff --git a/tests/kms_cursor_legacy.c b/tests/kms_cursor_legacy.c
> > index 8180b043..505e3f9d 100644
> > --- a/tests/kms_cursor_legacy.c
> > +++ b/tests/kms_cursor_legacy.c
> > @@ -27,6 +27,7 @@
> >  #include <sys/poll.h>
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include "igt_rand.h"
> >  #include "igt_stats.h"
> >  
> > diff --git a/tests/kms_draw_crc.c b/tests/kms_draw_crc.c
> > index c57d3a35..8cb4e147 100644
> > --- a/tests/kms_draw_crc.c
> > +++ b/tests/kms_draw_crc.c
> > @@ -25,6 +25,7 @@
> >  /* This program tests whether the igt_draw library actually works. */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  
> >  #define MAX_CONNECTORS 32
> >  
> > diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c
> > index 7964e052..10656b89 100644
> > --- a/tests/kms_fbc_crc.c
> > +++ b/tests/kms_fbc_crc.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <errno.h>
> >  #include <stdbool.h>
> >  #include <stdio.h>
> > diff --git a/tests/kms_flip_tiling.c b/tests/kms_flip_tiling.c
> > index 5aae29a8..8e1a2fb4 100644
> > --- a/tests/kms_flip_tiling.c
> > +++ b/tests/kms_flip_tiling.c
> > @@ -25,6 +25,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <errno.h>
> >  #include <stdbool.h>
> >  #include <stdio.h>
> > diff --git a/tests/kms_frontbuffer_tracking.c b/tests/kms_frontbuffer_tracking.c
> > index c24e4a81..4af5e006 100644
> > --- a/tests/kms_frontbuffer_tracking.c
> > +++ b/tests/kms_frontbuffer_tracking.c
> > @@ -25,6 +25,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include "igt_sysfs.h"
> >  #include <sys/types.h>
> >  #include <sys/stat.h>
> > diff --git a/tests/kms_mmap_write_crc.c b/tests/kms_mmap_write_crc.c
> > index e5f089f6..79efa792 100644
> > --- a/tests/kms_mmap_write_crc.c
> > +++ b/tests/kms_mmap_write_crc.c
> > @@ -31,6 +31,7 @@
> >  #include <string.h>
> >  
> >  #include "drmtest.h"
> > +#include "igt_crc.h"
> >  #include "igt_debugfs.h"
> >  #include "igt_kms.h"
> >  #include "intel_chipset.h"
> > diff --git a/tests/kms_mmio_vs_cs_flip.c b/tests/kms_mmio_vs_cs_flip.c
> > index fa947d9c..ee1d202a 100644
> > --- a/tests/kms_mmio_vs_cs_flip.c
> > +++ b/tests/kms_mmio_vs_cs_flip.c
> > @@ -22,6 +22,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <errno.h>
> >  #include <stdbool.h>
> >  #include <stdio.h>
> > diff --git a/tests/kms_pipe_color.c b/tests/kms_pipe_color.c
> > index a3100fae..389fb3de 100644
> > --- a/tests/kms_pipe_color.c
> > +++ b/tests/kms_pipe_color.c
> > @@ -28,6 +28,7 @@
> >  #include "drm.h"
> >  #include "drmtest.h"
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  
> >  IGT_TEST_DESCRIPTION("Test Color Features at Pipe level");
> >  
> > diff --git a/tests/kms_pipe_crc_basic.c b/tests/kms_pipe_crc_basic.c
> > index 35adddba..38da3a42 100644
> > --- a/tests/kms_pipe_crc_basic.c
> > +++ b/tests/kms_pipe_crc_basic.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include "igt_sysfs.h"
> >  #include <errno.h>
> >  #include <stdbool.h>
> > diff --git a/tests/kms_plane.c b/tests/kms_plane.c
> > index 1d92a62b..2fa58e8f 100644
> > --- a/tests/kms_plane.c
> > +++ b/tests/kms_plane.c
> > @@ -25,6 +25,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <errno.h>
> >  #include <stdbool.h>
> >  #include <stdio.h>
> > diff --git a/tests/kms_plane_lowres.c b/tests/kms_plane_lowres.c
> > index ee39759c..a4e37275 100644
> > --- a/tests/kms_plane_lowres.c
> > +++ b/tests/kms_plane_lowres.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include "drmtest.h"
> >  #include <errno.h>
> >  #include <stdbool.h>
> > diff --git a/tests/kms_plane_multiple.c b/tests/kms_plane_multiple.c
> > index f6c62235..1b60a067 100644
> > --- a/tests/kms_plane_multiple.c
> > +++ b/tests/kms_plane_multiple.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include "drmtest.h"
> >  #include <errno.h>
> >  #include <stdbool.h>
> > diff --git a/tests/kms_plane_scaling.c b/tests/kms_plane_scaling.c
> > index 1457894a..d554f27f 100644
> > --- a/tests/kms_plane_scaling.c
> > +++ b/tests/kms_plane_scaling.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <math.h>
> >  
> >  
> > diff --git a/tests/kms_pwrite_crc.c b/tests/kms_pwrite_crc.c
> > index ee895db6..f1e6f023 100644
> > --- a/tests/kms_pwrite_crc.c
> > +++ b/tests/kms_pwrite_crc.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <errno.h>
> >  #include <limits.h>
> >  #include <stdbool.h>
> > diff --git a/tests/kms_rotation_crc.c b/tests/kms_rotation_crc.c
> > index 83e37f12..fa361100 100644
> > --- a/tests/kms_rotation_crc.c
> > +++ b/tests/kms_rotation_crc.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <math.h>
> >  
> >  #define MAX_FENCES 32
> > diff --git a/tests/kms_universal_plane.c b/tests/kms_universal_plane.c
> > index 31f07804..14300b7a 100644
> > --- a/tests/kms_universal_plane.c
> > +++ b/tests/kms_universal_plane.c
> > @@ -22,6 +22,7 @@
> >   */
> >  
> >  #include "igt.h"
> > +#include "igt_crc.h"
> >  #include <errno.h>
> >  #include <stdbool.h>
> >  #include <stdio.h>
> > diff --git a/tools/intel_display_crc.c b/tools/intel_display_crc.c
> > index d1b28ea7..104f432f 100644
> > --- a/tools/intel_display_crc.c
> > +++ b/tools/intel_display_crc.c
> > @@ -30,6 +30,7 @@
> >  #include <unistd.h>
> >  
> >  #include "igt_core.h"
> > +#include "igt_crc.h"
> >  #include "igt_debugfs.h"
> >  #include "igt_kms.h"
> >  
> > -- 
> > 2.13.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

end of thread, other threads:[~2017-07-17 15:06 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-06 16:14 [PATCH i-g-t 0/7] igt: Add support for testing writeback connectors Liviu Dudau
2017-07-06 16:14 ` [PATCH i-g-t 1/7] igt: lib/igt_crc: Split out CRC functionality Liviu Dudau
2017-07-17 13:50   ` Arkadiusz Hiler
2017-07-17 15:06     ` Liviu Dudau
2017-07-06 16:14 ` [PATCH i-g-t 2/7] lib/igt_kms: Add writeback support in lib/ Liviu Dudau
2017-07-06 16:14 ` [PATCH i-g-t 3/7] kms_writeback: Add initial writeback tests Liviu Dudau
2017-07-06 16:14 ` [PATCH i-g-t 4/7] lib: Add function to hash a framebuffer Liviu Dudau
2017-07-06 16:14 ` [PATCH i-g-t 5/7] kms_writeback: Add writeback-check-output Liviu Dudau
2017-07-06 16:14 ` [PATCH i-g-t 6/7] lib/igt_kms: Add igt_output_clone_pipe for cloning Liviu Dudau
2017-07-06 16:14 ` [PATCH i-g-t 7/7] kms_writeback: Add tests using a cloned output Liviu Dudau

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.