All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH igt 1/4] lib/igt_debugfs: Don't fail if debugfs is already mounted
@ 2014-06-11 16:41 ville.syrjala
  2014-06-11 16:41 ` [PATCH igt 2/4] lib/igt_debufs: Add IGT_NO_FORCEWAKE environment variable ville.syrjala
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: ville.syrjala @ 2014-06-11 16:41 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Remove the igt_assert() from the debugfs mount. It will fail if debugfs
is already mounted. With the assert in place it's very annying to use
igt without i915 loaded (eg. to dump BIOS configured registers).

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 lib/igt_debugfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index f21f671..809d447 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -102,7 +102,7 @@ static bool __igt_debugfs_init(igt_debugfs_t *debugfs)
 
 	igt_assert(stat("/sys/kernel/debug", &st) == 0);
 
-	igt_assert(mount("debug", "/sys/kernel/debug", "debugfs", 0, 0) == 0);
+	mount("debug", "/sys/kernel/debug", "debugfs", 0, 0);
 
 find_minor:
 	strcpy(debugfs->root, path);
-- 
1.8.5.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH igt 2/4] lib/igt_debufs: Add IGT_NO_FORCEWAKE environment variable
  2014-06-11 16:41 [PATCH igt 1/4] lib/igt_debugfs: Don't fail if debugfs is already mounted ville.syrjala
@ 2014-06-11 16:41 ` ville.syrjala
  2014-06-11 16:41 ` [PATCH igt 3/4] tools: Add intel_iosf_sb_{read, write} tools ville.syrjala
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: ville.syrjala @ 2014-06-11 16:41 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

If IGT_NO_FORCEWAKE is set, skip the forcewake open. Useful when you
want to poke at register without otherwise disturbing the GPU.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 lib/igt_debugfs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 809d447..2f655a1 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -618,6 +618,8 @@ void igt_enable_prefault(void)
  */
 int igt_open_forcewake_handle(void)
 {
+	if (getenv("IGT_NO_FORCEWAKE"))
+		return -1;
 	return igt_debugfs_open("i915_forcewake_user", O_WRONLY);
 }
 
-- 
1.8.5.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH igt 3/4] tools: Add intel_iosf_sb_{read, write} tools
  2014-06-11 16:41 [PATCH igt 1/4] lib/igt_debugfs: Don't fail if debugfs is already mounted ville.syrjala
  2014-06-11 16:41 ` [PATCH igt 2/4] lib/igt_debufs: Add IGT_NO_FORCEWAKE environment variable ville.syrjala
