Message ID | 20170706161424.30173-2-liviu.dudau@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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.
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
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"