[Intel-gfx] [PATCH 2/2] tests: add kms_edp_vdd_race

Paulo Zanoni przanoni at gmail.com
Mon Nov 11 19:25:36 CET 2013


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

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

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



-- 
Paulo Zanoni



More information about the Intel-gfx mailing list