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