[igt,4/4] tools/intel_poller: Add a new tool that will poll various display registers

Submitted by Ville Syrjala on June 11, 2014, 4:41 p.m.

Details

Message ID 1402504880-27525-4-git-send-email-ville.syrjala@linux.intel.com
State New, archived
Headers show

Not browsing as part of any series.

Commit Message

Ville Syrjala June 11, 2014, 4:41 p.m.
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

intel_poller can be used to poll various display registers
(IIR,scanline/pixel/flip/frame counter, live address, etc.).

It can be used to determine eg. at which scanline or pixel count certain
events occur.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---

Ideas for a better name are welcome!


 lib/intel_reg.h        |   22 +-
 tools/Makefile.sources |    1 +
 tools/intel_poller.c   | 1471 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1491 insertions(+), 3 deletions(-)
 create mode 100644 tools/intel_poller.c

Patch hide | download patch | download mbox

diff --git a/lib/intel_reg.h b/lib/intel_reg.h
index 84e05e4..87a14c9 100644
--- a/lib/intel_reg.h
+++ b/lib/intel_reg.h
@@ -2248,7 +2248,11 @@  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 #define PIPE_PIXEL_MASK		0x00ffffff
 #define PIPE_PIXEL_SHIFT	0
-
+/*
+ * g4x+ frame/flip counters
+ */
+#define PIPEAFRMCOUNT_G4X	0x70040
+#define PIPEAFLIPCOUNT_G4X	0x70044
 /*
  * Computing GMCH M and N values.
  *
@@ -2296,20 +2300,24 @@  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define PIPEBSTAT		0x71024
 #define PIPEBFRAMEHIGH		0x71040
 #define PIPEBFRAMEPIXEL		0x71044
+#define PIPEBFRMCOUNT_G4X	0x71040
+#define PIPEBFLIPCOUNT_G4X	0x71044
 
 #define PIPEB_GMCH_DATA_M	0x71050
 #define PIPEB_GMCH_DATA_N	0x71054
 #define PIPEB_DP_LINK_M		0x71060
 #define PIPEB_DP_LINK_N		0x71064
 
+#define PIPEC_DSL		0x72000
+
 #define PIPECCONF 		0x72008
 
 #define PIPECGCMAXRED		0x72010
 #define PIPECGCMAXGREEN		0x72014
 #define PIPECGCMAXBLUE		0x72018
 #define PIPECSTAT		0x72024
-#define PIPECFRAMEHIGH		0x72040
-#define PIPECFRAMEPIXEL		0x72044
+#define PIPECFRMCOUNT_G4X	0x72040
+#define PIPECFLIPCOUNT_G4X	0x72044
 
 #define PIPEC_GMCH_DATA_M	0x72050
 #define PIPEC_GMCH_DATA_N	0x72054
@@ -2370,12 +2378,15 @@  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #define DSPASURF		0x7019C
 #define DSPATILEOFF		0x701A4
+#define DSPASURFLIVE		0x701AC
 
 #define DSPBSURF		0x7119C
 #define DSPBTILEOFF		0x711A4
+#define DSPBSURFLIVE		0x711AC
 
 #define DSPCSURF		0x7219C
 #define DSPCTILEOFF		0x721A4
+#define DSPCSURFLIVE		0x721AC
 
 #define VGACNTRL		0x71400
 # define VGA_DISP_DISABLE			(1 << 31)
@@ -2879,6 +2890,11 @@  typedef enum {
 #define DEIIR	0x44008
 #define DEIER	0x4400c
 
+#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + 0x10 * (pipe))
+#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + 0x10 * (pipe))
+#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + 0x10 * (pipe))
+#define GEN8_DE_PIPE_IER(pipe) (0x4440c + 0x10 * (pipe))
+
 /* GT interrupt */
 #define GT_SYNC_STATUS		(1 << 2)
 #define GT_USER_INTERRUPT	(1 << 0)
diff --git a/tools/Makefile.sources b/tools/Makefile.sources
index c2535e7..6f6ca4a 100644
--- a/tools/Makefile.sources
+++ b/tools/Makefile.sources
@@ -12,6 +12,7 @@  bin_PROGRAMS = 				\
 	intel_iosf_sb_write		\
 	intel_opregion_decode		\
 	intel_perf_counters		\
+	intel_poller			\
 	intel_stepping 			\
 	intel_reg_checker 		\
 	intel_reg_dumper 		\