@ 2014-06-11 16:41 ` ville.syrjala
  2014-06-11 16:41 ` [PATCH igt 4/4] tools/intel_poller: Add a new tool that will poll various display registers ville.syrjala
  2014-06-12  7:20 ` [PATCH igt 1/4] lib/igt_debugfs: Don't fail if debugfs is already mounted Daniel Vetter
  3 siblings, 0 replies; 6+ messages in thread
From: ville.syrjala @ 2014-06-11 16:41 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add generic tools to poke at IOSF sideband. The user needs to
manually specify SB port as well as the register.

TODO: Maybe add symbolic names for the units? Would avoid having
to trawl the docs for the magic hex value.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 lib/intel_io.h              |  2 ++
 lib/intel_iosf.c            | 14 ++++++++++
 tools/Makefile.sources      |  2 ++
 tools/intel_iosf_sb_read.c  | 62 +++++++++++++++++++++++++++++++++++++++++
 tools/intel_iosf_sb_write.c | 67 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 147 insertions(+)
 create mode 100644 tools/intel_iosf_sb_read.c
 create mode 100644 tools/intel_iosf_sb_write.c

diff --git a/lib/intel_io.h b/lib/intel_io.h
index 78a6f4d..8293353 100644
--- a/lib/intel_io.h
+++ b/lib/intel_io.h
@@ -50,6 +50,8 @@ uint32_t intel_dpio_reg_read(uint32_t reg, int phy);
 void intel_dpio_reg_write(uint32_t reg, uint32_t val, int phy);
 uint32_t intel_flisdsi_reg_read(uint32_t reg);
 void intel_flisdsi_reg_write(uint32_t reg, uint32_t val);
+uint32_t intel_iosf_sb_read(uint32_t port, uint32_t reg);
+void intel_iosf_sb_write(uint32_t port, uint32_t reg, uint32_t val);
 
 int intel_punit_read(uint8_t addr, uint32_t *val);
 int intel_punit_write(uint8_t addr, uint32_t val);
diff --git a/lib/intel_iosf.c b/lib/intel_iosf.c
index ca20638..2f1ef90 100644
--- a/lib/intel_iosf.c
+++ b/lib/intel_iosf.c
@@ -173,3 +173,17 @@ void intel_flisdsi_reg_write(uint32_t reg, uint32_t val)
 {
 	vlv_sideband_rw(IOSF_PORT_FLISDSI, SB_CRWRDA_NP, reg, &val);
 }
+
+uint32_t intel_iosf_sb_read(uint32_t port, uint32_t reg)
+{
+	uint32_t val;
+
+	vlv_sideband_rw(port, SB_CRRDDA_NP, reg, &val);
+
+	return val;
+}
+
+void intel_iosf_sb_write(uint32_t port, uint32_t reg, uint32_t val)
+{
+	vlv_sideband_rw(port, SB_CRWRDA_NP, reg, &val);
+}
diff --git a/tools/Makefile.sources b/tools/Makefile.sources
index 0f63845..c2535e7 100644
--- a/tools/Makefile.sources
+++ b/tools/Makefile.sources
@@ -8,6 +8,8 @@ bin_PROGRAMS = 				\
 	intel_gpu_top 			\
 	intel_gpu_time 			\
 	intel_gtt 			\
+	intel_iosf_sb_read		\
+	intel_iosf_sb_write		\
 	intel_opregion_decode		\
 	intel_perf_counters		\
 	intel_stepping 			\
diff --git a/tools/intel_iosf_sb_read.c b/tools/intel_iosf_sb_read.c
new file mode 100644
index 0000000..216defe
--- /dev/null
+++ b/tools/intel_iosf_sb_read.c
@@ -0,0 +1,62 @@
+/*
+ * 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 <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <string.h>
+#include "intel_io.h"
+#include "intel_chipset.h"
+
+static void usage(const char *name)
+{
+	printf("Warning : This program will work only on Valleyview\n"
+	       "Usage: %s <port> <reg>\n"
+	       "\t port/reg : in 0xXXXX format\n",
+	       name);
+}
+
+int main(int argc, char *argv[])
+{
+	uint32_t port, reg, val;
+	struct pci_device *dev = intel_get_pci_device();
+
+	if (argc != 3 || !IS_VALLEYVIEW(dev->device_id)) {
+		usage(argv[0]);
+		return 1;
+	}
+
+	port = strtoul(argv[1], NULL, 16);
+	reg = strtoul(argv[2], NULL, 16);
+
+	intel_register_access_init(dev, 0);
+
+	val = intel_iosf_sb_read(port, reg);
+	printf("0x%02x/0x%04x : 0x%08x\n", port, reg, val);
+
+	intel_register_access_fini();
+
+	return 0;
+}
diff --git a/tools/intel_iosf_sb_write.c b/tools/intel_iosf_sb_write.c
new file mode 100644
index 0000000..0d3dea2
--- /dev/null
+++ b/tools/intel_iosf_sb_write.c
@@ -0,0 +1,67 @@
+/*
+ * 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 <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <string.h>
+#include "intel_io.h"
+#include "intel_chipset.h"
+
+static void usage(const char *name)
+{
+	printf("Warning : This program will work only on Valleyview\n"
+	       "Usage: %s <port> <reg> <val>\n"
+	       "\t port/reg/val : in 0xXXXX format\n",
+	       name);
+}
+
+int main(int argc, char** argv)
+{
+	uint32_t port, reg, val, tmp;
+	struct pci_device *dev = intel_get_pci_device();
+
+	if (argc != 4 || !IS_VALLEYVIEW(dev->device_id)) {
+		usage(argv[0]);
+		return 1;
+	}
+
+	port = strtoul(argv[1], NULL, 16);
+	reg = strtoul(argv[2], NULL, 16);
+	val = strtoul(argv[3], NULL, 16);
+
+	intel_register_access_init(dev, 0);
+
+	tmp = intel_iosf_sb_read(port, reg);
+	printf("Value before: 0x%X\n", tmp);
+
+	intel_iosf_sb_write(port, reg, val);
+
+	tmp = intel_iosf_sb_read(port, reg);
+	printf("Value after: 0x%X\n", tmp);
+
+	intel_register_access_fini();
+
+	return 0;
+}
-- 
1.8.5.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH igt 4/4] tools/intel_poller: Add a new tool that will poll various display registers
  2014-06-11 16:41 [PATCH igt 1/4] lib/igt_debugfs: Don't fail if debugfs is already mounted ville.syrjala
  2014-06-11 16:41 ` [PATCH igt 2/4] lib/igt_debufs: Add IGT_NO_FORCEWAKE environment variable ville.syrjala
  2014-06-11 16:41 ` [PATCH igt 3/4] tools: Add intel_iosf_sb_{read, write} tools ville.syrjala
@ 2014-06-11 16:41 ` ville.syrjala
  2014-06-12  7:21   ` Daniel Vetter
  2014-06-12  7:20 ` [PATCH igt 1/4] lib/igt_debugfs: Don't fail if debugfs is already mounted Daniel Vetter
  3 siblings, 1 reply; 6+ messages in thread
