mirror of
https://github.com/tiagovignatti/intel-gpu-tools.git
synced 2025-06-20 14:26:17 +00:00
debugfs_pipe_crc: Let's check CRCs!
Let's add a new test that sets a mode, wait for a few vblanks (3) and then make sure we read 3 identical CRCs. Some subtests check for various parsing errors. In the process, improve the debugfs helpers to deal with CRCs. Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
This commit is contained in:
parent
f673775fe8
commit
4ba97ddf96
@ -28,7 +28,10 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "drmtest.h"
|
||||
#include "igt_display.h"
|
||||
#include "igt_debugfs.h"
|
||||
|
||||
int igt_debugfs_init(igt_debugfs_t *debugfs)
|
||||
@ -82,3 +85,199 @@ FILE *igt_debugfs_fopen(igt_debugfs_t *debugfs, const char *filename,
|
||||
sprintf(buf, "%s/%s", debugfs->dri_path, filename);
|
||||
return fopen(buf, mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pipe CRC
|
||||
*/
|
||||
|
||||
bool igt_crc_is_null(igt_crc_t *crc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < crc->n_words; i++)
|
||||
if (crc->crc[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igt_crc_equal(igt_crc_t *a, igt_crc_t *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (a->n_words != b->n_words)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < a->n_words; i++)
|
||||
if (a->crc[i] != b->crc[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *igt_crc_to_string(igt_crc_t *crc)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
if (crc->n_words == 5)
|
||||
sprintf(buf, "%08x %08x %08x %08x %08x", crc->crc[0],
|
||||
crc->crc[1], crc->crc[2], crc->crc[3], crc->crc[4]);
|
||||
else
|
||||
igt_assert(0);
|
||||
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
/* (6 fields, 8 chars each, space separated (5) + '\n') */
|
||||
#define PIPE_CRC_LINE_LEN (6 * 8 + 5 + 1)
|
||||
/* account for \'0' */
|
||||
#define PIPE_CRC_BUFFER_LEN (PIPE_CRC_LINE_LEN + 1)
|
||||
|
||||
struct _igt_pipe_crc {
|
||||
int drm_fd;
|
||||
|
||||
int ctl_fd;
|
||||
int crc_fd;
|
||||
int line_len;
|
||||
int buffer_len;
|
||||
|
||||
enum pipe pipe;
|
||||
enum intel_pipe_crc_source source;
|
||||
};
|
||||
|
||||
igt_pipe_crc_t *
|
||||
igt_pipe_crc_new(igt_debugfs_t *debugfs, int drm_fd, enum pipe pipe,
|
||||
enum intel_pipe_crc_source source)
|
||||
{
|
||||
igt_pipe_crc_t *pipe_crc;
|
||||
char buf[128];
|
||||
|
||||
pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc));
|
||||
|
||||
pipe_crc->ctl_fd = igt_debugfs_open(debugfs,
|
||||
"i915_display_crc_ctl", O_WRONLY);
|
||||
igt_assert(pipe_crc->crc_fd != -1);
|
||||
|
||||
sprintf(buf, "i915_pipe_%c_crc", pipe_name(pipe));
|
||||
pipe_crc->crc_fd = igt_debugfs_open(debugfs, buf, O_RDONLY);
|
||||
igt_assert(pipe_crc->crc_fd != -1);
|
||||
|
||||
pipe_crc->line_len = PIPE_CRC_LINE_LEN;
|
||||
pipe_crc->buffer_len = PIPE_CRC_BUFFER_LEN;
|
||||
pipe_crc->drm_fd = drm_fd;
|
||||
pipe_crc->pipe = pipe;
|
||||
pipe_crc->source = source;
|
||||
|
||||
return pipe_crc;
|
||||
}
|
||||
|
||||
static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
sprintf(buf, "pipe %c none", pipe_name(pipe));
|
||||
write(fd, buf, strlen(buf));
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn off everything
|
||||
*/
|
||||
void igt_pipe_crc_reset(void)
|
||||
{
|
||||
igt_debugfs_t debugfs;
|
||||
int fd;
|
||||
|
||||
igt_debugfs_init(&debugfs);
|
||||
fd = igt_debugfs_open(&debugfs, "i915_display_crc_ctl", O_WRONLY);
|
||||
|
||||
igt_pipe_crc_pipe_off(fd, PIPE_A);
|
||||
igt_pipe_crc_pipe_off(fd, PIPE_B);
|
||||
igt_pipe_crc_pipe_off(fd, PIPE_C);
|
||||
}
|
||||
|
||||
void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc)
|
||||
{
|
||||
close(pipe_crc->ctl_fd);
|
||||
close(pipe_crc->crc_fd);
|
||||
free(pipe_crc);
|
||||
}
|
||||
|
||||
static const char *pipe_crc_sources[] = {
|
||||
"none",
|
||||
"plane1",
|
||||
"plane2",
|
||||
"pf",
|
||||
};
|
||||
|
||||
static const char *pipe_crc_source_name(enum intel_pipe_crc_source source)
|
||||
{
|
||||
return pipe_crc_sources[source];
|
||||
}
|
||||
|
||||
void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc)
|
||||
{
|
||||
char buf[64];
|
||||
igt_crc_t *crcs = NULL;
|
||||
|
||||
igt_wait_for_vblank(pipe_crc->drm_fd, pipe_crc->pipe);
|
||||
|
||||
sprintf(buf, "pipe %c %s", pipe_name(pipe_crc->pipe),
|
||||
pipe_crc_source_name(pipe_crc->source));
|
||||
write(pipe_crc->ctl_fd, buf, strlen(buf));
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
|
||||
free(crcs);
|
||||
}
|
||||
|
||||
void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
sprintf(buf, "pipe %c none", pipe_name(pipe_crc->pipe));
|
||||
write(pipe_crc->ctl_fd, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static bool pipe_crc_init_from_string(igt_crc_t *crc, const char *line)
|
||||
{
|
||||
int n;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read @n_crcs from the @pipe_crc. This function blocks until @n_crcs are
|
||||
* retrieved.
|
||||
*/
|
||||
void
|
||||
igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
|
||||
igt_crc_t **out_crcs)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
igt_crc_t *crcs;
|
||||
char buf[pipe_crc->buffer_len];
|
||||
int n = 0;
|
||||
|
||||
crcs = calloc(n_crcs, sizeof(igt_crc_t));
|
||||
|
||||
do {
|
||||
igt_crc_t *crc = &crcs[n];
|
||||
|
||||
bytes_read = read(pipe_crc->crc_fd, &buf, pipe_crc->line_len);
|
||||
igt_assert_cmpint(bytes_read, ==, pipe_crc->line_len);
|
||||
buf[bytes_read] = '\0';
|
||||
|
||||
if (!pipe_crc_init_from_string(crc, buf))
|
||||
continue;
|
||||
|
||||
n++;
|
||||
} while (n < n_crcs);
|
||||
|
||||
*out_crcs = crcs;
|
||||
}
|
||||
|
@ -25,8 +25,12 @@
|
||||
#ifndef __IGT_DEBUGFS_H__
|
||||
#define __IGT_DEBUGFS_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "igt_display.h"
|
||||
|
||||
typedef struct {
|
||||
char root[128];
|
||||
char dri_path[128];
|
||||
@ -37,4 +41,37 @@ int igt_debugfs_open(igt_debugfs_t *debugfs, const char *filename, int mode);
|
||||
FILE *igt_debugfs_fopen(igt_debugfs_t *debugfs, const char *filename,
|
||||
const char *mode);
|
||||
|
||||
/*
|
||||
* Pipe CRC
|
||||
*/
|
||||
|
||||
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_MAX,
|
||||
};
|
||||
|
||||
typedef struct _igt_pipe_crc igt_pipe_crc_t;
|
||||
typedef struct {
|
||||
uint32_t frame;
|
||||
int n_words;
|
||||
uint32_t crc[5];
|
||||
} igt_crc_t;
|
||||
|
||||
bool igt_crc_is_null(igt_crc_t *crc);
|
||||
bool igt_crc_equal(igt_crc_t *a, igt_crc_t *b);
|
||||
char *igt_crc_to_string(igt_crc_t *crc);
|
||||
|
||||
igt_pipe_crc_t *
|
||||
igt_pipe_crc_new(igt_debugfs_t *debugfs, int drm_fd, enum pipe pipe,
|
||||
enum intel_pipe_crc_source source);
|
||||
void igt_pipe_crc_reset(void);
|
||||
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);
|
||||
void igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs,
|
||||
igt_crc_t **out_crcs);
|
||||
|
||||
#endif /* __IGT_DEBUGFS_H__ */
|
||||
|
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
# Please keep sorted alphabetically
|
||||
ddi_compute_wrpll
|
||||
debugfs_pipe_crc
|
||||
drm_get_client_auth
|
||||
drm_vma_limiter
|
||||
drm_vma_limiter_cached
|
||||
|
@ -17,6 +17,7 @@ NOUVEAU_TESTS_M = \
|
||||
endif
|
||||
|
||||
TESTS_progs_M = \
|
||||
debugfs_pipe_crc \
|
||||
gem_basic \
|
||||
gem_caching \
|
||||
gem_concurrent_blit \
|
||||
|
237
tests/debugfs_pipe_crc.c
Normal file
237
tests/debugfs_pipe_crc.c
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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 <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "drmtest.h"
|
||||
#include "igt_debugfs.h"
|
||||
|
||||
typedef struct {
|
||||
struct kmstest_connector_config config;
|
||||
drmModeModeInfo mode;
|
||||
struct kmstest_fb fb;
|
||||
bool valid;
|
||||
} connector_t;
|
||||
|
||||
typedef struct {
|
||||
int drm_fd;
|
||||
igt_debugfs_t debugfs;
|
||||
drmModeRes *resources;
|
||||
int n_connectors;
|
||||
connector_t *connectors;
|
||||
FILE *ctl;
|
||||
} data_t;
|
||||
|
||||
static void test_bad_command(data_t *data, const char *cmd)
|
||||
{
|
||||
size_t written;
|
||||
|
||||
written = fwrite(cmd, 1, strlen(cmd), data->ctl);
|
||||
fflush(data->ctl);
|
||||
igt_assert_cmpint(written, ==, (strlen(cmd)));
|
||||
igt_assert(ferror(data->ctl));
|
||||
igt_assert_cmpint(errno, ==, EINVAL);
|
||||
}
|
||||
|
||||
static void connector_init(data_t *data, connector_t *connector, uint32_t id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = kmstest_get_connector_config(data->drm_fd, id, -1UL,
|
||||
&connector->config);
|
||||
if (ret == 0)
|
||||
connector->valid = true;
|
||||
|
||||
}
|
||||
|
||||
static void connector_fini(connector_t *connector)
|
||||
{
|
||||
kmstest_free_connector_config(&connector->config);
|
||||
}
|
||||
|
||||
static bool
|
||||
connector_set_mode(data_t *data, connector_t *connector, drmModeModeInfo *mode)
|
||||
{
|
||||
struct kmstest_connector_config *config = &connector->config;
|
||||
unsigned int fb_id;
|
||||
cairo_t *cr;
|
||||
int ret;
|
||||
|
||||
fb_id = kmstest_create_fb(data->drm_fd,
|
||||
mode->hdisplay, mode->vdisplay,
|
||||
32 /* bpp */, 24 /* depth */,
|
||||
false /* tiling */,
|
||||
&connector->fb);
|
||||
igt_assert(fb_id);
|
||||
|
||||
cr = kmstest_get_cairo_ctx(data->drm_fd, &connector->fb);
|
||||
kmstest_paint_color(cr, 0, 0, mode->hdisplay, mode->vdisplay,
|
||||
0.0, 1.0, 0.0);
|
||||
igt_assert(cairo_status(cr) == 0);
|
||||
|
||||
#if 0
|
||||
fprintf(stdout, "Using pipe %c, %dx%d\n", pipe_name(config->pipe),
|
||||
mode->hdisplay, mode->vdisplay);
|
||||
#endif
|
||||
|
||||
ret = drmModeSetCrtc(data->drm_fd,
|
||||
config->crtc->crtc_id,
|
||||
connector->fb.fb_id,
|
||||
0, 0, /* x, y */
|
||||
&config->connector->connector_id,
|
||||
1,
|
||||
mode);
|
||||
igt_assert(ret == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void display_init(data_t *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
data->resources = drmModeGetResources(data->drm_fd);
|
||||
igt_assert(data->resources);
|
||||
|
||||
data->n_connectors = data->resources->count_connectors;
|
||||
data->connectors = calloc(data->n_connectors, sizeof(connector_t));
|
||||
igt_assert(data->connectors);
|
||||
|
||||
for (i = 0; i < data->n_connectors; i++) {
|
||||
uint32_t id = data->resources->connectors[i];
|
||||
|
||||
connector_init(data, &data->connectors[i], id);
|
||||
}
|
||||
}
|
||||
|
||||
static void display_fini(data_t *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < data->n_connectors; i++)
|
||||
connector_fini(&data->connectors[i]);
|
||||
free(data->connectors);
|
||||
|
||||
drmModeFreeResources(data->resources);
|
||||
}
|
||||
|
||||
static connector_t *
|
||||
display_find_first_valid_connector(data_t *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < data->n_connectors; i++) {
|
||||
connector_t *connector = &data->connectors[i];
|
||||
|
||||
if (connector->valid)
|
||||
return connector;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_read_crc(data_t *data)
|
||||
{
|
||||
connector_t *connector;
|
||||
igt_pipe_crc_t *pipe_crc;
|
||||
igt_crc_t *crcs = NULL;
|
||||
|
||||
connector = display_find_first_valid_connector(data);
|
||||
if (!connector)
|
||||
igt_skip("Could not find a valid connector \n");
|
||||
|
||||
pipe_crc = igt_pipe_crc_new(&data->debugfs, data->drm_fd,
|
||||
connector->config.pipe,
|
||||
INTEL_PIPE_CRC_SOURCE_PLANE1);
|
||||
|
||||
connector_set_mode(data, connector, &connector->config.default_mode);
|
||||
|
||||
igt_pipe_crc_start(pipe_crc);
|
||||
|
||||
/* wait for 3 vblanks and the corresponding 3 CRCs */
|
||||
igt_pipe_crc_get_crcs(pipe_crc, 3, &crcs);
|
||||
|
||||
igt_pipe_crc_stop(pipe_crc);
|
||||
|
||||
/* and ensure that they'are all equal, we haven't changed the fb */
|
||||
igt_assert(igt_crc_equal(&crcs[0], &crcs[1]));
|
||||
igt_assert(igt_crc_equal(&crcs[1], &crcs[2]));
|
||||
|
||||
free(crcs);
|
||||
igt_pipe_crc_free(pipe_crc);
|
||||
}
|
||||
|
||||
static void exit_handler(int sig)
|
||||
{
|
||||
igt_pipe_crc_reset();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
data_t data = {0, };
|
||||
|
||||
igt_subtest_init(argc, argv);
|
||||
|
||||
igt_fixture {
|
||||
data.drm_fd = drm_open_any();
|
||||
do_or_die(igt_set_vt_graphics_mode());
|
||||
do_or_die(igt_install_exit_handler(exit_handler));
|
||||
|
||||
display_init(&data);
|
||||
|
||||
igt_debugfs_init(&data.debugfs);
|
||||
data.ctl = igt_debugfs_fopen(&data.debugfs,
|
||||
"i915_display_crc_ctl", "r+");
|
||||
if (!data.ctl)
|
||||
igt_skip("No display_crc_ctl found, kernel too old\n");
|
||||
}
|
||||
|
||||
igt_subtest("bad-pipe")
|
||||
test_bad_command(&data, "pipe D none");
|
||||
|
||||
igt_subtest("bad-source")
|
||||
test_bad_command(&data, "pipe A foo");
|
||||
|
||||
igt_subtest("bad-nb-words-1")
|
||||
test_bad_command(&data, "pipe foo");
|
||||
|
||||
igt_subtest("bad-nb-words-3")
|
||||
test_bad_command(&data, "pipe A none option");
|
||||
|
||||
igt_subtest("read-crc")
|
||||
test_read_crc(&data);
|
||||
|
||||
igt_fixture {
|
||||
igt_pipe_crc_reset();
|
||||
display_fini(&data);
|
||||
fclose(data.ctl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user