diff --git a/tools/intel_poller.c b/tools/intel_poller.c
new file mode 100644
index 0000000..ebc594a
--- /dev/null
+++ b/tools/intel_poller.c
@@ -0,0 +1,1471 @@ 
+/*
+ * 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 <assert.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <string.h>
+#include "intel_chipset.h"
+#include "intel_io.h"
+#include "igt_debugfs.h"
+#include "drmtest.h"
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#define max(a,b) ((a) > (b) ? (a) : (b))
+
+enum test {
+	TEST_INVALID,
+	TEST_PIPESTAT,
+	TEST_IIR,
+	TEST_IIR_GEN2,
+	TEST_IIR_GEN3,
+	TEST_DEIIR,
+	TEST_FRAMECOUNT,
+	TEST_FRAMECOUNT_GEN3,
+	TEST_FRAMECOUNT_G4X,
+	TEST_FLIPCOUNT,
+	TEST_PAN,
+	TEST_FLIP,
+	TEST_SURFLIVE,
+	TEST_WRAP,
+	TEST_FIELD,
+};
+
+static uint32_t vlv_offset;
+
+static volatile bool quit;
+
+static void sighandler(int x)
+{
+	quit = true;
+}
+
+static uint16_t read_reg_16(uint32_t reg)
+{
+	return *(volatile uint16_t *)((volatile char*)mmio + vlv_offset + reg);
+}
+
+static uint32_t read_reg(uint32_t reg)
+{
+	return *(volatile uint32_t *)((volatile char*)mmio + vlv_offset + reg);
+}
+
+static void write_reg_16(uint32_t reg, uint16_t val)
+{
+	*(volatile uint16_t *)((volatile char*)mmio + vlv_offset + reg) = val;
+}
+
+static void write_reg(uint32_t reg, uint32_t val)
+{
+	*(volatile uint32_t *)((volatile char*)mmio + vlv_offset + reg) = val;
+}
+
+static int pipe_to_plane(uint32_t devid, int pipe)
+{
+	if (!IS_GEN2(devid) && !IS_GEN3(devid))
+		return pipe;
+
+	switch (pipe) {
+	case 0:
+		if ((read_reg(DSPACNTR) & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B)
+			return 1;
+		return 0;
+	case 1:
+		if ((read_reg(DSPACNTR) & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)
+			return 0;
+		return 1;
+	}
+
+	assert(0);
+
+	return 0;
+}
+
+static uint32_t dspoffset_reg(uint32_t devid, int pipe)
+{
+	bool use_tileoff;
+
+	pipe = pipe_to_plane(devid, pipe);
+
+	if (IS_GEN2(devid) || IS_GEN3(devid))
+		use_tileoff = false;
+	if (IS_HASWELL(devid) || IS_BROADWELL(devid))
+		use_tileoff = true;
+	else {
+		switch (pipe) {
+		case 0:
+			use_tileoff = read_reg(DSPACNTR) & DISPLAY_PLANE_TILED;
+			break;
+		case 1:
+			use_tileoff = read_reg(DSPBCNTR) & DISPLAY_PLANE_TILED;
+			break;
+		case 2:
+			use_tileoff = read_reg(DSPCCNTR) & DISPLAY_PLANE_TILED;
+			break;
+		}
+	}
+
+	if (use_tileoff) {
+		switch (pipe) {
+		case 0:
+			return DSPATILEOFF;
+		case 1:
+			return DSPBTILEOFF;
+		case 2:
+			return DSPCTILEOFF;
+		}
+	} else {
+		switch (pipe) {
+		case 0:
+			return DSPABASE;
+		case 1:
+			return DSPBBASE;
+		case 2:
+			return DSPCBASE;
+		}
+	}
+
+	assert(0);
+
+	return 0;
+}
+
+static uint32_t dspsurf_reg(uint32_t devid, int pipe)
+{
+	pipe = pipe_to_plane(devid, pipe);
+
+	if (IS_GEN2(devid) || IS_GEN3(devid)) {
+		switch (pipe) {
+		case 0:
+			return DSPABASE;
+		case 1:
+			return DSPBBASE;
+		case 2:
+			return DSPCBASE;
+		}
+	} else {
+		switch (pipe) {
+		case 0:
+			return DSPASURF;
+		case 1:
+			return DSPBSURF;
+		case 2:
+			return DSPCSURF;
+		}
+	}
+
+	assert(0);
+
+	return 0;
+}
+
+static uint32_t dsl_reg(int pipe)
+{
+	switch (pipe) {
+	case 0:
+		return PIPEA_DSL;
+	case 1:
+		return PIPEB_DSL;
+	case 2:
+		return PIPEC_DSL;
+	}
+
+	assert(0);
+
+	return 0;
+}
+
+static void poll_pixel_pipestat(int pipe, int bit, uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t pix, pix1, pix2, iir, iir1, iir2, iir_bit, iir_mask;
+	int i = 0;
+
+	switch (pipe) {
+	case 0:
+		pix = PIPEAFRAMEPIXEL;
+		iir_bit = 1 << bit;
+		iir = PIPEASTAT;
+		break;
+	case 1:
+		pix = PIPEBFRAMEPIXEL;
+		iir_bit = 1 << bit;
+		iir = PIPEBSTAT;
+		break;
+	default:
+		return;
+	}
+
+	iir_mask = read_reg(iir) & 0x7fff0000;
+
+	write_reg(iir, iir_mask | iir_bit);
+
+	while (!quit) {
+		pix1 = read_reg(pix);
+		iir1 = read_reg(iir);
+		iir2 = read_reg(iir);
+		pix2 = read_reg(pix);
+
+		if (!(iir2 & iir_bit))
+			continue;
+
+		if (iir1 & iir_bit) {
+			write_reg(iir, iir_mask | iir_bit);
+			continue;
+		}
+
+		pix1 &= PIPE_PIXEL_MASK;
+		pix2 &= PIPE_PIXEL_MASK;
+
+		min[i] = pix1;
+		max[i] = pix2;
+		if (++i >= count)
+			break;
+	}
+}
+
+static void poll_pixel_iir_gen3(int pipe, int bit, uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t pix, pix1, pix2, iir1, iir2, imr_save, ier_save;
+	int i = 0;
+
+	bit = 1 << bit;
+
+	switch (pipe) {
+	case 0:
+		pix = PIPEAFRAMEPIXEL;
+		break;
+	case 1:
+		pix = PIPEBFRAMEPIXEL;
+		break;
+	default:
+		return;
+	}
+
+	imr_save = read_reg(IMR);
+	ier_save = read_reg(IER);
+
+	write_reg(IER, ier_save & ~bit);
+	write_reg(IMR, imr_save & ~bit);
+
+	write_reg(IIR, bit);
+
+	while (!quit) {
+		pix1 = read_reg(pix);
+		iir1 = read_reg(IIR);
+		iir2 = read_reg(IIR);
+		pix2 = read_reg(pix);
+
+		if (!(iir2 & bit))
+			continue;
+
+		write_reg(IIR, bit);
+
+		if (iir1 & bit)
+			continue;
+
+		pix1 &= PIPE_PIXEL_MASK;
+		pix2 &= PIPE_PIXEL_MASK;
+
+		min[i] = pix1;
+		max[i] = pix2;
+		if (++i >= count)
+			break;
+	}
+
+	write_reg(IMR, imr_save);
+	write_reg(IER, ier_save);
+}
+
+static void poll_pixel_framecount_gen3(int pipe, uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t pix, pix1, pix2, frm1, frm2;
+	int i = 0;
+
+	switch (pipe) {
+	case 0:
+		pix = PIPEAFRAMEPIXEL;
+		break;
+	case 1:
+		pix = PIPEBFRAMEPIXEL;
+		break;
+	default:
+		return;
+	}
+
+	while (!quit) {
+		pix1 = read_reg(pix);
+		pix2 = read_reg(pix);
+
+		frm1 = pix1 >> 24;
+		frm2 = pix2 >> 24;
+
+		if (frm1 + 1 != frm2)
+			continue;
+
+		pix1 &= PIPE_PIXEL_MASK;
+		pix2 &= PIPE_PIXEL_MASK;
+
+		min[i] = pix1;
+		max[i] = pix2;
+		if (++i >= count)
+			break;
+	}
+}
+
+static void poll_pixel_pan(uint32_t devid, int pipe, int target_pixel, int target_fuzz,
+			   uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t pix, pix1 = 0, pix2 = 0;
+	uint32_t saved, surf = 0;
+	int i = 0;
+
+	switch (pipe) {
+	case 0:
+		pix = PIPEAFRAMEPIXEL;
+		break;
+	case 1:
+		pix = PIPEBFRAMEPIXEL;
+		break;
+	default:
+		return;
+	}
+
+	surf = dspoffset_reg(devid, pipe);
+
+	saved = read_reg(surf);
+
+	while (!quit) {
+		while (!quit){
+			pix1 = read_reg(pix) & PIPE_PIXEL_MASK;
+			if (pix1 == target_pixel)
+				break;
+		}
+
+		write_reg(surf, saved+256);
+
+		while (!quit){
+			pix2 = read_reg(pix) & PIPE_PIXEL_MASK;
+			if (pix2 >= target_pixel + target_fuzz)
+				break;
+		}
+
+		write_reg(surf, saved);
+
+		min[i] = pix1;
+		max[i] = pix2;
+		if (++i >= count)
+			break;
+	}
+
+	write_reg(surf, saved);
+}
+
+static void poll_pixel_flip(uint32_t devid, int pipe, int target_pixel, int target_fuzz,
+			    uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t pix, pix1, pix2;
+	uint32_t saved, surf = 0;
+	int i = 0;
+
+	switch (pipe) {
+	case 0:
+		pix = PIPEAFRAMEPIXEL;
+	case 1:
+		pix = PIPEBFRAMEPIXEL;
+	default:
+		return;
+	}
+
+	surf = dspsurf_reg(devid, pipe);
+
+	saved = read_reg(surf);
+
+	while (!quit) {
+		while (!quit){
+			pix1 = read_reg(pix) & PIPE_PIXEL_MASK;
+			if (pix1 == target_pixel)
+				break;
+		}
+
+		write_reg(surf, saved+4096);
+
+		while (!quit){
+			pix2 = read_reg(pix) & PIPE_PIXEL_MASK;
+			if (pix2 >= target_pixel + target_fuzz)
+				break;
+		}
+
+		write_reg(surf, saved);
+
+		min[i] = pix1;
+		max[i] = pix2;
+		if (++i >= count)
+			break;
+	}
+
+	write_reg(surf, saved);
+}
+
+static void poll_pixel_wrap(int pipe, uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t pix, pix1, pix2;
+	int i = 0;
+
+	switch (pipe) {
+	case 0:
+		pix = PIPEAFRAMEPIXEL;
+		break;
+	case 1:
+		pix = PIPEBFRAMEPIXEL;
+		break;
+	default:
+		return;
+	}
+
+	while (!quit) {
+		pix1 = read_reg(pix);
+		pix2 = read_reg(pix);
+
+		pix1 &= PIPE_PIXEL_MASK;
+		pix2 &= PIPE_PIXEL_MASK;
+
+		if (pix2 >= pix1)
+			continue;
+
+		min[i] = pix1;
+		max[i] = pix2;
+		if (++i >= count)
+			break;
+	}
+}
+
+static void poll_dsl_pipestat(int pipe, int bit,
+			      uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1, dsl2, iir, iir1, iir2, iir_bit, iir_mask;
+	bool field1, field2;
+	int i[2] = {};
+
+	switch (pipe) {
+	case 0:
+		iir_bit = 1 << bit;
+		iir = PIPEASTAT;
+		break;
+	case 1:
+		iir_bit = 1 << bit;
+		iir = PIPEBSTAT;
+		break;
+	default:
+		return;
+	}
+
+	dsl = dsl_reg(pipe);
+
+	iir_mask = read_reg(iir) & 0x7fff0000;
+
+	write_reg(iir, iir_mask | iir_bit);
+
+	while (!quit) {
+		dsl1 = read_reg(dsl);
+		iir1 = read_reg(iir);
+		iir2 = read_reg(iir);
+		dsl2 = read_reg(dsl);
+
+		field1 = dsl1 & 0x80000000;
+		field2 = dsl2 & 0x80000000;
+		dsl1 &= ~0x80000000;
+		dsl2 &= ~0x80000000;
+
+		if (!(iir2 & iir_bit))
+			continue;
+
+		if (iir1 & iir_bit) {
+			write_reg(iir, iir_mask | iir_bit);
+			continue;
+		}
+
+		if (field1 != field2)
+			printf("fields are different (%u:%u -> %u:%u)\n",
+			       field1, dsl1, field2, dsl2);
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			break;
+	}
+}
+
+static void poll_dsl_iir_gen2(int pipe, int bit,
+			      uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1, dsl2, iir1, iir2, imr_save, ier_save;
+	bool field1, field2;
+	int i[2] = {};
+
+	bit = 1 << bit;
+
+	dsl = dsl_reg(pipe);
+
+	imr_save = read_reg_16(IMR);
+	ier_save = read_reg_16(IER);
+
+	write_reg_16(IER, ier_save & ~bit);
+	write_reg_16(IMR, imr_save & ~bit);
+
+	write_reg_16(IIR, bit);
+
+	while (!quit) {
+		dsl1 = read_reg(dsl);
+		iir1 = read_reg_16(IIR);
+		iir2 = read_reg_16(IIR);
+		dsl2 = read_reg(dsl);
+
+		field1 = dsl1 & 0x80000000;
+		field2 = dsl2 & 0x80000000;
+		dsl1 &= ~0x80000000;
+		dsl2 &= ~0x80000000;
+
+		if (!(iir2 & bit))
+			continue;
+
+		write_reg_16(IIR, bit);
+
+		if (iir1 & bit)
+			continue;
+
+		if (field1 != field2)
+			printf("fields are different (%u:%u -> %u:%u)\n",
+			       field1, dsl1, field2, dsl2);
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			break;
+	}
+
+	write_reg_16(IMR, imr_save);
+	write_reg_16(IER, ier_save);
+}
+
+static void poll_dsl_iir_gen3(int pipe, int bit,
+			      uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1, dsl2, iir1, iir2, imr_save, ier_save;
+	bool field1, field2;
+	int i[2] = {};
+
+	bit = 1 << bit;
+
+	dsl = dsl_reg(pipe);
+
+	imr_save = read_reg(IMR);
+	ier_save = read_reg(IER);
+
+	write_reg(IER, ier_save & ~bit);
+	write_reg(IMR, imr_save & ~bit);
+
+	write_reg(IIR, bit);
+
+	while (!quit) {
+		dsl1 = read_reg(dsl);
+		iir1 = read_reg(IIR);
+		iir2 = read_reg(IIR);
+		dsl2 = read_reg(dsl);
+
+		field1 = dsl1 & 0x80000000;
+		field2 = dsl2 & 0x80000000;
+		dsl1 &= ~0x80000000;
+		dsl2 &= ~0x80000000;
+
+		if (!(iir2 & bit))
+			continue;
+
+		write_reg(IIR, bit);
+
+		if (iir1 & bit)
+			continue;
+
+		if (field1 != field2)
+			printf("fields are different (%u:%u -> %u:%u)\n",
+			       field1, dsl1, field2, dsl2);
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			break;
+	}
+
+	write_reg(IMR, imr_save);
+	write_reg(IER, ier_save);
+}
+
+static void poll_dsl_deiir(uint32_t devid, int pipe, int bit,
+			   uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1, dsl2, iir1, iir2, imr_save, ier_save;
+	bool field1, field2;
+	uint32_t iir, ier, imr;
+	int i[2] = {};
+
+	bit = 1 << bit;
+
+	dsl = dsl_reg(pipe);
+
+	if (IS_GEN8(devid)) {
+		iir = GEN8_DE_PIPE_IIR(pipe);
+		ier = GEN8_DE_PIPE_IER(pipe);
+		imr = GEN8_DE_PIPE_IMR(pipe);
+	} else {
+		iir = DEIIR;
+		ier = DEIER;
+		imr = DEIMR;
+	}
+
+	imr_save = read_reg(imr);
+	ier_save = read_reg(ier);
+
+	write_reg(ier, ier_save & ~bit);
+	write_reg(imr, imr_save & ~bit);
+
+	write_reg(iir, bit);
+
+	while (!quit) {
+		dsl1 = read_reg(dsl);
+		iir1 = read_reg(iir);
+		iir2 = read_reg(iir);
+		dsl2 = read_reg(dsl);
+
+		field1 = dsl1 & 0x80000000;
+		field2 = dsl2 & 0x80000000;
+		dsl1 &= ~0x80000000;
+		dsl2 &= ~0x80000000;
+
+		if (!(iir2 & bit))
+			continue;
+
+		write_reg(iir, bit);
+
+		if (iir1 & bit)
+			continue;
+
+		if (field1 != field2)
+			printf("fields are different (%u:%u -> %u:%u)\n",
+			       field1, dsl1, field2, dsl2);
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			break;
+	}
+
+	write_reg(imr, imr_save);
+	write_reg(ier, ier_save);
+}
+
+static void poll_dsl_framecount_g4x(int pipe, uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1, dsl2, frm, frm1, frm2;
+	bool field1, field2;
+	int i[2] = {};
+
+	switch (pipe) {
+	case 0:
+		frm = PIPEAFRMCOUNT_G4X;
+		break;
+	case 1:
+		frm = PIPEBFRMCOUNT_G4X;
+		break;
+	case 2:
+		frm = PIPECFRMCOUNT_G4X;
+		break;
+	default:
+		return;
+	}
+
+	dsl = dsl_reg(pipe);
+
+	while (!quit) {
+		dsl1 = read_reg(dsl);
+		frm1 = read_reg(frm);
+		frm2 = read_reg(frm);
+		dsl2 = read_reg(dsl);
+
+		field1 = dsl1 & 0x80000000;
+		field2 = dsl2 & 0x80000000;
+		dsl1 &= ~0x80000000;
+		dsl2 &= ~0x80000000;
+
+		if (frm1 + 1 != frm2)
+			continue;
+
+		if (field1 != field2)
+			printf("fields are different (%u:%u -> %u:%u)\n",
+			       field1, dsl1, field2, dsl2);
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			break;
+	}
+}
+
+static void poll_dsl_flipcount_g4x(uint32_t devid, int pipe,
+				   uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1, dsl2, flp, flp1, flp2, surf;
+	bool field1, field2;
+	int i[2] = {};
+
+	switch (pipe) {
+	case 0:
+		flp = PIPEAFLIPCOUNT_G4X;
+		break;
+	case 1:
+		flp = PIPEBFLIPCOUNT_G4X;
+		break;
+	case 2:
+		flp = PIPECFLIPCOUNT_G4X;
+		break;
+	default:
+		return;
+	}
+
+	dsl = dsl_reg(pipe);
+	surf = dspsurf_reg(devid, pipe);
+
+	while (!quit) {
+		usleep(10);
+		dsl1 = read_reg(dsl);
+		flp1 = read_reg(flp);
+		dsl2 = read_reg(dsl);
+
+		field1 = dsl1 & 0x80000000;
+		field2 = dsl2 & 0x80000000;
+		dsl1 &= ~0x80000000;
+		dsl2 &= ~0x80000000;
+
+		if (field1 != field2)
+			printf("fields are different (%u:%u -> %u:%u)\n",
+			       field1, dsl1, field2, dsl2);
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			return;
+
+		write_reg(surf, read_reg(surf));
+
+		while (!quit) {
+			dsl1 = read_reg(dsl);
+			flp2 = read_reg(flp);
+			dsl2 = read_reg(dsl);
+
+			field1 = dsl1 & 0x80000000;
+			field2 = dsl2 & 0x80000000;
+			dsl1 &= ~0x80000000;
+			dsl2 &= ~0x80000000;
+
+			if (flp1 == flp2)
+				continue;
+
+			if (field1 != field2)
+				printf("fields are different (%u:%u -> %u:%u)\n",
+				       field1, dsl1, field2, dsl2);
+
+			min[field1*count+i[field1]] = dsl1;
+			max[field1*count+i[field1]] = dsl2;
+			if (++i[field1] >= count)
+				break;
+		}
+		if (i[field1] >= count)
+			break;
+	}
+}
+
+static void poll_dsl_framecount_gen3(int pipe, uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1, dsl2, frm, frm1, frm2;
+	bool field1, field2;
+	int i[2] = {};
+
+	switch (pipe) {
+	case 0:
+		frm = PIPEAFRAMEPIXEL;
+		break;
+	case 1:
+		frm = PIPEBFRAMEPIXEL;
+		break;
+	default:
+		return;
+	}
+
+	dsl = dsl_reg(pipe);
+
+	while (!quit) {
+		dsl1 = read_reg(dsl);
+		frm1 = read_reg(frm) >> 24;
+		frm2 = read_reg(frm) >> 24;
+		dsl2 = read_reg(dsl);
+
+		field1 = dsl1 & 0x80000000;
+		field2 = dsl2 & 0x80000000;
+		dsl1 &= ~0x80000000;
+		dsl2 &= ~0x80000000;
+
+		if (frm1 + 1 != frm2)
+			continue;
+
+		if (field1 != field2)
+			printf("fields are different (%u:%u -> %u:%u)\n",
+			       field1, dsl1, field2, dsl2);
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			break;
+	}
+}
+
+static void poll_dsl_pan(uint32_t devid, int pipe, int target_scanline, int target_fuzz,
+			 uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1 = 0, dsl2 = 0;
+	bool field1 = false, field2 = false;
+	uint32_t saved, surf = 0;
+	int i[2] = {};
+
+	dsl = dsl_reg(pipe);
+	surf = dspoffset_reg(devid, pipe);
+
+	saved = read_reg(surf);
+
+	while (!quit) {
+		while (!quit) {
+			dsl1 = read_reg(dsl);
+			field1 = dsl1 & 0x80000000;
+			dsl1 &= ~0x80000000;
+			if (dsl1 == target_scanline)
+				break;
+		}
+
+		write_reg(surf, saved+256);
+
+		while (!quit) {
+			dsl2 = read_reg(dsl);
+			field2 = dsl1 & 0x80000000;
+			dsl2 &= ~0x80000000;
+			if (dsl2 == target_scanline + target_fuzz)
+				break;
+		}
+
+		write_reg(surf, saved);
+
+		if (field1 != field2)
+			printf("fields are different (%u:%u -> %u:%u)\n",
+			       field1, dsl1, field2, dsl2);
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			break;
+	}
+
+	write_reg(surf, saved);
+}
+
+static void poll_dsl_flip(uint32_t devid, int pipe, int target_scanline, int target_fuzz,
+			  uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1 = 0, dsl2 = 0;
+	bool field1 = false, field2 = false;
+	uint32_t saved, surf = 0;
+	int i[2] = {};
+
+	dsl = dsl_reg(pipe);
+	surf = dspsurf_reg(devid, pipe);
+
+	saved = read_reg(surf);
+
+	while (!quit) {
+		while (!quit) {
+			dsl1 = read_reg(dsl);
+			field1 = dsl1 & 0x80000000;
+			dsl1 &= ~0x80000000;
+			if (dsl1 == target_scanline)
+				break;
+		}
+
+		write_reg(surf, saved+4096);
+
+		while (!quit) {
+			dsl2 = read_reg(dsl);
+			field2 = dsl1 & 0x80000000;
+			dsl2 &= ~0x80000000;
+			if (dsl2 == target_scanline + target_fuzz)
+				break;
+		}
+
+		write_reg(surf, saved);
+
+		if (field1 != field2)
+			printf("fields are different (%u:%u -> %u:%u)\n",
+			       field1, dsl1, field2, dsl2);
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			break;
+	}
+
+	write_reg(surf, saved);
+}
+
+static void poll_dsl_surflive(uint32_t devid, int pipe,
+			      uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1 = 0, dsl2 = 0, surf, surf1, surf2, surflive, surfl1 = 0, surfl2, saved, tmp;
+	bool field1 = false, field2 = false;
+	int i[2] = {};
+
+	switch (pipe) {
+	case 0:
+		surflive = DSPASURFLIVE;
+		break;
+	case 1:
+		surflive = DSPBSURFLIVE;
+		break;
+	case 2:
+		surflive = DSPCSURFLIVE;
+		break;
+	default:
+		return;
+	}
+
+	dsl = dsl_reg(pipe);
+	surf = dspsurf_reg(devid, pipe);
+
+	saved = read_reg(surf);
+
+	surf1 = saved & ~0xfff;
+	surf2 = surf1 + 4096;
+
+	while (!quit) {
+		write_reg(surf, surf2);
+
+		while (!quit) {
+			dsl1 = read_reg(dsl);
+			surfl1 = read_reg(surflive) & ~0xfff;
+			surfl2 = read_reg(surflive) & ~0xfff;
+			dsl2 = read_reg(dsl);
+
+			field1 = dsl1 & 0x80000000;
+			field2 = dsl2 & 0x80000000;
+			dsl1 &= ~0x80000000;
+			dsl2 &= ~0x80000000;
+
+			if (surfl2 == surf2)
+				break;
+		}
+
+		if (surfl1 != surf2) {
+			if (field1 != field2)
+				printf("fields are different (%u:%u -> %u:%u)\n",
+				       field1, dsl1, field2, dsl2);
+
+			min[field1*count+i[field1]] = dsl1;
+			max[field1*count+i[field1]] = dsl2;
+			if (++i[field1] >= count)
+				break;
+		}
+
+		tmp = surf1;
+		surf1 = surf2;
+		surf2 = tmp;
+	}
+
+	write_reg(surf, saved);
+}
+
+static void poll_dsl_wrap(int pipe, uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1, dsl2;
+	bool field1, field2;
+	int i[2] = {};
+
+	dsl = dsl_reg(pipe);
+
+	while (!quit) {
+		dsl1 = read_reg(dsl);
+		dsl2 = read_reg(dsl);
+
+		field1 = dsl1 & 0x80000000;
+		field2 = dsl2 & 0x80000000;
+		dsl1 &= ~0x80000000;
+		dsl2 &= ~0x80000000;
+
+		if (dsl2 >= dsl1)
+			continue;
+
+		if (field1 != field2)
+			printf("fields are different (%u:%u -> %u:%u)\n",
+			       field1, dsl1, field2, dsl2);
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			break;
+	}
+}
+
+static void poll_dsl_field(int pipe, uint32_t *min, uint32_t *max, const int count)
+{
+	uint32_t dsl, dsl1, dsl2;
+	bool field1, field2;
+	int i[2] = {};
+
+	dsl = dsl_reg(pipe);
+
+	while (!quit) {
+		dsl1 = read_reg(dsl);
+		dsl2 = read_reg(dsl);
+
+		field1 = dsl1 & 0x80000000;
+		field2 = dsl2 & 0x80000000;
+		dsl1 &= ~0x80000000;
+		dsl2 &= ~0x80000000;
+
+		if (field1 == field2)
+			continue;
+
+		min[field1*count+i[field1]] = dsl1;
+		max[field1*count+i[field1]] = dsl2;
+		if (++i[field1] >= count)
+			break;
+	}
+}
+
+static char pipe_name(int pipe)
+{
+	return pipe + 'A';
+}
+
+static const char *test_name(enum test test, int pipe, int bit, bool test_pixel_count)
+{
+	static char str[32];
+	const char *type = test_pixel_count ? "pixel" : "dsl";
+
+	switch (test) {
+	case TEST_PIPESTAT:
+		snprintf(str, sizeof str, "%s / pipe %c / PIPESTAT[%d] (gmch)", type, pipe_name(pipe), bit);
+		return str;
+	case TEST_IIR_GEN2:
+		snprintf(str, sizeof str, "%s / pipe %c / IIR[%d] (gen2)", type, pipe_name(pipe), bit);
+		return str;
+	case TEST_IIR_GEN3:
+		snprintf(str, sizeof str, "%s / pipe %c / IIR[%d] (gen3+)", type, pipe_name(pipe), bit);
+		return str;
+	case TEST_DEIIR:
+		snprintf(str, sizeof str, "%s / pipe %c / DEIIR[%d] (pch)", type, pipe_name(pipe), bit);
+		return str;
+	case TEST_FRAMECOUNT_GEN3:
+		snprintf(str, sizeof str, "%s / pipe %c / Frame count (gen3/4)", type, pipe_name(pipe));
+		return str;
+	case TEST_FRAMECOUNT_G4X:
+		snprintf(str, sizeof str, "%s / pipe %c / Frame count (g4x+)", type, pipe_name(pipe));
+		return str;
+	case TEST_FLIPCOUNT:
+		snprintf(str, sizeof str, "%s / pipe %c / Flip count (g4x+)", type, pipe_name(pipe));
+		return str;
+	case TEST_PAN:
+		snprintf(str, sizeof str, "%s / pipe %c / Pan", type, pipe_name(pipe));
+		return str;
+	case TEST_FLIP:
+		snprintf(str, sizeof str, "%s / pipe %c / Flip", type, pipe_name(pipe));
+		return str;
+	case TEST_SURFLIVE:
+		snprintf(str, sizeof str, "%s / pipe %c / Surflive", type, pipe_name(pipe));
+		return str;
+	case TEST_WRAP:
+		snprintf(str, sizeof str, "%s / pipe %c / Wrap", type, pipe_name(pipe));
+		return str;
+	case TEST_FIELD:
+		snprintf(str, sizeof str, "%s / pipe %c / Field", type, pipe_name(pipe));
+		return str;
+	default:
+		return "";
+	}
+}
+
+static void usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s [options]\n"
+		" -t,--test <pipestat|iir|framecount|flipcount|pan|flip|surflive|wrap|field>\n"
+		" -p,--pipe <pipe>\n"
+		" -b,--bit <bit>\n"
+		" -l,--line <target scanline/pixel>\n"
+		" -f,--fuzz <target fuzz>\n"
+		" -x,--pixel\n",
+		name);
+	exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+	int fd, i;
+	int pipe = 0, bit = 0, target_scanline = 0, target_fuzz = 1;
+	bool test_pixelcount = false;
+	uint32_t devid;
+	uint32_t min[2*128] = {};
+	uint32_t max[2*128] = {};
+	uint32_t a, b;
+	enum test test = TEST_INVALID;
+	const int count = ARRAY_SIZE(min)/2;
+
+	for (;;) {
+		static const struct option long_options[] = {
+			{ .name = "test", .has_arg = required_argument, },
+			{ .name = "pipe", .has_arg = required_argument, },
+			{ .name = "bit", .has_arg = required_argument, },
+			{ .name = "line", .has_arg = required_argument, },
+			{ .name = "fuzz", .has_arg = required_argument, },
+			{ .name = "pixel", .has_arg = no_argument, },
+			{ },
+		};
+
+		int opt = getopt_long(argc, argv, "t:p:b:l:f:x", long_options, NULL);
+		if (opt == -1)
+			break;
+
+		switch (opt) {
+		case 't':
+			if (!strcmp(optarg, "pipestat"))
+				test = TEST_PIPESTAT;
+			else if (!strcmp(optarg, "iir"))
+				test = TEST_IIR;
+			else if (!strcmp(optarg, "framecount"))
+				test = TEST_FRAMECOUNT;
+			else if (!strcmp(optarg, "flipcount"))
+				test = TEST_FLIPCOUNT;
+			else if (!strcmp(optarg, "pan"))
+				test = TEST_PAN;
+			else if (!strcmp(optarg, "flip"))
+				test = TEST_FLIP;
+			else if (!strcmp(optarg, "surflive"))
+				test = TEST_SURFLIVE;
+			else if (!strcmp(optarg, "wrap"))
+				test = TEST_WRAP;
+			else if (!strcmp(optarg, "field"))
+				test = TEST_FIELD;
+			else
+				usage(argv[0]);
+			break;
+		case 'p':
+			pipe = atoi(optarg);
+			if (pipe < 0 || pipe > 2)
+				usage(argv[0]);
+			break;
+		case 'b':
+			bit = atoi(optarg);
+			if (bit < 0 || bit > 31)
+				usage(argv[0]);
+			break;
+		case 'l':
+			target_scanline = atoi(optarg);
+			if (target_scanline < 0)
+				usage(argv[0]);
+			break;
+		case 'f':
+			target_fuzz = atoi(optarg);
+			if (target_fuzz <= 0)
+				usage(argv[0]);
+			break;
+		case 'x':
+			test_pixelcount = true;
+			break;
+		}
+	}
+
+	fd = drm_open_any();
+	devid = intel_get_drm_devid(fd);
+	close(fd);
+
+	/*
+	 * check if the requires registers are
+	 * avilable on the current platform.
+	 */
+	if (IS_GEN2(devid)) {
+		if (pipe > 1)
+			usage(argv[0]);
+
+		if (test_pixelcount)
+			usage(argv[0]);
+
+		switch (test) {
+		case TEST_IIR:
+			test = TEST_IIR_GEN2;
+			break;
+		case TEST_PIPESTAT:
+		case TEST_PAN:
+			break;
+		case TEST_FLIP:
+			test = TEST_PAN;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	} else if (IS_GEN3(devid) ||
+		   (IS_GEN4(devid) && !IS_G4X(devid))) {
+		if (pipe > 1)
+			usage(argv[0]);
+
+		switch (test) {
+		case TEST_IIR:
+			test = TEST_IIR_GEN3;
+			break;
+		case TEST_FRAMECOUNT:
+			test = TEST_FRAMECOUNT_GEN3;
+			break;
+		case TEST_PIPESTAT:
+		case TEST_PAN:
+		case TEST_WRAP:
+		case TEST_FIELD:
+			break;
+		case TEST_FLIP:
+			if (IS_GEN3(devid))
+				test = TEST_PAN;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	} else if (IS_G4X(devid) || IS_VALLEYVIEW(devid)) {
+		if (IS_VALLEYVIEW(devid))
+			vlv_offset = 0x180000;
+
+		if (pipe > 1)
+			usage(argv[0]);
+
+		if (test_pixelcount)
+			usage(argv[0]);
+
+		switch (test) {
+		case TEST_IIR:
+			test = TEST_IIR_GEN3;
+			break;
+		case TEST_FRAMECOUNT:
+			test = TEST_FRAMECOUNT_G4X;
+			break;
+		case TEST_FLIPCOUNT:
+		case TEST_PIPESTAT:
+		case TEST_PAN:
+		case TEST_FLIP:
+		case TEST_SURFLIVE:
+		case TEST_WRAP:
+		case TEST_FIELD:
+			break;
+		default:
+			usage(argv[0]);
+		}
+	} else if (HAS_PCH_SPLIT(devid) &&
+		   (IS_GEN5(devid) || IS_GEN6(devid) || IS_GEN7(devid))) {
+		if (pipe > 1 &&
+		    (IS_GEN5(devid) || IS_GEN6(devid)))
+			usage(argv[0]);
+
+		if (test_pixelcount)
+			usage(argv[0]);
+
+		switch (test) {
+		case TEST_IIR:
+			test = TEST_DEIIR;
+			break;
+		case TEST_FRAMECOUNT:
+			test = TEST_FRAMECOUNT_G4X;
+			break;
+		case TEST_FLIPCOUNT:
+		case TEST_PAN:
+		case TEST_FLIP:
+		case TEST_SURFLIVE:
+		case TEST_WRAP:
+		case TEST_FIELD:
+			break;
+		default:
+			usage(argv[0]);
+		}
+	} else if (IS_GEN8(devid)) {
+		if (test_pixelcount)
+			usage(argv[0]);
+
+		switch (test) {
+		case TEST_IIR:
+			test = TEST_DEIIR;
+			break;
+		case TEST_FRAMECOUNT:
+			test = TEST_FRAMECOUNT_G4X;
+			break;
+		case TEST_FLIPCOUNT:
+		case TEST_PAN:
+		case TEST_FLIP:
+		case TEST_SURFLIVE:
+		case TEST_WRAP:
+		case TEST_FIELD:
+			break;
+		default:
+			usage(argv[0]);
+		}
+	} else {
+		usage(argv[0]);
+	}
+
+	switch (test) {
+	case TEST_IIR:
+	case TEST_FRAMECOUNT:
+		/* should no longer have the generic tests here */
+		assert(0);
+	default:
+		break;
+	}
+
+	intel_register_access_init(intel_get_pci_device(), 0);
+
+	printf("%s?\n", test_name(test, pipe, bit, test_pixelcount));
+
+	signal(SIGHUP, sighandler);
+	signal(SIGINT, sighandler);
+	signal(SIGTERM, sighandler);
+
+	switch (test) {
+	case TEST_PIPESTAT:
+		if (test_pixelcount)
+			poll_pixel_pipestat(pipe, bit, min, max, count);
+		else
+			poll_dsl_pipestat(pipe, bit, min, max, count);
+		break;
+	case TEST_IIR_GEN2:
+		assert(!test_pixelcount);
+		poll_dsl_iir_gen2(pipe, bit, min, max, count);
+		break;
+	case TEST_IIR_GEN3:
+		if (test_pixelcount)
+			poll_pixel_iir_gen3(pipe, bit, min, max, count);
+		else
+			poll_dsl_iir_gen3(pipe, bit, min, max, count);
+		break;
+	case TEST_DEIIR:
+		assert(!test_pixelcount);
+		poll_dsl_deiir(devid, pipe, bit, min, max, count);
+		break;
+	case TEST_FRAMECOUNT_GEN3:
+		if (test_pixelcount)
+			poll_pixel_framecount_gen3(pipe, min, max, count);
+		else
+			poll_dsl_framecount_gen3(pipe, min, max, count);
+		break;
+	case TEST_FRAMECOUNT_G4X:
+		assert(!test_pixelcount);
+		poll_dsl_framecount_g4x(pipe, min, max, count);
+		break;
+	case TEST_FLIPCOUNT:
+		assert(!test_pixelcount);
+		poll_dsl_flipcount_g4x(devid, pipe, min, max, count);
+		break;
+	case TEST_PAN:
+		if (test_pixelcount)
+			poll_pixel_pan(devid, pipe, target_scanline, target_fuzz,
+				       min, max, count);
+		else
+			poll_dsl_pan(devid, pipe, target_scanline, target_fuzz,
+				     min, max, count);
+		break;
+	case TEST_FLIP:
+		if (test_pixelcount)
+			poll_pixel_flip(devid, pipe, target_scanline, target_fuzz,
+					min, max, count);
+		else
+			poll_dsl_flip(devid, pipe, target_scanline, target_fuzz,
+				      min, max, count);
+		break;
+	case TEST_SURFLIVE:
+		poll_dsl_surflive(devid, pipe, min, max, count);
+		break;
+	case TEST_WRAP:
+		if (test_pixelcount)
+			poll_pixel_wrap(pipe, min, max, count);
+		else
+			poll_dsl_wrap(pipe, min, max, count);
+		break;
+	case TEST_FIELD:
+		poll_dsl_field(pipe, min, max, count);
+		break;
+	default:
+		assert(0);
+	}
+
+	intel_register_access_fini();
+
+	if (quit)
+		return 0;
+
+	for (i = 0; i < count; i++) {
+		if (min[0*count+i] == 0 && max[0*count+i] == 0)
+			break;
+		printf("[%u] %4u - %4u (%4u)\n", 0, min[0*count+i], max[0*count+i],
+		       (min[0*count+i] + max[0*count+i] + 1) >> 1);
+	}
+	for (i = 0; i < count; i++) {
+		if (min[1*count+i] == 0 && max[1*count+i] == 0)
+			break;
+		printf("[%u] %4u - %4u (%4u)\n", 1, min[1*count+i], max[1*count+i],
+		       (min[1*count+i] + max[1*count+i] + 1) >> 1);
+	}
+
+	a = 0;
+	b = 0xffffffff;
+	for (i = 0; i < count; i++) {
+		if (min[0*count+i] == 0 && max[0*count+i] == 0)
+			break;
+		a = max(a, min[0*count+i]);
+		b = min(b, max[0*count+i]);
+	}
+
+	printf("%s: [%u] %6u - %6u\n", test_name(test, pipe, bit, test_pixelcount), 0, a, b);
+
+	a = 0;
+	b = 0xffffffff;
+	for (i = 0; i < count; i++) {
+		if (min[1*count+i] == 0 && max[1*count+i] == 0)
+			break;
+		a = max(a, min[1*count+i]);
+		b = min(b, max[1*count+i]);
+	}
+
+	printf("%s: [%u] %6u - %6u\n", test_name(test, pipe, bit, test_pixelcount), 1, a, b);
+
+	return 0;
+}

Comments

On Wed, Jun 11, 2014 at 07:41:20PM +0300, ville.syrjala@linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> intel_poller can be used to poll various display registers
> (IIR,scanline/pixel/flip/frame counter, live address, etc.).
> 
> It can be used to determine eg. at which scanline or pixel count certain
> events occur.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
> 
> Ideas for a better name are welcome!

intel_display_poller maybe since the use-case is display specific. But
not really important imo.
-Daniel

> 
> 
>  lib/intel_reg.h        |   22 +-
>  tools/Makefile.sources |    1 +
>  tools/intel_poller.c   | 1471 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1491 insertions(+), 3 deletions(-)
>  create mode 100644 tools/intel_poller.c
> 
> diff --git a/lib/intel_reg.h b/lib/intel_reg.h
> index 84e05e4..87a14c9 100644
> --- a/lib/intel_reg.h
> +++ b/lib/intel_reg.h
> @@ -2248,7 +2248,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>   */
>  #define PIPE_PIXEL_MASK		0x00ffffff
>  #define PIPE_PIXEL_SHIFT	0
> -
> +/*
> + * g4x+ frame/flip counters
> + */
> +#define PIPEAFRMCOUNT_G4X	0x70040
> +#define PIPEAFLIPCOUNT_G4X	0x70044
>  /*
>   * Computing GMCH M and N values.
>   *
> @@ -2296,20 +2300,24 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>  #define PIPEBSTAT		0x71024
>  #define PIPEBFRAMEHIGH		0x71040
>  #define PIPEBFRAMEPIXEL		0x71044
> +#define PIPEBFRMCOUNT_G4X	0x71040
> +#define PIPEBFLIPCOUNT_G4X	0x71044
>  
>  #define PIPEB_GMCH_DATA_M	0x71050
>  #define PIPEB_GMCH_DATA_N	0x71054
>  #define PIPEB_DP_LINK_M		0x71060
>  #define PIPEB_DP_LINK_N		0x71064
>  
> +#define PIPEC_DSL		0x72000
> +
>  #define PIPECCONF 		0x72008
>  
>  #define PIPECGCMAXRED		0x72010
>  #define PIPECGCMAXGREEN		0x72014
>  #define PIPECGCMAXBLUE		0x72018
>  #define PIPECSTAT		0x72024
> -#define PIPECFRAMEHIGH		0x72040
> -#define PIPECFRAMEPIXEL		0x72044
> +#define PIPECFRMCOUNT_G4X	0x72040
> +#define PIPECFLIPCOUNT_G4X	0x72044
>  
>  #define PIPEC_GMCH_DATA_M	0x72050
>  #define PIPEC_GMCH_DATA_N	0x72054
> @@ -2370,12 +2378,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>  
>  #define DSPASURF		0x7019C
>  #define DSPATILEOFF		0x701A4
> +#define DSPASURFLIVE		0x701AC
>  
>  #define DSPBSURF		0x7119C
>  #define DSPBTILEOFF		0x711A4
> +#define DSPBSURFLIVE		0x711AC
>  
>  #define DSPCSURF		0x7219C
>  #define DSPCTILEOFF		0x721A4
> +#define DSPCSURFLIVE		0x721AC
>  
>  #define VGACNTRL		0x71400
>  # define VGA_DISP_DISABLE			(1 << 31)
> @@ -2879,6 +2890,11 @@ typedef enum {
>  #define DEIIR	0x44008
>  #define DEIER	0x4400c
>  
> +#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + 0x10 * (pipe))
> +#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + 0x10 * (pipe))
> +#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + 0x10 * (pipe))
> +#define GEN8_DE_PIPE_IER(pipe) (0x4440c + 0x10 * (pipe))
> +
>  /* GT interrupt */
>  #define GT_SYNC_STATUS		(1 << 2)
>  #define GT_USER_INTERRUPT	(1 << 0)
> diff --git a/tools/Makefile.sources b/tools/Makefile.sources
> index c2535e7..6f6ca4a 100644
> --- a/tools/Makefile.sources
> +++ b/tools/Makefile.sources
> @@ -12,6 +12,7 @@ bin_PROGRAMS = 				\
>  	intel_iosf_sb_write		\
>  	intel_opregion_decode		\
>  	intel_perf_counters		\
> +	intel_poller			\
>  	intel_stepping 			\
>  	intel_reg_checker 		\
>  	intel_reg_dumper 		\
> diff --git a/tools/intel_poller.c b/tools/intel_poller.c
> new file mode 100644
> index 0000000..ebc594a
> --- /dev/null
> +++ b/tools/intel_poller.c
> @@ -0,0 +1,1471 @@
> +/*
> + * 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 <assert.h>
> +#include <fcntl.h>
> +#include <getopt.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <stdbool.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <err.h>
> +#include <string.h>
> +#include "intel_chipset.h"
> +#include "intel_io.h"
> +#include "igt_debugfs.h"
> +#include "drmtest.h"
> +
> +#define min(a,b) ((a) < (b) ? (a) : (b))
> +#define max(a,b) ((a) > (b) ? (a) : (b))
> +
> +enum test {
> +	TEST_INVALID,
> +	TEST_PIPESTAT,
> +	TEST_IIR,
> +	TEST_IIR_GEN2,
> +	TEST_IIR_GEN3,
> +	TEST_DEIIR,
> +	TEST_FRAMECOUNT,
> +	TEST_FRAMECOUNT_GEN3,
> +	TEST_FRAMECOUNT_G4X,
> +	TEST_FLIPCOUNT,
> +	TEST_PAN,
> +	TEST_FLIP,
> +	TEST_SURFLIVE,
> +	TEST_WRAP,
> +	TEST_FIELD,
> +};
> +
> +static uint32_t vlv_offset;
> +
> +static volatile bool quit;
> +
> +static void sighandler(int x)
> +{
> +	quit = true;
> +}
> +
> +static uint16_t read_reg_16(uint32_t reg)
> +{
> +	return *(volatile uint16_t *)((volatile char*)mmio + vlv_offset + reg);
> +}
> +
> +static uint32_t read_reg(uint32_t reg)
> +{
> +	return *(volatile uint32_t *)((volatile char*)mmio + vlv_offset + reg);
> +}
> +
> +static void write_reg_16(uint32_t reg, uint16_t val)
> +{
> +	*(volatile uint16_t *)((volatile char*)mmio + vlv_offset + reg) = val;
> +}
> +
> +static void write_reg(uint32_t reg, uint32_t val)
> +{
> +	*(volatile uint32_t *)((volatile char*)mmio + vlv_offset + reg) = val;
> +}
> +
> +static int pipe_to_plane(uint32_t devid, int pipe)
> +{
> +	if (!IS_GEN2(devid) && !IS_GEN3(devid))
> +		return pipe;
> +
> +	switch (pipe) {
> +	case 0:
> +		if ((read_reg(DSPACNTR) & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B)
> +			return 1;
> +		return 0;
> +	case 1:
> +		if ((read_reg(DSPACNTR) & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)
> +			return 0;
> +		return 1;
> +	}
> +
> +	assert(0);
> +
> +	return 0;
> +}
> +
> +static uint32_t dspoffset_reg(uint32_t devid, int pipe)
> +{
> +	bool use_tileoff;
> +
> +	pipe = pipe_to_plane(devid, pipe);
> +
> +	if (IS_GEN2(devid) || IS_GEN3(devid))
> +		use_tileoff = false;
> +	if (IS_HASWELL(devid) || IS_BROADWELL(devid))
> +		use_tileoff = true;
> +	else {
> +		switch (pipe) {
> +		case 0:
> +			use_tileoff = read_reg(DSPACNTR) & DISPLAY_PLANE_TILED;
> +			break;
> +		case 1:
> +			use_tileoff = read_reg(DSPBCNTR) & DISPLAY_PLANE_TILED;
> +			break;
> +		case 2:
> +			use_tileoff = read_reg(DSPCCNTR) & DISPLAY_PLANE_TILED;
> +			break;
> +		}
> +	}
> +
> +	if (use_tileoff) {
> +		switch (pipe) {
> +		case 0:
> +			return DSPATILEOFF;
> +		case 1:
> +			return DSPBTILEOFF;
> +		case 2:
> +			return DSPCTILEOFF;
> +		}
> +	} else {
> +		switch (pipe) {
> +		case 0:
> +			return DSPABASE;
> +		case 1:
> +			return DSPBBASE;
> +		case 2:
> +			return DSPCBASE;
> +		}
> +	}
> +
> +	assert(0);
> +
> +	return 0;
> +}
> +
> +static uint32_t dspsurf_reg(uint32_t devid, int pipe)
> +{
> +	pipe = pipe_to_plane(devid, pipe);
> +
> +	if (IS_GEN2(devid) || IS_GEN3(devid)) {
> +		switch (pipe) {
> +		case 0:
> +			return DSPABASE;
> +		case 1:
> +			return DSPBBASE;
> +		case 2:
> +			return DSPCBASE;
> +		}
> +	} else {
> +		switch (pipe) {
> +		case 0:
> +			return DSPASURF;
> +		case 1:
> +			return DSPBSURF;
> +		case 2:
> +			return DSPCSURF;
> +		}
> +	}
> +
> +	assert(0);
> +
> +	return 0;
> +}
> +
> +static uint32_t dsl_reg(int pipe)
> +{
> +	switch (pipe) {
> +	case 0:
> +		return PIPEA_DSL;
> +	case 1:
> +		return PIPEB_DSL;
> +	case 2:
> +		return PIPEC_DSL;
> +	}
> +
> +	assert(0);
> +
> +	return 0;
> +}
> +
> +static void poll_pixel_pipestat(int pipe, int bit, uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t pix, pix1, pix2, iir, iir1, iir2, iir_bit, iir_mask;
> +	int i = 0;
> +
> +	switch (pipe) {
> +	case 0:
> +		pix = PIPEAFRAMEPIXEL;
> +		iir_bit = 1 << bit;
> +		iir = PIPEASTAT;
> +		break;
> +	case 1:
> +		pix = PIPEBFRAMEPIXEL;
> +		iir_bit = 1 << bit;
> +		iir = PIPEBSTAT;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	iir_mask = read_reg(iir) & 0x7fff0000;
> +
> +	write_reg(iir, iir_mask | iir_bit);
> +
> +	while (!quit) {
> +		pix1 = read_reg(pix);
> +		iir1 = read_reg(iir);
> +		iir2 = read_reg(iir);
> +		pix2 = read_reg(pix);
> +
> +		if (!(iir2 & iir_bit))
> +			continue;
> +
> +		if (iir1 & iir_bit) {
> +			write_reg(iir, iir_mask | iir_bit);
> +			continue;
> +		}
> +
> +		pix1 &= PIPE_PIXEL_MASK;
> +		pix2 &= PIPE_PIXEL_MASK;
> +
> +		min[i] = pix1;
> +		max[i] = pix2;
> +		if (++i >= count)
> +			break;
> +	}
> +}
> +
> +static void poll_pixel_iir_gen3(int pipe, int bit, uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t pix, pix1, pix2, iir1, iir2, imr_save, ier_save;
> +	int i = 0;
> +
> +	bit = 1 << bit;
> +
> +	switch (pipe) {
> +	case 0:
> +		pix = PIPEAFRAMEPIXEL;
> +		break;
> +	case 1:
> +		pix = PIPEBFRAMEPIXEL;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	imr_save = read_reg(IMR);
> +	ier_save = read_reg(IER);
> +
> +	write_reg(IER, ier_save & ~bit);
> +	write_reg(IMR, imr_save & ~bit);
> +
> +	write_reg(IIR, bit);
> +
> +	while (!quit) {
> +		pix1 = read_reg(pix);
> +		iir1 = read_reg(IIR);
> +		iir2 = read_reg(IIR);
> +		pix2 = read_reg(pix);
> +
> +		if (!(iir2 & bit))
> +			continue;
> +
> +		write_reg(IIR, bit);
> +
> +		if (iir1 & bit)
> +			continue;
> +
> +		pix1 &= PIPE_PIXEL_MASK;
> +		pix2 &= PIPE_PIXEL_MASK;
> +
> +		min[i] = pix1;
> +		max[i] = pix2;
> +		if (++i >= count)
> +			break;
> +	}
> +
> +	write_reg(IMR, imr_save);
> +	write_reg(IER, ier_save);
> +}
> +
> +static void poll_pixel_framecount_gen3(int pipe, uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t pix, pix1, pix2, frm1, frm2;
> +	int i = 0;
> +
> +	switch (pipe) {
> +	case 0:
> +		pix = PIPEAFRAMEPIXEL;
> +		break;
> +	case 1:
> +		pix = PIPEBFRAMEPIXEL;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	while (!quit) {
> +		pix1 = read_reg(pix);
> +		pix2 = read_reg(pix);
> +
> +		frm1 = pix1 >> 24;
> +		frm2 = pix2 >> 24;
> +
> +		if (frm1 + 1 != frm2)
> +			continue;
> +
> +		pix1 &= PIPE_PIXEL_MASK;
> +		pix2 &= PIPE_PIXEL_MASK;
> +
> +		min[i] = pix1;
> +		max[i] = pix2;
> +		if (++i >= count)
> +			break;
> +	}
> +}
> +
> +static void poll_pixel_pan(uint32_t devid, int pipe, int target_pixel, int target_fuzz,
> +			   uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t pix, pix1 = 0, pix2 = 0;
> +	uint32_t saved, surf = 0;
> +	int i = 0;
> +
> +	switch (pipe) {
> +	case 0:
> +		pix = PIPEAFRAMEPIXEL;
> +		break;
> +	case 1:
> +		pix = PIPEBFRAMEPIXEL;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	surf = dspoffset_reg(devid, pipe);
> +
> +	saved = read_reg(surf);
> +
> +	while (!quit) {
> +		while (!quit){
> +			pix1 = read_reg(pix) & PIPE_PIXEL_MASK;
> +			if (pix1 == target_pixel)
> +				break;
> +		}
> +
> +		write_reg(surf, saved+256);
> +
> +		while (!quit){
> +			pix2 = read_reg(pix) & PIPE_PIXEL_MASK;
> +			if (pix2 >= target_pixel + target_fuzz)
> +				break;
> +		}
> +
> +		write_reg(surf, saved);
> +
> +		min[i] = pix1;
> +		max[i] = pix2;
> +		if (++i >= count)
> +			break;
> +	}
> +
> +	write_reg(surf, saved);
> +}
> +
> +static void poll_pixel_flip(uint32_t devid, int pipe, int target_pixel, int target_fuzz,
> +			    uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t pix, pix1, pix2;
> +	uint32_t saved, surf = 0;
> +	int i = 0;
> +
> +	switch (pipe) {
> +	case 0:
> +		pix = PIPEAFRAMEPIXEL;
> +	case 1:
> +		pix = PIPEBFRAMEPIXEL;
> +	default:
> +		return;
> +	}
> +
> +	surf = dspsurf_reg(devid, pipe);
> +
> +	saved = read_reg(surf);
> +
> +	while (!quit) {
> +		while (!quit){
> +			pix1 = read_reg(pix) & PIPE_PIXEL_MASK;
> +			if (pix1 == target_pixel)
> +				break;
> +		}
> +
> +		write_reg(surf, saved+4096);
> +
> +		while (!quit){
> +			pix2 = read_reg(pix) & PIPE_PIXEL_MASK;
> +			if (pix2 >= target_pixel + target_fuzz)
> +				break;
> +		}
> +
> +		write_reg(surf, saved);
> +
> +		min[i] = pix1;
> +		max[i] = pix2;
> +		if (++i >= count)
> +			break;
> +	}
> +
> +	write_reg(surf, saved);
> +}
> +
> +static void poll_pixel_wrap(int pipe, uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t pix, pix1, pix2;
> +	int i = 0;
> +
> +	switch (pipe) {
> +	case 0:
> +		pix = PIPEAFRAMEPIXEL;
> +		break;
> +	case 1:
> +		pix = PIPEBFRAMEPIXEL;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	while (!quit) {
> +		pix1 = read_reg(pix);
> +		pix2 = read_reg(pix);
> +
> +		pix1 &= PIPE_PIXEL_MASK;
> +		pix2 &= PIPE_PIXEL_MASK;
> +
> +		if (pix2 >= pix1)
> +			continue;
> +
> +		min[i] = pix1;
> +		max[i] = pix2;
> +		if (++i >= count)
> +			break;
> +	}
> +}
> +
> +static void poll_dsl_pipestat(int pipe, int bit,
> +			      uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1, dsl2, iir, iir1, iir2, iir_bit, iir_mask;
> +	bool field1, field2;
> +	int i[2] = {};
> +
> +	switch (pipe) {
> +	case 0:
> +		iir_bit = 1 << bit;
> +		iir = PIPEASTAT;
> +		break;
> +	case 1:
> +		iir_bit = 1 << bit;
> +		iir = PIPEBSTAT;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	dsl = dsl_reg(pipe);
> +
> +	iir_mask = read_reg(iir) & 0x7fff0000;
> +
> +	write_reg(iir, iir_mask | iir_bit);
> +
> +	while (!quit) {
> +		dsl1 = read_reg(dsl);
> +		iir1 = read_reg(iir);
> +		iir2 = read_reg(iir);
> +		dsl2 = read_reg(dsl);
> +
> +		field1 = dsl1 & 0x80000000;
> +		field2 = dsl2 & 0x80000000;
> +		dsl1 &= ~0x80000000;
> +		dsl2 &= ~0x80000000;
> +
> +		if (!(iir2 & iir_bit))
> +			continue;
> +
> +		if (iir1 & iir_bit) {
> +			write_reg(iir, iir_mask | iir_bit);
> +			continue;
> +		}
> +
> +		if (field1 != field2)
> +			printf("fields are different (%u:%u -> %u:%u)\n",
> +			       field1, dsl1, field2, dsl2);
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			break;
> +	}
> +}
> +
> +static void poll_dsl_iir_gen2(int pipe, int bit,
> +			      uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1, dsl2, iir1, iir2, imr_save, ier_save;
> +	bool field1, field2;
> +	int i[2] = {};
> +
> +	bit = 1 << bit;
> +
> +	dsl = dsl_reg(pipe);
> +
> +	imr_save = read_reg_16(IMR);
> +	ier_save = read_reg_16(IER);
> +
> +	write_reg_16(IER, ier_save & ~bit);
> +	write_reg_16(IMR, imr_save & ~bit);
> +
> +	write_reg_16(IIR, bit);
> +
> +	while (!quit) {
> +		dsl1 = read_reg(dsl);
> +		iir1 = read_reg_16(IIR);
> +		iir2 = read_reg_16(IIR);
> +		dsl2 = read_reg(dsl);
> +
> +		field1 = dsl1 & 0x80000000;
> +		field2 = dsl2 & 0x80000000;
> +		dsl1 &= ~0x80000000;
> +		dsl2 &= ~0x80000000;
> +
> +		if (!(iir2 & bit))
> +			continue;
> +
> +		write_reg_16(IIR, bit);
> +
> +		if (iir1 & bit)
> +			continue;
> +
> +		if (field1 != field2)
> +			printf("fields are different (%u:%u -> %u:%u)\n",
> +			       field1, dsl1, field2, dsl2);
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			break;
> +	}
> +
> +	write_reg_16(IMR, imr_save);
> +	write_reg_16(IER, ier_save);
> +}
> +
> +static void poll_dsl_iir_gen3(int pipe, int bit,
> +			      uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1, dsl2, iir1, iir2, imr_save, ier_save;
> +	bool field1, field2;
> +	int i[2] = {};
> +
> +	bit = 1 << bit;
> +
> +	dsl = dsl_reg(pipe);
> +
> +	imr_save = read_reg(IMR);
> +	ier_save = read_reg(IER);
> +
> +	write_reg(IER, ier_save & ~bit);
> +	write_reg(IMR, imr_save & ~bit);
> +
> +	write_reg(IIR, bit);
> +
> +	while (!quit) {
> +		dsl1 = read_reg(dsl);
> +		iir1 = read_reg(IIR);
> +		iir2 = read_reg(IIR);
> +		dsl2 = read_reg(dsl);
> +
> +		field1 = dsl1 & 0x80000000;
> +		field2 = dsl2 & 0x80000000;
> +		dsl1 &= ~0x80000000;
> +		dsl2 &= ~0x80000000;
> +
> +		if (!(iir2 & bit))
> +			continue;
> +
> +		write_reg(IIR, bit);
> +
> +		if (iir1 & bit)
> +			continue;
> +
> +		if (field1 != field2)
> +			printf("fields are different (%u:%u -> %u:%u)\n",
> +			       field1, dsl1, field2, dsl2);
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			break;
> +	}
> +
> +	write_reg(IMR, imr_save);
> +	write_reg(IER, ier_save);
> +}
> +
> +static void poll_dsl_deiir(uint32_t devid, int pipe, int bit,
> +			   uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1, dsl2, iir1, iir2, imr_save, ier_save;
> +	bool field1, field2;
> +	uint32_t iir, ier, imr;
> +	int i[2] = {};
> +
> +	bit = 1 << bit;
> +
> +	dsl = dsl_reg(pipe);
> +
> +	if (IS_GEN8(devid)) {
> +		iir = GEN8_DE_PIPE_IIR(pipe);
> +		ier = GEN8_DE_PIPE_IER(pipe);
> +		imr = GEN8_DE_PIPE_IMR(pipe);
> +	} else {
> +		iir = DEIIR;
> +		ier = DEIER;
> +		imr = DEIMR;
> +	}
> +
> +	imr_save = read_reg(imr);
> +	ier_save = read_reg(ier);
> +
> +	write_reg(ier, ier_save & ~bit);
> +	write_reg(imr, imr_save & ~bit);
> +
> +	write_reg(iir, bit);
> +
> +	while (!quit) {
> +		dsl1 = read_reg(dsl);
> +		iir1 = read_reg(iir);
> +		iir2 = read_reg(iir);
> +		dsl2 = read_reg(dsl);
> +
> +		field1 = dsl1 & 0x80000000;
> +		field2 = dsl2 & 0x80000000;
> +		dsl1 &= ~0x80000000;
> +		dsl2 &= ~0x80000000;
> +
> +		if (!(iir2 & bit))
> +			continue;
> +
> +		write_reg(iir, bit);
> +
> +		if (iir1 & bit)
> +			continue;
> +
> +		if (field1 != field2)
> +			printf("fields are different (%u:%u -> %u:%u)\n",
> +			       field1, dsl1, field2, dsl2);
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			break;
> +	}
> +
> +	write_reg(imr, imr_save);
> +	write_reg(ier, ier_save);
> +}
> +
> +static void poll_dsl_framecount_g4x(int pipe, uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1, dsl2, frm, frm1, frm2;
> +	bool field1, field2;
> +	int i[2] = {};
> +
> +	switch (pipe) {
> +	case 0:
> +		frm = PIPEAFRMCOUNT_G4X;
> +		break;
> +	case 1:
> +		frm = PIPEBFRMCOUNT_G4X;
> +		break;
> +	case 2:
> +		frm = PIPECFRMCOUNT_G4X;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	dsl = dsl_reg(pipe);
> +
> +	while (!quit) {
> +		dsl1 = read_reg(dsl);
> +		frm1 = read_reg(frm);
> +		frm2 = read_reg(frm);
> +		dsl2 = read_reg(dsl);
> +
> +		field1 = dsl1 & 0x80000000;
> +		field2 = dsl2 & 0x80000000;
> +		dsl1 &= ~0x80000000;
> +		dsl2 &= ~0x80000000;
> +
> +		if (frm1 + 1 != frm2)
> +			continue;
> +
> +		if (field1 != field2)
> +			printf("fields are different (%u:%u -> %u:%u)\n",
> +			       field1, dsl1, field2, dsl2);
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			break;
> +	}
> +}
> +
> +static void poll_dsl_flipcount_g4x(uint32_t devid, int pipe,
> +				   uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1, dsl2, flp, flp1, flp2, surf;
> +	bool field1, field2;
> +	int i[2] = {};
> +
> +	switch (pipe) {
> +	case 0:
> +		flp = PIPEAFLIPCOUNT_G4X;
> +		break;
> +	case 1:
> +		flp = PIPEBFLIPCOUNT_G4X;
> +		break;
> +	case 2:
> +		flp = PIPECFLIPCOUNT_G4X;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	dsl = dsl_reg(pipe);
> +	surf = dspsurf_reg(devid, pipe);
> +
> +	while (!quit) {
> +		usleep(10);
> +		dsl1 = read_reg(dsl);
> +		flp1 = read_reg(flp);
> +		dsl2 = read_reg(dsl);
> +
> +		field1 = dsl1 & 0x80000000;
> +		field2 = dsl2 & 0x80000000;
> +		dsl1 &= ~0x80000000;
> +		dsl2 &= ~0x80000000;
> +
> +		if (field1 != field2)
> +			printf("fields are different (%u:%u -> %u:%u)\n",
> +			       field1, dsl1, field2, dsl2);
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			return;
> +
> +		write_reg(surf, read_reg(surf));
> +
> +		while (!quit) {
> +			dsl1 = read_reg(dsl);
> +			flp2 = read_reg(flp);
> +			dsl2 = read_reg(dsl);
> +
> +			field1 = dsl1 & 0x80000000;
> +			field2 = dsl2 & 0x80000000;
> +			dsl1 &= ~0x80000000;
> +			dsl2 &= ~0x80000000;
> +
> +			if (flp1 == flp2)
> +				continue;
> +
> +			if (field1 != field2)
> +				printf("fields are different (%u:%u -> %u:%u)\n",
> +				       field1, dsl1, field2, dsl2);
> +
> +			min[field1*count+i[field1]] = dsl1;
> +			max[field1*count+i[field1]] = dsl2;
> +			if (++i[field1] >= count)
> +				break;
> +		}
> +		if (i[field1] >= count)
> +			break;
> +	}
> +}
> +
> +static void poll_dsl_framecount_gen3(int pipe, uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1, dsl2, frm, frm1, frm2;
> +	bool field1, field2;
> +	int i[2] = {};
> +
> +	switch (pipe) {
> +	case 0:
> +		frm = PIPEAFRAMEPIXEL;
> +		break;
> +	case 1:
> +		frm = PIPEBFRAMEPIXEL;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	dsl = dsl_reg(pipe);
> +
> +	while (!quit) {
> +		dsl1 = read_reg(dsl);
> +		frm1 = read_reg(frm) >> 24;
> +		frm2 = read_reg(frm) >> 24;
> +		dsl2 = read_reg(dsl);
> +
> +		field1 = dsl1 & 0x80000000;
> +		field2 = dsl2 & 0x80000000;
> +		dsl1 &= ~0x80000000;
> +		dsl2 &= ~0x80000000;
> +
> +		if (frm1 + 1 != frm2)
> +			continue;
> +
> +		if (field1 != field2)
> +			printf("fields are different (%u:%u -> %u:%u)\n",
> +			       field1, dsl1, field2, dsl2);
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			break;
> +	}
> +}
> +
> +static void poll_dsl_pan(uint32_t devid, int pipe, int target_scanline, int target_fuzz,
> +			 uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1 = 0, dsl2 = 0;
> +	bool field1 = false, field2 = false;
> +	uint32_t saved, surf = 0;
> +	int i[2] = {};
> +
> +	dsl = dsl_reg(pipe);
> +	surf = dspoffset_reg(devid, pipe);
> +
> +	saved = read_reg(surf);
> +
> +	while (!quit) {
> +		while (!quit) {
> +			dsl1 = read_reg(dsl);
> +			field1 = dsl1 & 0x80000000;
> +			dsl1 &= ~0x80000000;
> +			if (dsl1 == target_scanline)
> +				break;
> +		}
> +
> +		write_reg(surf, saved+256);
> +
> +		while (!quit) {
> +			dsl2 = read_reg(dsl);
> +			field2 = dsl1 & 0x80000000;
> +			dsl2 &= ~0x80000000;
> +			if (dsl2 == target_scanline + target_fuzz)
> +				break;
> +		}
> +
> +		write_reg(surf, saved);
> +
> +		if (field1 != field2)
> +			printf("fields are different (%u:%u -> %u:%u)\n",
> +			       field1, dsl1, field2, dsl2);
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			break;
> +	}
> +
> +	write_reg(surf, saved);
> +}
> +
> +static void poll_dsl_flip(uint32_t devid, int pipe, int target_scanline, int target_fuzz,
> +			  uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1 = 0, dsl2 = 0;
> +	bool field1 = false, field2 = false;
> +	uint32_t saved, surf = 0;
> +	int i[2] = {};
> +
> +	dsl = dsl_reg(pipe);
> +	surf = dspsurf_reg(devid, pipe);
> +
> +	saved = read_reg(surf);
> +
> +	while (!quit) {
> +		while (!quit) {
> +			dsl1 = read_reg(dsl);
> +			field1 = dsl1 & 0x80000000;
> +			dsl1 &= ~0x80000000;
> +			if (dsl1 == target_scanline)
> +				break;
> +		}
> +
> +		write_reg(surf, saved+4096);
> +
> +		while (!quit) {
> +			dsl2 = read_reg(dsl);
> +			field2 = dsl1 & 0x80000000;
> +			dsl2 &= ~0x80000000;
> +			if (dsl2 == target_scanline + target_fuzz)
> +				break;
> +		}
> +
> +		write_reg(surf, saved);
> +
> +		if (field1 != field2)
> +			printf("fields are different (%u:%u -> %u:%u)\n",
> +			       field1, dsl1, field2, dsl2);
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			break;
> +	}
> +
> +	write_reg(surf, saved);
> +}
> +
> +static void poll_dsl_surflive(uint32_t devid, int pipe,
> +			      uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1 = 0, dsl2 = 0, surf, surf1, surf2, surflive, surfl1 = 0, surfl2, saved, tmp;
> +	bool field1 = false, field2 = false;
> +	int i[2] = {};
> +
> +	switch (pipe) {
> +	case 0:
> +		surflive = DSPASURFLIVE;
> +		break;
> +	case 1:
> +		surflive = DSPBSURFLIVE;
> +		break;
> +	case 2:
> +		surflive = DSPCSURFLIVE;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	dsl = dsl_reg(pipe);
> +	surf = dspsurf_reg(devid, pipe);
> +
> +	saved = read_reg(surf);
> +
> +	surf1 = saved & ~0xfff;
> +	surf2 = surf1 + 4096;
> +
> +	while (!quit) {
> +		write_reg(surf, surf2);
> +
> +		while (!quit) {
> +			dsl1 = read_reg(dsl);
> +			surfl1 = read_reg(surflive) & ~0xfff;
> +			surfl2 = read_reg(surflive) & ~0xfff;
> +			dsl2 = read_reg(dsl);
> +
> +			field1 = dsl1 & 0x80000000;
> +			field2 = dsl2 & 0x80000000;
> +			dsl1 &= ~0x80000000;
> +			dsl2 &= ~0x80000000;
> +
> +			if (surfl2 == surf2)
> +				break;
> +		}
> +
> +		if (surfl1 != surf2) {
> +			if (field1 != field2)
> +				printf("fields are different (%u:%u -> %u:%u)\n",
> +				       field1, dsl1, field2, dsl2);
> +
> +			min[field1*count+i[field1]] = dsl1;
> +			max[field1*count+i[field1]] = dsl2;
> +			if (++i[field1] >= count)
> +				break;
> +		}
> +
> +		tmp = surf1;
> +		surf1 = surf2;
> +		surf2 = tmp;
> +	}
> +
> +	write_reg(surf, saved);
> +}
> +
> +static void poll_dsl_wrap(int pipe, uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1, dsl2;
> +	bool field1, field2;
> +	int i[2] = {};
> +
> +	dsl = dsl_reg(pipe);
> +
> +	while (!quit) {
> +		dsl1 = read_reg(dsl);
> +		dsl2 = read_reg(dsl);
> +
> +		field1 = dsl1 & 0x80000000;
> +		field2 = dsl2 & 0x80000000;
> +		dsl1 &= ~0x80000000;
> +		dsl2 &= ~0x80000000;
> +
> +		if (dsl2 >= dsl1)
> +			continue;
> +
> +		if (field1 != field2)
> +			printf("fields are different (%u:%u -> %u:%u)\n",
> +			       field1, dsl1, field2, dsl2);
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			break;
> +	}
> +}
> +
> +static void poll_dsl_field(int pipe, uint32_t *min, uint32_t *max, const int count)
> +{
> +	uint32_t dsl, dsl1, dsl2;
> +	bool field1, field2;
> +	int i[2] = {};
> +
> +	dsl = dsl_reg(pipe);
> +
> +	while (!quit) {
> +		dsl1 = read_reg(dsl);
> +		dsl2 = read_reg(dsl);
> +
> +		field1 = dsl1 & 0x80000000;
> +		field2 = dsl2 & 0x80000000;
> +		dsl1 &= ~0x80000000;
> +		dsl2 &= ~0x80000000;
> +
> +		if (field1 == field2)
> +			continue;
> +
> +		min[field1*count+i[field1]] = dsl1;
> +		max[field1*count+i[field1]] = dsl2;
> +		if (++i[field1] >= count)
> +			break;
> +	}
> +}
> +
> +static char pipe_name(int pipe)
> +{
> +	return pipe + 'A';
> +}
> +
> +static const char *test_name(enum test test, int pipe, int bit, bool test_pixel_count)
> +{
> +	static char str[32];
> +	const char *type = test_pixel_count ? "pixel" : "dsl";
> +
> +	switch (test) {
> +	case TEST_PIPESTAT:
> +		snprintf(str, sizeof str, "%s / pipe %c / PIPESTAT[%d] (gmch)", type, pipe_name(pipe), bit);
> +		return str;
> +	case TEST_IIR_GEN2:
> +		snprintf(str, sizeof str, "%s / pipe %c / IIR[%d] (gen2)", type, pipe_name(pipe), bit);
> +		return str;
> +	case TEST_IIR_GEN3:
> +		snprintf(str, sizeof str, "%s / pipe %c / IIR[%d] (gen3+)", type, pipe_name(pipe), bit);
> +		return str;
> +	case TEST_DEIIR:
> +		snprintf(str, sizeof str, "%s / pipe %c / DEIIR[%d] (pch)", type, pipe_name(pipe), bit);
> +		return str;
> +	case TEST_FRAMECOUNT_GEN3:
> +		snprintf(str, sizeof str, "%s / pipe %c / Frame count (gen3/4)", type, pipe_name(pipe));
> +		return str;
> +	case TEST_FRAMECOUNT_G4X:
> +		snprintf(str, sizeof str, "%s / pipe %c / Frame count (g4x+)", type, pipe_name(pipe));
> +		return str;
> +	case TEST_FLIPCOUNT:
> +		snprintf(str, sizeof str, "%s / pipe %c / Flip count (g4x+)", type, pipe_name(pipe));
> +		return str;
> +	case TEST_PAN:
> +		snprintf(str, sizeof str, "%s / pipe %c / Pan", type, pipe_name(pipe));
> +		return str;
> +	case TEST_FLIP:
> +		snprintf(str, sizeof str, "%s / pipe %c / Flip", type, pipe_name(pipe));
> +		return str;
> +	case TEST_SURFLIVE:
> +		snprintf(str, sizeof str, "%s / pipe %c / Surflive", type, pipe_name(pipe));
> +		return str;
> +	case TEST_WRAP:
> +		snprintf(str, sizeof str, "%s / pipe %c / Wrap", type, pipe_name(pipe));
> +		return str;
> +	case TEST_FIELD:
> +		snprintf(str, sizeof str, "%s / pipe %c / Field", type, pipe_name(pipe));
> +		return str;
> +	default:
> +		return "";
> +	}
> +}
> +
> +static void usage(const char *name)
> +{
> +	fprintf(stderr, "Usage: %s [options]\n"
> +		" -t,--test <pipestat|iir|framecount|flipcount|pan|flip|surflive|wrap|field>\n"
> +		" -p,--pipe <pipe>\n"
> +		" -b,--bit <bit>\n"
> +		" -l,--line <target scanline/pixel>\n"
> +		" -f,--fuzz <target fuzz>\n"
> +		" -x,--pixel\n",
> +		name);
> +	exit(1);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int fd, i;
> +	int pipe = 0, bit = 0, target_scanline = 0, target_fuzz = 1;
> +	bool test_pixelcount = false;
> +	uint32_t devid;
> +	uint32_t min[2*128] = {};
> +	uint32_t max[2*128] = {};
> +	uint32_t a, b;
> +	enum test test = TEST_INVALID;
> +	const int count = ARRAY_SIZE(min)/2;
> +
> +	for (;;) {
> +		static const struct option long_options[] = {
> +			{ .name = "test", .has_arg = required_argument, },
> +			{ .name = "pipe", .has_arg = required_argument, },
> +			{ .name = "bit", .has_arg = required_argument, },
> +			{ .name = "line", .has_arg = required_argument, },
> +			{ .name = "fuzz", .has_arg = required_argument, },
> +			{ .name = "pixel", .has_arg = no_argument, },
> +			{ },
> +		};
> +
> +		int opt = getopt_long(argc, argv, "t:p:b:l:f:x", long_options, NULL);
> +		if (opt == -1)
> +			break;
> +
> +		switch (opt) {
> +		case 't':
> +			if (!strcmp(optarg, "pipestat"))
> +				test = TEST_PIPESTAT;
> +			else if (!strcmp(optarg, "iir"))
> +				test = TEST_IIR;
> +			else if (!strcmp(optarg, "framecount"))
> +				test = TEST_FRAMECOUNT;
> +			else if (!strcmp(optarg, "flipcount"))
> +				test = TEST_FLIPCOUNT;
> +			else if (!strcmp(optarg, "pan"))
> +				test = TEST_PAN;
> +			else if (!strcmp(optarg, "flip"))
> +				test = TEST_FLIP;
> +			else if (!strcmp(optarg, "surflive"))
> +				test = TEST_SURFLIVE;
> +			else if (!strcmp(optarg, "wrap"))
> +				test = TEST_WRAP;
> +			else if (!strcmp(optarg, "field"))
> +				test = TEST_FIELD;
> +			else
> +				usage(argv[0]);
> +			break;
> +		case 'p':
> +			pipe = atoi(optarg);
> +			if (pipe < 0 || pipe > 2)
> +				usage(argv[0]);
> +			break;
> +		case 'b':
> +			bit = atoi(optarg);
> +			if (bit < 0 || bit > 31)
> +				usage(argv[0]);
> +			break;
> +		case 'l':
> +			target_scanline = atoi(optarg);
> +			if (target_scanline < 0)
> +				usage(argv[0]);
> +			break;
> +		case 'f':
> +			target_fuzz = atoi(optarg);
> +			if (target_fuzz <= 0)
> +				usage(argv[0]);
> +			break;
> +		case 'x':
> +			test_pixelcount = true;
> +			break;
> +		}
> +	}
> +
> +	fd = drm_open_any();
> +	devid = intel_get_drm_devid(fd);
> +	close(fd);
> +
> +	/*
> +	 * check if the requires registers are
> +	 * avilable on the current platform.
> +	 */
> +	if (IS_GEN2(devid)) {
> +		if (pipe > 1)
> +			usage(argv[0]);
> +
> +		if (test_pixelcount)
> +			usage(argv[0]);
> +
> +		switch (test) {
> +		case TEST_IIR:
> +			test = TEST_IIR_GEN2;
> +			break;
> +		case TEST_PIPESTAT:
> +		case TEST_PAN:
> +			break;
> +		case TEST_FLIP:
> +			test = TEST_PAN;
> +			break;
> +		default:
> +			usage(argv[0]);
> +		}
> +	} else if (IS_GEN3(devid) ||
> +		   (IS_GEN4(devid) && !IS_G4X(devid))) {
> +		if (pipe > 1)
> +			usage(argv[0]);
> +
> +		switch (test) {
> +		case TEST_IIR:
> +			test = TEST_IIR_GEN3;
> +			break;
> +		case TEST_FRAMECOUNT:
> +			test = TEST_FRAMECOUNT_GEN3;
> +			break;
> +		case TEST_PIPESTAT:
> +		case TEST_PAN:
> +		case TEST_WRAP:
> +		case TEST_FIELD:
> +			break;
> +		case TEST_FLIP:
> +			if (IS_GEN3(devid))
> +				test = TEST_PAN;
> +			break;
> +		default:
> +			usage(argv[0]);
> +		}
> +	} else if (IS_G4X(devid) || IS_VALLEYVIEW(devid)) {
> +		if (IS_VALLEYVIEW(devid))
> +			vlv_offset = 0x180000;
> +
> +		if (pipe > 1)
> +			usage(argv[0]);
> +
> +		if (test_pixelcount)
> +			usage(argv[0]);
> +
> +		switch (test) {
> +		case TEST_IIR:
> +			test = TEST_IIR_GEN3;
> +			break;
> +		case TEST_FRAMECOUNT:
> +			test = TEST_FRAMECOUNT_G4X;
> +			break;
> +		case TEST_FLIPCOUNT:
> +		case TEST_PIPESTAT:
> +		case TEST_PAN:
> +		case TEST_FLIP:
> +		case TEST_SURFLIVE:
> +		case TEST_WRAP:
> +		case TEST_FIELD:
> +			break;
> +		default:
> +			usage(argv[0]);
> +		}
> +	} else if (HAS_PCH_SPLIT(devid) &&
> +		   (IS_GEN5(devid) || IS_GEN6(devid) || IS_GEN7(devid))) {
> +		if (pipe > 1 &&
> +		    (IS_GEN5(devid) || IS_GEN6(devid)))
> +			usage(argv[0]);
> +
> +		if (test_pixelcount)
> +			usage(argv[0]);
> +
> +		switch (test) {
> +		case TEST_IIR:
> +			test = TEST_DEIIR;
> +			break;
> +		case TEST_FRAMECOUNT:
> +			test = TEST_FRAMECOUNT_G4X;
> +			break;
> +		case TEST_FLIPCOUNT:
> +		case TEST_PAN:
> +		case TEST_FLIP:
> +		case TEST_SURFLIVE:
> +		case TEST_WRAP:
> +		case TEST_FIELD:
> +			break;
> +		default:
> +			usage(argv[0]);
> +		}
> +	} else if (IS_GEN8(devid)) {
> +		if (test_pixelcount)
> +			usage(argv[0]);
> +
> +		switch (test) {
> +		case TEST_IIR:
> +			test = TEST_DEIIR;
> +			break;
> +		case TEST_FRAMECOUNT:
> +			test = TEST_FRAMECOUNT_G4X;
> +			break;
> +		case TEST_FLIPCOUNT:
> +		case TEST_PAN:
> +		case TEST_FLIP:
> +		case TEST_SURFLIVE:
> +		case TEST_WRAP:
> +		case TEST_FIELD:
> +			break;
> +		default:
> +			usage(argv[0]);
> +		}
> +	} else {
> +		usage(argv[0]);
> +	}
> +
> +	switch (test) {
> +	case TEST_IIR:
> +	case TEST_FRAMECOUNT:
> +		/* should no longer have the generic tests here */
> +		assert(0);
> +	default:
> +		break;
> +	}
> +
> +	intel_register_access_init(intel_get_pci_device(), 0);
> +
> +	printf("%s?\n", test_name(test, pipe, bit, test_pixelcount));
> +
> +	signal(SIGHUP, sighandler);
> +	signal(SIGINT, sighandler);
> +	signal(SIGTERM, sighandler);
> +
> +	switch (test) {
> +	case TEST_PIPESTAT:
> +		if (test_pixelcount)
> +			poll_pixel_pipestat(pipe, bit, min, max, count);
> +		else
> +			poll_dsl_pipestat(pipe, bit, min, max, count);
> +		break;
> +	case TEST_IIR_GEN2:
> +		assert(!test_pixelcount);
> +		poll_dsl_iir_gen2(pipe, bit, min, max, count);
> +		break;
> +	case TEST_IIR_GEN3:
> +		if (test_pixelcount)
> +			poll_pixel_iir_gen3(pipe, bit, min, max, count);
> +		else
> +			poll_dsl_iir_gen3(pipe, bit, min, max, count);
> +		break;
> +	case TEST_DEIIR:
> +		assert(!test_pixelcount);
> +		poll_dsl_deiir(devid, pipe, bit, min, max, count);
> +		break;
> +	case TEST_FRAMECOUNT_GEN3:
> +		if (test_pixelcount)
> +			poll_pixel_framecount_gen3(pipe, min, max, count);
> +		else
> +			poll_dsl_framecount_gen3(pipe, min, max, count);
> +		break;
> +	case TEST_FRAMECOUNT_G4X:
> +		assert(!test_pixelcount);
> +		poll_dsl_framecount_g4x(pipe, min, max, count);
> +		break;
> +	case TEST_FLIPCOUNT:
> +		assert(!test_pixelcount);
> +		poll_dsl_flipcount_g4x(devid, pipe, min, max, count);
> +		break;
> +	case TEST_PAN:
> +		if (test_pixelcount)
> +			poll_pixel_pan(devid, pipe, target_scanline, target_fuzz,
> +				       min, max, count);
> +		else
> +			poll_dsl_pan(devid, pipe, target_scanline, target_fuzz,
> +				     min, max, count);
> +		break;
> +	case TEST_FLIP:
> +		if (test_pixelcount)
> +			poll_pixel_flip(devid, pipe, target_scanline, target_fuzz,
> +					min, max, count);
> +		else
> +			poll_dsl_flip(devid, pipe, target_scanline, target_fuzz,
> +				      min, max, count);
> +		break;
> +	case TEST_SURFLIVE:
> +		poll_dsl_surflive(devid, pipe, min, max, count);
> +		break;
> +	case TEST_WRAP:
> +		if (test_pixelcount)
> +			poll_pixel_wrap(pipe, min, max, count);
> +		else
> +			poll_dsl_wrap(pipe, min, max, count);
> +		break;
> +	case TEST_FIELD:
> +		poll_dsl_field(pipe, min, max, count);
> +		break;
> +	default:
> +		assert(0);
> +	}
> +
> +	intel_register_access_fini();
> +
> +	if (quit)
> +		return 0;
> +
> +	for (i = 0; i < count; i++) {
> +		if (min[0*count+i] == 0 && max[0*count+i] == 0)
> +			break;
> +		printf("[%u] %4u - %4u (%4u)\n", 0, min[0*count+i], max[0*count+i],
> +		       (min[0*count+i] + max[0*count+i] + 1) >> 1);
> +	}
> +	for (i = 0; i < count; i++) {
> +		if (min[1*count+i] == 0 && max[1*count+i] == 0)
> +			break;
> +		printf("[%u] %4u - %4u (%4u)\n", 1, min[1*count+i], max[1*count+i],
> +		       (min[1*count+i] + max[1*count+i] + 1) >> 1);
> +	}
> +
> +	a = 0;
> +	b = 0xffffffff;
> +	for (i = 0; i < count; i++) {
> +		if (min[0*count+i] == 0 && max[0*count+i] == 0)
> +			break;
> +		a = max(a, min[0*count+i]);
> +		b = min(b, max[0*count+i]);
> +	}
> +
> +	printf("%s: [%u] %6u - %6u\n", test_name(test, pipe, bit, test_pixelcount), 0, a, b);
> +
> +	a = 0;
> +	b = 0xffffffff;
> +	for (i = 0; i < count; i++) {
> +		if (min[1*count+i] == 0 && max[1*count+i] == 0)
> +			break;
> +		a = max(a, min[1*count+i]);
> +		b = min(b, max[1*count+i]);
> +	}
> +
> +	printf("%s: [%u] %6u - %6u\n", test_name(test, pipe, bit, test_pixelcount), 1, a, b);
> +
> +	return 0;
> +}
> -- 
> 1.8.5.5
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx