Em Qua, 2017-06-21 às 13:40 +0530, Lohith BS escreveu: > Idleness DRRS: > By default the DRRS state will be at DRRS_HIGH_RR. When a > Display > content is Idle for more than 1Sec Idleness will be declared > and > DRRS_LOW_RR will be invoked, changing the refresh rate to the > lower most refresh rate supported by the panel. As soon as > there > is a display content change there will be a DRRS state > transition > as DRRS_LOW_RR--> DRRS_HIGH_RR, changing the refresh rate to > the > highest refresh rate supported by the panel. > > To test this, Idleness DRRS IGT will probe the DRRS state at below > instances and compare with the expected state. > > Instance Expected State > 1. Immediately after rendering the still image DRRS_HI > GH_RR > 2. After a delay of 1.2Sec DRRS_LOW_RR > 3. After changing the frame buffer DRRS_HIGH_R > R > 4. After a delay of 1.2Sec DRRS_LOW_RR > 5. After changing the frame buffer DRRS_HIGH_R > R > 6. After a delay of 1.2Sec DRRS_LOW_RR > > The test checks the driver DRRS state from the debugfs entry. To > check the > actual refresh-rate, the number of vblanks received per sec. > The refresh-rate calculated is checked against the expected refresh- > rate > with a tolerance value of 2. > > This patch is a continuation of the earlier work > https://patchwork.freedesktop.org/patch/45472/ towards igt for > idleness > > DRRS. The code is tested on Broxton BXT_T platform. > > v2: Addressed the comments and suggestions from Vlad, Marius. > The signoff details from the earlier work are also included. > > v3: Modified vblank rate calculation by using reply-sequence, > provided by > drmWaitVBlank, as suggested by Chris Wilson. > > v4: As suggested from Chris Wilson and Daniel Vetter > 1) Avoided using pthread for calculating vblank refresh rate, > instead used drmWaitVBlank reply sequence. > 2) Avoided using kernel-specific info like transitional delays, > instead polling mechanism with timeout is used. > 3) Included edp-DRRS as a subtest in > kms_frontbuffer_tracking.c, > instead of having a separate test. I completely disagree with the way this part was implemented. The code added to kms_frontbuffer_tracking.c uses pretty much zero of the infrastructure provided by the file. This patch adds a completely unrelated set of functions to kms_frontbuffer_tracking.c. If we're not going to use the current subtests & infrastructure, please make it a separate test. > > This is in continuation of last patch "https://patchwork.freedesktop. > org/patch/117149/" > > Signed-off-by: Lohith BS <lohith.bs@xxxxxxxxx> > Signed-off-by: Ramalingam C <ramalingam.c@xxxxxxxxx> > Signed-off-by: Vandana Kannan <vandana.kannan@xxxxxxxxx> > Signed-off-by: aknautiy <ankit.k.nautiyal@xxxxxxxxx> > --- > tests/kms_frontbuffer_tracking.c | 453 > ++++++++++++++++++++++++++++++++++++++- > 1 file changed, 452 insertions(+), 1 deletion(-) > > diff --git a/tests/kms_frontbuffer_tracking.c > b/tests/kms_frontbuffer_tracking.c > index c24e4a8..4d46e1e 100644 > --- a/tests/kms_frontbuffer_tracking.c > +++ b/tests/kms_frontbuffer_tracking.c > @@ -32,9 +32,18 @@ > #include <poll.h> > #include <pthread.h> > > +#include "drmtest.h" > +#include "igt_debugfs.h" > +#include "igt_kms.h" > +#include "intel_chipset.h" > +#include "intel_batchbuffer.h" > +#include "ioctl_wrappers.h" > +#include <time.h> > +#include <stdlib.h> > +#include <sys/time.h> > > IGT_TEST_DESCRIPTION("Test the Kernel's frontbuffer tracking > mechanism and " > - "its related features: FBC and PSR"); > + "its related features: DRRS, FBC and PSR"); > > /* > * One of the aspects of this test is that, for every subtest, we > try different > @@ -327,6 +336,41 @@ drmModeModeInfo std_1024_mode = { > .name = "Custom 1024x768", > }; > > +#define DRRS_TOLERANCE_THRESHOLD 2 > +#define DRRS_POLL_TIMEOUT_PERIOD_MS 5000 > +#define DRRS_STATUS_BYTES_CNT 1000 > +#define DRRS_MAX_ITERATION 3 > + > +/* > + * Struct to hold drrs test related data > + */ > +typedef struct { > + uint32_t devid; > + uint32_t handle[2]; > + igt_display_t display; > + igt_output_t *output; > + enum pipe pipe; > + igt_plane_t *primary; > + struct igt_fb fb[2]; > + uint32_t fb_id[2]; > +} drrs_data_t; > + > +/* > + * Structure to count vblank and note the starting time of the > counter > + */ > +typedef struct { > + unsigned int vbl_count; > + struct timeval start; > +} vbl_info; > + > +/* > + * Structure for refresh rate type > + */ > +typedef struct{ > + int rate; > + const char *name; > +} refresh_rate_t; > + > static drmModeModeInfoPtr > get_connector_smallest_mode(drmModeConnectorPtr c) > { > int i; > @@ -3415,6 +3459,410 @@ static const char *flip_str(enum flip_type > flip) > > #define TEST_MODE_ITER_END } } } } } } > > +static inline uint32_t pipe_select(int pipe) > +{ > + if (pipe > 1) > + return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; > + else if (pipe > 0) > + return DRM_VBLANK_SECONDARY; > + else > + return DRM_VBLANK_ABSOLUTE; > +} > + > +/* > + * Calculates the total no. of millisec elapsed since timeval start > + */ > +static double igt_millisec_elapsed(const struct timeval *start) > +{ > + struct timeval curr; > + > + gettimeofday(&curr, NULL); > + return (1e3*(curr.tv_sec - start->tv_sec) + > + (curr.tv_usec - start- > >tv_usec)/1000.00); > +} > + > +/* > + * Func to read the DRRS status from debugfs > + */ > +static bool read_drrs_status(char *str) > +{ > + FILE *fp; > + int fd; > + int cnt; > + > + fd = igt_debugfs_open(drm.fd, "i915_drrs_status", O_RDONLY); > + igt_assert(fd); > + fp = fdopen(fd, "r"); > + igt_require(fp); > + cnt = fread(str, DRRS_STATUS_BYTES_CNT - 1, 1, fp); > + > + if (!cnt) { > + if (!feof(fp)) { > + igt_critical("Failed to read > i915_drrs_status:%d \n", > + ferror(fp)); > + return false; > + } > + clearerr(fp); > + } > + fclose(fp); > + > + return true; > +} > + > +/* > + * Func to check for DRRS support > + */ > +static bool is_drrs_supported(void) > +{ > + char str[DRRS_STATUS_BYTES_CNT] = {}; > + > + if (!read_drrs_status(str)) > + return false; > + > + return strstr(str, "DRRS Supported: Yes") != NULL; > +} > + > +/* > + * Func to check if DRRS is enabled by driver. > + */ > +static bool is_drrs_enabled(void) > +{ > + char str[DRRS_STATUS_BYTES_CNT] = {}; > + > + if (!read_drrs_status(str)) > + return false; > + > + return strstr(str, "Idleness DRRS: Disabled") == NULL; > +} > + > + > +/* > + * vbl_rate = vbl_count/time taken > + */ > +static double vbl_rate(const union drm_wait_vblank *start, > + const union drm_wait_vblank *end) > +{ > + double s, e; > + > + s = start->reply.tval_sec + 1e-6 * start->reply.tval_usec; > + e = end->reply.tval_sec + 1e-6 * end->reply.tval_usec; > + return ((end->reply.sequence - start->reply.sequence) / (e - > s)); > +} > + > +/* > + * refresh_rate = (20 vblanks) /(time for 20vblanks) > + */ > +int calculate_refresh_rate(drrs_data_t *data) > +{ > + union drm_wait_vblank start, end; > + struct timeval start_tv; > + int refresh_rate; > + > + memset(&start, 0, sizeof(start)); > + start.request.type = DRM_VBLANK_RELATIVE | pipe_select(data- > >pipe); > + > + if (drmWaitVBlank(drm.fd, &start) != 0) { > + igt_critical("drmWaitVBlank Failed!\n"); > + return -1; > + } > + gettimeofday(&start_tv, NULL); > + memset(&end, 0, sizeof(end)); > + end.request.type = DRM_VBLANK_RELATIVE | pipe_select(data- > >pipe); > + > + /* Configured to wait for 20 vblank events*/ > + end.request.sequence = 20; > + > + if (drmWaitVBlank(drm.fd, &end) != 0) { > + igt_critical("drmWaitVBlank Failed!\n"); > + return -1; > + } > + refresh_rate = vbl_rate(&start, &end); > + > + return refresh_rate; > +} > + > +/* > + * Poll for DRRS transition from high to low with 5 seconds time > out. > + */ > +int wait_for_drrs_switch_to_low(drrs_data_t *data) > +{ > + char drrs_status[DRRS_STATUS_BYTES_CNT] = {}; > + const char *drrs_low_name = "DRRS_LOW_RR"; > + int status = 1; > + struct timeval start_tv; > + > + gettimeofday(&start_tv, NULL); > + > + while (igt_millisec_elapsed(&start_tv) < > DRRS_POLL_TIMEOUT_PERIOD_MS) { > + > + if (!read_drrs_status(drrs_status)) { > + status = -1; > + break; > + } > + > + if (strstr(drrs_status, drrs_low_name) != NULL) > + break; > + } > + > + if (igt_millisec_elapsed(&start_tv) > > DRRS_POLL_TIMEOUT_PERIOD_MS) { > + > + igt_critical("DRRS failed to switch refresh rate > from " > + "higher to lower\n"); > + > + status = -1; > + } > + > + return status; > +} > + > +/* > + * Check if calulated refresh rate is same as expected refresh rate > + * Returns 0 in case of pass , 1 in case of failure, and -1 for > error. > + */ > +static int check_refresh_rate(drrs_data_t *data, refresh_rate_t > *expected_rr) > +{ > + int refresh_rate = -1; > + char drrs_status[DRRS_STATUS_BYTES_CNT] = {}; > + > + /* Get the DRRS Status from the debugfs entry */ > + if (!read_drrs_status(drrs_status)) > + return -1; > + > + refresh_rate = calculate_refresh_rate(data); > + > + if (refresh_rate < 0) { > + igt_critical("Refresh rate calculation FAILED\n"); > + return -1; > + } > + > + /* Compare with Expected Refresh Rate */ > + if (strstr(drrs_status, expected_rr->name) != NULL > + && abs(refresh_rate - expected_rr->rate) <= > DRRS_TOLERANCE_THRESHOLD) { > + return 0; > + } > + igt_critical("Expected %s : FAILED.\n", expected_rr->name); > + > + return 1; > +} > + > +/* > + * This function > + * 1. Creates framebuffers > + * 2. Apply framebuffers alternatively and count the vblank refresh > rate > + * which should be equal to highest refresh rate supported. > + * 3. Poll for DRRS to toggle from DRRS_HIGH_RR -> DRRS_LOW_RR with > 5sec > + * timeout using kernel debugfs entry(i915_drrs_status). > + * 4. Once DRRS switches to LOW we count the vblank refresh rate > which > + * should be equal to lowest refresh rate supported. > + * 5. The above calculated vblank refresh rates can have a tolerance > of 2. > + */ > +static int execute_test(drrs_data_t *data) > +{ > + igt_display_t *display = &data->display; > + igt_output_t *output = data->output; > + drmModeModeInfo *mode, *supported_modes; > + int test_failed = 0; > + int ret, i, i_mod, count_modes; > + refresh_rate_t high_rr, low_rr; > + > + high_rr.name = "DRRS_HIGH_RR"; > + high_rr.rate = 0; > + low_rr.name = "DRRS_LOW_RR"; > + low_rr.rate = 0; > + > + /* get the max and min supported refresh rates for the > display */ > + supported_modes = output->config.connector->modes; > + count_modes = output->config.connector->count_modes; > + > + /* minimum 2 modes are required for DRRS */ > + igt_assert_f(count_modes >= 2, "Minimum 2 modes required for > DRRS\n"); > + > + for (i = 0; i < count_modes; i++) { > + int rr = supported_modes[i].vrefresh; > + > + if (i == 0) { > + high_rr.rate = low_rr.rate = rr; > + continue; > + } > + > + if (high_rr.rate < rr) > + high_rr.rate = rr; > + > + if (low_rr.rate > rr) > + low_rr.rate = rr; > + } > + > + igt_output_set_pipe(output, data->pipe); > + data->primary = igt_output_get_plane(data->output, > + DRM_PLANE_TYPE_OVERLAY); > + mode = igt_output_get_mode(data->output); > + data->fb_id[0] = igt_create_color_fb(drm.fd, mode->hdisplay, > + mode->vdisplay, > + DRM_FORMAT_XRGB8888, > + LOCAL_DRM_FORMAT_MOD > _NONE, > + 0.0, 100.1, 0.0, > &data->fb[0]); > + > + igt_assert(data->fb_id[0]); > + data->fb_id[1] = igt_create_color_fb(drm.fd, mode->hdisplay, > + mode->vdisplay, > + DRM_FORMAT_XRGB8888, > + LOCAL_DRM_FORMAT_MOD > _NONE, > + 100.1, 0.0, 0.0, > + &data->fb[1]); > + > + igt_assert(data->fb_id[1]); > + data->handle[0] = data->fb[0].gem_handle; > + data->handle[1] = data->fb[1].gem_handle; > + > + for (i = 1; i <= DRRS_MAX_ITERATION; i++) { > + i_mod = i % 2; > + igt_plane_set_fb(data->primary, &data->fb[i_mod]); > + igt_display_commit(display); > + > + if (!is_drrs_enabled()) { > + igt_critical("DRRS not enabled\n"); > + igt_plane_set_fb(data->primary, NULL); > + igt_output_set_pipe(output, PIPE_ANY); > + igt_display_commit(display); > + igt_remove_fb(drm.fd, &data->fb[0]); > + igt_remove_fb(drm.fd, &data->fb[1]); > + return -1; > + } > + > + /* expecting High RR */ > + ret = check_refresh_rate(data, &high_rr); > + > + if (ret == -1) > + return -1; > + > + if (ret == 1) > + test_failed = 1; > + > + /* > + * Poll kernel debugfs entry for DRRS > + * transition from High to Low > + */ > + ret = wait_for_drrs_switch_to_low(data); > + > + if (ret == -1) > + return 1; > + > + /* expecting Low RR */ > + ret = check_refresh_rate(data, &low_rr); > + > + if (ret == -1) > + return -1; > + > + if (ret == 1) > + test_failed = 1; > + } > + > + return test_failed; > +} > + > +/* > + * Func to free the framebuffers after the test completion. > + */ > +static void finish_crtc(drrs_data_t *data) > +{ > + igt_plane_set_fb(data->primary, NULL); > + igt_output_set_pipe(data->output, PIPE_ANY); > + igt_display_commit(&data->display); > + > + igt_remove_fb(drm.fd, &data->fb[0]); > + igt_remove_fb(drm.fd, &data->fb[1]); > +} > + > +/* > + * Func to reset the display structures after the test completion. > + */ > +static void reset_display(drrs_data_t *data) > +{ > + igt_display_t *display = &data->display; > + enum pipe pipe_id; > + > + for_each_pipe(display, pipe_id) { > + igt_pipe_t *pipe = &display->pipes[pipe_id]; > + igt_plane_t *plane = igt_pipe_get_plane_type(pipe, > + DRM_PLANE_TYPE_PRIMARY); > + > + if (plane->fb) > + igt_plane_set_fb(plane, NULL); > + } > + > + for_each_connected_output(display, data->output) > + igt_output_set_pipe(data->output, PIPE_ANY); > +} > + > +/* > + * Func to run the drrs test for the eDP display. > + */ > +static void run_test(drrs_data_t *data) > +{ > + int ret; > + igt_display_t *display = &data->display; > + > + reset_display(data); > + > + for_each_pipe_with_valid_output(display, data->pipe, data- > >output) { > + drmModeConnectorPtr c = data->output- > >config.connector; > + > + if (c->connector_type != DRM_MODE_CONNECTOR_eDP || > + c->connection != DRM_MODE_CONNECTED) > + continue; > + > + ret = execute_test(data); > + > + igt_skip_on_f(ret == -1, > + "%s on pipe %s, connector > %s:SKIPPED\n", > + igt_subtest_name(), > + kmstest_pipe_name(data- > >pipe), > + igt_output_name(data- > >output)); > + > + igt_fail_on_f(ret == 1, > + "%s on pipe %s, connector > %s:FAILED\n", > + igt_subtest_name(), > + kmstest_pipe_name(data- > >pipe), > + igt_output_name(data- > >output)); > + > + igt_assert_f(ret == 0, > + "%s on pipe %s, connector %s: > PASSED\n", > + igt_subtest_name(), > + kmstest_pipe_name(data- > >pipe), > + igt_output_name(data- > >output)); > + > + finish_crtc(data); > + } > +} > + > +/* > + * Function to test edp-DRRS feature.Exits from the function if PSR > is enabled > + */ > +void edp_drrs_test(void) > +{ > + drrs_data_t data = {}; > + > + igt_assert_f(!psr.can_test, > + "DRRS cannot be tested as PSR is > enabled\n"); > + igt_skip_on_simulation(); > + > + /* > + * Using the same drm.fd which was opened during > setup_environment > + */ > + igt_assert_f(drm.fd != -1, "Invalid fd\n"); > + data.devid = intel_get_drm_devid(drm.fd); > + igt_assert_f(data.devid >= 0, "Invalid dev id\n"); > + > + /* > + * Check if the DRRS is supported.If yes call the Idleness > DRRS test > + */ > + igt_require_f(is_drrs_supported(), > + "DRRS not supported:check VBT/panel > caps\n"); > + igt_display_init(&data.display, drm.fd); > + run_test(&data); > + igt_display_fini(&data.display); > +} > + > int main(int argc, char *argv[]) > { > struct test_mode t; > @@ -3628,6 +4076,9 @@ int main(int argc, char *argv[]) > suspend_subtest(&t); > TEST_MODE_ITER_END > > + igt_subtest_f("edp-DRRS") > + edp_drrs_test(); > + > t.pipes = PIPE_SINGLE; > t.screen = SCREEN_PRIM; > t.plane = PLANE_PRI; _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx