mirror of
				https://github.com/tiagovignatti/intel-gpu-tools.git
				synced 2025-11-04 03:58:27 +00:00 
			
		
		
		
	Apply the new API to all call sites within the test suite using the following semantic patch: // Semantic patch for replacing drm_open_any* with arch-specific drm_open_driver* calls @@ identifier i =~ "\bdrm_open_any\b"; @@ - i() + drm_open_driver(DRIVER_INTEL) @@ identifier i =~ "\bdrm_open_any_master\b"; @@ - i() + drm_open_driver_master(DRIVER_INTEL) @@ identifier i =~ "\bdrm_open_any_render\b"; @@ - i() + drm_open_driver_render(DRIVER_INTEL) @@ identifier i =~ "\b__drm_open_any\b"; @@ - i() + __drm_open_driver(DRIVER_INTEL) Signed-off-by: Micah Fedke <micah.fedke@collabora.co.uk> Signed-off-by: Thomas Wood <thomas.wood@intel.com>
		
			
				
	
	
		
			546 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			546 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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 = DRM_EVENT_CONTEXT_VERSION,
 | 
						|
		.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 bool
 | 
						|
test_plane(data_t *data, igt_output_t *output, enum pipe pipe, enum igt_plane 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);
 | 
						|
	igt_display_commit(&data->display);
 | 
						|
 | 
						|
	if (!output->valid) {
 | 
						|
		igt_output_set_pipe(output, PIPE_ANY);
 | 
						|
		igt_display_commit(&data->display);
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	primary = igt_output_get_plane(output, 0);
 | 
						|
	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(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);
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * 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 bool
 | 
						|
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);
 | 
						|
	igt_display_commit(&data->display);
 | 
						|
 | 
						|
	if (!output->valid) {
 | 
						|
		igt_output_set_pipe(output, PIPE_ANY);
 | 
						|
		igt_display_commit(&data->display);
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	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(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);
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
run_plane_test(data_t *data)
 | 
						|
{
 | 
						|
	igt_output_t *output;
 | 
						|
	enum igt_plane plane = 1; /* testing with one sprite is enough */
 | 
						|
	int valid_tests = 0;
 | 
						|
	enum pipe pipe;
 | 
						|
 | 
						|
	for_each_connected_output(&data->display, output) {
 | 
						|
		for_each_pipe(&data->display, pipe) {
 | 
						|
			igt_require(data->display.pipes[pipe].n_planes > 2);
 | 
						|
 | 
						|
			if (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_connected_output(&data->display, output) {
 | 
						|
		for_each_pipe(&data->display, pipe) {
 | 
						|
			if (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();
 | 
						|
		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);
 | 
						|
	}
 | 
						|
}
 |