xref: /dragonfly/sys/dev/drm/i915/i915_irq.c (revision e9243325)
1c4a9e910SFrançois Tigeot /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
2c4a9e910SFrançois Tigeot  */
3c4a9e910SFrançois Tigeot /*-
4c4a9e910SFrançois Tigeot  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
5c4a9e910SFrançois Tigeot  * All Rights Reserved.
6c4a9e910SFrançois Tigeot  *
7c4a9e910SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
8c4a9e910SFrançois Tigeot  * copy of this software and associated documentation files (the
9c4a9e910SFrançois Tigeot  * "Software"), to deal in the Software without restriction, including
10c4a9e910SFrançois Tigeot  * without limitation the rights to use, copy, modify, merge, publish,
11c4a9e910SFrançois Tigeot  * distribute, sub license, and/or sell copies of the Software, and to
12c4a9e910SFrançois Tigeot  * permit persons to whom the Software is furnished to do so, subject to
13c4a9e910SFrançois Tigeot  * the following conditions:
14c4a9e910SFrançois Tigeot  *
15c4a9e910SFrançois Tigeot  * The above copyright notice and this permission notice (including the
16c4a9e910SFrançois Tigeot  * next paragraph) shall be included in all copies or substantial portions
17c4a9e910SFrançois Tigeot  * of the Software.
18c4a9e910SFrançois Tigeot  *
19c4a9e910SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20c4a9e910SFrançois Tigeot  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21c4a9e910SFrançois Tigeot  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22c4a9e910SFrançois Tigeot  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23c4a9e910SFrançois Tigeot  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24c4a9e910SFrançois Tigeot  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25c4a9e910SFrançois Tigeot  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26c4a9e910SFrançois Tigeot  *
27e3adcf8fSFrançois Tigeot  * $FreeBSD: src/sys/dev/drm2/i915/i915_irq.c,v 1.1 2012/05/22 11:07:44 kib Exp $
28c4a9e910SFrançois Tigeot  */
29c4a9e910SFrançois Tigeot 
30e3adcf8fSFrançois Tigeot #include <sys/sfbuf.h>
31e3adcf8fSFrançois Tigeot 
3218e26a6dSFrançois Tigeot #include <drm/drmP.h>
335c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
34c4a9e910SFrançois Tigeot #include "i915_drv.h"
35e3adcf8fSFrançois Tigeot #include "intel_drv.h"
36c4a9e910SFrançois Tigeot 
37e3adcf8fSFrançois Tigeot static void i915_capture_error_state(struct drm_device *dev);
38e3adcf8fSFrançois Tigeot static u32 ring_last_seqno(struct intel_ring_buffer *ring);
39c4a9e910SFrançois Tigeot 
40c4a9e910SFrançois Tigeot /**
41c4a9e910SFrançois Tigeot  * Interrupts that are always left unmasked.
42c4a9e910SFrançois Tigeot  *
43c4a9e910SFrançois Tigeot  * Since pipe events are edge-triggered from the PIPESTAT register to IIR,
44c4a9e910SFrançois Tigeot  * we leave them always unmasked in IMR and then control enabling them through
45c4a9e910SFrançois Tigeot  * PIPESTAT alone.
46c4a9e910SFrançois Tigeot  */
47e3adcf8fSFrançois Tigeot #define I915_INTERRUPT_ENABLE_FIX			\
48e3adcf8fSFrançois Tigeot 	(I915_ASLE_INTERRUPT |				\
49e3adcf8fSFrançois Tigeot 	 I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |		\
50e3adcf8fSFrançois Tigeot 	 I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |		\
51e3adcf8fSFrançois Tigeot 	 I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |	\
52e3adcf8fSFrançois Tigeot 	 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |	\
53e3adcf8fSFrançois Tigeot 	 I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
54c4a9e910SFrançois Tigeot 
55c4a9e910SFrançois Tigeot /** Interrupts that we mask and unmask at runtime. */
56e3adcf8fSFrançois Tigeot #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT | I915_BSD_USER_INTERRUPT)
57c4a9e910SFrançois Tigeot 
58e3adcf8fSFrançois Tigeot #define I915_PIPE_VBLANK_STATUS	(PIPE_START_VBLANK_INTERRUPT_STATUS |\
59e3adcf8fSFrançois Tigeot 				 PIPE_VBLANK_INTERRUPT_STATUS)
60e3adcf8fSFrançois Tigeot 
61e3adcf8fSFrançois Tigeot #define I915_PIPE_VBLANK_ENABLE	(PIPE_START_VBLANK_INTERRUPT_ENABLE |\
62e3adcf8fSFrançois Tigeot 				 PIPE_VBLANK_INTERRUPT_ENABLE)
63c4a9e910SFrançois Tigeot 
64c4a9e910SFrançois Tigeot #define DRM_I915_VBLANK_PIPE_ALL	(DRM_I915_VBLANK_PIPE_A | \
65c4a9e910SFrançois Tigeot 					 DRM_I915_VBLANK_PIPE_B)
66c4a9e910SFrançois Tigeot 
67e3adcf8fSFrançois Tigeot /* For display hotplug interrupt */
68e3adcf8fSFrançois Tigeot static void
69e3adcf8fSFrançois Tigeot ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
70c4a9e910SFrançois Tigeot {
71e3adcf8fSFrançois Tigeot 	if ((dev_priv->irq_mask & mask) != 0) {
72e3adcf8fSFrançois Tigeot 		dev_priv->irq_mask &= ~mask;
73e3adcf8fSFrançois Tigeot 		I915_WRITE(DEIMR, dev_priv->irq_mask);
74e3adcf8fSFrançois Tigeot 		POSTING_READ(DEIMR);
75c4a9e910SFrançois Tigeot 	}
76c4a9e910SFrançois Tigeot }
77c4a9e910SFrançois Tigeot 
78c4a9e910SFrançois Tigeot static inline void
79e3adcf8fSFrançois Tigeot ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
80c4a9e910SFrançois Tigeot {
81e3adcf8fSFrançois Tigeot 	if ((dev_priv->irq_mask & mask) != mask) {
82e3adcf8fSFrançois Tigeot 		dev_priv->irq_mask |= mask;
83e3adcf8fSFrançois Tigeot 		I915_WRITE(DEIMR, dev_priv->irq_mask);
84e3adcf8fSFrançois Tigeot 		POSTING_READ(DEIMR);
85c4a9e910SFrançois Tigeot 	}
86c4a9e910SFrançois Tigeot }
87c4a9e910SFrançois Tigeot 
88c4a9e910SFrançois Tigeot void
89c4a9e910SFrançois Tigeot i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
90c4a9e910SFrançois Tigeot {
91c4a9e910SFrançois Tigeot 	if ((dev_priv->pipestat[pipe] & mask) != mask) {
92e3adcf8fSFrançois Tigeot 		u32 reg = PIPESTAT(pipe);
93c4a9e910SFrançois Tigeot 
94c4a9e910SFrançois Tigeot 		dev_priv->pipestat[pipe] |= mask;
95c4a9e910SFrançois Tigeot 		/* Enable the interrupt, clear any pending status */
96c4a9e910SFrançois Tigeot 		I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16));
97e3adcf8fSFrançois Tigeot 		POSTING_READ(reg);
98c4a9e910SFrançois Tigeot 	}
99c4a9e910SFrançois Tigeot }
100c4a9e910SFrançois Tigeot 
101c4a9e910SFrançois Tigeot void
102c4a9e910SFrançois Tigeot i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
103c4a9e910SFrançois Tigeot {
104c4a9e910SFrançois Tigeot 	if ((dev_priv->pipestat[pipe] & mask) != 0) {
105e3adcf8fSFrançois Tigeot 		u32 reg = PIPESTAT(pipe);
106c4a9e910SFrançois Tigeot 
107c4a9e910SFrançois Tigeot 		dev_priv->pipestat[pipe] &= ~mask;
108c4a9e910SFrançois Tigeot 		I915_WRITE(reg, dev_priv->pipestat[pipe]);
109e3adcf8fSFrançois Tigeot 		POSTING_READ(reg);
110c4a9e910SFrançois Tigeot 	}
111c4a9e910SFrançois Tigeot }
112c4a9e910SFrançois Tigeot 
113c4a9e910SFrançois Tigeot /**
114e3adcf8fSFrançois Tigeot  * intel_enable_asle - enable ASLE interrupt for OpRegion
115e3adcf8fSFrançois Tigeot  */
116e3adcf8fSFrançois Tigeot void intel_enable_asle(struct drm_device *dev)
117e3adcf8fSFrançois Tigeot {
118e3adcf8fSFrançois Tigeot 	drm_i915_private_t *dev_priv = dev->dev_private;
119e3adcf8fSFrançois Tigeot 
120e3adcf8fSFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
121e3adcf8fSFrançois Tigeot 
122e3adcf8fSFrançois Tigeot 	if (HAS_PCH_SPLIT(dev))
123e3adcf8fSFrançois Tigeot 		ironlake_enable_display_irq(dev_priv, DE_GSE);
124e3adcf8fSFrançois Tigeot 	else {
125e3adcf8fSFrançois Tigeot 		i915_enable_pipestat(dev_priv, 1,
126e3adcf8fSFrançois Tigeot 				     PIPE_LEGACY_BLC_EVENT_ENABLE);
127e3adcf8fSFrançois Tigeot 		if (INTEL_INFO(dev)->gen >= 4)
128e3adcf8fSFrançois Tigeot 			i915_enable_pipestat(dev_priv, 0,
129e3adcf8fSFrançois Tigeot 					     PIPE_LEGACY_BLC_EVENT_ENABLE);
130e3adcf8fSFrançois Tigeot 	}
131e3adcf8fSFrançois Tigeot 
132e3adcf8fSFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
133e3adcf8fSFrançois Tigeot }
134e3adcf8fSFrançois Tigeot 
135e3adcf8fSFrançois Tigeot /**
136c4a9e910SFrançois Tigeot  * i915_pipe_enabled - check if a pipe is enabled
137c4a9e910SFrançois Tigeot  * @dev: DRM device
138c4a9e910SFrançois Tigeot  * @pipe: pipe to check
139c4a9e910SFrançois Tigeot  *
140c4a9e910SFrançois Tigeot  * Reading certain registers when the pipe is disabled can hang the chip.
141c4a9e910SFrançois Tigeot  * Use this routine to make sure the PLL is running and the pipe is active
142c4a9e910SFrançois Tigeot  * before reading such registers if unsure.
143c4a9e910SFrançois Tigeot  */
144c4a9e910SFrançois Tigeot static int
145c4a9e910SFrançois Tigeot i915_pipe_enabled(struct drm_device *dev, int pipe)
146c4a9e910SFrançois Tigeot {
147c4a9e910SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
148e3adcf8fSFrançois Tigeot 	return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
149c4a9e910SFrançois Tigeot }
150c4a9e910SFrançois Tigeot 
151c4a9e910SFrançois Tigeot /* Called from drm generic code, passed a 'crtc', which
152c4a9e910SFrançois Tigeot  * we use as a pipe index
153c4a9e910SFrançois Tigeot  */
154e3adcf8fSFrançois Tigeot static u32
155e3adcf8fSFrançois Tigeot i915_get_vblank_counter(struct drm_device *dev, int pipe)
156c4a9e910SFrançois Tigeot {
157c4a9e910SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
158c4a9e910SFrançois Tigeot 	unsigned long high_frame;
159c4a9e910SFrançois Tigeot 	unsigned long low_frame;
160e3adcf8fSFrançois Tigeot 	u32 high1, high2, low;
161c4a9e910SFrançois Tigeot 
162c4a9e910SFrançois Tigeot 	if (!i915_pipe_enabled(dev, pipe)) {
163e3adcf8fSFrançois Tigeot 		DRM_DEBUG("trying to get vblank count for disabled "
164e3adcf8fSFrançois Tigeot 				"pipe %c\n", pipe_name(pipe));
165c4a9e910SFrançois Tigeot 		return 0;
166c4a9e910SFrançois Tigeot 	}
167c4a9e910SFrançois Tigeot 
168e3adcf8fSFrançois Tigeot 	high_frame = PIPEFRAME(pipe);
169e3adcf8fSFrançois Tigeot 	low_frame = PIPEFRAMEPIXEL(pipe);
170e3adcf8fSFrançois Tigeot 
171c4a9e910SFrançois Tigeot 	/*
172c4a9e910SFrançois Tigeot 	 * High & low register fields aren't synchronized, so make sure
173c4a9e910SFrançois Tigeot 	 * we get a low value that's stable across two reads of the high
174c4a9e910SFrançois Tigeot 	 * register.
175c4a9e910SFrançois Tigeot 	 */
176c4a9e910SFrançois Tigeot 	do {
177e3adcf8fSFrançois Tigeot 		high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
178e3adcf8fSFrançois Tigeot 		low   = I915_READ(low_frame)  & PIPE_FRAME_LOW_MASK;
179e3adcf8fSFrançois Tigeot 		high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
180c4a9e910SFrançois Tigeot 	} while (high1 != high2);
181c4a9e910SFrançois Tigeot 
182e3adcf8fSFrançois Tigeot 	high1 >>= PIPE_FRAME_HIGH_SHIFT;
183e3adcf8fSFrançois Tigeot 	low >>= PIPE_FRAME_LOW_SHIFT;
184e3adcf8fSFrançois Tigeot 	return (high1 << 8) | low;
185c4a9e910SFrançois Tigeot }
186c4a9e910SFrançois Tigeot 
187e3adcf8fSFrançois Tigeot static u32
188e3adcf8fSFrançois Tigeot gm45_get_vblank_counter(struct drm_device *dev, int pipe)
189c4a9e910SFrançois Tigeot {
190c4a9e910SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
191e3adcf8fSFrançois Tigeot 	int reg = PIPE_FRMCOUNT_GM45(pipe);
192c4a9e910SFrançois Tigeot 
193c4a9e910SFrançois Tigeot 	if (!i915_pipe_enabled(dev, pipe)) {
194e3adcf8fSFrançois Tigeot 		DRM_DEBUG("i915: trying to get vblank count for disabled "
195e3adcf8fSFrançois Tigeot 				 "pipe %c\n", pipe_name(pipe));
196c4a9e910SFrançois Tigeot 		return 0;
197c4a9e910SFrançois Tigeot 	}
198c4a9e910SFrançois Tigeot 
199c4a9e910SFrançois Tigeot 	return I915_READ(reg);
200c4a9e910SFrançois Tigeot }
201c4a9e910SFrançois Tigeot 
202e3adcf8fSFrançois Tigeot static int
203e3adcf8fSFrançois Tigeot i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
204e3adcf8fSFrançois Tigeot     int *vpos, int *hpos)
205e3adcf8fSFrançois Tigeot {
206e3adcf8fSFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
207e3adcf8fSFrançois Tigeot 	u32 vbl = 0, position = 0;
208e3adcf8fSFrançois Tigeot 	int vbl_start, vbl_end, htotal, vtotal;
209e3adcf8fSFrançois Tigeot 	bool in_vbl = true;
210e3adcf8fSFrançois Tigeot 	int ret = 0;
211e3adcf8fSFrançois Tigeot 
212e3adcf8fSFrançois Tigeot 	if (!i915_pipe_enabled(dev, pipe)) {
213e3adcf8fSFrançois Tigeot 		DRM_DEBUG("i915: trying to get scanoutpos for disabled "
214e3adcf8fSFrançois Tigeot 				 "pipe %c\n", pipe_name(pipe));
215e3adcf8fSFrançois Tigeot 		return 0;
216e3adcf8fSFrançois Tigeot 	}
217e3adcf8fSFrançois Tigeot 
218e3adcf8fSFrançois Tigeot 	/* Get vtotal. */
219e3adcf8fSFrançois Tigeot 	vtotal = 1 + ((I915_READ(VTOTAL(pipe)) >> 16) & 0x1fff);
220e3adcf8fSFrançois Tigeot 
221e3adcf8fSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 4) {
222e3adcf8fSFrançois Tigeot 		/* No obvious pixelcount register. Only query vertical
223e3adcf8fSFrançois Tigeot 		 * scanout position from Display scan line register.
224e3adcf8fSFrançois Tigeot 		 */
225e3adcf8fSFrançois Tigeot 		position = I915_READ(PIPEDSL(pipe));
226e3adcf8fSFrançois Tigeot 
227e3adcf8fSFrançois Tigeot 		/* Decode into vertical scanout position. Don't have
228e3adcf8fSFrançois Tigeot 		 * horizontal scanout position.
229e3adcf8fSFrançois Tigeot 		 */
230e3adcf8fSFrançois Tigeot 		*vpos = position & 0x1fff;
231e3adcf8fSFrançois Tigeot 		*hpos = 0;
232e3adcf8fSFrançois Tigeot 	} else {
233e3adcf8fSFrançois Tigeot 		/* Have access to pixelcount since start of frame.
234e3adcf8fSFrançois Tigeot 		 * We can split this into vertical and horizontal
235e3adcf8fSFrançois Tigeot 		 * scanout position.
236e3adcf8fSFrançois Tigeot 		 */
237e3adcf8fSFrançois Tigeot 		position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
238e3adcf8fSFrançois Tigeot 
239e3adcf8fSFrançois Tigeot 		htotal = 1 + ((I915_READ(HTOTAL(pipe)) >> 16) & 0x1fff);
240e3adcf8fSFrançois Tigeot 		*vpos = position / htotal;
241e3adcf8fSFrançois Tigeot 		*hpos = position - (*vpos * htotal);
242e3adcf8fSFrançois Tigeot 	}
243e3adcf8fSFrançois Tigeot 
244e3adcf8fSFrançois Tigeot 	/* Query vblank area. */
245e3adcf8fSFrançois Tigeot 	vbl = I915_READ(VBLANK(pipe));
246e3adcf8fSFrançois Tigeot 
247e3adcf8fSFrançois Tigeot 	/* Test position against vblank region. */
248e3adcf8fSFrançois Tigeot 	vbl_start = vbl & 0x1fff;
249e3adcf8fSFrançois Tigeot 	vbl_end = (vbl >> 16) & 0x1fff;
250e3adcf8fSFrançois Tigeot 
251e3adcf8fSFrançois Tigeot 	if ((*vpos < vbl_start) || (*vpos > vbl_end))
252e3adcf8fSFrançois Tigeot 		in_vbl = false;
253e3adcf8fSFrançois Tigeot 
254e3adcf8fSFrançois Tigeot 	/* Inside "upper part" of vblank area? Apply corrective offset: */
255e3adcf8fSFrançois Tigeot 	if (in_vbl && (*vpos >= vbl_start))
256e3adcf8fSFrançois Tigeot 		*vpos = *vpos - vtotal;
257e3adcf8fSFrançois Tigeot 
258e3adcf8fSFrançois Tigeot 	/* Readouts valid? */
259e3adcf8fSFrançois Tigeot 	if (vbl > 0)
260e3adcf8fSFrançois Tigeot 		ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
261e3adcf8fSFrançois Tigeot 
262e3adcf8fSFrançois Tigeot 	/* In vblank? */
263e3adcf8fSFrançois Tigeot 	if (in_vbl)
264e3adcf8fSFrançois Tigeot 		ret |= DRM_SCANOUTPOS_INVBL;
265e3adcf8fSFrançois Tigeot 
266e3adcf8fSFrançois Tigeot 	return ret;
267e3adcf8fSFrançois Tigeot }
268e3adcf8fSFrançois Tigeot 
269e3adcf8fSFrançois Tigeot static int
270e3adcf8fSFrançois Tigeot i915_get_vblank_timestamp(struct drm_device *dev, int pipe, int *max_error,
271e3adcf8fSFrançois Tigeot     struct timeval *vblank_time, unsigned flags)
272e3adcf8fSFrançois Tigeot {
273e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
274e3adcf8fSFrançois Tigeot 	struct drm_crtc *crtc;
275e3adcf8fSFrançois Tigeot 
276e3adcf8fSFrançois Tigeot 	if (pipe < 0 || pipe >= dev_priv->num_pipe) {
277e3adcf8fSFrançois Tigeot 		DRM_ERROR("Invalid crtc %d\n", pipe);
278e3adcf8fSFrançois Tigeot 		return -EINVAL;
279e3adcf8fSFrançois Tigeot 	}
280e3adcf8fSFrançois Tigeot 
281e3adcf8fSFrançois Tigeot 	/* Get drm_crtc to timestamp: */
282e3adcf8fSFrançois Tigeot 	crtc = intel_get_crtc_for_pipe(dev, pipe);
283e3adcf8fSFrançois Tigeot 	if (crtc == NULL) {
284e3adcf8fSFrançois Tigeot 		DRM_ERROR("Invalid crtc %d\n", pipe);
285e3adcf8fSFrançois Tigeot 		return -EINVAL;
286e3adcf8fSFrançois Tigeot 	}
287e3adcf8fSFrançois Tigeot 
288e3adcf8fSFrançois Tigeot 	if (!crtc->enabled) {
289e3adcf8fSFrançois Tigeot #if 0
290e3adcf8fSFrançois Tigeot 		DRM_DEBUG("crtc %d is disabled\n", pipe);
291e3adcf8fSFrançois Tigeot #endif
292e3adcf8fSFrançois Tigeot 		return -EBUSY;
293e3adcf8fSFrançois Tigeot 	}
294e3adcf8fSFrançois Tigeot 
295e3adcf8fSFrançois Tigeot 	/* Helper routine in DRM core does all the work: */
296e3adcf8fSFrançois Tigeot 	return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
297e3adcf8fSFrançois Tigeot 						     vblank_time, flags,
298e3adcf8fSFrançois Tigeot 						     crtc);
299e3adcf8fSFrançois Tigeot }
300e3adcf8fSFrançois Tigeot 
301e3adcf8fSFrançois Tigeot /*
302e3adcf8fSFrançois Tigeot  * Handle hotplug events outside the interrupt handler proper.
303e3adcf8fSFrançois Tigeot  */
304abf1f4f4SFrançois Tigeot static void i915_hotplug_work_func(struct work_struct *work)
305e3adcf8fSFrançois Tigeot {
306abf1f4f4SFrançois Tigeot 	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
307abf1f4f4SFrançois Tigeot 						    hotplug_work);
308e3adcf8fSFrançois Tigeot 	struct drm_device *dev = dev_priv->dev;
309abf1f4f4SFrançois Tigeot 	struct drm_mode_config *mode_config = &dev->mode_config;
310e3adcf8fSFrançois Tigeot 	struct intel_encoder *encoder;
311e3adcf8fSFrançois Tigeot 
312af4b81b9SFrançois Tigeot 	lockmgr(&mode_config->mutex, LK_EXCLUSIVE);
313e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("running encoder hotplug functions\n");
314e3adcf8fSFrançois Tigeot 
315e3adcf8fSFrançois Tigeot 	list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
316e3adcf8fSFrançois Tigeot 		if (encoder->hot_plug)
317e3adcf8fSFrançois Tigeot 			encoder->hot_plug(encoder);
318e3adcf8fSFrançois Tigeot 
319af4b81b9SFrançois Tigeot 	lockmgr(&mode_config->mutex, LK_RELEASE);
320e3adcf8fSFrançois Tigeot 
321e3adcf8fSFrançois Tigeot 	/* Just fire off a uevent and let userspace tell us what to do */
322e3adcf8fSFrançois Tigeot #if 0
323e3adcf8fSFrançois Tigeot 	drm_helper_hpd_irq_event(dev);
324e3adcf8fSFrançois Tigeot #endif
325e3adcf8fSFrançois Tigeot }
326e3adcf8fSFrançois Tigeot 
327a2296444SFrançois Tigeot static void ironlake_handle_rps_change(struct drm_device *dev)
328e3adcf8fSFrançois Tigeot {
329e3adcf8fSFrançois Tigeot 	drm_i915_private_t *dev_priv = dev->dev_private;
330e3adcf8fSFrançois Tigeot 	u32 busy_up, busy_down, max_avg, min_avg;
331a2296444SFrançois Tigeot 	u8 new_delay;
332a2296444SFrançois Tigeot 
333a2296444SFrançois Tigeot 	lockmgr(&mchdev_lock, LK_EXCLUSIVE);
334a2296444SFrançois Tigeot 
335a2296444SFrançois Tigeot 	I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
336a2296444SFrançois Tigeot 
337abf1f4f4SFrançois Tigeot 	new_delay = dev_priv->rps.cur_delay;
338e3adcf8fSFrançois Tigeot 
339e3adcf8fSFrançois Tigeot 	I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG);
340e3adcf8fSFrançois Tigeot 	busy_up = I915_READ(RCPREVBSYTUPAVG);
341e3adcf8fSFrançois Tigeot 	busy_down = I915_READ(RCPREVBSYTDNAVG);
342e3adcf8fSFrançois Tigeot 	max_avg = I915_READ(RCBMAXAVG);
343e3adcf8fSFrançois Tigeot 	min_avg = I915_READ(RCBMINAVG);
344e3adcf8fSFrançois Tigeot 
345e3adcf8fSFrançois Tigeot 	/* Handle RCS change request from hw */
346e3adcf8fSFrançois Tigeot 	if (busy_up > max_avg) {
347abf1f4f4SFrançois Tigeot 		if (dev_priv->rps.cur_delay != dev_priv->rps.max_delay)
348abf1f4f4SFrançois Tigeot 			new_delay = dev_priv->rps.cur_delay - 1;
349abf1f4f4SFrançois Tigeot 		if (new_delay < dev_priv->rps.max_delay)
350abf1f4f4SFrançois Tigeot 			new_delay = dev_priv->rps.max_delay;
351e3adcf8fSFrançois Tigeot 	} else if (busy_down < min_avg) {
352abf1f4f4SFrançois Tigeot 		if (dev_priv->rps.cur_delay != dev_priv->rps.min_delay)
353abf1f4f4SFrançois Tigeot 			new_delay = dev_priv->rps.cur_delay + 1;
354abf1f4f4SFrançois Tigeot 		if (new_delay > dev_priv->rps.min_delay)
355abf1f4f4SFrançois Tigeot 			new_delay = dev_priv->rps.min_delay;
356e3adcf8fSFrançois Tigeot 	}
357e3adcf8fSFrançois Tigeot 
358e3adcf8fSFrançois Tigeot 	if (ironlake_set_drps(dev, new_delay))
359abf1f4f4SFrançois Tigeot 		dev_priv->rps.cur_delay = new_delay;
360e3adcf8fSFrançois Tigeot 
361a2296444SFrançois Tigeot 	lockmgr(&mchdev_lock, LK_RELEASE);
362a2296444SFrançois Tigeot 
363e3adcf8fSFrançois Tigeot 	return;
364e3adcf8fSFrançois Tigeot }
365e3adcf8fSFrançois Tigeot 
366e3adcf8fSFrançois Tigeot static void notify_ring(struct drm_device *dev,
367e3adcf8fSFrançois Tigeot 			struct intel_ring_buffer *ring)
368e3adcf8fSFrançois Tigeot {
369e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
370e3adcf8fSFrançois Tigeot 	u32 seqno;
371e3adcf8fSFrançois Tigeot 
372e3adcf8fSFrançois Tigeot 	if (ring->obj == NULL)
373e3adcf8fSFrançois Tigeot 		return;
374e3adcf8fSFrançois Tigeot 
375e3adcf8fSFrançois Tigeot 	seqno = ring->get_seqno(ring);
376e3adcf8fSFrançois Tigeot 
377e3adcf8fSFrançois Tigeot 	lockmgr(&ring->irq_lock, LK_EXCLUSIVE);
378e3adcf8fSFrançois Tigeot 	ring->irq_seqno = seqno;
379e3adcf8fSFrançois Tigeot 	wakeup(ring);
380e3adcf8fSFrançois Tigeot 	lockmgr(&ring->irq_lock, LK_RELEASE);
381e3adcf8fSFrançois Tigeot 
382e3adcf8fSFrançois Tigeot 	if (i915_enable_hangcheck) {
383e3adcf8fSFrançois Tigeot 		dev_priv->hangcheck_count = 0;
3841b386112SFrançois Tigeot 		mod_timer(&dev_priv->hangcheck_timer,
3851b386112SFrançois Tigeot 			  round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
386e3adcf8fSFrançois Tigeot 	}
387e3adcf8fSFrançois Tigeot }
388e3adcf8fSFrançois Tigeot 
389abf1f4f4SFrançois Tigeot static void gen6_pm_rps_work(struct work_struct *work)
390e3adcf8fSFrançois Tigeot {
391abf1f4f4SFrançois Tigeot 	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
392abf1f4f4SFrançois Tigeot 						    rps.work);
393e3adcf8fSFrançois Tigeot 	u32 pm_iir, pm_imr;
394abf1f4f4SFrançois Tigeot 	u8 new_delay;
395e3adcf8fSFrançois Tigeot 
396abf1f4f4SFrançois Tigeot 	spin_lock(&dev_priv->rps.lock);
397abf1f4f4SFrançois Tigeot 	pm_iir = dev_priv->rps.pm_iir;
398abf1f4f4SFrançois Tigeot 	dev_priv->rps.pm_iir = 0;
399e3adcf8fSFrançois Tigeot 	pm_imr = I915_READ(GEN6_PMIMR);
400e3adcf8fSFrançois Tigeot 	I915_WRITE(GEN6_PMIMR, 0);
401abf1f4f4SFrançois Tigeot 	spin_unlock(&dev_priv->rps.lock);
402e3adcf8fSFrançois Tigeot 
403abf1f4f4SFrançois Tigeot 	if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0)
404e3adcf8fSFrançois Tigeot 		return;
405e3adcf8fSFrançois Tigeot 
406abf1f4f4SFrançois Tigeot 	lockmgr(&dev_priv->rps.hw_lock, LK_EXCLUSIVE);
407e3adcf8fSFrançois Tigeot 
408abf1f4f4SFrançois Tigeot 	if (pm_iir & GEN6_PM_RP_UP_THRESHOLD)
409abf1f4f4SFrançois Tigeot 		new_delay = dev_priv->rps.cur_delay + 1;
410abf1f4f4SFrançois Tigeot 	else
411abf1f4f4SFrançois Tigeot 		new_delay = dev_priv->rps.cur_delay - 1;
412e3adcf8fSFrançois Tigeot 
413abf1f4f4SFrançois Tigeot 	/* sysfs frequency interfaces may have snuck in while servicing the
414abf1f4f4SFrançois Tigeot 	 * interrupt
415e3adcf8fSFrançois Tigeot 	 */
416abf1f4f4SFrançois Tigeot 	if (!(new_delay > dev_priv->rps.max_delay ||
417abf1f4f4SFrançois Tigeot 	      new_delay < dev_priv->rps.min_delay)) {
418abf1f4f4SFrançois Tigeot 		gen6_set_rps(dev_priv->dev, new_delay);
419abf1f4f4SFrançois Tigeot 	}
420abf1f4f4SFrançois Tigeot 
421abf1f4f4SFrançois Tigeot 	lockmgr(&dev_priv->rps.hw_lock, LK_RELEASE);
422e3adcf8fSFrançois Tigeot }
423e3adcf8fSFrançois Tigeot 
424a2296444SFrançois Tigeot static void snb_gt_irq_handler(struct drm_device *dev,
425a2296444SFrançois Tigeot 			       struct drm_i915_private *dev_priv,
426a2296444SFrançois Tigeot 			       u32 gt_iir)
427a2296444SFrançois Tigeot {
428a2296444SFrançois Tigeot 
429a2296444SFrançois Tigeot 	if (gt_iir & (GEN6_RENDER_USER_INTERRUPT |
430a2296444SFrançois Tigeot 		      GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT))
431a2296444SFrançois Tigeot 		notify_ring(dev, &dev_priv->ring[RCS]);
432a2296444SFrançois Tigeot 	if (gt_iir & GEN6_BSD_USER_INTERRUPT)
433a2296444SFrançois Tigeot 		notify_ring(dev, &dev_priv->ring[VCS]);
434a2296444SFrançois Tigeot 	if (gt_iir & GEN6_BLITTER_USER_INTERRUPT)
435a2296444SFrançois Tigeot 		notify_ring(dev, &dev_priv->ring[BCS]);
436a2296444SFrançois Tigeot 
437a2296444SFrançois Tigeot 	if (gt_iir & (GT_GEN6_BLT_CS_ERROR_INTERRUPT |
438a2296444SFrançois Tigeot 		      GT_GEN6_BSD_CS_ERROR_INTERRUPT |
439a2296444SFrançois Tigeot 		      GT_RENDER_CS_ERROR_INTERRUPT)) {
440a2296444SFrançois Tigeot 		DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
441a2296444SFrançois Tigeot 		i915_handle_error(dev, false);
442a2296444SFrançois Tigeot 	}
443a2296444SFrançois Tigeot 
444a2296444SFrançois Tigeot #if 0
445a2296444SFrançois Tigeot 	if (gt_iir & GT_GEN7_L3_PARITY_ERROR_INTERRUPT)
446a2296444SFrançois Tigeot 		ivybridge_handle_parity_error(dev);
447a2296444SFrançois Tigeot #endif
448a2296444SFrançois Tigeot }
449a2296444SFrançois Tigeot 
450a2296444SFrançois Tigeot static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
451a2296444SFrançois Tigeot 				u32 pm_iir)
452a2296444SFrançois Tigeot {
453a2296444SFrançois Tigeot 
454a2296444SFrançois Tigeot 	/*
455a2296444SFrançois Tigeot 	 * IIR bits should never already be set because IMR should
456a2296444SFrançois Tigeot 	 * prevent an interrupt from being shown in IIR. The warning
457a2296444SFrançois Tigeot 	 * displays a case where we've unsafely cleared
458a2296444SFrançois Tigeot 	 * dev_priv->rps.pm_iir. Although missing an interrupt of the same
459a2296444SFrançois Tigeot 	 * type is not a problem, it displays a problem in the logic.
460a2296444SFrançois Tigeot 	 *
461a2296444SFrançois Tigeot 	 * The mask bit in IMR is cleared by dev_priv->rps.work.
462a2296444SFrançois Tigeot 	 */
463a2296444SFrançois Tigeot 
464abf1f4f4SFrançois Tigeot 	spin_lock(&dev_priv->rps.lock);
465abf1f4f4SFrançois Tigeot 	dev_priv->rps.pm_iir |= pm_iir;
466abf1f4f4SFrançois Tigeot 	I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
467a2296444SFrançois Tigeot 	POSTING_READ(GEN6_PMIMR);
468abf1f4f4SFrançois Tigeot 	spin_unlock(&dev_priv->rps.lock);
469a2296444SFrançois Tigeot 
470abf1f4f4SFrançois Tigeot 	queue_work(dev_priv->wq, &dev_priv->rps.work);
471a2296444SFrançois Tigeot }
472a2296444SFrançois Tigeot 
473*e9243325SFrançois Tigeot static irqreturn_t valleyview_irq_handler(void *arg)
474*e9243325SFrançois Tigeot {
475*e9243325SFrançois Tigeot 	struct drm_device *dev = (struct drm_device *) arg;
476*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
477*e9243325SFrançois Tigeot 	u32 iir, gt_iir, pm_iir;
478*e9243325SFrançois Tigeot 	int pipe;
479*e9243325SFrançois Tigeot 	u32 pipe_stats[I915_MAX_PIPES];
480*e9243325SFrançois Tigeot 	bool blc_event;
481*e9243325SFrançois Tigeot 
482*e9243325SFrançois Tigeot 	atomic_inc(&dev_priv->irq_received);
483*e9243325SFrançois Tigeot 
484*e9243325SFrançois Tigeot 	while (true) {
485*e9243325SFrançois Tigeot 		iir = I915_READ(VLV_IIR);
486*e9243325SFrançois Tigeot 		gt_iir = I915_READ(GTIIR);
487*e9243325SFrançois Tigeot 		pm_iir = I915_READ(GEN6_PMIIR);
488*e9243325SFrançois Tigeot 
489*e9243325SFrançois Tigeot 		if (gt_iir == 0 && pm_iir == 0 && iir == 0)
490*e9243325SFrançois Tigeot 			goto out;
491*e9243325SFrançois Tigeot 
492*e9243325SFrançois Tigeot 		snb_gt_irq_handler(dev, dev_priv, gt_iir);
493*e9243325SFrançois Tigeot 
494*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
495*e9243325SFrançois Tigeot 		for_each_pipe(pipe) {
496*e9243325SFrançois Tigeot 			int reg = PIPESTAT(pipe);
497*e9243325SFrançois Tigeot 			pipe_stats[pipe] = I915_READ(reg);
498*e9243325SFrançois Tigeot 
499*e9243325SFrançois Tigeot 			/*
500*e9243325SFrançois Tigeot 			 * Clear the PIPE*STAT regs before the IIR
501*e9243325SFrançois Tigeot 			 */
502*e9243325SFrançois Tigeot 			if (pipe_stats[pipe] & 0x8000ffff) {
503*e9243325SFrançois Tigeot 				if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
504*e9243325SFrançois Tigeot 					DRM_DEBUG_DRIVER("pipe %c underrun\n",
505*e9243325SFrançois Tigeot 							 pipe_name(pipe));
506*e9243325SFrançois Tigeot 				I915_WRITE(reg, pipe_stats[pipe]);
507*e9243325SFrançois Tigeot 			}
508*e9243325SFrançois Tigeot 		}
509*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_RELEASE);
510*e9243325SFrançois Tigeot 
511*e9243325SFrançois Tigeot 		for_each_pipe(pipe) {
512*e9243325SFrançois Tigeot 			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
513*e9243325SFrançois Tigeot 				drm_handle_vblank(dev, pipe);
514*e9243325SFrançois Tigeot 
515*e9243325SFrançois Tigeot 			if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) {
516*e9243325SFrançois Tigeot 				intel_prepare_page_flip(dev, pipe);
517*e9243325SFrançois Tigeot 				intel_finish_page_flip(dev, pipe);
518*e9243325SFrançois Tigeot 			}
519*e9243325SFrançois Tigeot 		}
520*e9243325SFrançois Tigeot 
521*e9243325SFrançois Tigeot 		/* Consume port.  Then clear IIR or we'll miss events */
522*e9243325SFrançois Tigeot 		if (iir & I915_DISPLAY_PORT_INTERRUPT) {
523*e9243325SFrançois Tigeot 			u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
524*e9243325SFrançois Tigeot 
525*e9243325SFrançois Tigeot 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
526*e9243325SFrançois Tigeot 					 hotplug_status);
527*e9243325SFrançois Tigeot 			if (hotplug_status & dev_priv->hotplug_supported_mask)
528*e9243325SFrançois Tigeot 				queue_work(dev_priv->wq,
529*e9243325SFrançois Tigeot 					   &dev_priv->hotplug_work);
530*e9243325SFrançois Tigeot 
531*e9243325SFrançois Tigeot 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
532*e9243325SFrançois Tigeot 			I915_READ(PORT_HOTPLUG_STAT);
533*e9243325SFrançois Tigeot 		}
534*e9243325SFrançois Tigeot 
535*e9243325SFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
536*e9243325SFrançois Tigeot 			blc_event = true;
537*e9243325SFrançois Tigeot 
538*e9243325SFrançois Tigeot 		if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
539*e9243325SFrançois Tigeot 			gen6_queue_rps_work(dev_priv, pm_iir);
540*e9243325SFrançois Tigeot 
541*e9243325SFrançois Tigeot 		I915_WRITE(GTIIR, gt_iir);
542*e9243325SFrançois Tigeot 		I915_WRITE(GEN6_PMIIR, pm_iir);
543*e9243325SFrançois Tigeot 		I915_WRITE(VLV_IIR, iir);
544*e9243325SFrançois Tigeot 	}
545*e9243325SFrançois Tigeot 
546*e9243325SFrançois Tigeot out:
547*e9243325SFrançois Tigeot 	return;
548*e9243325SFrançois Tigeot }
549*e9243325SFrançois Tigeot 
550a2296444SFrançois Tigeot static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
551e3adcf8fSFrançois Tigeot {
552e3adcf8fSFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
553e3adcf8fSFrançois Tigeot 	int pipe;
554e3adcf8fSFrançois Tigeot 
555a2296444SFrançois Tigeot 	if (pch_iir & SDE_HOTPLUG_MASK)
556abf1f4f4SFrançois Tigeot 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
557e3adcf8fSFrançois Tigeot 
558e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_AUDIO_POWER_MASK)
559a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
560e3adcf8fSFrançois Tigeot 				 (pch_iir & SDE_AUDIO_POWER_MASK) >>
561e3adcf8fSFrançois Tigeot 				 SDE_AUDIO_POWER_SHIFT);
562e3adcf8fSFrançois Tigeot 
563e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_GMBUS)
564a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
565e3adcf8fSFrançois Tigeot 
566e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_AUDIO_HDCP_MASK)
567a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n");
568e3adcf8fSFrançois Tigeot 
569e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_AUDIO_TRANS_MASK)
570a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH transcoder audio interrupt\n");
571e3adcf8fSFrançois Tigeot 
572e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_POISON)
573a2296444SFrançois Tigeot 		DRM_ERROR("PCH poison interrupt\n");
574e3adcf8fSFrançois Tigeot 
575e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_FDI_MASK)
576e3adcf8fSFrançois Tigeot 		for_each_pipe(pipe)
577a2296444SFrançois Tigeot 			DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
578e3adcf8fSFrançois Tigeot 					 pipe_name(pipe),
579e3adcf8fSFrançois Tigeot 					 I915_READ(FDI_RX_IIR(pipe)));
580e3adcf8fSFrançois Tigeot 
581e3adcf8fSFrançois Tigeot 	if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE))
582a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n");
583e3adcf8fSFrançois Tigeot 
584e3adcf8fSFrançois Tigeot 	if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR))
585a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
586e3adcf8fSFrançois Tigeot 
587e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_TRANSB_FIFO_UNDER)
588a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n");
589e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_TRANSA_FIFO_UNDER)
590a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
591a2296444SFrançois Tigeot }
592a2296444SFrançois Tigeot 
593a2296444SFrançois Tigeot static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
594a2296444SFrançois Tigeot {
595a2296444SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
596a2296444SFrançois Tigeot 	int pipe;
597a2296444SFrançois Tigeot 
598a2296444SFrançois Tigeot 	if (pch_iir & SDE_HOTPLUG_MASK_CPT)
599abf1f4f4SFrançois Tigeot 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
600a2296444SFrançois Tigeot 
601a2296444SFrançois Tigeot 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT)
602a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
603a2296444SFrançois Tigeot 				 (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
604a2296444SFrançois Tigeot 				 SDE_AUDIO_POWER_SHIFT_CPT);
605a2296444SFrançois Tigeot 
606a2296444SFrançois Tigeot 	if (pch_iir & SDE_AUX_MASK_CPT)
607a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("AUX channel interrupt\n");
608a2296444SFrançois Tigeot 
609a2296444SFrançois Tigeot 	if (pch_iir & SDE_GMBUS_CPT)
610a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
611a2296444SFrançois Tigeot 
612a2296444SFrançois Tigeot 	if (pch_iir & SDE_AUDIO_CP_REQ_CPT)
613a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("Audio CP request interrupt\n");
614a2296444SFrançois Tigeot 
615a2296444SFrançois Tigeot 	if (pch_iir & SDE_AUDIO_CP_CHG_CPT)
616a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("Audio CP change interrupt\n");
617a2296444SFrançois Tigeot 
618a2296444SFrançois Tigeot 	if (pch_iir & SDE_FDI_MASK_CPT)
619a2296444SFrançois Tigeot 		for_each_pipe(pipe)
620a2296444SFrançois Tigeot 			DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
621a2296444SFrançois Tigeot 					 pipe_name(pipe),
622a2296444SFrançois Tigeot 					 I915_READ(FDI_RX_IIR(pipe)));
623e3adcf8fSFrançois Tigeot }
624e3adcf8fSFrançois Tigeot 
625e3adcf8fSFrançois Tigeot static void
626e3adcf8fSFrançois Tigeot ivybridge_irq_handler(void *arg)
627c4a9e910SFrançois Tigeot {
628c4a9e910SFrançois Tigeot 	struct drm_device *dev = (struct drm_device *) arg;
629c4a9e910SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
630a2296444SFrançois Tigeot 	u32 de_iir, gt_iir, de_ier, pm_iir;
631a2296444SFrançois Tigeot 	int i;
632e3adcf8fSFrançois Tigeot 
633e3adcf8fSFrançois Tigeot 	atomic_inc(&dev_priv->irq_received);
634e3adcf8fSFrançois Tigeot 
635e3adcf8fSFrançois Tigeot 	/* disable master interrupt before clearing iir  */
636e3adcf8fSFrançois Tigeot 	de_ier = I915_READ(DEIER);
637e3adcf8fSFrançois Tigeot 	I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
638e3adcf8fSFrançois Tigeot 
639e3adcf8fSFrançois Tigeot 	gt_iir = I915_READ(GTIIR);
640a2296444SFrançois Tigeot 	if (gt_iir) {
641a2296444SFrançois Tigeot 		snb_gt_irq_handler(dev, dev_priv, gt_iir);
642a2296444SFrançois Tigeot 		I915_WRITE(GTIIR, gt_iir);
643e3adcf8fSFrançois Tigeot 	}
644e3adcf8fSFrançois Tigeot 
645a2296444SFrançois Tigeot 	de_iir = I915_READ(DEIER);
646a2296444SFrançois Tigeot 	if (de_iir) {
647a2296444SFrançois Tigeot #if 0
648a2296444SFrançois Tigeot 		if (de_iir & DE_GSE_IVB)
649e3adcf8fSFrançois Tigeot 			intel_opregion_gse_intr(dev);
650e3adcf8fSFrançois Tigeot #endif
651a2296444SFrançois Tigeot 
652a2296444SFrançois Tigeot 		for (i = 0; i < 3; i++) {
653a2296444SFrançois Tigeot 			if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
654a2296444SFrançois Tigeot 				drm_handle_vblank(dev, i);
655a2296444SFrançois Tigeot 			if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) {
656a2296444SFrançois Tigeot 				intel_prepare_page_flip(dev, i);
657a2296444SFrançois Tigeot 				intel_finish_page_flip_plane(dev, i);
658e3adcf8fSFrançois Tigeot 			}
659e3adcf8fSFrançois Tigeot 		}
660e3adcf8fSFrançois Tigeot 
661e3adcf8fSFrançois Tigeot 		/* check event from PCH */
662e3adcf8fSFrançois Tigeot 		if (de_iir & DE_PCH_EVENT_IVB) {
663a2296444SFrançois Tigeot 			u32 pch_iir = I915_READ(SDEIIR);
664e3adcf8fSFrançois Tigeot 
665a2296444SFrançois Tigeot 			cpt_irq_handler(dev, pch_iir);
666e3adcf8fSFrançois Tigeot 
667a2296444SFrançois Tigeot 			/* clear PCH hotplug event before clear CPU irq */
668e3adcf8fSFrançois Tigeot 			I915_WRITE(SDEIIR, pch_iir);
669a2296444SFrançois Tigeot 		}
670e3adcf8fSFrançois Tigeot 
671a2296444SFrançois Tigeot 		I915_WRITE(DEIIR, de_iir);
672a2296444SFrançois Tigeot 	}
673a2296444SFrançois Tigeot 
674a2296444SFrançois Tigeot 	pm_iir = I915_READ(GEN6_PMIIR);
675a2296444SFrançois Tigeot 	if (pm_iir) {
676a2296444SFrançois Tigeot 		if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
677a2296444SFrançois Tigeot 			gen6_queue_rps_work(dev_priv, pm_iir);
678a2296444SFrançois Tigeot 		I915_WRITE(GEN6_PMIIR, pm_iir);
679a2296444SFrançois Tigeot 	}
680a2296444SFrançois Tigeot 
681e3adcf8fSFrançois Tigeot 	I915_WRITE(DEIER, de_ier);
682e3adcf8fSFrançois Tigeot 	POSTING_READ(DEIER);
683e3adcf8fSFrançois Tigeot }
684e3adcf8fSFrançois Tigeot 
685a2296444SFrançois Tigeot static void ilk_gt_irq_handler(struct drm_device *dev,
686a2296444SFrançois Tigeot 			       struct drm_i915_private *dev_priv,
687a2296444SFrançois Tigeot 			       u32 gt_iir)
688a2296444SFrançois Tigeot {
689a2296444SFrançois Tigeot 	if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
690a2296444SFrançois Tigeot 		notify_ring(dev, &dev_priv->ring[RCS]);
691a2296444SFrançois Tigeot 	if (gt_iir & GT_BSD_USER_INTERRUPT)
692a2296444SFrançois Tigeot 		notify_ring(dev, &dev_priv->ring[VCS]);
693a2296444SFrançois Tigeot }
694a2296444SFrançois Tigeot 
695e3adcf8fSFrançois Tigeot static void
696e3adcf8fSFrançois Tigeot ironlake_irq_handler(void *arg)
697e3adcf8fSFrançois Tigeot {
698e3adcf8fSFrançois Tigeot 	struct drm_device *dev = arg;
699e3adcf8fSFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
700e3adcf8fSFrançois Tigeot 	u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
701e3adcf8fSFrançois Tigeot 
702e3adcf8fSFrançois Tigeot 	atomic_inc(&dev_priv->irq_received);
703e3adcf8fSFrançois Tigeot 
704e3adcf8fSFrançois Tigeot 	/* disable master interrupt before clearing iir  */
705e3adcf8fSFrançois Tigeot 	de_ier = I915_READ(DEIER);
706e3adcf8fSFrançois Tigeot 	I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
707e3adcf8fSFrançois Tigeot 	POSTING_READ(DEIER);
708e3adcf8fSFrançois Tigeot 
709e3adcf8fSFrançois Tigeot 	de_iir = I915_READ(DEIIR);
710e3adcf8fSFrançois Tigeot 	gt_iir = I915_READ(GTIIR);
711e3adcf8fSFrançois Tigeot 	pch_iir = I915_READ(SDEIIR);
712e3adcf8fSFrançois Tigeot 	pm_iir = I915_READ(GEN6_PMIIR);
713e3adcf8fSFrançois Tigeot 
714e3adcf8fSFrançois Tigeot 	if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 &&
715e3adcf8fSFrançois Tigeot 	    (!IS_GEN6(dev) || pm_iir == 0))
716e3adcf8fSFrançois Tigeot 		goto done;
717e3adcf8fSFrançois Tigeot 
718a2296444SFrançois Tigeot 	if (IS_GEN5(dev))
719a2296444SFrançois Tigeot 		ilk_gt_irq_handler(dev, dev_priv, gt_iir);
720e3adcf8fSFrançois Tigeot 	else
721a2296444SFrançois Tigeot 		snb_gt_irq_handler(dev, dev_priv, gt_iir);
722e3adcf8fSFrançois Tigeot 
723f4e1c372SFrançois Tigeot 	if (gt_iir & GT_GEN6_BLT_USER_INTERRUPT)
724ad50ea93SFrançois Tigeot 		notify_ring(dev, &dev_priv->ring[BCS]);
725e3adcf8fSFrançois Tigeot 
726e3adcf8fSFrançois Tigeot 	if (de_iir & DE_GSE) {
727e3adcf8fSFrançois Tigeot #if 1
728e3adcf8fSFrançois Tigeot 		KIB_NOTYET();
729e3adcf8fSFrançois Tigeot #else
730e3adcf8fSFrançois Tigeot 		intel_opregion_gse_intr(dev);
731e3adcf8fSFrançois Tigeot #endif
732e3adcf8fSFrançois Tigeot 	}
733e3adcf8fSFrançois Tigeot 
734a2296444SFrançois Tigeot 	if (de_iir & DE_PIPEA_VBLANK)
735a2296444SFrançois Tigeot 		drm_handle_vblank(dev, 0);
736a2296444SFrançois Tigeot 
737a2296444SFrançois Tigeot 	if (de_iir & DE_PIPEB_VBLANK)
738a2296444SFrançois Tigeot 		drm_handle_vblank(dev, 1);
739a2296444SFrançois Tigeot 
740e3adcf8fSFrançois Tigeot 	if (de_iir & DE_PLANEA_FLIP_DONE) {
741e3adcf8fSFrançois Tigeot 		intel_prepare_page_flip(dev, 0);
742e3adcf8fSFrançois Tigeot 		intel_finish_page_flip_plane(dev, 0);
743e3adcf8fSFrançois Tigeot 	}
744e3adcf8fSFrançois Tigeot 
745e3adcf8fSFrançois Tigeot 	if (de_iir & DE_PLANEB_FLIP_DONE) {
746e3adcf8fSFrançois Tigeot 		intel_prepare_page_flip(dev, 1);
747e3adcf8fSFrançois Tigeot 		intel_finish_page_flip_plane(dev, 1);
748e3adcf8fSFrançois Tigeot 	}
749e3adcf8fSFrançois Tigeot 
750e3adcf8fSFrançois Tigeot 	/* check event from PCH */
751e3adcf8fSFrançois Tigeot 	if (de_iir & DE_PCH_EVENT) {
752a2296444SFrançois Tigeot 		if (HAS_PCH_CPT(dev))
753a2296444SFrançois Tigeot 			cpt_irq_handler(dev, pch_iir);
754a2296444SFrançois Tigeot 		else
755a2296444SFrançois Tigeot 			ibx_irq_handler(dev, pch_iir);
756e3adcf8fSFrançois Tigeot 	}
757e3adcf8fSFrançois Tigeot 
758a2296444SFrançois Tigeot 	if (IS_GEN5(dev) &&  de_iir & DE_PCU_EVENT)
759a2296444SFrançois Tigeot 		ironlake_handle_rps_change(dev);
760e3adcf8fSFrançois Tigeot 
761a2296444SFrançois Tigeot 	if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)
762a2296444SFrançois Tigeot 		gen6_queue_rps_work(dev_priv, pm_iir);
763e3adcf8fSFrançois Tigeot 
764e3adcf8fSFrançois Tigeot 	/* should clear PCH hotplug event before clear CPU irq */
765e3adcf8fSFrançois Tigeot 	I915_WRITE(SDEIIR, pch_iir);
766e3adcf8fSFrançois Tigeot 	I915_WRITE(GTIIR, gt_iir);
767e3adcf8fSFrançois Tigeot 	I915_WRITE(DEIIR, de_iir);
768e3adcf8fSFrançois Tigeot 	I915_WRITE(GEN6_PMIIR, pm_iir);
769e3adcf8fSFrançois Tigeot 
770e3adcf8fSFrançois Tigeot done:
771e3adcf8fSFrançois Tigeot 	I915_WRITE(DEIER, de_ier);
772e3adcf8fSFrançois Tigeot 	POSTING_READ(DEIER);
773e3adcf8fSFrançois Tigeot }
774e3adcf8fSFrançois Tigeot 
775e3adcf8fSFrançois Tigeot /**
776e3adcf8fSFrançois Tigeot  * i915_error_work_func - do process context error handling work
777e3adcf8fSFrançois Tigeot  * @work: work struct
778e3adcf8fSFrançois Tigeot  *
779e3adcf8fSFrançois Tigeot  * Fire an error uevent so userspace can see that a hang or error
780e3adcf8fSFrançois Tigeot  * was detected.
781e3adcf8fSFrançois Tigeot  */
782abf1f4f4SFrançois Tigeot static void i915_error_work_func(struct work_struct *work)
783e3adcf8fSFrançois Tigeot {
784abf1f4f4SFrançois Tigeot 	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
785abf1f4f4SFrançois Tigeot 						    error_work);
786e3adcf8fSFrançois Tigeot 	struct drm_device *dev = dev_priv->dev;
787e3adcf8fSFrançois Tigeot 
788e3adcf8fSFrançois Tigeot 	/* kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); */
789e3adcf8fSFrançois Tigeot 
790d65a337fSFrançois Tigeot 	if (atomic_read(&dev_priv->mm.wedged)) {
791abf1f4f4SFrançois Tigeot 		DRM_DEBUG_DRIVER("resetting chip\n");
792e3adcf8fSFrançois Tigeot 		/* kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); */
793e3adcf8fSFrançois Tigeot 		if (!i915_reset(dev, GRDOM_RENDER)) {
794d65a337fSFrançois Tigeot 			atomic_set(&dev_priv->mm.wedged, 0);
795e3adcf8fSFrançois Tigeot 			/* kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); */
796e3adcf8fSFrançois Tigeot 		}
797e3adcf8fSFrançois Tigeot 		lockmgr(&dev_priv->error_completion_lock, LK_EXCLUSIVE);
798e3adcf8fSFrançois Tigeot 		dev_priv->error_completion++;
799e3adcf8fSFrançois Tigeot 		wakeup(&dev_priv->error_completion);
800e3adcf8fSFrançois Tigeot 		lockmgr(&dev_priv->error_completion_lock, LK_RELEASE);
801e3adcf8fSFrançois Tigeot 	}
802e3adcf8fSFrançois Tigeot }
803e3adcf8fSFrançois Tigeot 
804c4a9e910SFrançois Tigeot /* Set the vblank monitor pipe
805c4a9e910SFrançois Tigeot  */
806c4a9e910SFrançois Tigeot int i915_vblank_pipe_set(struct drm_device *dev, void *data,
807c4a9e910SFrançois Tigeot 			 struct drm_file *file_priv)
808c4a9e910SFrançois Tigeot {
809c4a9e910SFrançois Tigeot 	drm_i915_private_t *dev_priv = dev->dev_private;
810c4a9e910SFrançois Tigeot 
811c4a9e910SFrançois Tigeot 	if (!dev_priv) {
812c4a9e910SFrançois Tigeot 		DRM_ERROR("called with no initialization\n");
813c4a9e910SFrançois Tigeot 		return -EINVAL;
814c4a9e910SFrançois Tigeot 	}
815c4a9e910SFrançois Tigeot 
816c4a9e910SFrançois Tigeot 	return 0;
817c4a9e910SFrançois Tigeot }
818c4a9e910SFrançois Tigeot 
819c4a9e910SFrançois Tigeot int i915_vblank_pipe_get(struct drm_device *dev, void *data,
820c4a9e910SFrançois Tigeot 			 struct drm_file *file_priv)
821c4a9e910SFrançois Tigeot {
822c4a9e910SFrançois Tigeot 	drm_i915_private_t *dev_priv = dev->dev_private;
823c4a9e910SFrançois Tigeot 	drm_i915_vblank_pipe_t *pipe = data;
824c4a9e910SFrançois Tigeot 
825c4a9e910SFrançois Tigeot 	if (!dev_priv) {
826c4a9e910SFrançois Tigeot 		DRM_ERROR("called with no initialization\n");
827c4a9e910SFrançois Tigeot 		return -EINVAL;
828c4a9e910SFrançois Tigeot 	}
829c4a9e910SFrançois Tigeot 
830c4a9e910SFrançois Tigeot 	pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
831c4a9e910SFrançois Tigeot 
832c4a9e910SFrançois Tigeot 	return 0;
833c4a9e910SFrançois Tigeot }
834c4a9e910SFrançois Tigeot 
835c4a9e910SFrançois Tigeot /**
836c4a9e910SFrançois Tigeot  * Schedule buffer swap at given vertical blank.
837c4a9e910SFrançois Tigeot  */
838c4a9e910SFrançois Tigeot int i915_vblank_swap(struct drm_device *dev, void *data,
839c4a9e910SFrançois Tigeot 		     struct drm_file *file_priv)
840c4a9e910SFrançois Tigeot {
841c4a9e910SFrançois Tigeot 	/* The delayed swap mechanism was fundamentally racy, and has been
842c4a9e910SFrançois Tigeot 	 * removed.  The model was that the client requested a delayed flip/swap
843c4a9e910SFrançois Tigeot 	 * from the kernel, then waited for vblank before continuing to perform
844c4a9e910SFrançois Tigeot 	 * rendering.  The problem was that the kernel might wake the client
845c4a9e910SFrançois Tigeot 	 * up before it dispatched the vblank swap (since the lock has to be
846c4a9e910SFrançois Tigeot 	 * held while touching the ringbuffer), in which case the client would
847c4a9e910SFrançois Tigeot 	 * clear and start the next frame before the swap occurred, and
848c4a9e910SFrançois Tigeot 	 * flicker would occur in addition to likely missing the vblank.
849c4a9e910SFrançois Tigeot 	 *
850c4a9e910SFrançois Tigeot 	 * In the absence of this ioctl, userland falls back to a correct path
851c4a9e910SFrançois Tigeot 	 * of waiting for a vblank, then dispatching the swap on its own.
852c4a9e910SFrançois Tigeot 	 * Context switching to userland and back is plenty fast enough for
853c4a9e910SFrançois Tigeot 	 * meeting the requirements of vblank swapping.
854c4a9e910SFrançois Tigeot 	 */
855c4a9e910SFrançois Tigeot 	return -EINVAL;
856c4a9e910SFrançois Tigeot }
857c4a9e910SFrançois Tigeot 
858e3adcf8fSFrançois Tigeot static struct drm_i915_error_object *
859e3adcf8fSFrançois Tigeot i915_error_object_create(struct drm_i915_private *dev_priv,
860e3adcf8fSFrançois Tigeot     struct drm_i915_gem_object *src)
861e3adcf8fSFrançois Tigeot {
862e3adcf8fSFrançois Tigeot 	struct drm_i915_error_object *dst;
863e3adcf8fSFrançois Tigeot 	struct sf_buf *sf;
864e3adcf8fSFrançois Tigeot 	void *d, *s;
865e3adcf8fSFrançois Tigeot 	int page, page_count;
866e3adcf8fSFrançois Tigeot 	u32 reloc_offset;
867e3adcf8fSFrançois Tigeot 
868e3adcf8fSFrançois Tigeot 	if (src == NULL || src->pages == NULL)
869e3adcf8fSFrançois Tigeot 		return NULL;
870e3adcf8fSFrançois Tigeot 
871e3adcf8fSFrançois Tigeot 	page_count = src->base.size / PAGE_SIZE;
872e3adcf8fSFrançois Tigeot 
873e3adcf8fSFrançois Tigeot 	dst = kmalloc(sizeof(*dst) + page_count * sizeof(u32 *), DRM_I915_GEM,
874e3adcf8fSFrançois Tigeot 	    M_NOWAIT);
875e3adcf8fSFrançois Tigeot 	if (dst == NULL)
876e3adcf8fSFrançois Tigeot 		return (NULL);
877e3adcf8fSFrançois Tigeot 
878e3adcf8fSFrançois Tigeot 	reloc_offset = src->gtt_offset;
879e3adcf8fSFrançois Tigeot 	for (page = 0; page < page_count; page++) {
880e3adcf8fSFrançois Tigeot 		d = kmalloc(PAGE_SIZE, DRM_I915_GEM, M_NOWAIT);
881e3adcf8fSFrançois Tigeot 		if (d == NULL)
882e3adcf8fSFrançois Tigeot 			goto unwind;
883e3adcf8fSFrançois Tigeot 
884e3adcf8fSFrançois Tigeot 		if (reloc_offset < dev_priv->mm.gtt_mappable_end) {
885e3adcf8fSFrançois Tigeot 			/* Simply ignore tiling or any overlapping fence.
886e3adcf8fSFrançois Tigeot 			 * It's part of the error state, and this hopefully
887e3adcf8fSFrançois Tigeot 			 * captures what the GPU read.
888e3adcf8fSFrançois Tigeot 			 */
889e3adcf8fSFrançois Tigeot 			s = pmap_mapdev_attr(src->base.dev->agp->base +
890e3adcf8fSFrançois Tigeot 			    reloc_offset, PAGE_SIZE, PAT_WRITE_COMBINING);
891e3adcf8fSFrançois Tigeot 			memcpy(d, s, PAGE_SIZE);
892e3adcf8fSFrançois Tigeot 			pmap_unmapdev((vm_offset_t)s, PAGE_SIZE);
893e3adcf8fSFrançois Tigeot 		} else {
894e3adcf8fSFrançois Tigeot 			drm_clflush_pages(&src->pages[page], 1);
895e3adcf8fSFrançois Tigeot 
896e3adcf8fSFrançois Tigeot 			sf = sf_buf_alloc(src->pages[page]);
897e3adcf8fSFrançois Tigeot 			if (sf != NULL) {
898e3adcf8fSFrançois Tigeot 				s = (void *)(uintptr_t)sf_buf_kva(sf);
899e3adcf8fSFrançois Tigeot 				memcpy(d, s, PAGE_SIZE);
900e3adcf8fSFrançois Tigeot 				sf_buf_free(sf);
901e3adcf8fSFrançois Tigeot 			} else {
902e3adcf8fSFrançois Tigeot 				bzero(d, PAGE_SIZE);
903e3adcf8fSFrançois Tigeot 				strcpy(d, "XXXKIB");
904e3adcf8fSFrançois Tigeot 			}
905e3adcf8fSFrançois Tigeot 
906e3adcf8fSFrançois Tigeot 			drm_clflush_pages(&src->pages[page], 1);
907e3adcf8fSFrançois Tigeot 		}
908e3adcf8fSFrançois Tigeot 
909e3adcf8fSFrançois Tigeot 		dst->pages[page] = d;
910e3adcf8fSFrançois Tigeot 
911e3adcf8fSFrançois Tigeot 		reloc_offset += PAGE_SIZE;
912e3adcf8fSFrançois Tigeot 	}
913e3adcf8fSFrançois Tigeot 	dst->page_count = page_count;
914e3adcf8fSFrançois Tigeot 	dst->gtt_offset = src->gtt_offset;
915e3adcf8fSFrançois Tigeot 
916e3adcf8fSFrançois Tigeot 	return (dst);
917e3adcf8fSFrançois Tigeot 
918e3adcf8fSFrançois Tigeot unwind:
919e3adcf8fSFrançois Tigeot 	while (page--)
920e3adcf8fSFrançois Tigeot 		drm_free(dst->pages[page], DRM_I915_GEM);
921e3adcf8fSFrançois Tigeot 	drm_free(dst, DRM_I915_GEM);
922e3adcf8fSFrançois Tigeot 	return (NULL);
923e3adcf8fSFrançois Tigeot }
924e3adcf8fSFrançois Tigeot 
925e3adcf8fSFrançois Tigeot static void
926e3adcf8fSFrançois Tigeot i915_error_object_free(struct drm_i915_error_object *obj)
927e3adcf8fSFrançois Tigeot {
928e3adcf8fSFrançois Tigeot 	int page;
929e3adcf8fSFrançois Tigeot 
930e3adcf8fSFrançois Tigeot 	if (obj == NULL)
931e3adcf8fSFrançois Tigeot 		return;
932e3adcf8fSFrançois Tigeot 
933e3adcf8fSFrançois Tigeot 	for (page = 0; page < obj->page_count; page++)
934e3adcf8fSFrançois Tigeot 		drm_free(obj->pages[page], DRM_I915_GEM);
935e3adcf8fSFrançois Tigeot 
936e3adcf8fSFrançois Tigeot 	drm_free(obj, DRM_I915_GEM);
937e3adcf8fSFrançois Tigeot }
938e3adcf8fSFrançois Tigeot 
939e3adcf8fSFrançois Tigeot static void
940e3adcf8fSFrançois Tigeot i915_error_state_free(struct drm_device *dev,
941e3adcf8fSFrançois Tigeot 		      struct drm_i915_error_state *error)
942e3adcf8fSFrançois Tigeot {
943e3adcf8fSFrançois Tigeot 	int i;
944e3adcf8fSFrançois Tigeot 
945e3adcf8fSFrançois Tigeot 	for (i = 0; i < DRM_ARRAY_SIZE(error->ring); i++) {
946e3adcf8fSFrançois Tigeot 		i915_error_object_free(error->ring[i].batchbuffer);
947e3adcf8fSFrançois Tigeot 		i915_error_object_free(error->ring[i].ringbuffer);
948e3adcf8fSFrançois Tigeot 		drm_free(error->ring[i].requests, DRM_I915_GEM);
949e3adcf8fSFrançois Tigeot 	}
950e3adcf8fSFrançois Tigeot 
951e3adcf8fSFrançois Tigeot 	drm_free(error->active_bo, DRM_I915_GEM);
952e3adcf8fSFrançois Tigeot 	drm_free(error->overlay, DRM_I915_GEM);
953e3adcf8fSFrançois Tigeot 	drm_free(error, DRM_I915_GEM);
954e3adcf8fSFrançois Tigeot }
955e3adcf8fSFrançois Tigeot 
956e3adcf8fSFrançois Tigeot static u32
957e3adcf8fSFrançois Tigeot capture_bo_list(struct drm_i915_error_buffer *err, int count,
958e3adcf8fSFrançois Tigeot     struct list_head *head)
959e3adcf8fSFrançois Tigeot {
960e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
961e3adcf8fSFrançois Tigeot 	int i = 0;
962e3adcf8fSFrançois Tigeot 
963e3adcf8fSFrançois Tigeot 	list_for_each_entry(obj, head, mm_list) {
964e3adcf8fSFrançois Tigeot 		err->size = obj->base.size;
965e3adcf8fSFrançois Tigeot 		err->name = obj->base.name;
966e3adcf8fSFrançois Tigeot 		err->seqno = obj->last_rendering_seqno;
967e3adcf8fSFrançois Tigeot 		err->gtt_offset = obj->gtt_offset;
968e3adcf8fSFrançois Tigeot 		err->read_domains = obj->base.read_domains;
969e3adcf8fSFrançois Tigeot 		err->write_domain = obj->base.write_domain;
970e3adcf8fSFrançois Tigeot 		err->fence_reg = obj->fence_reg;
971e3adcf8fSFrançois Tigeot 		err->pinned = 0;
972e3adcf8fSFrançois Tigeot 		if (obj->pin_count > 0)
973e3adcf8fSFrançois Tigeot 			err->pinned = 1;
974e3adcf8fSFrançois Tigeot 		if (obj->user_pin_count > 0)
975e3adcf8fSFrançois Tigeot 			err->pinned = -1;
976e3adcf8fSFrançois Tigeot 		err->tiling = obj->tiling_mode;
977e3adcf8fSFrançois Tigeot 		err->dirty = obj->dirty;
978e3adcf8fSFrançois Tigeot 		err->purgeable = obj->madv != I915_MADV_WILLNEED;
979e3adcf8fSFrançois Tigeot 		err->ring = obj->ring ? obj->ring->id : -1;
980e3adcf8fSFrançois Tigeot 		err->cache_level = obj->cache_level;
981e3adcf8fSFrançois Tigeot 
982e3adcf8fSFrançois Tigeot 		if (++i == count)
983e3adcf8fSFrançois Tigeot 			break;
984e3adcf8fSFrançois Tigeot 
985e3adcf8fSFrançois Tigeot 		err++;
986e3adcf8fSFrançois Tigeot 	}
987e3adcf8fSFrançois Tigeot 
988e3adcf8fSFrançois Tigeot 	return (i);
989e3adcf8fSFrançois Tigeot }
990e3adcf8fSFrançois Tigeot 
991e3adcf8fSFrançois Tigeot static void
992e3adcf8fSFrançois Tigeot i915_gem_record_fences(struct drm_device *dev,
993e3adcf8fSFrançois Tigeot     struct drm_i915_error_state *error)
994e3adcf8fSFrançois Tigeot {
995e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
996e3adcf8fSFrançois Tigeot 	int i;
997e3adcf8fSFrançois Tigeot 
998e3adcf8fSFrançois Tigeot 	/* Fences */
999e3adcf8fSFrançois Tigeot 	switch (INTEL_INFO(dev)->gen) {
1000e3adcf8fSFrançois Tigeot 	case 7:
1001e3adcf8fSFrançois Tigeot 	case 6:
1002e3adcf8fSFrançois Tigeot 		for (i = 0; i < 16; i++)
1003e3adcf8fSFrançois Tigeot 			error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
1004e3adcf8fSFrançois Tigeot 		break;
1005e3adcf8fSFrançois Tigeot 	case 5:
1006e3adcf8fSFrançois Tigeot 	case 4:
1007e3adcf8fSFrançois Tigeot 		for (i = 0; i < 16; i++)
1008e3adcf8fSFrançois Tigeot 			error->fence[i] = I915_READ64(FENCE_REG_965_0 +
1009e3adcf8fSFrançois Tigeot 			    (i * 8));
1010e3adcf8fSFrançois Tigeot 		break;
1011e3adcf8fSFrançois Tigeot 	case 3:
1012e3adcf8fSFrançois Tigeot 		if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
1013e3adcf8fSFrançois Tigeot 			for (i = 0; i < 8; i++)
1014e3adcf8fSFrançois Tigeot 				error->fence[i+8] = I915_READ(FENCE_REG_945_8 +
1015e3adcf8fSFrançois Tigeot 				    (i * 4));
1016e3adcf8fSFrançois Tigeot 	case 2:
1017e3adcf8fSFrançois Tigeot 		for (i = 0; i < 8; i++)
1018e3adcf8fSFrançois Tigeot 			error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
1019e3adcf8fSFrançois Tigeot 		break;
1020e3adcf8fSFrançois Tigeot 
1021e3adcf8fSFrançois Tigeot 	}
1022e3adcf8fSFrançois Tigeot }
1023e3adcf8fSFrançois Tigeot 
1024e3adcf8fSFrançois Tigeot static struct drm_i915_error_object *
1025e3adcf8fSFrançois Tigeot i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
1026e3adcf8fSFrançois Tigeot 			     struct intel_ring_buffer *ring)
1027e3adcf8fSFrançois Tigeot {
1028e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
1029e3adcf8fSFrançois Tigeot 	u32 seqno;
1030e3adcf8fSFrançois Tigeot 
1031e3adcf8fSFrançois Tigeot 	if (!ring->get_seqno)
1032e3adcf8fSFrançois Tigeot 		return (NULL);
1033e3adcf8fSFrançois Tigeot 
1034e3adcf8fSFrançois Tigeot 	seqno = ring->get_seqno(ring);
1035e3adcf8fSFrançois Tigeot 	list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
1036e3adcf8fSFrançois Tigeot 		if (obj->ring != ring)
1037e3adcf8fSFrançois Tigeot 			continue;
1038e3adcf8fSFrançois Tigeot 
1039e3adcf8fSFrançois Tigeot 		if (i915_seqno_passed(seqno, obj->last_rendering_seqno))
1040e3adcf8fSFrançois Tigeot 			continue;
1041e3adcf8fSFrançois Tigeot 
1042e3adcf8fSFrançois Tigeot 		if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
1043e3adcf8fSFrançois Tigeot 			continue;
1044e3adcf8fSFrançois Tigeot 
1045e3adcf8fSFrançois Tigeot 		/* We need to copy these to an anonymous buffer as the simplest
1046e3adcf8fSFrançois Tigeot 		 * method to avoid being overwritten by userspace.
1047e3adcf8fSFrançois Tigeot 		 */
1048e3adcf8fSFrançois Tigeot 		return (i915_error_object_create(dev_priv, obj));
1049e3adcf8fSFrançois Tigeot 	}
1050e3adcf8fSFrançois Tigeot 
1051e3adcf8fSFrançois Tigeot 	return NULL;
1052e3adcf8fSFrançois Tigeot }
1053e3adcf8fSFrançois Tigeot 
1054e3adcf8fSFrançois Tigeot static void
1055e3adcf8fSFrançois Tigeot i915_record_ring_state(struct drm_device *dev,
1056e3adcf8fSFrançois Tigeot     struct drm_i915_error_state *error,
1057e3adcf8fSFrançois Tigeot     struct intel_ring_buffer *ring)
1058e3adcf8fSFrançois Tigeot {
1059e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1060e3adcf8fSFrançois Tigeot 
1061e3adcf8fSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 6) {
1062e3adcf8fSFrançois Tigeot 		error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base));
1063e3adcf8fSFrançois Tigeot 		error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring));
1064e3adcf8fSFrançois Tigeot 		error->semaphore_mboxes[ring->id][0]
1065e3adcf8fSFrançois Tigeot 			= I915_READ(RING_SYNC_0(ring->mmio_base));
1066e3adcf8fSFrançois Tigeot 		error->semaphore_mboxes[ring->id][1]
1067e3adcf8fSFrançois Tigeot 			= I915_READ(RING_SYNC_1(ring->mmio_base));
1068e3adcf8fSFrançois Tigeot 	}
1069e3adcf8fSFrançois Tigeot 
1070e3adcf8fSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 4) {
1071e3adcf8fSFrançois Tigeot 		error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base));
1072e3adcf8fSFrançois Tigeot 		error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
1073e3adcf8fSFrançois Tigeot 		error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
1074e3adcf8fSFrançois Tigeot 		error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
1075e3adcf8fSFrançois Tigeot 		if (ring->id == RCS) {
1076e3adcf8fSFrançois Tigeot 			error->instdone1 = I915_READ(INSTDONE1);
1077e3adcf8fSFrançois Tigeot 			error->bbaddr = I915_READ64(BB_ADDR);
1078e3adcf8fSFrançois Tigeot 		}
1079e3adcf8fSFrançois Tigeot 	} else {
1080e3adcf8fSFrançois Tigeot 		error->ipeir[ring->id] = I915_READ(IPEIR);
1081e3adcf8fSFrançois Tigeot 		error->ipehr[ring->id] = I915_READ(IPEHR);
1082e3adcf8fSFrançois Tigeot 		error->instdone[ring->id] = I915_READ(INSTDONE);
1083e3adcf8fSFrançois Tigeot 	}
1084e3adcf8fSFrançois Tigeot 
1085e3adcf8fSFrançois Tigeot 	error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base));
1086e3adcf8fSFrançois Tigeot 	error->seqno[ring->id] = ring->get_seqno(ring);
1087e3adcf8fSFrançois Tigeot 	error->acthd[ring->id] = intel_ring_get_active_head(ring);
1088e3adcf8fSFrançois Tigeot 	error->head[ring->id] = I915_READ_HEAD(ring);
1089e3adcf8fSFrançois Tigeot 	error->tail[ring->id] = I915_READ_TAIL(ring);
1090e3adcf8fSFrançois Tigeot 
1091e3adcf8fSFrançois Tigeot 	error->cpu_ring_head[ring->id] = ring->head;
1092e3adcf8fSFrançois Tigeot 	error->cpu_ring_tail[ring->id] = ring->tail;
1093e3adcf8fSFrançois Tigeot }
1094e3adcf8fSFrançois Tigeot 
1095e3adcf8fSFrançois Tigeot static void
1096e3adcf8fSFrançois Tigeot i915_gem_record_rings(struct drm_device *dev,
1097e3adcf8fSFrançois Tigeot     struct drm_i915_error_state *error)
1098e3adcf8fSFrançois Tigeot {
1099e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1100e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_request *request;
1101e3adcf8fSFrançois Tigeot 	int i, count;
1102e3adcf8fSFrançois Tigeot 
1103e3adcf8fSFrançois Tigeot 	for (i = 0; i < I915_NUM_RINGS; i++) {
1104ad50ea93SFrançois Tigeot 		struct intel_ring_buffer *ring = &dev_priv->ring[i];
1105e3adcf8fSFrançois Tigeot 
1106e3adcf8fSFrançois Tigeot 		if (ring->obj == NULL)
1107e3adcf8fSFrançois Tigeot 			continue;
1108e3adcf8fSFrançois Tigeot 
1109e3adcf8fSFrançois Tigeot 		i915_record_ring_state(dev, error, ring);
1110e3adcf8fSFrançois Tigeot 
1111e3adcf8fSFrançois Tigeot 		error->ring[i].batchbuffer =
1112e3adcf8fSFrançois Tigeot 			i915_error_first_batchbuffer(dev_priv, ring);
1113e3adcf8fSFrançois Tigeot 
1114e3adcf8fSFrançois Tigeot 		error->ring[i].ringbuffer =
1115e3adcf8fSFrançois Tigeot 			i915_error_object_create(dev_priv, ring->obj);
1116e3adcf8fSFrançois Tigeot 
1117e3adcf8fSFrançois Tigeot 		count = 0;
1118e3adcf8fSFrançois Tigeot 		list_for_each_entry(request, &ring->request_list, list)
1119e3adcf8fSFrançois Tigeot 			count++;
1120e3adcf8fSFrançois Tigeot 
1121e3adcf8fSFrançois Tigeot 		error->ring[i].num_requests = count;
1122e3adcf8fSFrançois Tigeot 		error->ring[i].requests = kmalloc(count *
1123e3adcf8fSFrançois Tigeot 		    sizeof(struct drm_i915_error_request), DRM_I915_GEM,
1124e3adcf8fSFrançois Tigeot 		    M_WAITOK);
1125e3adcf8fSFrançois Tigeot 		if (error->ring[i].requests == NULL) {
1126e3adcf8fSFrançois Tigeot 			error->ring[i].num_requests = 0;
1127e3adcf8fSFrançois Tigeot 			continue;
1128e3adcf8fSFrançois Tigeot 		}
1129e3adcf8fSFrançois Tigeot 
1130e3adcf8fSFrançois Tigeot 		count = 0;
1131e3adcf8fSFrançois Tigeot 		list_for_each_entry(request, &ring->request_list, list) {
1132e3adcf8fSFrançois Tigeot 			struct drm_i915_error_request *erq;
1133e3adcf8fSFrançois Tigeot 
1134e3adcf8fSFrançois Tigeot 			erq = &error->ring[i].requests[count++];
1135e3adcf8fSFrançois Tigeot 			erq->seqno = request->seqno;
1136e3adcf8fSFrançois Tigeot 			erq->jiffies = request->emitted_jiffies;
1137e3adcf8fSFrançois Tigeot 			erq->tail = request->tail;
1138e3adcf8fSFrançois Tigeot 		}
1139e3adcf8fSFrançois Tigeot 	}
1140e3adcf8fSFrançois Tigeot }
1141e3adcf8fSFrançois Tigeot 
1142e3adcf8fSFrançois Tigeot static void
1143e3adcf8fSFrançois Tigeot i915_capture_error_state(struct drm_device *dev)
1144e3adcf8fSFrançois Tigeot {
1145e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1146e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
1147e3adcf8fSFrançois Tigeot 	struct drm_i915_error_state *error;
1148e3adcf8fSFrançois Tigeot 	int i, pipe;
1149e3adcf8fSFrançois Tigeot 
1150e3adcf8fSFrançois Tigeot 	lockmgr(&dev_priv->error_lock, LK_EXCLUSIVE);
1151e3adcf8fSFrançois Tigeot 	error = dev_priv->first_error;
1152e3adcf8fSFrançois Tigeot 	lockmgr(&dev_priv->error_lock, LK_RELEASE);
1153e3adcf8fSFrançois Tigeot 	if (error != NULL)
1154e3adcf8fSFrançois Tigeot 		return;
1155e3adcf8fSFrançois Tigeot 
1156e3adcf8fSFrançois Tigeot 	/* Account for pipe specific data like PIPE*STAT */
1157e3adcf8fSFrançois Tigeot 	error = kmalloc(sizeof(*error), DRM_I915_GEM, M_NOWAIT | M_ZERO);
1158e3adcf8fSFrançois Tigeot 	if (error == NULL) {
1159e3adcf8fSFrançois Tigeot 		DRM_DEBUG("out of memory, not capturing error state\n");
1160e3adcf8fSFrançois Tigeot 		return;
1161e3adcf8fSFrançois Tigeot 	}
1162e3adcf8fSFrançois Tigeot 
1163e3adcf8fSFrançois Tigeot 	DRM_INFO("capturing error event; look for more information in "
1164e3adcf8fSFrançois Tigeot 	    "sysctl hw.dri.%d.info.i915_error_state\n", dev->sysctl_node_idx);
1165e3adcf8fSFrançois Tigeot 
1166e3adcf8fSFrançois Tigeot 	error->eir = I915_READ(EIR);
1167e3adcf8fSFrançois Tigeot 	error->pgtbl_er = I915_READ(PGTBL_ER);
1168e3adcf8fSFrançois Tigeot 	for_each_pipe(pipe)
1169e3adcf8fSFrançois Tigeot 		error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
1170e3adcf8fSFrançois Tigeot 
1171e3adcf8fSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 6) {
1172e3adcf8fSFrançois Tigeot 		error->error = I915_READ(ERROR_GEN6);
1173e3adcf8fSFrançois Tigeot 		error->done_reg = I915_READ(DONE_REG);
1174e3adcf8fSFrançois Tigeot 	}
1175e3adcf8fSFrançois Tigeot 
1176e3adcf8fSFrançois Tigeot 	i915_gem_record_fences(dev, error);
1177e3adcf8fSFrançois Tigeot 	i915_gem_record_rings(dev, error);
1178e3adcf8fSFrançois Tigeot 
1179e3adcf8fSFrançois Tigeot 	/* Record buffers on the active and pinned lists. */
1180e3adcf8fSFrançois Tigeot 	error->active_bo = NULL;
1181e3adcf8fSFrançois Tigeot 	error->pinned_bo = NULL;
1182e3adcf8fSFrançois Tigeot 
1183e3adcf8fSFrançois Tigeot 	i = 0;
1184e3adcf8fSFrançois Tigeot 	list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list)
1185e3adcf8fSFrançois Tigeot 		i++;
1186e3adcf8fSFrançois Tigeot 	error->active_bo_count = i;
1187e3adcf8fSFrançois Tigeot 	list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list)
1188e3adcf8fSFrançois Tigeot 		i++;
1189e3adcf8fSFrançois Tigeot 	error->pinned_bo_count = i - error->active_bo_count;
1190e3adcf8fSFrançois Tigeot 
1191e3adcf8fSFrançois Tigeot 	error->active_bo = NULL;
1192e3adcf8fSFrançois Tigeot 	error->pinned_bo = NULL;
1193e3adcf8fSFrançois Tigeot 	if (i) {
1194e3adcf8fSFrançois Tigeot 		error->active_bo = kmalloc(sizeof(*error->active_bo) * i,
1195e3adcf8fSFrançois Tigeot 		    DRM_I915_GEM, M_NOWAIT);
1196e3adcf8fSFrançois Tigeot 		if (error->active_bo)
1197e3adcf8fSFrançois Tigeot 			error->pinned_bo = error->active_bo +
1198e3adcf8fSFrançois Tigeot 			    error->active_bo_count;
1199e3adcf8fSFrançois Tigeot 	}
1200e3adcf8fSFrançois Tigeot 
1201e3adcf8fSFrançois Tigeot 	if (error->active_bo)
1202e3adcf8fSFrançois Tigeot 		error->active_bo_count = capture_bo_list(error->active_bo,
1203e3adcf8fSFrançois Tigeot 		    error->active_bo_count, &dev_priv->mm.active_list);
1204e3adcf8fSFrançois Tigeot 
1205e3adcf8fSFrançois Tigeot 	if (error->pinned_bo)
1206e3adcf8fSFrançois Tigeot 		error->pinned_bo_count = capture_bo_list(error->pinned_bo,
1207e3adcf8fSFrançois Tigeot 		    error->pinned_bo_count, &dev_priv->mm.pinned_list);
1208e3adcf8fSFrançois Tigeot 
1209e3adcf8fSFrançois Tigeot 	microtime(&error->time);
1210e3adcf8fSFrançois Tigeot 
1211e3adcf8fSFrançois Tigeot 	error->overlay = intel_overlay_capture_error_state(dev);
1212e3adcf8fSFrançois Tigeot 	error->display = intel_display_capture_error_state(dev);
1213e3adcf8fSFrançois Tigeot 
1214e3adcf8fSFrançois Tigeot 	lockmgr(&dev_priv->error_lock, LK_EXCLUSIVE);
1215e3adcf8fSFrançois Tigeot 	if (dev_priv->first_error == NULL) {
1216e3adcf8fSFrançois Tigeot 		dev_priv->first_error = error;
1217e3adcf8fSFrançois Tigeot 		error = NULL;
1218e3adcf8fSFrançois Tigeot 	}
1219e3adcf8fSFrançois Tigeot 	lockmgr(&dev_priv->error_lock, LK_RELEASE);
1220e3adcf8fSFrançois Tigeot 
1221e3adcf8fSFrançois Tigeot 	if (error != NULL)
1222e3adcf8fSFrançois Tigeot 		i915_error_state_free(dev, error);
1223e3adcf8fSFrançois Tigeot }
1224e3adcf8fSFrançois Tigeot 
1225e3adcf8fSFrançois Tigeot void
1226e3adcf8fSFrançois Tigeot i915_destroy_error_state(struct drm_device *dev)
1227e3adcf8fSFrançois Tigeot {
1228e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1229e3adcf8fSFrançois Tigeot 	struct drm_i915_error_state *error;
1230e3adcf8fSFrançois Tigeot 
1231e3adcf8fSFrançois Tigeot 	lockmgr(&dev_priv->error_lock, LK_EXCLUSIVE);
1232e3adcf8fSFrançois Tigeot 	error = dev_priv->first_error;
1233e3adcf8fSFrançois Tigeot 	dev_priv->first_error = NULL;
1234e3adcf8fSFrançois Tigeot 	lockmgr(&dev_priv->error_lock, LK_RELEASE);
1235e3adcf8fSFrançois Tigeot 
1236e3adcf8fSFrançois Tigeot 	if (error != NULL)
1237e3adcf8fSFrançois Tigeot 		i915_error_state_free(dev, error);
1238c4a9e910SFrançois Tigeot }
1239*e9243325SFrançois Tigeot 
1240*e9243325SFrançois Tigeot static void i915_report_and_clear_eir(struct drm_device *dev)
1241*e9243325SFrançois Tigeot {
1242*e9243325SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1243*e9243325SFrançois Tigeot 	u32 eir = I915_READ(EIR);
1244*e9243325SFrançois Tigeot 	int pipe;
1245*e9243325SFrançois Tigeot 
1246*e9243325SFrançois Tigeot 	if (!eir)
1247*e9243325SFrançois Tigeot 		return;
1248*e9243325SFrançois Tigeot 
1249*e9243325SFrançois Tigeot 	kprintf("i915: render error detected, EIR: 0x%08x\n", eir);
1250*e9243325SFrançois Tigeot 
1251*e9243325SFrançois Tigeot 	if (IS_G4X(dev)) {
1252*e9243325SFrançois Tigeot 		if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
1253*e9243325SFrançois Tigeot 			u32 ipeir = I915_READ(IPEIR_I965);
1254*e9243325SFrançois Tigeot 
1255*e9243325SFrançois Tigeot 			kprintf("  IPEIR: 0x%08x\n",
1256*e9243325SFrançois Tigeot 			       I915_READ(IPEIR_I965));
1257*e9243325SFrançois Tigeot 			kprintf("  IPEHR: 0x%08x\n",
1258*e9243325SFrançois Tigeot 			       I915_READ(IPEHR_I965));
1259*e9243325SFrançois Tigeot 			kprintf("  INSTDONE: 0x%08x\n",
1260*e9243325SFrançois Tigeot 			       I915_READ(INSTDONE_I965));
1261*e9243325SFrançois Tigeot 			kprintf("  INSTPS: 0x%08x\n",
1262*e9243325SFrançois Tigeot 			       I915_READ(INSTPS));
1263*e9243325SFrançois Tigeot 			kprintf("  INSTDONE1: 0x%08x\n",
1264*e9243325SFrançois Tigeot 			       I915_READ(INSTDONE1));
1265*e9243325SFrançois Tigeot 			kprintf("  ACTHD: 0x%08x\n",
1266*e9243325SFrançois Tigeot 			       I915_READ(ACTHD_I965));
1267*e9243325SFrançois Tigeot 			I915_WRITE(IPEIR_I965, ipeir);
1268*e9243325SFrançois Tigeot 			POSTING_READ(IPEIR_I965);
1269*e9243325SFrançois Tigeot 		}
1270*e9243325SFrançois Tigeot 		if (eir & GM45_ERROR_PAGE_TABLE) {
1271*e9243325SFrançois Tigeot 			u32 pgtbl_err = I915_READ(PGTBL_ER);
1272*e9243325SFrançois Tigeot 			kprintf("page table error\n");
1273*e9243325SFrançois Tigeot 			kprintf("  PGTBL_ER: 0x%08x\n",
1274*e9243325SFrançois Tigeot 			       pgtbl_err);
1275*e9243325SFrançois Tigeot 			I915_WRITE(PGTBL_ER, pgtbl_err);
1276*e9243325SFrançois Tigeot 			POSTING_READ(PGTBL_ER);
1277*e9243325SFrançois Tigeot 		}
1278*e9243325SFrançois Tigeot 	}
1279*e9243325SFrançois Tigeot 
1280*e9243325SFrançois Tigeot 	if (!IS_GEN2(dev)) {
1281*e9243325SFrançois Tigeot 		if (eir & I915_ERROR_PAGE_TABLE) {
1282*e9243325SFrançois Tigeot 			u32 pgtbl_err = I915_READ(PGTBL_ER);
1283*e9243325SFrançois Tigeot 			kprintf("page table error\n");
1284*e9243325SFrançois Tigeot 			kprintf("  PGTBL_ER: 0x%08x\n",
1285*e9243325SFrançois Tigeot 			       pgtbl_err);
1286*e9243325SFrançois Tigeot 			I915_WRITE(PGTBL_ER, pgtbl_err);
1287*e9243325SFrançois Tigeot 			POSTING_READ(PGTBL_ER);
1288*e9243325SFrançois Tigeot 		}
1289*e9243325SFrançois Tigeot 	}
1290*e9243325SFrançois Tigeot 
1291*e9243325SFrançois Tigeot 	if (eir & I915_ERROR_MEMORY_REFRESH) {
1292*e9243325SFrançois Tigeot 		kprintf("memory refresh error:\n");
1293*e9243325SFrançois Tigeot 		for_each_pipe(pipe)
1294*e9243325SFrançois Tigeot 			kprintf("pipe %c stat: 0x%08x\n",
1295*e9243325SFrançois Tigeot 			       pipe_name(pipe), I915_READ(PIPESTAT(pipe)));
1296*e9243325SFrançois Tigeot 		/* pipestat has already been acked */
1297*e9243325SFrançois Tigeot 	}
1298*e9243325SFrançois Tigeot 	if (eir & I915_ERROR_INSTRUCTION) {
1299*e9243325SFrançois Tigeot 		kprintf("instruction error\n");
1300*e9243325SFrançois Tigeot 		kprintf("  INSTPM: 0x%08x\n",
1301*e9243325SFrançois Tigeot 		       I915_READ(INSTPM));
1302*e9243325SFrançois Tigeot 		if (INTEL_INFO(dev)->gen < 4) {
1303*e9243325SFrançois Tigeot 			u32 ipeir = I915_READ(IPEIR);
1304*e9243325SFrançois Tigeot 
1305*e9243325SFrançois Tigeot 			kprintf("  IPEIR: 0x%08x\n",
1306*e9243325SFrançois Tigeot 			       I915_READ(IPEIR));
1307*e9243325SFrançois Tigeot 			kprintf("  IPEHR: 0x%08x\n",
1308*e9243325SFrançois Tigeot 			       I915_READ(IPEHR));
1309*e9243325SFrançois Tigeot 			kprintf("  INSTDONE: 0x%08x\n",
1310*e9243325SFrançois Tigeot 			       I915_READ(INSTDONE));
1311*e9243325SFrançois Tigeot 			kprintf("  ACTHD: 0x%08x\n",
1312*e9243325SFrançois Tigeot 			       I915_READ(ACTHD));
1313*e9243325SFrançois Tigeot 			I915_WRITE(IPEIR, ipeir);
1314*e9243325SFrançois Tigeot 			POSTING_READ(IPEIR);
1315*e9243325SFrançois Tigeot 		} else {
1316*e9243325SFrançois Tigeot 			u32 ipeir = I915_READ(IPEIR_I965);
1317*e9243325SFrançois Tigeot 
1318*e9243325SFrançois Tigeot 			kprintf("  IPEIR: 0x%08x\n",
1319*e9243325SFrançois Tigeot 			       I915_READ(IPEIR_I965));
1320*e9243325SFrançois Tigeot 			kprintf("  IPEHR: 0x%08x\n",
1321*e9243325SFrançois Tigeot 			       I915_READ(IPEHR_I965));
1322*e9243325SFrançois Tigeot 			kprintf("  INSTDONE: 0x%08x\n",
1323*e9243325SFrançois Tigeot 			       I915_READ(INSTDONE_I965));
1324*e9243325SFrançois Tigeot 			kprintf("  INSTPS: 0x%08x\n",
1325*e9243325SFrançois Tigeot 			       I915_READ(INSTPS));
1326*e9243325SFrançois Tigeot 			kprintf("  INSTDONE1: 0x%08x\n",
1327*e9243325SFrançois Tigeot 			       I915_READ(INSTDONE1));
1328*e9243325SFrançois Tigeot 			kprintf("  ACTHD: 0x%08x\n",
1329*e9243325SFrançois Tigeot 			       I915_READ(ACTHD_I965));
1330*e9243325SFrançois Tigeot 			I915_WRITE(IPEIR_I965, ipeir);
1331*e9243325SFrançois Tigeot 			POSTING_READ(IPEIR_I965);
1332*e9243325SFrançois Tigeot 		}
1333*e9243325SFrançois Tigeot 	}
1334*e9243325SFrançois Tigeot 
1335*e9243325SFrançois Tigeot 	I915_WRITE(EIR, eir);
1336*e9243325SFrançois Tigeot 	POSTING_READ(EIR);
1337*e9243325SFrançois Tigeot 	eir = I915_READ(EIR);
1338*e9243325SFrançois Tigeot 	if (eir) {
1339*e9243325SFrançois Tigeot 		/*
1340*e9243325SFrançois Tigeot 		 * some errors might have become stuck,
1341*e9243325SFrançois Tigeot 		 * mask them.
1342*e9243325SFrançois Tigeot 		 */
1343*e9243325SFrançois Tigeot 		DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
1344*e9243325SFrançois Tigeot 		I915_WRITE(EMR, I915_READ(EMR) | eir);
1345*e9243325SFrançois Tigeot 		I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
1346*e9243325SFrançois Tigeot 	}
1347*e9243325SFrançois Tigeot }
1348*e9243325SFrançois Tigeot 
1349*e9243325SFrançois Tigeot /**
1350*e9243325SFrançois Tigeot  * i915_handle_error - handle an error interrupt
1351*e9243325SFrançois Tigeot  * @dev: drm device
1352*e9243325SFrançois Tigeot  *
1353*e9243325SFrançois Tigeot  * Do some basic checking of regsiter state at error interrupt time and
1354*e9243325SFrançois Tigeot  * dump it to the syslog.  Also call i915_capture_error_state() to make
1355*e9243325SFrançois Tigeot  * sure we get a record and make it available in debugfs.  Fire a uevent
1356*e9243325SFrançois Tigeot  * so userspace knows something bad happened (should trigger collection
1357*e9243325SFrançois Tigeot  * of a ring dump etc.).
1358*e9243325SFrançois Tigeot  */
1359*e9243325SFrançois Tigeot void i915_handle_error(struct drm_device *dev, bool wedged)
1360*e9243325SFrançois Tigeot {
1361*e9243325SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1362*e9243325SFrançois Tigeot 
1363*e9243325SFrançois Tigeot 	i915_capture_error_state(dev);
1364*e9243325SFrançois Tigeot 	i915_report_and_clear_eir(dev);
1365*e9243325SFrançois Tigeot 
1366*e9243325SFrançois Tigeot 	if (wedged) {
1367*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->error_completion_lock, LK_EXCLUSIVE);
1368*e9243325SFrançois Tigeot 		dev_priv->error_completion = 0;
1369*e9243325SFrançois Tigeot 		atomic_set(&dev_priv->mm.wedged, 1);
1370*e9243325SFrançois Tigeot 		/* unlock acts as rel barrier for store to wedged */
1371*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->error_completion_lock, LK_RELEASE);
1372*e9243325SFrançois Tigeot 
1373*e9243325SFrançois Tigeot 		/*
1374*e9243325SFrançois Tigeot 		 * Wakeup waiting processes so they don't hang
1375*e9243325SFrançois Tigeot 		 */
1376*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->ring[RCS].irq_lock, LK_EXCLUSIVE);
1377*e9243325SFrançois Tigeot 		wakeup(&dev_priv->ring[RCS]);
1378*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->ring[RCS].irq_lock, LK_RELEASE);
1379*e9243325SFrançois Tigeot 		if (HAS_BSD(dev)) {
1380*e9243325SFrançois Tigeot 			lockmgr(&dev_priv->ring[VCS].irq_lock, LK_EXCLUSIVE);
1381*e9243325SFrançois Tigeot 			wakeup(&dev_priv->ring[VCS]);
1382*e9243325SFrançois Tigeot 			lockmgr(&dev_priv->ring[VCS].irq_lock, LK_RELEASE);
1383*e9243325SFrançois Tigeot 		}
1384*e9243325SFrançois Tigeot 		if (HAS_BLT(dev)) {
1385*e9243325SFrançois Tigeot 			lockmgr(&dev_priv->ring[BCS].irq_lock, LK_EXCLUSIVE);
1386*e9243325SFrançois Tigeot 			wakeup(&dev_priv->ring[BCS]);
1387*e9243325SFrançois Tigeot 			lockmgr(&dev_priv->ring[BCS].irq_lock, LK_RELEASE);
1388*e9243325SFrançois Tigeot 		}
1389*e9243325SFrançois Tigeot 	}
1390*e9243325SFrançois Tigeot 
1391*e9243325SFrançois Tigeot 	queue_work(dev_priv->wq, &dev_priv->error_work);
1392*e9243325SFrançois Tigeot }
1393*e9243325SFrançois Tigeot 
1394*e9243325SFrançois Tigeot static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
1395*e9243325SFrançois Tigeot {
1396*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = dev->dev_private;
1397*e9243325SFrançois Tigeot 	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
1398*e9243325SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1399*e9243325SFrançois Tigeot 	struct drm_i915_gem_object *obj;
1400*e9243325SFrançois Tigeot 	struct intel_unpin_work *work;
1401*e9243325SFrançois Tigeot 	bool stall_detected;
1402*e9243325SFrançois Tigeot 
1403*e9243325SFrançois Tigeot 	/* Ignore early vblank irqs */
1404*e9243325SFrançois Tigeot 	if (intel_crtc == NULL)
1405*e9243325SFrançois Tigeot 		return;
1406*e9243325SFrançois Tigeot 
1407*e9243325SFrançois Tigeot 	lockmgr(&dev->event_lock, LK_EXCLUSIVE);
1408*e9243325SFrançois Tigeot 	work = intel_crtc->unpin_work;
1409*e9243325SFrançois Tigeot 
1410*e9243325SFrançois Tigeot 	if (work == NULL || atomic_read(&work->pending) ||
1411*e9243325SFrançois Tigeot 	    !work->enable_stall_check) {
1412*e9243325SFrançois Tigeot 		/* Either the pending flip IRQ arrived, or we're too early. Don't check */
1413*e9243325SFrançois Tigeot 		lockmgr(&dev->event_lock, LK_RELEASE);
1414*e9243325SFrançois Tigeot 		return;
1415*e9243325SFrançois Tigeot 	}
1416*e9243325SFrançois Tigeot 
1417*e9243325SFrançois Tigeot 	/* Potential stall - if we see that the flip has happened, assume a missed interrupt */
1418*e9243325SFrançois Tigeot 	obj = work->pending_flip_obj;
1419*e9243325SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 4) {
1420*e9243325SFrançois Tigeot 		int dspsurf = DSPSURF(intel_crtc->plane);
1421*e9243325SFrançois Tigeot 		stall_detected = I915_READ(dspsurf) == obj->gtt_offset;
1422*e9243325SFrançois Tigeot 	} else {
1423*e9243325SFrançois Tigeot 		int dspaddr = DSPADDR(intel_crtc->plane);
1424*e9243325SFrançois Tigeot 		stall_detected = I915_READ(dspaddr) == (obj->gtt_offset +
1425*e9243325SFrançois Tigeot 							crtc->y * crtc->fb->pitches[0] +
1426*e9243325SFrançois Tigeot 							crtc->x * crtc->fb->bits_per_pixel/8);
1427*e9243325SFrançois Tigeot 	}
1428*e9243325SFrançois Tigeot 
1429*e9243325SFrançois Tigeot 	lockmgr(&dev->event_lock, LK_RELEASE);
1430*e9243325SFrançois Tigeot 
1431*e9243325SFrançois Tigeot 	if (stall_detected) {
1432*e9243325SFrançois Tigeot 		DRM_DEBUG("Pageflip stall detected\n");
1433*e9243325SFrançois Tigeot 		intel_prepare_page_flip(dev, intel_crtc->plane);
1434*e9243325SFrançois Tigeot 	}
1435*e9243325SFrançois Tigeot }
1436*e9243325SFrançois Tigeot 
1437*e9243325SFrançois Tigeot /* Called from drm generic code, passed 'crtc' which
1438*e9243325SFrançois Tigeot  * we use as a pipe index
1439*e9243325SFrançois Tigeot  */
1440*e9243325SFrançois Tigeot static int
1441*e9243325SFrançois Tigeot i915_enable_vblank(struct drm_device *dev, int pipe)
1442*e9243325SFrançois Tigeot {
1443*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1444*e9243325SFrançois Tigeot 
1445*e9243325SFrançois Tigeot 	if (!i915_pipe_enabled(dev, pipe))
1446*e9243325SFrançois Tigeot 		return -EINVAL;
1447*e9243325SFrançois Tigeot 
1448*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1449*e9243325SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 4)
1450*e9243325SFrançois Tigeot 		i915_enable_pipestat(dev_priv, pipe,
1451*e9243325SFrançois Tigeot 				     PIPE_START_VBLANK_INTERRUPT_ENABLE);
1452*e9243325SFrançois Tigeot 	else
1453*e9243325SFrançois Tigeot 		i915_enable_pipestat(dev_priv, pipe,
1454*e9243325SFrançois Tigeot 				     PIPE_VBLANK_INTERRUPT_ENABLE);
1455*e9243325SFrançois Tigeot 
1456*e9243325SFrançois Tigeot 	/* maintain vblank delivery even in deep C-states */
1457*e9243325SFrançois Tigeot 	if (dev_priv->info->gen == 3)
1458*e9243325SFrançois Tigeot 		I915_WRITE(INSTPM, INSTPM_AGPBUSY_DIS << 16);
1459*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1460*e9243325SFrançois Tigeot 
1461*e9243325SFrançois Tigeot 	return 0;
1462*e9243325SFrançois Tigeot }
1463*e9243325SFrançois Tigeot 
1464*e9243325SFrançois Tigeot static int
1465*e9243325SFrançois Tigeot ironlake_enable_vblank(struct drm_device *dev, int pipe)
1466*e9243325SFrançois Tigeot {
1467*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1468*e9243325SFrançois Tigeot 
1469*e9243325SFrançois Tigeot 	if (!i915_pipe_enabled(dev, pipe))
1470*e9243325SFrançois Tigeot 		return -EINVAL;
1471*e9243325SFrançois Tigeot 
1472*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1473*e9243325SFrançois Tigeot 	ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
1474*e9243325SFrançois Tigeot 	    DE_PIPEA_VBLANK : DE_PIPEB_VBLANK);
1475*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1476*e9243325SFrançois Tigeot 
1477*e9243325SFrançois Tigeot 	return 0;
1478*e9243325SFrançois Tigeot }
1479*e9243325SFrançois Tigeot 
1480*e9243325SFrançois Tigeot static int
1481*e9243325SFrançois Tigeot ivybridge_enable_vblank(struct drm_device *dev, int pipe)
1482*e9243325SFrançois Tigeot {
1483*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1484*e9243325SFrançois Tigeot 
1485*e9243325SFrançois Tigeot 	if (!i915_pipe_enabled(dev, pipe))
1486*e9243325SFrançois Tigeot 		return -EINVAL;
1487*e9243325SFrançois Tigeot 
1488*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1489*e9243325SFrançois Tigeot 	ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
1490*e9243325SFrançois Tigeot 				    DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
1491*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1492*e9243325SFrançois Tigeot 
1493*e9243325SFrançois Tigeot 	return 0;
1494*e9243325SFrançois Tigeot }
1495*e9243325SFrançois Tigeot 
1496*e9243325SFrançois Tigeot static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
1497*e9243325SFrançois Tigeot {
1498*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1499*e9243325SFrançois Tigeot 	u32 imr;
1500*e9243325SFrançois Tigeot 
1501*e9243325SFrançois Tigeot 	if (!i915_pipe_enabled(dev, pipe))
1502*e9243325SFrançois Tigeot 		return -EINVAL;
1503*e9243325SFrançois Tigeot 
1504*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1505*e9243325SFrançois Tigeot 	imr = I915_READ(VLV_IMR);
1506*e9243325SFrançois Tigeot 	if (pipe == 0)
1507*e9243325SFrançois Tigeot 		imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
1508*e9243325SFrançois Tigeot 	else
1509*e9243325SFrançois Tigeot 		imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
1510*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IMR, imr);
1511*e9243325SFrançois Tigeot 	i915_enable_pipestat(dev_priv, pipe,
1512*e9243325SFrançois Tigeot 			     PIPE_START_VBLANK_INTERRUPT_ENABLE);
1513*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1514*e9243325SFrançois Tigeot 
1515*e9243325SFrançois Tigeot 	return 0;
1516*e9243325SFrançois Tigeot }
1517*e9243325SFrançois Tigeot 
1518*e9243325SFrançois Tigeot /* Called from drm generic code, passed 'crtc' which
1519*e9243325SFrançois Tigeot  * we use as a pipe index
1520*e9243325SFrançois Tigeot  */
1521*e9243325SFrançois Tigeot static void
1522*e9243325SFrançois Tigeot i915_disable_vblank(struct drm_device *dev, int pipe)
1523*e9243325SFrançois Tigeot {
1524*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1525*e9243325SFrançois Tigeot 
1526*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1527*e9243325SFrançois Tigeot 	if (dev_priv->info->gen == 3)
1528*e9243325SFrançois Tigeot 		I915_WRITE(INSTPM,
1529*e9243325SFrançois Tigeot 			   INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS);
1530*e9243325SFrançois Tigeot 
1531*e9243325SFrançois Tigeot 	i915_disable_pipestat(dev_priv, pipe,
1532*e9243325SFrançois Tigeot 	    PIPE_VBLANK_INTERRUPT_ENABLE |
1533*e9243325SFrançois Tigeot 	    PIPE_START_VBLANK_INTERRUPT_ENABLE);
1534*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1535*e9243325SFrançois Tigeot }
1536*e9243325SFrançois Tigeot 
1537*e9243325SFrançois Tigeot static void
1538*e9243325SFrançois Tigeot ironlake_disable_vblank(struct drm_device *dev, int pipe)
1539*e9243325SFrançois Tigeot {
1540*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1541*e9243325SFrançois Tigeot 
1542*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1543*e9243325SFrançois Tigeot 	ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
1544*e9243325SFrançois Tigeot 	    DE_PIPEA_VBLANK : DE_PIPEB_VBLANK);
1545*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1546*e9243325SFrançois Tigeot }
1547*e9243325SFrançois Tigeot 
1548*e9243325SFrançois Tigeot static void
1549*e9243325SFrançois Tigeot ivybridge_disable_vblank(struct drm_device *dev, int pipe)
1550*e9243325SFrançois Tigeot {
1551*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1552*e9243325SFrançois Tigeot 
1553*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1554*e9243325SFrançois Tigeot 	ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
1555*e9243325SFrançois Tigeot 				     DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
1556*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1557*e9243325SFrançois Tigeot }
1558*e9243325SFrançois Tigeot 
1559*e9243325SFrançois Tigeot static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
1560*e9243325SFrançois Tigeot {
1561*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1562*e9243325SFrançois Tigeot 	u32 imr;
1563*e9243325SFrançois Tigeot 
1564*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1565*e9243325SFrançois Tigeot 	i915_disable_pipestat(dev_priv, pipe,
1566*e9243325SFrançois Tigeot 			      PIPE_START_VBLANK_INTERRUPT_ENABLE);
1567*e9243325SFrançois Tigeot 	imr = I915_READ(VLV_IMR);
1568*e9243325SFrançois Tigeot 	if (pipe == 0)
1569*e9243325SFrançois Tigeot 		imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
1570*e9243325SFrançois Tigeot 	else
1571*e9243325SFrançois Tigeot 		imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
1572*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IMR, imr);
1573*e9243325SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1574*e9243325SFrançois Tigeot }
1575*e9243325SFrançois Tigeot 
1576*e9243325SFrançois Tigeot static u32
1577*e9243325SFrançois Tigeot ring_last_seqno(struct intel_ring_buffer *ring)
1578*e9243325SFrançois Tigeot {
1579*e9243325SFrançois Tigeot 
1580*e9243325SFrançois Tigeot 	if (list_empty(&ring->request_list))
1581*e9243325SFrançois Tigeot 		return (0);
1582*e9243325SFrançois Tigeot 	else
1583*e9243325SFrançois Tigeot 		return (list_entry(ring->request_list.prev,
1584*e9243325SFrançois Tigeot 		    struct drm_i915_gem_request, list)->seqno);
1585*e9243325SFrançois Tigeot }
1586*e9243325SFrançois Tigeot 
1587*e9243325SFrançois Tigeot static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
1588*e9243325SFrançois Tigeot {
1589*e9243325SFrançois Tigeot 	if (list_empty(&ring->request_list) ||
1590*e9243325SFrançois Tigeot 	    i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
1591*e9243325SFrançois Tigeot 		/* Issue a wake-up to catch stuck h/w. */
1592*e9243325SFrançois Tigeot 		if (ring->waiting_seqno) {
1593*e9243325SFrançois Tigeot 			DRM_ERROR(
1594*e9243325SFrançois Tigeot "Hangcheck timer elapsed... %s idle [waiting on %d, at %d], missed IRQ?\n",
1595*e9243325SFrançois Tigeot 				  ring->name,
1596*e9243325SFrançois Tigeot 				  ring->waiting_seqno,
1597*e9243325SFrançois Tigeot 				  ring->get_seqno(ring));
1598*e9243325SFrançois Tigeot 			wakeup(ring);
1599*e9243325SFrançois Tigeot 			*err = true;
1600*e9243325SFrançois Tigeot 		}
1601*e9243325SFrançois Tigeot 		return true;
1602*e9243325SFrançois Tigeot 	}
1603*e9243325SFrançois Tigeot 	return false;
1604*e9243325SFrançois Tigeot }
1605*e9243325SFrançois Tigeot 
1606*e9243325SFrançois Tigeot static bool kick_ring(struct intel_ring_buffer *ring)
1607*e9243325SFrançois Tigeot {
1608*e9243325SFrançois Tigeot 	struct drm_device *dev = ring->dev;
1609*e9243325SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1610*e9243325SFrançois Tigeot 	u32 tmp = I915_READ_CTL(ring);
1611*e9243325SFrançois Tigeot 	if (tmp & RING_WAIT) {
1612*e9243325SFrançois Tigeot 		DRM_ERROR("Kicking stuck wait on %s\n",
1613*e9243325SFrançois Tigeot 			  ring->name);
1614*e9243325SFrançois Tigeot 		I915_WRITE_CTL(ring, tmp);
1615*e9243325SFrançois Tigeot 		return true;
1616*e9243325SFrançois Tigeot 	}
1617*e9243325SFrançois Tigeot 	return false;
1618*e9243325SFrançois Tigeot }
1619*e9243325SFrançois Tigeot 
1620*e9243325SFrançois Tigeot /**
1621*e9243325SFrançois Tigeot  * This is called when the chip hasn't reported back with completed
1622*e9243325SFrançois Tigeot  * batchbuffers in a long time. The first time this is called we simply record
1623*e9243325SFrançois Tigeot  * ACTHD. If ACTHD hasn't changed by the time the hangcheck timer elapses
1624*e9243325SFrançois Tigeot  * again, we assume the chip is wedged and try to fix it.
1625*e9243325SFrançois Tigeot  */
1626*e9243325SFrançois Tigeot void i915_hangcheck_elapsed(unsigned long data)
1627*e9243325SFrançois Tigeot {
1628*e9243325SFrançois Tigeot 	struct drm_device *dev = (struct drm_device *)data;
1629*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = dev->dev_private;
1630*e9243325SFrançois Tigeot 	uint32_t acthd, instdone, instdone1, acthd_bsd, acthd_blt;
1631*e9243325SFrançois Tigeot 	bool err = false;
1632*e9243325SFrançois Tigeot 
1633*e9243325SFrançois Tigeot 	if (!i915_enable_hangcheck)
1634*e9243325SFrançois Tigeot 		return;
1635*e9243325SFrançois Tigeot 
1636*e9243325SFrançois Tigeot 	/* If all work is done then ACTHD clearly hasn't advanced. */
1637*e9243325SFrançois Tigeot 	if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) &&
1638*e9243325SFrançois Tigeot 	    i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) &&
1639*e9243325SFrançois Tigeot 	    i915_hangcheck_ring_idle(&dev_priv->ring[BCS], &err)) {
1640*e9243325SFrançois Tigeot 		dev_priv->hangcheck_count = 0;
1641*e9243325SFrançois Tigeot 		if (err)
1642*e9243325SFrançois Tigeot 			goto repeat;
1643*e9243325SFrançois Tigeot 		return;
1644*e9243325SFrançois Tigeot 	}
1645*e9243325SFrançois Tigeot 
1646*e9243325SFrançois Tigeot 	if (INTEL_INFO(dev)->gen < 4) {
1647*e9243325SFrançois Tigeot 		instdone = I915_READ(INSTDONE);
1648*e9243325SFrançois Tigeot 		instdone1 = 0;
1649*e9243325SFrançois Tigeot 	} else {
1650*e9243325SFrançois Tigeot 		instdone = I915_READ(INSTDONE_I965);
1651*e9243325SFrançois Tigeot 		instdone1 = I915_READ(INSTDONE1);
1652*e9243325SFrançois Tigeot 	}
1653*e9243325SFrançois Tigeot 	acthd = intel_ring_get_active_head(&dev_priv->ring[RCS]);
1654*e9243325SFrançois Tigeot 	acthd_bsd = HAS_BSD(dev) ?
1655*e9243325SFrançois Tigeot 		intel_ring_get_active_head(&dev_priv->ring[VCS]) : 0;
1656*e9243325SFrançois Tigeot 	acthd_blt = HAS_BLT(dev) ?
1657*e9243325SFrançois Tigeot 		intel_ring_get_active_head(&dev_priv->ring[BCS]) : 0;
1658*e9243325SFrançois Tigeot 
1659*e9243325SFrançois Tigeot 	if (dev_priv->last_acthd == acthd &&
1660*e9243325SFrançois Tigeot 	    dev_priv->last_acthd_bsd == acthd_bsd &&
1661*e9243325SFrançois Tigeot 	    dev_priv->last_acthd_blt == acthd_blt &&
1662*e9243325SFrançois Tigeot 	    dev_priv->last_instdone == instdone &&
1663*e9243325SFrançois Tigeot 	    dev_priv->last_instdone1 == instdone1) {
1664*e9243325SFrançois Tigeot 		if (dev_priv->hangcheck_count++ > 1) {
1665*e9243325SFrançois Tigeot 			DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
1666*e9243325SFrançois Tigeot 			i915_handle_error(dev, true);
1667*e9243325SFrançois Tigeot 
1668*e9243325SFrançois Tigeot 			if (!IS_GEN2(dev)) {
1669*e9243325SFrançois Tigeot 				/* Is the chip hanging on a WAIT_FOR_EVENT?
1670*e9243325SFrançois Tigeot 				 * If so we can simply poke the RB_WAIT bit
1671*e9243325SFrançois Tigeot 				 * and break the hang. This should work on
1672*e9243325SFrançois Tigeot 				 * all but the second generation chipsets.
1673*e9243325SFrançois Tigeot 				 */
1674*e9243325SFrançois Tigeot 				if (kick_ring(&dev_priv->ring[RCS]))
1675*e9243325SFrançois Tigeot 					goto repeat;
1676*e9243325SFrançois Tigeot 
1677*e9243325SFrançois Tigeot 				if (HAS_BSD(dev) &&
1678*e9243325SFrançois Tigeot 				    kick_ring(&dev_priv->ring[VCS]))
1679*e9243325SFrançois Tigeot 					goto repeat;
1680*e9243325SFrançois Tigeot 
1681*e9243325SFrançois Tigeot 				if (HAS_BLT(dev) &&
1682*e9243325SFrançois Tigeot 				    kick_ring(&dev_priv->ring[BCS]))
1683*e9243325SFrançois Tigeot 					goto repeat;
1684*e9243325SFrançois Tigeot 			}
1685*e9243325SFrançois Tigeot 
1686*e9243325SFrançois Tigeot 			return;
1687*e9243325SFrançois Tigeot 		}
1688*e9243325SFrançois Tigeot 	} else {
1689*e9243325SFrançois Tigeot 		dev_priv->hangcheck_count = 0;
1690*e9243325SFrançois Tigeot 
1691*e9243325SFrançois Tigeot 		dev_priv->last_acthd = acthd;
1692*e9243325SFrançois Tigeot 		dev_priv->last_acthd_bsd = acthd_bsd;
1693*e9243325SFrançois Tigeot 		dev_priv->last_acthd_blt = acthd_blt;
1694*e9243325SFrançois Tigeot 		dev_priv->last_instdone = instdone;
1695*e9243325SFrançois Tigeot 		dev_priv->last_instdone1 = instdone1;
1696*e9243325SFrançois Tigeot 	}
1697*e9243325SFrançois Tigeot 
1698*e9243325SFrançois Tigeot repeat:
1699*e9243325SFrançois Tigeot 	/* Reset timer case chip hangs without another request being added */
1700*e9243325SFrançois Tigeot 	mod_timer(&dev_priv->hangcheck_timer,
1701*e9243325SFrançois Tigeot 		  round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
1702*e9243325SFrançois Tigeot }
1703*e9243325SFrançois Tigeot 
1704*e9243325SFrançois Tigeot 
1705*e9243325SFrançois Tigeot /* drm_dma.h hooks
1706*e9243325SFrançois Tigeot */
1707*e9243325SFrançois Tigeot static void
1708*e9243325SFrançois Tigeot ironlake_irq_preinstall(struct drm_device *dev)
1709*e9243325SFrançois Tigeot {
1710*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1711*e9243325SFrançois Tigeot 
1712*e9243325SFrançois Tigeot 	atomic_set(&dev_priv->irq_received, 0);
1713*e9243325SFrançois Tigeot 
1714*e9243325SFrançois Tigeot 	I915_WRITE(HWSTAM, 0xeffe);
1715*e9243325SFrançois Tigeot 
1716*e9243325SFrançois Tigeot 	/* XXX hotplug from PCH */
1717*e9243325SFrançois Tigeot 
1718*e9243325SFrançois Tigeot 	I915_WRITE(DEIMR, 0xffffffff);
1719*e9243325SFrançois Tigeot 	I915_WRITE(DEIER, 0x0);
1720*e9243325SFrançois Tigeot 	POSTING_READ(DEIER);
1721*e9243325SFrançois Tigeot 
1722*e9243325SFrançois Tigeot 	/* and GT */
1723*e9243325SFrançois Tigeot 	I915_WRITE(GTIMR, 0xffffffff);
1724*e9243325SFrançois Tigeot 	I915_WRITE(GTIER, 0x0);
1725*e9243325SFrançois Tigeot 	POSTING_READ(GTIER);
1726*e9243325SFrançois Tigeot 
1727*e9243325SFrançois Tigeot 	/* south display irq */
1728*e9243325SFrançois Tigeot 	I915_WRITE(SDEIMR, 0xffffffff);
1729*e9243325SFrançois Tigeot 	I915_WRITE(SDEIER, 0x0);
1730*e9243325SFrançois Tigeot 	POSTING_READ(SDEIER);
1731*e9243325SFrançois Tigeot }
1732*e9243325SFrançois Tigeot 
1733*e9243325SFrançois Tigeot static void valleyview_irq_preinstall(struct drm_device *dev)
1734*e9243325SFrançois Tigeot {
1735*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1736*e9243325SFrançois Tigeot 	int pipe;
1737*e9243325SFrançois Tigeot 
1738*e9243325SFrançois Tigeot 	atomic_set(&dev_priv->irq_received, 0);
1739*e9243325SFrançois Tigeot 
1740*e9243325SFrançois Tigeot 	/* VLV magic */
1741*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IMR, 0);
1742*e9243325SFrançois Tigeot 	I915_WRITE(RING_IMR(RENDER_RING_BASE), 0);
1743*e9243325SFrançois Tigeot 	I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0);
1744*e9243325SFrançois Tigeot 	I915_WRITE(RING_IMR(BLT_RING_BASE), 0);
1745*e9243325SFrançois Tigeot 
1746*e9243325SFrançois Tigeot 	/* and GT */
1747*e9243325SFrançois Tigeot 	I915_WRITE(GTIIR, I915_READ(GTIIR));
1748*e9243325SFrançois Tigeot 	I915_WRITE(GTIIR, I915_READ(GTIIR));
1749*e9243325SFrançois Tigeot 	I915_WRITE(GTIMR, 0xffffffff);
1750*e9243325SFrançois Tigeot 	I915_WRITE(GTIER, 0x0);
1751*e9243325SFrançois Tigeot 	POSTING_READ(GTIER);
1752*e9243325SFrançois Tigeot 
1753*e9243325SFrançois Tigeot 	I915_WRITE(DPINVGTT, 0xff);
1754*e9243325SFrançois Tigeot 
1755*e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_EN, 0);
1756*e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
1757*e9243325SFrançois Tigeot 	for_each_pipe(pipe)
1758*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), 0xffff);
1759*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IIR, 0xffffffff);
1760*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IMR, 0xffffffff);
1761*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IER, 0x0);
1762*e9243325SFrançois Tigeot 	POSTING_READ(VLV_IER);
1763*e9243325SFrançois Tigeot }
1764*e9243325SFrançois Tigeot 
1765*e9243325SFrançois Tigeot /*
1766*e9243325SFrançois Tigeot  * Enable digital hotplug on the PCH, and configure the DP short pulse
1767*e9243325SFrançois Tigeot  * duration to 2ms (which is the minimum in the Display Port spec)
1768*e9243325SFrançois Tigeot  *
1769*e9243325SFrançois Tigeot  * This register is the same on all known PCH chips.
1770*e9243325SFrançois Tigeot  */
1771*e9243325SFrançois Tigeot 
1772*e9243325SFrançois Tigeot static void ironlake_enable_pch_hotplug(struct drm_device *dev)
1773*e9243325SFrançois Tigeot {
1774*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1775*e9243325SFrançois Tigeot 	u32	hotplug;
1776*e9243325SFrançois Tigeot 
1777*e9243325SFrançois Tigeot 	hotplug = I915_READ(PCH_PORT_HOTPLUG);
1778*e9243325SFrançois Tigeot 	hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK);
1779*e9243325SFrançois Tigeot 	hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
1780*e9243325SFrançois Tigeot 	hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms;
1781*e9243325SFrançois Tigeot 	hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms;
1782*e9243325SFrançois Tigeot 	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
1783*e9243325SFrançois Tigeot }
1784*e9243325SFrançois Tigeot 
1785*e9243325SFrançois Tigeot static int ironlake_irq_postinstall(struct drm_device *dev)
1786*e9243325SFrançois Tigeot {
1787*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1788*e9243325SFrançois Tigeot 	/* enable kind of interrupts always enabled */
1789*e9243325SFrançois Tigeot 	u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
1790*e9243325SFrançois Tigeot 			   DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
1791*e9243325SFrançois Tigeot 	u32 render_irqs;
1792*e9243325SFrançois Tigeot 	u32 hotplug_mask;
1793*e9243325SFrançois Tigeot 
1794*e9243325SFrançois Tigeot 	dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
1795*e9243325SFrançois Tigeot 	dev_priv->irq_mask = ~display_mask;
1796*e9243325SFrançois Tigeot 
1797*e9243325SFrançois Tigeot 	/* should always can generate irq */
1798*e9243325SFrançois Tigeot 	I915_WRITE(DEIIR, I915_READ(DEIIR));
1799*e9243325SFrançois Tigeot 	I915_WRITE(DEIMR, dev_priv->irq_mask);
1800*e9243325SFrançois Tigeot 	I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK);
1801*e9243325SFrançois Tigeot 	POSTING_READ(DEIER);
1802*e9243325SFrançois Tigeot 
1803*e9243325SFrançois Tigeot 	dev_priv->gt_irq_mask = ~0;
1804*e9243325SFrançois Tigeot 
1805*e9243325SFrançois Tigeot 	I915_WRITE(GTIIR, I915_READ(GTIIR));
1806*e9243325SFrançois Tigeot 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
1807*e9243325SFrançois Tigeot 
1808*e9243325SFrançois Tigeot 	if (IS_GEN6(dev))
1809*e9243325SFrançois Tigeot 		render_irqs =
1810*e9243325SFrançois Tigeot 			GT_USER_INTERRUPT |
1811*e9243325SFrançois Tigeot 			GT_GEN6_BSD_USER_INTERRUPT |
1812*e9243325SFrançois Tigeot 			GT_GEN6_BLT_USER_INTERRUPT;
1813*e9243325SFrançois Tigeot 	else
1814*e9243325SFrançois Tigeot 		render_irqs =
1815*e9243325SFrançois Tigeot 			GT_USER_INTERRUPT |
1816*e9243325SFrançois Tigeot 			GT_PIPE_NOTIFY |
1817*e9243325SFrançois Tigeot 			GT_BSD_USER_INTERRUPT;
1818*e9243325SFrançois Tigeot 	I915_WRITE(GTIER, render_irqs);
1819*e9243325SFrançois Tigeot 	POSTING_READ(GTIER);
1820*e9243325SFrançois Tigeot 
1821*e9243325SFrançois Tigeot 	if (HAS_PCH_CPT(dev)) {
1822*e9243325SFrançois Tigeot 		hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
1823*e9243325SFrançois Tigeot 				SDE_PORTB_HOTPLUG_CPT |
1824*e9243325SFrançois Tigeot 				SDE_PORTC_HOTPLUG_CPT |
1825*e9243325SFrançois Tigeot 				SDE_PORTD_HOTPLUG_CPT);
1826*e9243325SFrançois Tigeot 	} else {
1827*e9243325SFrançois Tigeot 		hotplug_mask = (SDE_CRT_HOTPLUG |
1828*e9243325SFrançois Tigeot 				SDE_PORTB_HOTPLUG |
1829*e9243325SFrançois Tigeot 				SDE_PORTC_HOTPLUG |
1830*e9243325SFrançois Tigeot 				SDE_PORTD_HOTPLUG |
1831*e9243325SFrançois Tigeot 				SDE_AUX_MASK);
1832*e9243325SFrançois Tigeot 	}
1833*e9243325SFrançois Tigeot 
1834*e9243325SFrançois Tigeot 	dev_priv->pch_irq_mask = ~hotplug_mask;
1835*e9243325SFrançois Tigeot 
1836*e9243325SFrançois Tigeot 	I915_WRITE(SDEIIR, I915_READ(SDEIIR));
1837*e9243325SFrançois Tigeot 	I915_WRITE(SDEIMR, dev_priv->pch_irq_mask);
1838*e9243325SFrançois Tigeot 	I915_WRITE(SDEIER, hotplug_mask);
1839*e9243325SFrançois Tigeot 	POSTING_READ(SDEIER);
1840*e9243325SFrançois Tigeot 
1841*e9243325SFrançois Tigeot 	ironlake_enable_pch_hotplug(dev);
1842*e9243325SFrançois Tigeot 
1843*e9243325SFrançois Tigeot 	if (IS_IRONLAKE_M(dev)) {
1844*e9243325SFrançois Tigeot 		/* Clear & enable PCU event interrupts */
1845*e9243325SFrançois Tigeot 		I915_WRITE(DEIIR, DE_PCU_EVENT);
1846*e9243325SFrançois Tigeot 		I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
1847*e9243325SFrançois Tigeot 		ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
1848*e9243325SFrançois Tigeot 	}
1849*e9243325SFrançois Tigeot 
1850*e9243325SFrançois Tigeot 	return 0;
1851*e9243325SFrançois Tigeot }
1852*e9243325SFrançois Tigeot 
1853*e9243325SFrançois Tigeot 
1854*e9243325SFrançois Tigeot static int ivybridge_irq_postinstall(struct drm_device *dev)
1855*e9243325SFrançois Tigeot {
1856*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1857*e9243325SFrançois Tigeot 	/* enable kind of interrupts always enabled */
1858*e9243325SFrançois Tigeot 	u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
1859*e9243325SFrançois Tigeot 		DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB |
1860*e9243325SFrançois Tigeot 		DE_PLANEB_FLIP_DONE_IVB;
1861*e9243325SFrançois Tigeot 	u32 render_irqs;
1862*e9243325SFrançois Tigeot 	u32 hotplug_mask;
1863*e9243325SFrançois Tigeot 
1864*e9243325SFrançois Tigeot 	dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
1865*e9243325SFrançois Tigeot 	dev_priv->irq_mask = ~display_mask;
1866*e9243325SFrançois Tigeot 
1867*e9243325SFrançois Tigeot 	/* should always can generate irq */
1868*e9243325SFrançois Tigeot 	I915_WRITE(DEIIR, I915_READ(DEIIR));
1869*e9243325SFrançois Tigeot 	I915_WRITE(DEIMR, dev_priv->irq_mask);
1870*e9243325SFrançois Tigeot 	I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB |
1871*e9243325SFrançois Tigeot 		   DE_PIPEB_VBLANK_IVB);
1872*e9243325SFrançois Tigeot 	POSTING_READ(DEIER);
1873*e9243325SFrançois Tigeot 
1874*e9243325SFrançois Tigeot 	dev_priv->gt_irq_mask = ~0;
1875*e9243325SFrançois Tigeot 
1876*e9243325SFrançois Tigeot 	I915_WRITE(GTIIR, I915_READ(GTIIR));
1877*e9243325SFrançois Tigeot 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
1878*e9243325SFrançois Tigeot 
1879*e9243325SFrançois Tigeot 	render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT |
1880*e9243325SFrançois Tigeot 		GT_GEN6_BLT_USER_INTERRUPT;
1881*e9243325SFrançois Tigeot 	I915_WRITE(GTIER, render_irqs);
1882*e9243325SFrançois Tigeot 	POSTING_READ(GTIER);
1883*e9243325SFrançois Tigeot 
1884*e9243325SFrançois Tigeot 	hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
1885*e9243325SFrançois Tigeot 			SDE_PORTB_HOTPLUG_CPT |
1886*e9243325SFrançois Tigeot 			SDE_PORTC_HOTPLUG_CPT |
1887*e9243325SFrançois Tigeot 			SDE_PORTD_HOTPLUG_CPT);
1888*e9243325SFrançois Tigeot 	dev_priv->pch_irq_mask = ~hotplug_mask;
1889*e9243325SFrançois Tigeot 
1890*e9243325SFrançois Tigeot 	I915_WRITE(SDEIIR, I915_READ(SDEIIR));
1891*e9243325SFrançois Tigeot 	I915_WRITE(SDEIMR, dev_priv->pch_irq_mask);
1892*e9243325SFrançois Tigeot 	I915_WRITE(SDEIER, hotplug_mask);
1893*e9243325SFrançois Tigeot 	POSTING_READ(SDEIER);
1894*e9243325SFrançois Tigeot 
1895*e9243325SFrançois Tigeot 	ironlake_enable_pch_hotplug(dev);
1896*e9243325SFrançois Tigeot 
1897*e9243325SFrançois Tigeot 	return 0;
1898*e9243325SFrançois Tigeot }
1899*e9243325SFrançois Tigeot 
1900*e9243325SFrançois Tigeot 
1901*e9243325SFrançois Tigeot static int valleyview_irq_postinstall(struct drm_device *dev)
1902*e9243325SFrançois Tigeot {
1903*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1904*e9243325SFrançois Tigeot 	u32 enable_mask;
1905*e9243325SFrançois Tigeot 	u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
1906*e9243325SFrançois Tigeot 	u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
1907*e9243325SFrançois Tigeot 	u32 render_irqs;
1908*e9243325SFrançois Tigeot 	u16 msid;
1909*e9243325SFrançois Tigeot 
1910*e9243325SFrançois Tigeot 	enable_mask = I915_DISPLAY_PORT_INTERRUPT;
1911*e9243325SFrançois Tigeot 	enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
1912*e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
1913*e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
1914*e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
1915*e9243325SFrançois Tigeot 
1916*e9243325SFrançois Tigeot 	/*
1917*e9243325SFrançois Tigeot 	 *Leave vblank interrupts masked initially.  enable/disable will
1918*e9243325SFrançois Tigeot 	 * toggle them based on usage.
1919*e9243325SFrançois Tigeot 	 */
1920*e9243325SFrançois Tigeot 	dev_priv->irq_mask = (~enable_mask) |
1921*e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
1922*e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
1923*e9243325SFrançois Tigeot 
1924*e9243325SFrançois Tigeot 	dev_priv->pipestat[0] = 0;
1925*e9243325SFrançois Tigeot 	dev_priv->pipestat[1] = 0;
1926*e9243325SFrançois Tigeot 
1927*e9243325SFrançois Tigeot 	/* Hack for broken MSIs on VLV */
1928*e9243325SFrançois Tigeot 	pci_write_config(dev_priv->dev->dev, 0x94, 0xfee00000, 4);
1929*e9243325SFrançois Tigeot 	msid = pci_read_config(dev->dev, 0x98, 2);
1930*e9243325SFrançois Tigeot 	msid &= 0xff; /* mask out delivery bits */
1931*e9243325SFrançois Tigeot 	msid |= (1<<14);
1932*e9243325SFrançois Tigeot 	pci_write_config(dev_priv->dev->dev, 0x98, msid, 4);
1933*e9243325SFrançois Tigeot 
1934*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IMR, dev_priv->irq_mask);
1935*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IER, enable_mask);
1936*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IIR, 0xffffffff);
1937*e9243325SFrançois Tigeot 	I915_WRITE(PIPESTAT(0), 0xffff);
1938*e9243325SFrançois Tigeot 	I915_WRITE(PIPESTAT(1), 0xffff);
1939*e9243325SFrançois Tigeot 	POSTING_READ(VLV_IER);
1940*e9243325SFrançois Tigeot 
1941*e9243325SFrançois Tigeot 	i915_enable_pipestat(dev_priv, 0, pipestat_enable);
1942*e9243325SFrançois Tigeot 	i915_enable_pipestat(dev_priv, 1, pipestat_enable);
1943*e9243325SFrançois Tigeot 
1944*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IIR, 0xffffffff);
1945*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IIR, 0xffffffff);
1946*e9243325SFrançois Tigeot 
1947*e9243325SFrançois Tigeot 	I915_WRITE(GTIIR, I915_READ(GTIIR));
1948*e9243325SFrançois Tigeot 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
1949*e9243325SFrançois Tigeot 
1950*e9243325SFrançois Tigeot 	render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
1951*e9243325SFrançois Tigeot 		GEN6_BLITTER_USER_INTERRUPT;
1952*e9243325SFrançois Tigeot 	I915_WRITE(GTIER, render_irqs);
1953*e9243325SFrançois Tigeot 	POSTING_READ(GTIER);
1954*e9243325SFrançois Tigeot 
1955*e9243325SFrançois Tigeot 	/* ack & enable invalid PTE error interrupts */
1956*e9243325SFrançois Tigeot #if 0 /* FIXME: add support to irq handler for checking these bits */
1957*e9243325SFrançois Tigeot 	I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK);
1958*e9243325SFrançois Tigeot 	I915_WRITE(DPINVGTT, DPINVGTT_EN_MASK);
1959*e9243325SFrançois Tigeot #endif
1960*e9243325SFrançois Tigeot 
1961*e9243325SFrançois Tigeot 	I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
1962*e9243325SFrançois Tigeot 	/* Note HDMI and DP share bits */
1963*e9243325SFrançois Tigeot 	if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
1964*e9243325SFrançois Tigeot 		hotplug_en |= HDMIB_HOTPLUG_INT_EN;
1965*e9243325SFrançois Tigeot 	if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
1966*e9243325SFrançois Tigeot 		hotplug_en |= HDMIC_HOTPLUG_INT_EN;
1967*e9243325SFrançois Tigeot 	if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
1968*e9243325SFrançois Tigeot 		hotplug_en |= HDMID_HOTPLUG_INT_EN;
1969*e9243325SFrançois Tigeot 	if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
1970*e9243325SFrançois Tigeot 		hotplug_en |= SDVOC_HOTPLUG_INT_EN;
1971*e9243325SFrançois Tigeot 	if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
1972*e9243325SFrançois Tigeot 		hotplug_en |= SDVOB_HOTPLUG_INT_EN;
1973*e9243325SFrançois Tigeot 	if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
1974*e9243325SFrançois Tigeot 		hotplug_en |= CRT_HOTPLUG_INT_EN;
1975*e9243325SFrançois Tigeot 		hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
1976*e9243325SFrançois Tigeot 	}
1977*e9243325SFrançois Tigeot 
1978*e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
1979*e9243325SFrançois Tigeot 
1980*e9243325SFrançois Tigeot 	return 0;
1981*e9243325SFrançois Tigeot }
1982*e9243325SFrançois Tigeot 
1983*e9243325SFrançois Tigeot static void valleyview_irq_uninstall(struct drm_device *dev)
1984*e9243325SFrançois Tigeot {
1985*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1986*e9243325SFrançois Tigeot 	int pipe;
1987*e9243325SFrançois Tigeot 
1988*e9243325SFrançois Tigeot 	if (!dev_priv)
1989*e9243325SFrançois Tigeot 		return;
1990*e9243325SFrançois Tigeot 
1991*e9243325SFrançois Tigeot 	for_each_pipe(pipe)
1992*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), 0xffff);
1993*e9243325SFrançois Tigeot 
1994*e9243325SFrançois Tigeot 	I915_WRITE(HWSTAM, 0xffffffff);
1995*e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_EN, 0);
1996*e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
1997*e9243325SFrançois Tigeot 	for_each_pipe(pipe)
1998*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), 0xffff);
1999*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IIR, 0xffffffff);
2000*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IMR, 0xffffffff);
2001*e9243325SFrançois Tigeot 	I915_WRITE(VLV_IER, 0x0);
2002*e9243325SFrançois Tigeot 	POSTING_READ(VLV_IER);
2003*e9243325SFrançois Tigeot }
2004*e9243325SFrançois Tigeot 
2005*e9243325SFrançois Tigeot static void ironlake_irq_uninstall(struct drm_device *dev)
2006*e9243325SFrançois Tigeot {
2007*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2008*e9243325SFrançois Tigeot 
2009*e9243325SFrançois Tigeot 	if (!dev_priv)
2010*e9243325SFrançois Tigeot 		return;
2011*e9243325SFrançois Tigeot 
2012*e9243325SFrançois Tigeot 	I915_WRITE(HWSTAM, 0xffffffff);
2013*e9243325SFrançois Tigeot 
2014*e9243325SFrançois Tigeot 	I915_WRITE(DEIMR, 0xffffffff);
2015*e9243325SFrançois Tigeot 	I915_WRITE(DEIER, 0x0);
2016*e9243325SFrançois Tigeot 	I915_WRITE(DEIIR, I915_READ(DEIIR));
2017*e9243325SFrançois Tigeot 
2018*e9243325SFrançois Tigeot 	I915_WRITE(GTIMR, 0xffffffff);
2019*e9243325SFrançois Tigeot 	I915_WRITE(GTIER, 0x0);
2020*e9243325SFrançois Tigeot 	I915_WRITE(GTIIR, I915_READ(GTIIR));
2021*e9243325SFrançois Tigeot 
2022*e9243325SFrançois Tigeot 	I915_WRITE(SDEIMR, 0xffffffff);
2023*e9243325SFrançois Tigeot 	I915_WRITE(SDEIER, 0x0);
2024*e9243325SFrançois Tigeot 	I915_WRITE(SDEIIR, I915_READ(SDEIIR));
2025*e9243325SFrançois Tigeot }
2026*e9243325SFrançois Tigeot 
2027*e9243325SFrançois Tigeot static void i8xx_irq_preinstall(struct drm_device * dev)
2028*e9243325SFrançois Tigeot {
2029*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2030*e9243325SFrançois Tigeot 	int pipe;
2031*e9243325SFrançois Tigeot 
2032*e9243325SFrançois Tigeot 	atomic_set(&dev_priv->irq_received, 0);
2033*e9243325SFrançois Tigeot 
2034*e9243325SFrançois Tigeot 	for_each_pipe(pipe)
2035*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), 0);
2036*e9243325SFrançois Tigeot 	I915_WRITE16(IMR, 0xffff);
2037*e9243325SFrançois Tigeot 	I915_WRITE16(IER, 0x0);
2038*e9243325SFrançois Tigeot 	POSTING_READ16(IER);
2039*e9243325SFrançois Tigeot }
2040*e9243325SFrançois Tigeot 
2041*e9243325SFrançois Tigeot static int i8xx_irq_postinstall(struct drm_device *dev)
2042*e9243325SFrançois Tigeot {
2043*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2044*e9243325SFrançois Tigeot 
2045*e9243325SFrançois Tigeot 	dev_priv->pipestat[0] = 0;
2046*e9243325SFrançois Tigeot 	dev_priv->pipestat[1] = 0;
2047*e9243325SFrançois Tigeot 
2048*e9243325SFrançois Tigeot 	I915_WRITE16(EMR,
2049*e9243325SFrançois Tigeot 		     ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
2050*e9243325SFrançois Tigeot 
2051*e9243325SFrançois Tigeot 	/* Unmask the interrupts that we always want on. */
2052*e9243325SFrançois Tigeot 	dev_priv->irq_mask =
2053*e9243325SFrançois Tigeot 		~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
2054*e9243325SFrançois Tigeot 		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
2055*e9243325SFrançois Tigeot 		  I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2056*e9243325SFrançois Tigeot 		  I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
2057*e9243325SFrançois Tigeot 		  I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
2058*e9243325SFrançois Tigeot 	I915_WRITE16(IMR, dev_priv->irq_mask);
2059*e9243325SFrançois Tigeot 
2060*e9243325SFrançois Tigeot 	I915_WRITE16(IER,
2061*e9243325SFrançois Tigeot 		     I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
2062*e9243325SFrançois Tigeot 		     I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
2063*e9243325SFrançois Tigeot 		     I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
2064*e9243325SFrançois Tigeot 		     I915_USER_INTERRUPT);
2065*e9243325SFrançois Tigeot 	POSTING_READ16(IER);
2066*e9243325SFrançois Tigeot 
2067*e9243325SFrançois Tigeot 	return 0;
2068*e9243325SFrançois Tigeot }
2069*e9243325SFrançois Tigeot 
2070*e9243325SFrançois Tigeot static irqreturn_t i8xx_irq_handler(void *arg)
2071*e9243325SFrançois Tigeot {
2072*e9243325SFrançois Tigeot 	struct drm_device *dev = (struct drm_device *) arg;
2073*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2074*e9243325SFrançois Tigeot 	u16 iir, new_iir;
2075*e9243325SFrançois Tigeot 	u32 pipe_stats[2];
2076*e9243325SFrançois Tigeot 	int irq_received;
2077*e9243325SFrançois Tigeot 	int pipe;
2078*e9243325SFrançois Tigeot 	u16 flip_mask =
2079*e9243325SFrançois Tigeot 		I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2080*e9243325SFrançois Tigeot 		I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
2081*e9243325SFrançois Tigeot 
2082*e9243325SFrançois Tigeot 	atomic_inc(&dev_priv->irq_received);
2083*e9243325SFrançois Tigeot 
2084*e9243325SFrançois Tigeot 	iir = I915_READ16(IIR);
2085*e9243325SFrançois Tigeot 	if (iir == 0)
2086*e9243325SFrançois Tigeot 		return;
2087*e9243325SFrançois Tigeot 
2088*e9243325SFrançois Tigeot 	while (iir & ~flip_mask) {
2089*e9243325SFrançois Tigeot 		/* Can't rely on pipestat interrupt bit in iir as it might
2090*e9243325SFrançois Tigeot 		 * have been cleared after the pipestat interrupt was received.
2091*e9243325SFrançois Tigeot 		 * It doesn't set the bit in iir again, but it still produces
2092*e9243325SFrançois Tigeot 		 * interrupts (for non-MSI).
2093*e9243325SFrançois Tigeot 		 */
2094*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
2095*e9243325SFrançois Tigeot 		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
2096*e9243325SFrançois Tigeot 			i915_handle_error(dev, false);
2097*e9243325SFrançois Tigeot 
2098*e9243325SFrançois Tigeot 		for_each_pipe(pipe) {
2099*e9243325SFrançois Tigeot 			int reg = PIPESTAT(pipe);
2100*e9243325SFrançois Tigeot 			pipe_stats[pipe] = I915_READ(reg);
2101*e9243325SFrançois Tigeot 
2102*e9243325SFrançois Tigeot 			/*
2103*e9243325SFrançois Tigeot 			 * Clear the PIPE*STAT regs before the IIR
2104*e9243325SFrançois Tigeot 			 */
2105*e9243325SFrançois Tigeot 			if (pipe_stats[pipe] & 0x8000ffff) {
2106*e9243325SFrançois Tigeot 				if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
2107*e9243325SFrançois Tigeot 					DRM_DEBUG_DRIVER("pipe %c underrun\n",
2108*e9243325SFrançois Tigeot 							 pipe_name(pipe));
2109*e9243325SFrançois Tigeot 				I915_WRITE(reg, pipe_stats[pipe]);
2110*e9243325SFrançois Tigeot 				irq_received = 1;
2111*e9243325SFrançois Tigeot 			}
2112*e9243325SFrançois Tigeot 		}
2113*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_RELEASE);
2114*e9243325SFrançois Tigeot 
2115*e9243325SFrançois Tigeot 		I915_WRITE16(IIR, iir & ~flip_mask);
2116*e9243325SFrançois Tigeot 		new_iir = I915_READ16(IIR); /* Flush posted writes */
2117*e9243325SFrançois Tigeot 
2118*e9243325SFrançois Tigeot 		i915_update_dri1_breadcrumb(dev);
2119*e9243325SFrançois Tigeot 
2120*e9243325SFrançois Tigeot 		if (iir & I915_USER_INTERRUPT)
2121*e9243325SFrançois Tigeot 			notify_ring(dev, &dev_priv->ring[RCS]);
2122*e9243325SFrançois Tigeot 
2123*e9243325SFrançois Tigeot 		if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS &&
2124*e9243325SFrançois Tigeot 		    drm_handle_vblank(dev, 0)) {
2125*e9243325SFrançois Tigeot 			if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
2126*e9243325SFrançois Tigeot 				intel_prepare_page_flip(dev, 0);
2127*e9243325SFrançois Tigeot 				intel_finish_page_flip(dev, 0);
2128*e9243325SFrançois Tigeot 				flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT;
2129*e9243325SFrançois Tigeot 			}
2130*e9243325SFrançois Tigeot 		}
2131*e9243325SFrançois Tigeot 
2132*e9243325SFrançois Tigeot 		if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS &&
2133*e9243325SFrançois Tigeot 		    drm_handle_vblank(dev, 1)) {
2134*e9243325SFrançois Tigeot 			if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) {
2135*e9243325SFrançois Tigeot 				intel_prepare_page_flip(dev, 1);
2136*e9243325SFrançois Tigeot 				intel_finish_page_flip(dev, 1);
2137*e9243325SFrançois Tigeot 				flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
2138*e9243325SFrançois Tigeot 			}
2139*e9243325SFrançois Tigeot 		}
2140*e9243325SFrançois Tigeot 
2141*e9243325SFrançois Tigeot 		iir = new_iir;
2142*e9243325SFrançois Tigeot 	}
2143*e9243325SFrançois Tigeot 
2144*e9243325SFrançois Tigeot 	return;
2145*e9243325SFrançois Tigeot }
2146*e9243325SFrançois Tigeot 
2147*e9243325SFrançois Tigeot static void i8xx_irq_uninstall(struct drm_device * dev)
2148*e9243325SFrançois Tigeot {
2149*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2150*e9243325SFrançois Tigeot 	int pipe;
2151*e9243325SFrançois Tigeot 
2152*e9243325SFrançois Tigeot 	for_each_pipe(pipe) {
2153*e9243325SFrançois Tigeot 		/* Clear enable bits; then clear status bits */
2154*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), 0);
2155*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
2156*e9243325SFrançois Tigeot 	}
2157*e9243325SFrançois Tigeot 	I915_WRITE16(IMR, 0xffff);
2158*e9243325SFrançois Tigeot 	I915_WRITE16(IER, 0x0);
2159*e9243325SFrançois Tigeot 	I915_WRITE16(IIR, I915_READ16(IIR));
2160*e9243325SFrançois Tigeot }
2161*e9243325SFrançois Tigeot 
2162*e9243325SFrançois Tigeot static void i915_irq_preinstall(struct drm_device * dev)
2163*e9243325SFrançois Tigeot {
2164*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2165*e9243325SFrançois Tigeot 	int pipe;
2166*e9243325SFrançois Tigeot 
2167*e9243325SFrançois Tigeot 	atomic_set(&dev_priv->irq_received, 0);
2168*e9243325SFrançois Tigeot 
2169*e9243325SFrançois Tigeot 	if (I915_HAS_HOTPLUG(dev)) {
2170*e9243325SFrançois Tigeot 		I915_WRITE(PORT_HOTPLUG_EN, 0);
2171*e9243325SFrançois Tigeot 		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
2172*e9243325SFrançois Tigeot 	}
2173*e9243325SFrançois Tigeot 
2174*e9243325SFrançois Tigeot 	I915_WRITE16(HWSTAM, 0xeffe);
2175*e9243325SFrançois Tigeot 	for_each_pipe(pipe)
2176*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), 0);
2177*e9243325SFrançois Tigeot 	I915_WRITE(IMR, 0xffffffff);
2178*e9243325SFrançois Tigeot 	I915_WRITE(IER, 0x0);
2179*e9243325SFrançois Tigeot 	POSTING_READ(IER);
2180*e9243325SFrançois Tigeot }
2181*e9243325SFrançois Tigeot 
2182*e9243325SFrançois Tigeot static int i915_irq_postinstall(struct drm_device *dev)
2183*e9243325SFrançois Tigeot {
2184*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2185*e9243325SFrançois Tigeot 	u32 enable_mask;
2186*e9243325SFrançois Tigeot 
2187*e9243325SFrançois Tigeot 	dev_priv->pipestat[0] = 0;
2188*e9243325SFrançois Tigeot 	dev_priv->pipestat[1] = 0;
2189*e9243325SFrançois Tigeot 
2190*e9243325SFrançois Tigeot 	I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
2191*e9243325SFrançois Tigeot 
2192*e9243325SFrançois Tigeot 	/* Unmask the interrupts that we always want on. */
2193*e9243325SFrançois Tigeot 	dev_priv->irq_mask =
2194*e9243325SFrançois Tigeot 		~(I915_ASLE_INTERRUPT |
2195*e9243325SFrançois Tigeot 		  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
2196*e9243325SFrançois Tigeot 		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
2197*e9243325SFrançois Tigeot 		  I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2198*e9243325SFrançois Tigeot 		  I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
2199*e9243325SFrançois Tigeot 		  I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
2200*e9243325SFrançois Tigeot 
2201*e9243325SFrançois Tigeot 	enable_mask =
2202*e9243325SFrançois Tigeot 		I915_ASLE_INTERRUPT |
2203*e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
2204*e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
2205*e9243325SFrançois Tigeot 		I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
2206*e9243325SFrançois Tigeot 		I915_USER_INTERRUPT;
2207*e9243325SFrançois Tigeot 
2208*e9243325SFrançois Tigeot 	if (I915_HAS_HOTPLUG(dev)) {
2209*e9243325SFrançois Tigeot 		/* Enable in IER... */
2210*e9243325SFrançois Tigeot 		enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
2211*e9243325SFrançois Tigeot 		/* and unmask in IMR */
2212*e9243325SFrançois Tigeot 		dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT;
2213*e9243325SFrançois Tigeot 	}
2214*e9243325SFrançois Tigeot 
2215*e9243325SFrançois Tigeot 	I915_WRITE(IMR, dev_priv->irq_mask);
2216*e9243325SFrançois Tigeot 	I915_WRITE(IER, enable_mask);
2217*e9243325SFrançois Tigeot 	POSTING_READ(IER);
2218*e9243325SFrançois Tigeot 
2219*e9243325SFrançois Tigeot 	if (I915_HAS_HOTPLUG(dev)) {
2220*e9243325SFrançois Tigeot 		u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
2221*e9243325SFrançois Tigeot 
2222*e9243325SFrançois Tigeot 		if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
2223*e9243325SFrançois Tigeot 			hotplug_en |= HDMIB_HOTPLUG_INT_EN;
2224*e9243325SFrançois Tigeot 		if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
2225*e9243325SFrançois Tigeot 			hotplug_en |= HDMIC_HOTPLUG_INT_EN;
2226*e9243325SFrançois Tigeot 		if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
2227*e9243325SFrançois Tigeot 			hotplug_en |= HDMID_HOTPLUG_INT_EN;
2228*e9243325SFrançois Tigeot 		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
2229*e9243325SFrançois Tigeot 			hotplug_en |= SDVOC_HOTPLUG_INT_EN;
2230*e9243325SFrançois Tigeot 		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
2231*e9243325SFrançois Tigeot 			hotplug_en |= SDVOB_HOTPLUG_INT_EN;
2232*e9243325SFrançois Tigeot 		if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
2233*e9243325SFrançois Tigeot 			hotplug_en |= CRT_HOTPLUG_INT_EN;
2234*e9243325SFrançois Tigeot 			hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
2235*e9243325SFrançois Tigeot 		}
2236*e9243325SFrançois Tigeot 
2237*e9243325SFrançois Tigeot 		/* Ignore TV since it's buggy */
2238*e9243325SFrançois Tigeot 
2239*e9243325SFrançois Tigeot 		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
2240*e9243325SFrançois Tigeot 	}
2241*e9243325SFrançois Tigeot 
2242*e9243325SFrançois Tigeot #if 0
2243*e9243325SFrançois Tigeot 	intel_opregion_enable_asle(dev);
2244*e9243325SFrançois Tigeot #endif
2245*e9243325SFrançois Tigeot 
2246*e9243325SFrançois Tigeot 	return 0;
2247*e9243325SFrançois Tigeot }
2248*e9243325SFrançois Tigeot 
2249*e9243325SFrançois Tigeot static irqreturn_t i915_irq_handler(void *arg)
2250*e9243325SFrançois Tigeot {
2251*e9243325SFrançois Tigeot 	struct drm_device *dev = (struct drm_device *) arg;
2252*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2253*e9243325SFrançois Tigeot 	u32 iir, new_iir, pipe_stats[I915_MAX_PIPES];
2254*e9243325SFrançois Tigeot 	u32 flip_mask =
2255*e9243325SFrançois Tigeot 		I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2256*e9243325SFrançois Tigeot 		I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
2257*e9243325SFrançois Tigeot 	u32 flip[2] = {
2258*e9243325SFrançois Tigeot 		I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT,
2259*e9243325SFrançois Tigeot 		I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT
2260*e9243325SFrançois Tigeot 	};
2261*e9243325SFrançois Tigeot 	int pipe;
2262*e9243325SFrançois Tigeot 
2263*e9243325SFrançois Tigeot 	atomic_inc(&dev_priv->irq_received);
2264*e9243325SFrançois Tigeot 
2265*e9243325SFrançois Tigeot 	iir = I915_READ(IIR);
2266*e9243325SFrançois Tigeot 	do {
2267*e9243325SFrançois Tigeot 		bool irq_received = (iir & ~flip_mask) != 0;
2268*e9243325SFrançois Tigeot 		bool blc_event = false;
2269*e9243325SFrançois Tigeot 
2270*e9243325SFrançois Tigeot 		/* Can't rely on pipestat interrupt bit in iir as it might
2271*e9243325SFrançois Tigeot 		 * have been cleared after the pipestat interrupt was received.
2272*e9243325SFrançois Tigeot 		 * It doesn't set the bit in iir again, but it still produces
2273*e9243325SFrançois Tigeot 		 * interrupts (for non-MSI).
2274*e9243325SFrançois Tigeot 		 */
2275*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
2276*e9243325SFrançois Tigeot 		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
2277*e9243325SFrançois Tigeot 			i915_handle_error(dev, false);
2278*e9243325SFrançois Tigeot 
2279*e9243325SFrançois Tigeot 		for_each_pipe(pipe) {
2280*e9243325SFrançois Tigeot 			int reg = PIPESTAT(pipe);
2281*e9243325SFrançois Tigeot 			pipe_stats[pipe] = I915_READ(reg);
2282*e9243325SFrançois Tigeot 
2283*e9243325SFrançois Tigeot 			/* Clear the PIPE*STAT regs before the IIR */
2284*e9243325SFrançois Tigeot 			if (pipe_stats[pipe] & 0x8000ffff) {
2285*e9243325SFrançois Tigeot 				if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
2286*e9243325SFrançois Tigeot 					DRM_DEBUG_DRIVER("pipe %c underrun\n",
2287*e9243325SFrançois Tigeot 							 pipe_name(pipe));
2288*e9243325SFrançois Tigeot 				I915_WRITE(reg, pipe_stats[pipe]);
2289*e9243325SFrançois Tigeot 				irq_received = true;
2290*e9243325SFrançois Tigeot 			}
2291*e9243325SFrançois Tigeot 		}
2292*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_RELEASE);
2293*e9243325SFrançois Tigeot 
2294*e9243325SFrançois Tigeot 		if (!irq_received)
2295*e9243325SFrançois Tigeot 			break;
2296*e9243325SFrançois Tigeot 
2297*e9243325SFrançois Tigeot 		/* Consume port.  Then clear IIR or we'll miss events */
2298*e9243325SFrançois Tigeot 		if ((I915_HAS_HOTPLUG(dev)) &&
2299*e9243325SFrançois Tigeot 		    (iir & I915_DISPLAY_PORT_INTERRUPT)) {
2300*e9243325SFrançois Tigeot 			u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
2301*e9243325SFrançois Tigeot 
2302*e9243325SFrançois Tigeot 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
2303*e9243325SFrançois Tigeot 				  hotplug_status);
2304*e9243325SFrançois Tigeot 			if (hotplug_status & dev_priv->hotplug_supported_mask)
2305*e9243325SFrançois Tigeot 				queue_work(dev_priv->wq,
2306*e9243325SFrançois Tigeot 					   &dev_priv->hotplug_work);
2307*e9243325SFrançois Tigeot 
2308*e9243325SFrançois Tigeot 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
2309*e9243325SFrançois Tigeot 			POSTING_READ(PORT_HOTPLUG_STAT);
2310*e9243325SFrançois Tigeot 		}
2311*e9243325SFrançois Tigeot 
2312*e9243325SFrançois Tigeot 		I915_WRITE(IIR, iir & ~flip_mask);
2313*e9243325SFrançois Tigeot 		new_iir = I915_READ(IIR); /* Flush posted writes */
2314*e9243325SFrançois Tigeot 
2315*e9243325SFrançois Tigeot 		if (iir & I915_USER_INTERRUPT)
2316*e9243325SFrançois Tigeot 			notify_ring(dev, &dev_priv->ring[RCS]);
2317*e9243325SFrançois Tigeot 
2318*e9243325SFrançois Tigeot 		for_each_pipe(pipe) {
2319*e9243325SFrançois Tigeot 			int plane = pipe;
2320*e9243325SFrançois Tigeot 			if (IS_MOBILE(dev))
2321*e9243325SFrançois Tigeot 				plane = !plane;
2322*e9243325SFrançois Tigeot 			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
2323*e9243325SFrançois Tigeot 			    drm_handle_vblank(dev, pipe)) {
2324*e9243325SFrançois Tigeot 				if (iir & flip[plane]) {
2325*e9243325SFrançois Tigeot 					intel_prepare_page_flip(dev, plane);
2326*e9243325SFrançois Tigeot 					intel_finish_page_flip(dev, pipe);
2327*e9243325SFrançois Tigeot 					flip_mask &= ~flip[plane];
2328*e9243325SFrançois Tigeot 				}
2329*e9243325SFrançois Tigeot 			}
2330*e9243325SFrançois Tigeot 
2331*e9243325SFrançois Tigeot 			if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
2332*e9243325SFrançois Tigeot 				blc_event = true;
2333*e9243325SFrançois Tigeot 		}
2334*e9243325SFrançois Tigeot 
2335*e9243325SFrançois Tigeot #if 0
2336*e9243325SFrançois Tigeot 		if (blc_event || (iir & I915_ASLE_INTERRUPT))
2337*e9243325SFrançois Tigeot 			intel_opregion_asle_intr(dev);
2338*e9243325SFrançois Tigeot #endif
2339*e9243325SFrançois Tigeot 
2340*e9243325SFrançois Tigeot 		/* With MSI, interrupts are only generated when iir
2341*e9243325SFrançois Tigeot 		 * transitions from zero to nonzero.  If another bit got
2342*e9243325SFrançois Tigeot 		 * set while we were handling the existing iir bits, then
2343*e9243325SFrançois Tigeot 		 * we would never get another interrupt.
2344*e9243325SFrançois Tigeot 		 *
2345*e9243325SFrançois Tigeot 		 * This is fine on non-MSI as well, as if we hit this path
2346*e9243325SFrançois Tigeot 		 * we avoid exiting the interrupt handler only to generate
2347*e9243325SFrançois Tigeot 		 * another one.
2348*e9243325SFrançois Tigeot 		 *
2349*e9243325SFrançois Tigeot 		 * Note that for MSI this could cause a stray interrupt report
2350*e9243325SFrançois Tigeot 		 * if an interrupt landed in the time between writing IIR and
2351*e9243325SFrançois Tigeot 		 * the posting read.  This should be rare enough to never
2352*e9243325SFrançois Tigeot 		 * trigger the 99% of 100,000 interrupts test for disabling
2353*e9243325SFrançois Tigeot 		 * stray interrupts.
2354*e9243325SFrançois Tigeot 		 */
2355*e9243325SFrançois Tigeot 		iir = new_iir;
2356*e9243325SFrançois Tigeot 	} while (iir & ~flip_mask);
2357*e9243325SFrançois Tigeot 
2358*e9243325SFrançois Tigeot 	i915_update_dri1_breadcrumb(dev);
2359*e9243325SFrançois Tigeot }
2360*e9243325SFrançois Tigeot 
2361*e9243325SFrançois Tigeot static void i915_irq_uninstall(struct drm_device * dev)
2362*e9243325SFrançois Tigeot {
2363*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2364*e9243325SFrançois Tigeot 	int pipe;
2365*e9243325SFrançois Tigeot 
2366*e9243325SFrançois Tigeot 	if (I915_HAS_HOTPLUG(dev)) {
2367*e9243325SFrançois Tigeot 		I915_WRITE(PORT_HOTPLUG_EN, 0);
2368*e9243325SFrançois Tigeot 		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
2369*e9243325SFrançois Tigeot 	}
2370*e9243325SFrançois Tigeot 
2371*e9243325SFrançois Tigeot 	I915_WRITE16(HWSTAM, 0xffff);
2372*e9243325SFrançois Tigeot 	for_each_pipe(pipe) {
2373*e9243325SFrançois Tigeot 		/* Clear enable bits; then clear status bits */
2374*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), 0);
2375*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
2376*e9243325SFrançois Tigeot 	}
2377*e9243325SFrançois Tigeot 	I915_WRITE(IMR, 0xffffffff);
2378*e9243325SFrançois Tigeot 	I915_WRITE(IER, 0x0);
2379*e9243325SFrançois Tigeot 
2380*e9243325SFrançois Tigeot 	I915_WRITE(IIR, I915_READ(IIR));
2381*e9243325SFrançois Tigeot }
2382*e9243325SFrançois Tigeot 
2383*e9243325SFrançois Tigeot static void i965_irq_preinstall(struct drm_device * dev)
2384*e9243325SFrançois Tigeot {
2385*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2386*e9243325SFrançois Tigeot 	int pipe;
2387*e9243325SFrançois Tigeot 
2388*e9243325SFrançois Tigeot 	atomic_set(&dev_priv->irq_received, 0);
2389*e9243325SFrançois Tigeot 
2390*e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_EN, 0);
2391*e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
2392*e9243325SFrançois Tigeot 
2393*e9243325SFrançois Tigeot 	I915_WRITE(HWSTAM, 0xeffe);
2394*e9243325SFrançois Tigeot 	for_each_pipe(pipe)
2395*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), 0);
2396*e9243325SFrançois Tigeot 	I915_WRITE(IMR, 0xffffffff);
2397*e9243325SFrançois Tigeot 	I915_WRITE(IER, 0x0);
2398*e9243325SFrançois Tigeot 	POSTING_READ(IER);
2399*e9243325SFrançois Tigeot }
2400*e9243325SFrançois Tigeot 
2401*e9243325SFrançois Tigeot static int i965_irq_postinstall(struct drm_device *dev)
2402*e9243325SFrançois Tigeot {
2403*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2404*e9243325SFrançois Tigeot 	u32 hotplug_en;
2405*e9243325SFrançois Tigeot 	u32 enable_mask;
2406*e9243325SFrançois Tigeot 	u32 error_mask;
2407*e9243325SFrançois Tigeot 
2408*e9243325SFrançois Tigeot 	/* Unmask the interrupts that we always want on. */
2409*e9243325SFrançois Tigeot 	dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
2410*e9243325SFrançois Tigeot 			       I915_DISPLAY_PORT_INTERRUPT |
2411*e9243325SFrançois Tigeot 			       I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
2412*e9243325SFrançois Tigeot 			       I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
2413*e9243325SFrançois Tigeot 			       I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2414*e9243325SFrançois Tigeot 			       I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
2415*e9243325SFrançois Tigeot 			       I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
2416*e9243325SFrançois Tigeot 
2417*e9243325SFrançois Tigeot 	enable_mask = ~dev_priv->irq_mask;
2418*e9243325SFrançois Tigeot 	enable_mask |= I915_USER_INTERRUPT;
2419*e9243325SFrançois Tigeot 
2420*e9243325SFrançois Tigeot 	if (IS_G4X(dev))
2421*e9243325SFrançois Tigeot 		enable_mask |= I915_BSD_USER_INTERRUPT;
2422*e9243325SFrançois Tigeot 
2423*e9243325SFrançois Tigeot 	dev_priv->pipestat[0] = 0;
2424*e9243325SFrançois Tigeot 	dev_priv->pipestat[1] = 0;
2425*e9243325SFrançois Tigeot 
2426*e9243325SFrançois Tigeot 	/*
2427*e9243325SFrançois Tigeot 	 * Enable some error detection, note the instruction error mask
2428*e9243325SFrançois Tigeot 	 * bit is reserved, so we leave it masked.
2429*e9243325SFrançois Tigeot 	 */
2430*e9243325SFrançois Tigeot 	if (IS_G4X(dev)) {
2431*e9243325SFrançois Tigeot 		error_mask = ~(GM45_ERROR_PAGE_TABLE |
2432*e9243325SFrançois Tigeot 			       GM45_ERROR_MEM_PRIV |
2433*e9243325SFrançois Tigeot 			       GM45_ERROR_CP_PRIV |
2434*e9243325SFrançois Tigeot 			       I915_ERROR_MEMORY_REFRESH);
2435*e9243325SFrançois Tigeot 	} else {
2436*e9243325SFrançois Tigeot 		error_mask = ~(I915_ERROR_PAGE_TABLE |
2437*e9243325SFrançois Tigeot 			       I915_ERROR_MEMORY_REFRESH);
2438*e9243325SFrançois Tigeot 	}
2439*e9243325SFrançois Tigeot 	I915_WRITE(EMR, error_mask);
2440*e9243325SFrançois Tigeot 
2441*e9243325SFrançois Tigeot 	I915_WRITE(IMR, dev_priv->irq_mask);
2442*e9243325SFrançois Tigeot 	I915_WRITE(IER, enable_mask);
2443*e9243325SFrançois Tigeot 	POSTING_READ(IER);
2444*e9243325SFrançois Tigeot 
2445*e9243325SFrançois Tigeot 	/* Note HDMI and DP share hotplug bits */
2446*e9243325SFrançois Tigeot 	hotplug_en = 0;
2447*e9243325SFrançois Tigeot 	if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
2448*e9243325SFrançois Tigeot 		hotplug_en |= HDMIB_HOTPLUG_INT_EN;
2449*e9243325SFrançois Tigeot 	if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
2450*e9243325SFrançois Tigeot 		hotplug_en |= HDMIC_HOTPLUG_INT_EN;
2451*e9243325SFrançois Tigeot 	if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
2452*e9243325SFrançois Tigeot 		hotplug_en |= HDMID_HOTPLUG_INT_EN;
2453*e9243325SFrançois Tigeot 	if (IS_G4X(dev)) {
2454*e9243325SFrançois Tigeot 		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X)
2455*e9243325SFrançois Tigeot 			hotplug_en |= SDVOC_HOTPLUG_INT_EN;
2456*e9243325SFrançois Tigeot 		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X)
2457*e9243325SFrançois Tigeot 			hotplug_en |= SDVOB_HOTPLUG_INT_EN;
2458*e9243325SFrançois Tigeot 	} else {
2459*e9243325SFrançois Tigeot 		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965)
2460*e9243325SFrançois Tigeot 			hotplug_en |= SDVOC_HOTPLUG_INT_EN;
2461*e9243325SFrançois Tigeot 		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965)
2462*e9243325SFrançois Tigeot 			hotplug_en |= SDVOB_HOTPLUG_INT_EN;
2463*e9243325SFrançois Tigeot 	}
2464*e9243325SFrançois Tigeot 	if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
2465*e9243325SFrançois Tigeot 		hotplug_en |= CRT_HOTPLUG_INT_EN;
2466*e9243325SFrançois Tigeot 
2467*e9243325SFrançois Tigeot 		/* Programming the CRT detection parameters tends
2468*e9243325SFrançois Tigeot 		   to generate a spurious hotplug event about three
2469*e9243325SFrançois Tigeot 		   seconds later.  So just do it once.
2470*e9243325SFrançois Tigeot 		   */
2471*e9243325SFrançois Tigeot 		if (IS_G4X(dev))
2472*e9243325SFrançois Tigeot 			hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
2473*e9243325SFrançois Tigeot 		hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
2474*e9243325SFrançois Tigeot 	}
2475*e9243325SFrançois Tigeot 
2476*e9243325SFrançois Tigeot 	/* Ignore TV since it's buggy */
2477*e9243325SFrançois Tigeot 
2478*e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
2479*e9243325SFrançois Tigeot 
2480*e9243325SFrançois Tigeot #if 0
2481*e9243325SFrançois Tigeot 	intel_opregion_enable_asle(dev);
2482*e9243325SFrançois Tigeot #endif
2483*e9243325SFrançois Tigeot 
2484*e9243325SFrançois Tigeot 	return 0;
2485*e9243325SFrançois Tigeot }
2486*e9243325SFrançois Tigeot 
2487*e9243325SFrançois Tigeot 
2488*e9243325SFrançois Tigeot static void i965_irq_handler(void *arg)
2489*e9243325SFrançois Tigeot {
2490*e9243325SFrançois Tigeot 	struct drm_device *dev = (struct drm_device *) arg;
2491*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2492*e9243325SFrançois Tigeot 	u32 iir, new_iir;
2493*e9243325SFrançois Tigeot 	u32 pipe_stats[I915_MAX_PIPES];
2494*e9243325SFrançois Tigeot 	int irq_received;
2495*e9243325SFrançois Tigeot 	int pipe;
2496*e9243325SFrançois Tigeot 
2497*e9243325SFrançois Tigeot 	atomic_inc(&dev_priv->irq_received);
2498*e9243325SFrançois Tigeot 
2499*e9243325SFrançois Tigeot 	iir = I915_READ(IIR);
2500*e9243325SFrançois Tigeot 
2501*e9243325SFrançois Tigeot 	for (;;) {
2502*e9243325SFrançois Tigeot 		bool blc_event = false;
2503*e9243325SFrançois Tigeot 
2504*e9243325SFrançois Tigeot 		irq_received = iir != 0;
2505*e9243325SFrançois Tigeot 
2506*e9243325SFrançois Tigeot 		/* Can't rely on pipestat interrupt bit in iir as it might
2507*e9243325SFrançois Tigeot 		 * have been cleared after the pipestat interrupt was received.
2508*e9243325SFrançois Tigeot 		 * It doesn't set the bit in iir again, but it still produces
2509*e9243325SFrançois Tigeot 		 * interrupts (for non-MSI).
2510*e9243325SFrançois Tigeot 		 */
2511*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
2512*e9243325SFrançois Tigeot 		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
2513*e9243325SFrançois Tigeot 			i915_handle_error(dev, false);
2514*e9243325SFrançois Tigeot 
2515*e9243325SFrançois Tigeot 		for_each_pipe(pipe) {
2516*e9243325SFrançois Tigeot 			int reg = PIPESTAT(pipe);
2517*e9243325SFrançois Tigeot 			pipe_stats[pipe] = I915_READ(reg);
2518*e9243325SFrançois Tigeot 
2519*e9243325SFrançois Tigeot 			/*
2520*e9243325SFrançois Tigeot 			 * Clear the PIPE*STAT regs before the IIR
2521*e9243325SFrançois Tigeot 			 */
2522*e9243325SFrançois Tigeot 			if (pipe_stats[pipe] & 0x8000ffff) {
2523*e9243325SFrançois Tigeot 				if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
2524*e9243325SFrançois Tigeot 					DRM_DEBUG_DRIVER("pipe %c underrun\n",
2525*e9243325SFrançois Tigeot 							 pipe_name(pipe));
2526*e9243325SFrançois Tigeot 				I915_WRITE(reg, pipe_stats[pipe]);
2527*e9243325SFrançois Tigeot 				irq_received = 1;
2528*e9243325SFrançois Tigeot 			}
2529*e9243325SFrançois Tigeot 		}
2530*e9243325SFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_RELEASE);
2531*e9243325SFrançois Tigeot 
2532*e9243325SFrançois Tigeot 		if (!irq_received)
2533*e9243325SFrançois Tigeot 			break;
2534*e9243325SFrançois Tigeot 
2535*e9243325SFrançois Tigeot 		/* Consume port.  Then clear IIR or we'll miss events */
2536*e9243325SFrançois Tigeot 		if (iir & I915_DISPLAY_PORT_INTERRUPT) {
2537*e9243325SFrançois Tigeot 			u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
2538*e9243325SFrançois Tigeot 
2539*e9243325SFrançois Tigeot 			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
2540*e9243325SFrançois Tigeot 				  hotplug_status);
2541*e9243325SFrançois Tigeot 			if (hotplug_status & dev_priv->hotplug_supported_mask)
2542*e9243325SFrançois Tigeot 				queue_work(dev_priv->wq,
2543*e9243325SFrançois Tigeot 					   &dev_priv->hotplug_work);
2544*e9243325SFrançois Tigeot 
2545*e9243325SFrançois Tigeot 			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
2546*e9243325SFrançois Tigeot 			I915_READ(PORT_HOTPLUG_STAT);
2547*e9243325SFrançois Tigeot 		}
2548*e9243325SFrançois Tigeot 
2549*e9243325SFrançois Tigeot 		I915_WRITE(IIR, iir);
2550*e9243325SFrançois Tigeot 		new_iir = I915_READ(IIR); /* Flush posted writes */
2551*e9243325SFrançois Tigeot 
2552*e9243325SFrançois Tigeot 		if (iir & I915_USER_INTERRUPT)
2553*e9243325SFrançois Tigeot 			notify_ring(dev, &dev_priv->ring[RCS]);
2554*e9243325SFrançois Tigeot 		if (iir & I915_BSD_USER_INTERRUPT)
2555*e9243325SFrançois Tigeot 			notify_ring(dev, &dev_priv->ring[VCS]);
2556*e9243325SFrançois Tigeot 
2557*e9243325SFrançois Tigeot 		if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT)
2558*e9243325SFrançois Tigeot 			intel_prepare_page_flip(dev, 0);
2559*e9243325SFrançois Tigeot 
2560*e9243325SFrançois Tigeot 		if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT)
2561*e9243325SFrançois Tigeot 			intel_prepare_page_flip(dev, 1);
2562*e9243325SFrançois Tigeot 
2563*e9243325SFrançois Tigeot 		for_each_pipe(pipe) {
2564*e9243325SFrançois Tigeot 			if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
2565*e9243325SFrançois Tigeot 			    drm_handle_vblank(dev, pipe)) {
2566*e9243325SFrançois Tigeot 				i915_pageflip_stall_check(dev, pipe);
2567*e9243325SFrançois Tigeot 				intel_finish_page_flip(dev, pipe);
2568*e9243325SFrançois Tigeot 			}
2569*e9243325SFrançois Tigeot 
2570*e9243325SFrançois Tigeot 			if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
2571*e9243325SFrançois Tigeot 				blc_event = true;
2572*e9243325SFrançois Tigeot 		}
2573*e9243325SFrançois Tigeot 
2574*e9243325SFrançois Tigeot #if 0
2575*e9243325SFrançois Tigeot 		if (blc_event || (iir & I915_ASLE_INTERRUPT))
2576*e9243325SFrançois Tigeot 			intel_opregion_asle_intr(dev);
2577*e9243325SFrançois Tigeot #endif
2578*e9243325SFrançois Tigeot 
2579*e9243325SFrançois Tigeot 		/* With MSI, interrupts are only generated when iir
2580*e9243325SFrançois Tigeot 		 * transitions from zero to nonzero.  If another bit got
2581*e9243325SFrançois Tigeot 		 * set while we were handling the existing iir bits, then
2582*e9243325SFrançois Tigeot 		 * we would never get another interrupt.
2583*e9243325SFrançois Tigeot 		 *
2584*e9243325SFrançois Tigeot 		 * This is fine on non-MSI as well, as if we hit this path
2585*e9243325SFrançois Tigeot 		 * we avoid exiting the interrupt handler only to generate
2586*e9243325SFrançois Tigeot 		 * another one.
2587*e9243325SFrançois Tigeot 		 *
2588*e9243325SFrançois Tigeot 		 * Note that for MSI this could cause a stray interrupt report
2589*e9243325SFrançois Tigeot 		 * if an interrupt landed in the time between writing IIR and
2590*e9243325SFrançois Tigeot 		 * the posting read.  This should be rare enough to never
2591*e9243325SFrançois Tigeot 		 * trigger the 99% of 100,000 interrupts test for disabling
2592*e9243325SFrançois Tigeot 		 * stray interrupts.
2593*e9243325SFrançois Tigeot 		 */
2594*e9243325SFrançois Tigeot 		iir = new_iir;
2595*e9243325SFrançois Tigeot 	}
2596*e9243325SFrançois Tigeot 
2597*e9243325SFrançois Tigeot 	i915_update_dri1_breadcrumb(dev);
2598*e9243325SFrançois Tigeot }
2599*e9243325SFrançois Tigeot 
2600*e9243325SFrançois Tigeot static void i965_irq_uninstall(struct drm_device * dev)
2601*e9243325SFrançois Tigeot {
2602*e9243325SFrançois Tigeot 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2603*e9243325SFrançois Tigeot 	int pipe;
2604*e9243325SFrançois Tigeot 
2605*e9243325SFrançois Tigeot 	if (!dev_priv)
2606*e9243325SFrançois Tigeot 		return;
2607*e9243325SFrançois Tigeot 
2608*e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_EN, 0);
2609*e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
2610*e9243325SFrançois Tigeot 
2611*e9243325SFrançois Tigeot 	I915_WRITE(HWSTAM, 0xffffffff);
2612*e9243325SFrançois Tigeot 	for_each_pipe(pipe)
2613*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe), 0);
2614*e9243325SFrançois Tigeot 	I915_WRITE(IMR, 0xffffffff);
2615*e9243325SFrançois Tigeot 	I915_WRITE(IER, 0x0);
2616*e9243325SFrançois Tigeot 
2617*e9243325SFrançois Tigeot 	for_each_pipe(pipe)
2618*e9243325SFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe),
2619*e9243325SFrançois Tigeot 			   I915_READ(PIPESTAT(pipe)) & 0x8000ffff);
2620*e9243325SFrançois Tigeot 	I915_WRITE(IIR, I915_READ(IIR));
2621*e9243325SFrançois Tigeot }
2622*e9243325SFrançois Tigeot 
2623*e9243325SFrançois Tigeot void intel_irq_init(struct drm_device *dev)
2624*e9243325SFrançois Tigeot {
2625*e9243325SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
2626*e9243325SFrançois Tigeot 
2627*e9243325SFrançois Tigeot 	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
2628*e9243325SFrançois Tigeot 	INIT_WORK(&dev_priv->error_work, i915_error_work_func);
2629*e9243325SFrançois Tigeot 	INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
2630*e9243325SFrançois Tigeot 
2631*e9243325SFrançois Tigeot 	dev->driver->get_vblank_counter = i915_get_vblank_counter;
2632*e9243325SFrançois Tigeot 	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
2633*e9243325SFrançois Tigeot 	if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
2634*e9243325SFrançois Tigeot 		dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
2635*e9243325SFrançois Tigeot 		dev->driver->get_vblank_counter = gm45_get_vblank_counter;
2636*e9243325SFrançois Tigeot 	}
2637*e9243325SFrançois Tigeot 
2638*e9243325SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_MODESET))
2639*e9243325SFrançois Tigeot 		dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
2640*e9243325SFrançois Tigeot 	else
2641*e9243325SFrançois Tigeot 		dev->driver->get_vblank_timestamp = NULL;
2642*e9243325SFrançois Tigeot 	dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
2643*e9243325SFrançois Tigeot 
2644*e9243325SFrançois Tigeot 	if (IS_VALLEYVIEW(dev)) {
2645*e9243325SFrançois Tigeot 		dev->driver->irq_handler = valleyview_irq_handler;
2646*e9243325SFrançois Tigeot 		dev->driver->irq_preinstall = valleyview_irq_preinstall;
2647*e9243325SFrançois Tigeot 		dev->driver->irq_postinstall = valleyview_irq_postinstall;
2648*e9243325SFrançois Tigeot 		dev->driver->irq_uninstall = valleyview_irq_uninstall;
2649*e9243325SFrançois Tigeot 		dev->driver->enable_vblank = valleyview_enable_vblank;
2650*e9243325SFrançois Tigeot 		dev->driver->disable_vblank = valleyview_disable_vblank;
2651*e9243325SFrançois Tigeot 	} else if (IS_IVYBRIDGE(dev)) {
2652*e9243325SFrançois Tigeot 		/* Share pre & uninstall handlers with ILK/SNB */
2653*e9243325SFrançois Tigeot 		dev->driver->irq_handler = ivybridge_irq_handler;
2654*e9243325SFrançois Tigeot 		dev->driver->irq_preinstall = ironlake_irq_preinstall;
2655*e9243325SFrançois Tigeot 		dev->driver->irq_postinstall = ivybridge_irq_postinstall;
2656*e9243325SFrançois Tigeot 		dev->driver->irq_uninstall = ironlake_irq_uninstall;
2657*e9243325SFrançois Tigeot 		dev->driver->enable_vblank = ivybridge_enable_vblank;
2658*e9243325SFrançois Tigeot 		dev->driver->disable_vblank = ivybridge_disable_vblank;
2659*e9243325SFrançois Tigeot 	} else if (IS_HASWELL(dev)) {
2660*e9243325SFrançois Tigeot 		/* Share interrupts handling with IVB */
2661*e9243325SFrançois Tigeot 		dev->driver->irq_handler = ivybridge_irq_handler;
2662*e9243325SFrançois Tigeot 		dev->driver->irq_preinstall = ironlake_irq_preinstall;
2663*e9243325SFrançois Tigeot 		dev->driver->irq_postinstall = ivybridge_irq_postinstall;
2664*e9243325SFrançois Tigeot 		dev->driver->irq_uninstall = ironlake_irq_uninstall;
2665*e9243325SFrançois Tigeot 		dev->driver->enable_vblank = ivybridge_enable_vblank;
2666*e9243325SFrançois Tigeot 		dev->driver->disable_vblank = ivybridge_disable_vblank;
2667*e9243325SFrançois Tigeot 	} else if (HAS_PCH_SPLIT(dev)) {
2668*e9243325SFrançois Tigeot 		dev->driver->irq_handler = ironlake_irq_handler;
2669*e9243325SFrançois Tigeot 		dev->driver->irq_preinstall = ironlake_irq_preinstall;
2670*e9243325SFrançois Tigeot 		dev->driver->irq_postinstall = ironlake_irq_postinstall;
2671*e9243325SFrançois Tigeot 		dev->driver->irq_uninstall = ironlake_irq_uninstall;
2672*e9243325SFrançois Tigeot 		dev->driver->enable_vblank = ironlake_enable_vblank;
2673*e9243325SFrançois Tigeot 		dev->driver->disable_vblank = ironlake_disable_vblank;
2674*e9243325SFrançois Tigeot 	} else {
2675*e9243325SFrançois Tigeot 		if (INTEL_INFO(dev)->gen == 2) {
2676*e9243325SFrançois Tigeot 			dev->driver->irq_preinstall = i8xx_irq_preinstall;
2677*e9243325SFrançois Tigeot 			dev->driver->irq_postinstall = i8xx_irq_postinstall;
2678*e9243325SFrançois Tigeot 			dev->driver->irq_handler = i8xx_irq_handler;
2679*e9243325SFrançois Tigeot 			dev->driver->irq_uninstall = i8xx_irq_uninstall;
2680*e9243325SFrançois Tigeot 		} else if (INTEL_INFO(dev)->gen == 3) {
2681*e9243325SFrançois Tigeot 			dev->driver->irq_preinstall = i915_irq_preinstall;
2682*e9243325SFrançois Tigeot 			dev->driver->irq_postinstall = i915_irq_postinstall;
2683*e9243325SFrançois Tigeot 			dev->driver->irq_uninstall = i915_irq_uninstall;
2684*e9243325SFrançois Tigeot 			dev->driver->irq_handler = i915_irq_handler;
2685*e9243325SFrançois Tigeot 		} else {
2686*e9243325SFrançois Tigeot 			dev->driver->irq_preinstall = i965_irq_preinstall;
2687*e9243325SFrançois Tigeot 			dev->driver->irq_postinstall = i965_irq_postinstall;
2688*e9243325SFrançois Tigeot 			dev->driver->irq_uninstall = i965_irq_uninstall;
2689*e9243325SFrançois Tigeot 			dev->driver->irq_handler = i965_irq_handler;
2690*e9243325SFrançois Tigeot 		}
2691*e9243325SFrançois Tigeot 		dev->driver->enable_vblank = i915_enable_vblank;
2692*e9243325SFrançois Tigeot 		dev->driver->disable_vblank = i915_disable_vblank;
2693*e9243325SFrançois Tigeot 	}
2694*e9243325SFrançois Tigeot }
2695