diff options
-rw-r--r-- | tests/Makefile.sources | 1 | ||||
-rw-r--r-- | tests/kms_mmio_vs_cs_flip.c | 523 | ||||
-rw-r--r-- | tests/meson.build | 1 |
3 files changed, 0 insertions, 525 deletions
diff --git a/tests/Makefile.sources b/tests/Makefile.sources index 791e4f83..8066fb1a 100644 --- a/tests/Makefile.sources +++ b/tests/Makefile.sources @@ -194,7 +194,6 @@ TESTS_progs = \ kms_invalid_dotclock \ kms_legacy_colorkey \ kms_mmap_write_crc \ - kms_mmio_vs_cs_flip \ kms_panel_fitting \ kms_pipe_b_c_ivb \ kms_pipe_crc_basic \ diff --git a/tests/kms_mmio_vs_cs_flip.c b/tests/kms_mmio_vs_cs_flip.c deleted file mode 100644 index fa947d9c..00000000 --- a/tests/kms_mmio_vs_cs_flip.c +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright © 2014 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 "igt.h" -#include <errno.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> -#include <time.h> - - -typedef struct { - int drm_fd; - igt_display_t display; - igt_pipe_crc_t *pipe_crc; - drm_intel_bufmgr *bufmgr; - drm_intel_bo *busy_bo; - uint32_t devid; - bool flip_done; -} data_t; - -static void exec_nop(data_t *data, uint32_t handle, unsigned int ring) -{ - struct intel_batchbuffer *batch; - drm_intel_bo *bo; - - batch = intel_batchbuffer_alloc(data->bufmgr, data->devid); - igt_assert(batch); - - bo = gem_handle_to_libdrm_bo(data->bufmgr, data->drm_fd, "", handle); - igt_assert(bo); - - /* add relocs to make sure the kernel will think we write to dst */ - BEGIN_BATCH(4, 1); - OUT_BATCH(MI_BATCH_BUFFER_END); - OUT_BATCH(MI_NOOP); - OUT_RELOC(bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); - OUT_BATCH(MI_NOOP); - ADVANCE_BATCH(); - - intel_batchbuffer_flush_on_ring(batch, ring); - intel_batchbuffer_free(batch); - - drm_intel_bo_unreference(bo); -} - -static void exec_blt(data_t *data) -{ - struct intel_batchbuffer *batch; - int w, h, pitch, i; - - batch = intel_batchbuffer_alloc(data->bufmgr, data->devid); - igt_assert(batch); - - w = 8192; - h = data->busy_bo->size / (8192 * 4); - pitch = w * 4; - - for (i = 0; i < 40; i++) { - BLIT_COPY_BATCH_START(0); - OUT_BATCH((3 << 24) | /* 32 bits */ - (0xcc << 16) | /* copy ROP */ - pitch); - OUT_BATCH(0 << 16 | 0); - OUT_BATCH(h << 16 | w); - OUT_RELOC_FENCED(data->busy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); - OUT_BATCH(0 << 16 | 0); - OUT_BATCH(pitch); - OUT_RELOC_FENCED(data->busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0); - ADVANCE_BATCH(); - } - - intel_batchbuffer_flush(batch); - intel_batchbuffer_free(batch); -} - -static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, - unsigned int usec, void *_data) -{ - data_t *data = _data; - - data->flip_done = true; -} - -static void wait_for_flip(data_t *data, uint32_t flip_handle) -{ - struct timeval timeout = { - .tv_sec = 3, - .tv_usec = 0, - }; - drmEventContext evctx = { - .version = 2, - .page_flip_handler = page_flip_handler, - }; - fd_set fds; - - FD_ZERO(&fds); - FD_SET(data->drm_fd, &fds); - - while (!data->flip_done) { - int ret = select(data->drm_fd + 1, &fds, NULL, NULL, &timeout); - - if (ret < 0 && errno == EINTR) - continue; - - igt_assert_lte(0, ret); - - do_or_die(drmHandleEvent(data->drm_fd, &evctx)); - } - - /* - * The flip completion may have been signalled prematurely, so - * also submit another nop batch and wait for it to make sure - * the ring has really been drained. - */ - if (IS_GEN7(data->devid) || IS_GEN8(data->devid)) - exec_nop(data, flip_handle, I915_EXEC_BLT); - else - exec_nop(data, flip_handle, I915_EXEC_RENDER); - gem_sync(data->drm_fd, flip_handle); -} - -static void make_gpu_busy(data_t *data, uint32_t flip_handle) -{ - /* - * Make sure flip_handle has been used on the blt ring. - * This should make the flip use the same ring on gen7+. - */ - if (IS_GEN7(data->devid) || IS_GEN8(data->devid)) - exec_nop(data, flip_handle, I915_EXEC_BLT); - - /* - * Add a pile commands to the ring. The flip will be - * stuck behing these commands and hence gets delayed - * significantly. - */ - exec_blt(data); - - /* - * Make sure the render ring will block until the blt ring is clear. - * This is in case the flip will execute on the render ring and the - * blits were on the blt ring (this will be the case on gen6 at least). - * - * We can't add an explicit dependency between flip_handle and the - * blits since that would cause the driver to block until the blits - * have completed before it will perform a subsequent mmio flip, - * and so the test would fail to exercise the mmio vs. CS flip race. - */ - if (HAS_BLT_RING(data->devid)) - exec_nop(data, data->busy_bo->handle, I915_EXEC_RENDER); -} - -/* - * 1. set primary plane to full red - * 2. grab a reference crc - * 3. set primary plane to full blue - * 4. queue lots of GPU activity to delay the subsequent page flip - * 5. queue a page flip to the same blue fb - * 6. toggle a fullscreen sprite (green) on and back off again - * 7. set primary plane to red fb - * 8. wait for GPU to finish - * 9. compare current crc with reference crc - * - * We expect the primary plane to display full red at the end. - * If the sprite operations have interfered with the page flip, - * the driver may have mistakenly completed the flip before - * it was executed by the CS, and hence the subsequent mmio - * flips may have overtaken it. So once we've finished everything - * the CS flip may have been the last thing to occur, which means - * the primary plane may be full blue instead of the red it's - * supposed to be. - */ -static void -test_plane(data_t *data, igt_output_t *output, enum pipe pipe, int plane) -{ - struct igt_fb red_fb, green_fb, blue_fb; - drmModeModeInfo *mode; - igt_plane_t *primary, *sprite; - igt_crc_t ref_crc, crc; - int ret; - - igt_output_set_pipe(output, pipe); - - primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); - sprite = igt_output_get_plane(output, plane); - - mode = igt_output_get_mode(output); - igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, - DRM_FORMAT_XRGB8888, - LOCAL_DRM_FORMAT_MOD_NONE, - 1.0, 0.0, 0.0, - &red_fb); - igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, - DRM_FORMAT_XRGB8888, - LOCAL_DRM_FORMAT_MOD_NONE, - 0.0, 1.0, 0.0, - &green_fb); - igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, - DRM_FORMAT_XRGB8888, - LOCAL_DRM_FORMAT_MOD_NONE, - 0.0, 0.0, 1.0, - &blue_fb); - - /* - * Make sure these buffers are suited for display use - * because most of the modeset operations must be fast - * later on. - */ - igt_plane_set_fb(primary, &blue_fb); - igt_display_commit(&data->display); - igt_plane_set_fb(sprite, &green_fb); - igt_display_commit(&data->display); - igt_plane_set_fb(sprite, NULL); - igt_display_commit(&data->display); - - if (data->pipe_crc) - igt_pipe_crc_free(data->pipe_crc); - data->pipe_crc = igt_pipe_crc_new(data->drm_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO); - - /* set red fb and grab reference crc */ - igt_plane_set_fb(primary, &red_fb); - igt_display_commit(&data->display); - igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc); - - ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id, - blue_fb.fb_id, 0, 0, &output->id, 1, - mode); - igt_assert_eq(ret, 0); - - make_gpu_busy(data, blue_fb.gem_handle); - - data->flip_done = false; - ret = drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id, - blue_fb.fb_id, DRM_MODE_PAGE_FLIP_EVENT, data); - igt_assert_eq(ret, 0); - - /* - * Toggle a fullscreen sprite on and back off. This will result - * in the primary plane getting disabled and re-enbled, and that - * leads to mmio flips. The driver may then mistake the flip done - * interrupts from the mmio flips as the flip done interrupts for - * the CS flip, and hence subsequent mmio flips won't wait for the - * CS flips like they should. - */ - ret = drmModeSetPlane(data->drm_fd, - sprite->drm_plane->plane_id, - output->config.crtc->crtc_id, - green_fb.fb_id, 0, - 0, 0, mode->hdisplay, mode->vdisplay, - 0, 0, mode->hdisplay << 16, mode->vdisplay << 16); - igt_assert_eq(ret, 0); - ret = drmModeSetPlane(data->drm_fd, - sprite->drm_plane->plane_id, - output->config.crtc->crtc_id, - 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0); - igt_assert_eq(ret, 0); - - /* - * Set primary plane to red fb. This should wait for the CS flip - * to complete. But if the kernel mistook the flip done interrupt - * from the mmio flip as the flip done from the CS flip, this will - * not wait for anything. And hence the the CS flip will actually - * occur after this mmio flip. - */ - ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id, - red_fb.fb_id, 0, 0, &output->id, 1, - mode); - igt_assert_eq(ret, 0); - - /* Make sure the flip has been executed */ - wait_for_flip(data, blue_fb.gem_handle); - - /* Grab crc and compare with the extected result */ - igt_pipe_crc_collect_crc(data->pipe_crc, &crc); - - igt_plane_set_fb(primary, NULL); - igt_display_commit(&data->display); - - igt_remove_fb(data->drm_fd, &red_fb); - igt_remove_fb(data->drm_fd, &green_fb); - igt_remove_fb(data->drm_fd, &blue_fb); - - igt_pipe_crc_free(data->pipe_crc); - data->pipe_crc = NULL; - - igt_output_set_pipe(output, PIPE_ANY); - igt_display_commit(&data->display); - - igt_assert_crc_equal(&ref_crc, &crc); -} - -/* - * 1. set primary plane to full red - * 2. grab a reference crc - * 3. set primary plane to full green - * 4. wait for vblank - * 5. pan primary plane a bit (to cause a mmio flip w/o vblank wait) - * 6. queue lots of GPU activity to delay the subsequent page flip - * 6. queue a page flip to a blue fb - * 7. set primary plane to red fb - * 8. wait for GPU to finish - * 9. compare current crc with reference crc - * - * We expect the primary plane to display full red at the end. - * If the previously schedule primary plane pan operation has interfered - * with the following page flip, the driver may have mistakenly completed - * the flip before it was executed by the CS, and hence the subsequent mmio - * flips may have overtaken it. So once we've finished everything - * the CS flip may have been the last thing to occur, which means - * the primary plane may be full blue instead of the red it's - * supposed to be. - */ -static void -test_crtc(data_t *data, igt_output_t *output, enum pipe pipe) -{ - struct igt_fb red_fb, green_fb, blue_fb; - drmModeModeInfo *mode; - igt_plane_t *primary; - igt_crc_t ref_crc, crc; - int ret; - - igt_output_set_pipe(output, pipe); - - primary = igt_output_get_plane(output, 0); - - mode = igt_output_get_mode(output); - igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay+1, - DRM_FORMAT_XRGB8888, - LOCAL_DRM_FORMAT_MOD_NONE, - 1.0, 0.0, 0.0, - &red_fb); - igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay+1, - DRM_FORMAT_XRGB8888, - LOCAL_DRM_FORMAT_MOD_NONE, - 0.0, 0.0, 1.0, - &blue_fb); - igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay+1, - DRM_FORMAT_XRGB8888, - LOCAL_DRM_FORMAT_MOD_NONE, - 0.0, 1.0, 0.0, - &green_fb); - - /* - * Make sure these buffers are suited for display use - * because most of the modeset operations must be fast - * later on. - */ - igt_plane_set_fb(primary, &green_fb); - igt_display_commit(&data->display); - igt_plane_set_fb(primary, &blue_fb); - igt_display_commit(&data->display); - - if (data->pipe_crc) - igt_pipe_crc_free(data->pipe_crc); - data->pipe_crc = igt_pipe_crc_new(data->drm_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO); - - /* set red fb and grab reference crc */ - igt_plane_set_fb(primary, &red_fb); - igt_display_commit(&data->display); - igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc); - - /* - * Further down we need to issue an mmio flip w/o the kernel - * waiting for vblank. The easiest way is to just pan within - * the same FB. So pan away a bit here, and later we undo this - * with another pan which will result in the desired mmio flip. - */ - ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id, - green_fb.fb_id, 0, 1, &output->id, 1, - mode); - igt_assert_eq(ret, 0); - - /* - * Make it more likely that the CS flip has been submitted into the - * ring by the time the mmio flip from the drmModeSetCrtc() below - * completes. The driver will then mistake the flip done interrupt - * from the mmio flip as the flip done interrupt from the CS flip. - */ - igt_wait_for_vblank(data->drm_fd, pipe); - - /* now issue the mmio flip w/o vblank waits in the kernel, ie. pan a bit */ - ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id, - green_fb.fb_id, 0, 0, &output->id, 1, - mode); - igt_assert_eq(ret, 0); - - make_gpu_busy(data, blue_fb.gem_handle); - - /* - * Submit the CS flip. The commands must be emitted into the ring - * before the mmio flip from the panning operation completes. - */ - data->flip_done = false; - ret = drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id, - blue_fb.fb_id, DRM_MODE_PAGE_FLIP_EVENT, data); - igt_assert_eq(ret, 0); - - /* - * Set primary plane to red fb. This should wait for the CS flip - * to complete. But if the kernel mistook the flip done interrupt - * from the mmio flip as the flip done from the CS flip, this will - * not wait for anything. And hence the the CS flip will actually - * occur after this mmio flip. - */ - ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id, - red_fb.fb_id, 0, 0, &output->id, 1, - mode); - igt_assert_eq(ret, 0); - - /* Make sure the flip has been executed */ - wait_for_flip(data, blue_fb.gem_handle); - - /* Grab crc and compare with the extected result */ - igt_pipe_crc_collect_crc(data->pipe_crc, &crc); - - igt_plane_set_fb(primary, NULL); - igt_display_commit(&data->display); - - igt_remove_fb(data->drm_fd, &red_fb); - igt_remove_fb(data->drm_fd, &green_fb); - igt_remove_fb(data->drm_fd, &blue_fb); - - igt_pipe_crc_free(data->pipe_crc); - data->pipe_crc = NULL; - - igt_output_set_pipe(output, PIPE_ANY); - igt_display_commit(&data->display); - - igt_assert_crc_equal(&ref_crc, &crc); -} - -static void -run_plane_test(data_t *data) -{ - igt_output_t *output; - int plane = 1; /* testing with one sprite is enough */ - int valid_tests = 0; - enum pipe pipe; - - for_each_pipe_with_valid_output(&data->display, pipe, output) { - igt_require(data->display.pipes[pipe].n_planes > 2); - - test_plane(data, output, pipe, plane); - valid_tests++; - } - - igt_require_f(valid_tests, "no valid crtc/connector combinations found\n"); -} - -static void -run_crtc_test(data_t *data) -{ - igt_output_t *output; - int valid_tests = 0; - enum pipe pipe; - - for_each_pipe_with_valid_output(&data->display, pipe, output) { - test_crtc(data, output, pipe); - valid_tests++; - } - - igt_require_f(valid_tests, "no valid crtc/connector combinations found\n"); -} - -static data_t data; - -igt_main -{ - igt_skip_on_simulation(); - - igt_fixture { - data.drm_fd = drm_open_driver_master(DRIVER_INTEL); - - kmstest_set_vt_graphics_mode(); - - data.devid = intel_get_drm_devid(data.drm_fd); - - igt_require_pipe_crc(data.drm_fd); - igt_display_init(&data.display, data.drm_fd); - - data.bufmgr = drm_intel_bufmgr_gem_init(data.drm_fd, 4096); - igt_assert(data.bufmgr); - drm_intel_bufmgr_gem_enable_reuse(data.bufmgr); - - data.busy_bo = drm_intel_bo_alloc(data.bufmgr, "bo", - 64*1024*1024, 4096); - gem_set_tiling(data.drm_fd, data.busy_bo->handle, 0, 4096); - } - - igt_subtest_f("setplane_vs_cs_flip") - run_plane_test(&data); - - igt_subtest_f("setcrtc_vs_cs_flip") - run_crtc_test(&data); - - igt_fixture { - drm_intel_bo_unreference(data.busy_bo); - drm_intel_bufmgr_destroy(data.bufmgr); - igt_display_fini(&data.display); - } -} diff --git a/tests/meson.build b/tests/meson.build index 015afa47..1f00fc4f 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -170,7 +170,6 @@ test_progs = [ 'kms_invalid_dotclock', 'kms_legacy_colorkey', 'kms_mmap_write_crc', - 'kms_mmio_vs_cs_flip', 'kms_panel_fitting', 'kms_pipe_b_c_ivb', 'kms_pipe_crc_basic', |