From: ville.syrjala @ 2014-06-11 16:41 UTC (permalink / raw)
  To: intel-gfx

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

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

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH igt 1/4] lib/igt_debugfs: Don't fail if debugfs is already mounted
  2014-06-11 16:41 [PATCH igt 1/4] lib/igt_debugfs: Don't fail if debugfs is already mounted ville.syrjala
                   ` (2 preceding siblings ...)
  2014-06-11 16:41 ` [PATCH igt 4/4] tools/intel_poller: Add a new tool that will poll various display registers ville.syrjala
@ 2014-06-12  7:20 ` Daniel Vetter
  3 siblings, 0 replies; 6+ messages in thread
From: Daniel Vetter @ 2014-06-12  7:20 UTC (permalink / raw)
  To: ville.syrjala; +Cc: intel-gfx

On Wed, Jun 11, 2014 at 07:41:17PM +0300, ville.syrjala@linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Remove the igt_assert() from the debugfs mount. It will fail if debugfs
> is already mounted. With the assert in place it's very annying to use
> igt without i915 loaded (eg. to dump BIOS configured registers).
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  lib/igt_debugfs.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
> index f21f671..809d447 100644
> --- a/lib/igt_debugfs.c
> +++ b/lib/igt_debugfs.c
> @@ -102,7 +102,7 @@ static bool __igt_debugfs_init(igt_debugfs_t *debugfs)
>  
>  	igt_assert(stat("/sys/kernel/debug", &st) == 0);
>  
> -	igt_assert(mount("debug", "/sys/kernel/debug", "debugfs", 0, 0) == 0);
> +	mount("debug", "/sys/kernel/debug", "debugfs", 0, 0);

Hm, for me this just silently succeeds. Maybe just an igt_warn_on? But I'm
ok with this here, too.
-Daniel

>  
>  find_minor:
>  	strcpy(debugfs->root, path);
> -- 
> 1.8.5.5
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH igt 4/4] tools/intel_poller: Add a new tool that will poll various display registers
  2014-06-11 16:41 ` [PATCH igt 4/4] tools/intel_poller: Add a new tool that will poll various display registers ville.syrjala
@ 2014-06-12  7:21   ` Daniel Vetter
  0 siblings, 0 replies; 6+ messages in thread
From: Daniel Vetter @ 2014-06-12  7:21 UTC (permalink / raw)
  To: ville.syrjala; +Cc: intel-gfx

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

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-06-12  7:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-11 16:41 [PATCH igt 1/4] lib/igt_debugfs: Don't fail if debugfs is already mounted ville.syrjala
2014-06-11 16:41 ` [PATCH igt 2/4] lib/igt_debufs: Add IGT_NO_FORCEWAKE environment variable ville.syrjala
2014-06-11 16:41 ` [PATCH igt 3/4] tools: Add intel_iosf_sb_{read, write} tools ville.syrjala
2014-06-11 16:41 ` [PATCH igt 4/4] tools/intel_poller: Add a new tool that will poll various display registers ville.syrjala
2014-06-12  7:21   ` Daniel Vetter
2014-06-12  7:20 ` [PATCH igt 1/4] lib/igt_debugfs: Don't fail if debugfs is already mounted Daniel Vetter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.