xref: /dragonfly/sys/dev/drm/i915/i915_irq.c (revision 3f2dd94a)
1c4a9e910SFrançois Tigeot /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
2c4a9e910SFrançois Tigeot  */
300640ec9SFranç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 
29183e2373SFrançois Tigeot #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30183e2373SFrançois Tigeot 
31183e2373SFrançois Tigeot #include <linux/sysrq.h>
321487f786SFrançois Tigeot #include <linux/slab.h>
338621f407SFrançois Tigeot #include <linux/circ_buf.h>
3418e26a6dSFrançois Tigeot #include <drm/drmP.h>
355c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
36c4a9e910SFrançois Tigeot #include "i915_drv.h"
379edbd4a0SFrançois Tigeot #include "i915_trace.h"
38e3adcf8fSFrançois Tigeot #include "intel_drv.h"
39c4a9e910SFrançois Tigeot 
402c9916cdSFrançois Tigeot /**
412c9916cdSFrançois Tigeot  * DOC: interrupt handling
422c9916cdSFrançois Tigeot  *
432c9916cdSFrançois Tigeot  * These functions provide the basic support for enabling and disabling the
442c9916cdSFrançois Tigeot  * interrupt handling support. There's a lot more functionality in i915_irq.c
452c9916cdSFrançois Tigeot  * and related files, but that will be described in separate chapters.
462c9916cdSFrançois Tigeot  */
472c9916cdSFrançois Tigeot 
48352ff8bdSFrançois Tigeot static const u32 hpd_ilk[HPD_NUM_PINS] = {
49352ff8bdSFrançois Tigeot 	[HPD_PORT_A] = DE_DP_A_HOTPLUG,
50352ff8bdSFrançois Tigeot };
51352ff8bdSFrançois Tigeot 
52352ff8bdSFrançois Tigeot static const u32 hpd_ivb[HPD_NUM_PINS] = {
53352ff8bdSFrançois Tigeot 	[HPD_PORT_A] = DE_DP_A_HOTPLUG_IVB,
54352ff8bdSFrançois Tigeot };
55352ff8bdSFrançois Tigeot 
56352ff8bdSFrançois Tigeot static const u32 hpd_bdw[HPD_NUM_PINS] = {
57352ff8bdSFrançois Tigeot 	[HPD_PORT_A] = GEN8_PORT_DP_A_HOTPLUG,
58352ff8bdSFrançois Tigeot };
59352ff8bdSFrançois Tigeot 
602c9916cdSFrançois Tigeot static const u32 hpd_ibx[HPD_NUM_PINS] = {
618e26cdf6SFrançois Tigeot 	[HPD_CRT] = SDE_CRT_HOTPLUG,
628e26cdf6SFrançois Tigeot 	[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
638e26cdf6SFrançois Tigeot 	[HPD_PORT_B] = SDE_PORTB_HOTPLUG,
648e26cdf6SFrançois Tigeot 	[HPD_PORT_C] = SDE_PORTC_HOTPLUG,
658e26cdf6SFrançois Tigeot 	[HPD_PORT_D] = SDE_PORTD_HOTPLUG
668e26cdf6SFrançois Tigeot };
678e26cdf6SFrançois Tigeot 
682c9916cdSFrançois Tigeot static const u32 hpd_cpt[HPD_NUM_PINS] = {
698e26cdf6SFrançois Tigeot 	[HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
708e26cdf6SFrançois Tigeot 	[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT,
718e26cdf6SFrançois Tigeot 	[HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
728e26cdf6SFrançois Tigeot 	[HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
738e26cdf6SFrançois Tigeot 	[HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT
748e26cdf6SFrançois Tigeot };
758e26cdf6SFrançois Tigeot 
76a05eeebfSFrançois Tigeot static const u32 hpd_spt[HPD_NUM_PINS] = {
77352ff8bdSFrançois Tigeot 	[HPD_PORT_A] = SDE_PORTA_HOTPLUG_SPT,
78a05eeebfSFrançois Tigeot 	[HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
79a05eeebfSFrançois Tigeot 	[HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
80a05eeebfSFrançois Tigeot 	[HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT,
81a05eeebfSFrançois Tigeot 	[HPD_PORT_E] = SDE_PORTE_HOTPLUG_SPT
82a05eeebfSFrançois Tigeot };
83a05eeebfSFrançois Tigeot 
842c9916cdSFrançois Tigeot static const u32 hpd_mask_i915[HPD_NUM_PINS] = {
858e26cdf6SFrançois Tigeot 	[HPD_CRT] = CRT_HOTPLUG_INT_EN,
868e26cdf6SFrançois Tigeot 	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
878e26cdf6SFrançois Tigeot 	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
888e26cdf6SFrançois Tigeot 	[HPD_PORT_B] = PORTB_HOTPLUG_INT_EN,
898e26cdf6SFrançois Tigeot 	[HPD_PORT_C] = PORTC_HOTPLUG_INT_EN,
908e26cdf6SFrançois Tigeot 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
918e26cdf6SFrançois Tigeot };
928e26cdf6SFrançois Tigeot 
932c9916cdSFrançois Tigeot static const u32 hpd_status_g4x[HPD_NUM_PINS] = {
948e26cdf6SFrançois Tigeot 	[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
958e26cdf6SFrançois Tigeot 	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
968e26cdf6SFrançois Tigeot 	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
978e26cdf6SFrançois Tigeot 	[HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
988e26cdf6SFrançois Tigeot 	[HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
998e26cdf6SFrançois Tigeot 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
1008e26cdf6SFrançois Tigeot };
1018e26cdf6SFrançois Tigeot 
10219c468b4SFrançois Tigeot static const u32 hpd_status_i915[HPD_NUM_PINS] = {
1038e26cdf6SFrançois Tigeot 	[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
1048e26cdf6SFrançois Tigeot 	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
1058e26cdf6SFrançois Tigeot 	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
1068e26cdf6SFrançois Tigeot 	[HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
1078e26cdf6SFrançois Tigeot 	[HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
1088e26cdf6SFrançois Tigeot 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
1098e26cdf6SFrançois Tigeot };
1108e26cdf6SFrançois Tigeot 
11119c468b4SFrançois Tigeot /* BXT hpd list */
11219c468b4SFrançois Tigeot static const u32 hpd_bxt[HPD_NUM_PINS] = {
113352ff8bdSFrançois Tigeot 	[HPD_PORT_A] = BXT_DE_PORT_HP_DDIA,
11419c468b4SFrançois Tigeot 	[HPD_PORT_B] = BXT_DE_PORT_HP_DDIB,
11519c468b4SFrançois Tigeot 	[HPD_PORT_C] = BXT_DE_PORT_HP_DDIC
11619c468b4SFrançois Tigeot };
11719c468b4SFrançois Tigeot 
118ba55f2f5SFrançois Tigeot /* IIR can theoretically queue up two events. Be paranoid. */
119ba55f2f5SFrançois Tigeot #define GEN8_IRQ_RESET_NDX(type, which) do { \
120ba55f2f5SFrançois Tigeot 	I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
121ba55f2f5SFrançois Tigeot 	POSTING_READ(GEN8_##type##_IMR(which)); \
122ba55f2f5SFrançois Tigeot 	I915_WRITE(GEN8_##type##_IER(which), 0); \
123ba55f2f5SFrançois Tigeot 	I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
124ba55f2f5SFrançois Tigeot 	POSTING_READ(GEN8_##type##_IIR(which)); \
125ba55f2f5SFrançois Tigeot 	I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
126ba55f2f5SFrançois Tigeot 	POSTING_READ(GEN8_##type##_IIR(which)); \
127ba55f2f5SFrançois Tigeot } while (0)
128ba55f2f5SFrançois Tigeot 
129*3f2dd94aSFrançois Tigeot #define GEN3_IRQ_RESET(type) do { \
130ba55f2f5SFrançois Tigeot 	I915_WRITE(type##IMR, 0xffffffff); \
131ba55f2f5SFrançois Tigeot 	POSTING_READ(type##IMR); \
132ba55f2f5SFrançois Tigeot 	I915_WRITE(type##IER, 0); \
133ba55f2f5SFrançois Tigeot 	I915_WRITE(type##IIR, 0xffffffff); \
134ba55f2f5SFrançois Tigeot 	POSTING_READ(type##IIR); \
135ba55f2f5SFrançois Tigeot 	I915_WRITE(type##IIR, 0xffffffff); \
136ba55f2f5SFrançois Tigeot 	POSTING_READ(type##IIR); \
137ba55f2f5SFrançois Tigeot } while (0)
138ba55f2f5SFrançois Tigeot 
139*3f2dd94aSFrançois Tigeot #define GEN2_IRQ_RESET(type) do { \
140*3f2dd94aSFrançois Tigeot 	I915_WRITE16(type##IMR, 0xffff); \
141*3f2dd94aSFrançois Tigeot 	POSTING_READ16(type##IMR); \
142*3f2dd94aSFrançois Tigeot 	I915_WRITE16(type##IER, 0); \
143*3f2dd94aSFrançois Tigeot 	I915_WRITE16(type##IIR, 0xffff); \
144*3f2dd94aSFrançois Tigeot 	POSTING_READ16(type##IIR); \
145*3f2dd94aSFrançois Tigeot 	I915_WRITE16(type##IIR, 0xffff); \
146*3f2dd94aSFrançois Tigeot 	POSTING_READ16(type##IIR); \
147*3f2dd94aSFrançois Tigeot } while (0)
148*3f2dd94aSFrançois Tigeot 
149ba55f2f5SFrançois Tigeot /*
150ba55f2f5SFrançois Tigeot  * We should clear IMR at preinstall/uninstall, and just check at postinstall.
151ba55f2f5SFrançois Tigeot  */
gen3_assert_iir_is_zero(struct drm_i915_private * dev_priv,i915_reg_t reg)152*3f2dd94aSFrançois Tigeot static void gen3_assert_iir_is_zero(struct drm_i915_private *dev_priv,
153aee94f86SFrançois Tigeot 				    i915_reg_t reg)
154352ff8bdSFrançois Tigeot {
155352ff8bdSFrançois Tigeot 	u32 val = I915_READ(reg);
156352ff8bdSFrançois Tigeot 
157352ff8bdSFrançois Tigeot 	if (val == 0)
158352ff8bdSFrançois Tigeot 		return;
159352ff8bdSFrançois Tigeot 
160352ff8bdSFrançois Tigeot 	WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n",
161aee94f86SFrançois Tigeot 	     i915_mmio_reg_offset(reg), val);
162352ff8bdSFrançois Tigeot 	I915_WRITE(reg, 0xffffffff);
163352ff8bdSFrançois Tigeot 	POSTING_READ(reg);
164352ff8bdSFrançois Tigeot 	I915_WRITE(reg, 0xffffffff);
165352ff8bdSFrançois Tigeot 	POSTING_READ(reg);
166352ff8bdSFrançois Tigeot }
167ba55f2f5SFrançois Tigeot 
gen2_assert_iir_is_zero(struct drm_i915_private * dev_priv,i915_reg_t reg)168*3f2dd94aSFrançois Tigeot static void gen2_assert_iir_is_zero(struct drm_i915_private *dev_priv,
169*3f2dd94aSFrançois Tigeot 				    i915_reg_t reg)
170*3f2dd94aSFrançois Tigeot {
171*3f2dd94aSFrançois Tigeot 	u16 val = I915_READ16(reg);
172*3f2dd94aSFrançois Tigeot 
173*3f2dd94aSFrançois Tigeot 	if (val == 0)
174*3f2dd94aSFrançois Tigeot 		return;
175*3f2dd94aSFrançois Tigeot 
176*3f2dd94aSFrançois Tigeot 	WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n",
177*3f2dd94aSFrançois Tigeot 	     i915_mmio_reg_offset(reg), val);
178*3f2dd94aSFrançois Tigeot 	I915_WRITE16(reg, 0xffff);
179*3f2dd94aSFrançois Tigeot 	POSTING_READ16(reg);
180*3f2dd94aSFrançois Tigeot 	I915_WRITE16(reg, 0xffff);
181*3f2dd94aSFrançois Tigeot 	POSTING_READ16(reg);
182*3f2dd94aSFrançois Tigeot }
183*3f2dd94aSFrançois Tigeot 
184ba55f2f5SFrançois Tigeot #define GEN8_IRQ_INIT_NDX(type, which, imr_val, ier_val) do { \
185*3f2dd94aSFrançois Tigeot 	gen3_assert_iir_is_zero(dev_priv, GEN8_##type##_IIR(which)); \
186ba55f2f5SFrançois Tigeot 	I915_WRITE(GEN8_##type##_IER(which), (ier_val)); \
1872c9916cdSFrançois Tigeot 	I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \
1882c9916cdSFrançois Tigeot 	POSTING_READ(GEN8_##type##_IMR(which)); \
189ba55f2f5SFrançois Tigeot } while (0)
190ba55f2f5SFrançois Tigeot 
191*3f2dd94aSFrançois Tigeot #define GEN3_IRQ_INIT(type, imr_val, ier_val) do { \
192*3f2dd94aSFrançois Tigeot 	gen3_assert_iir_is_zero(dev_priv, type##IIR); \
193ba55f2f5SFrançois Tigeot 	I915_WRITE(type##IER, (ier_val)); \
1942c9916cdSFrançois Tigeot 	I915_WRITE(type##IMR, (imr_val)); \
1952c9916cdSFrançois Tigeot 	POSTING_READ(type##IMR); \
196ba55f2f5SFrançois Tigeot } while (0)
197ba55f2f5SFrançois Tigeot 
198*3f2dd94aSFrançois Tigeot #define GEN2_IRQ_INIT(type, imr_val, ier_val) do { \
199*3f2dd94aSFrançois Tigeot 	gen2_assert_iir_is_zero(dev_priv, type##IIR); \
200*3f2dd94aSFrançois Tigeot 	I915_WRITE16(type##IER, (ier_val)); \
201*3f2dd94aSFrançois Tigeot 	I915_WRITE16(type##IMR, (imr_val)); \
202*3f2dd94aSFrançois Tigeot 	POSTING_READ16(type##IMR); \
203*3f2dd94aSFrançois Tigeot } while (0)
204*3f2dd94aSFrançois Tigeot 
2052c9916cdSFrançois Tigeot static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
2064be47400SFrançois Tigeot static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
2072c9916cdSFrançois Tigeot 
208e3adcf8fSFrançois Tigeot /* For display hotplug interrupt */
209352ff8bdSFrançois Tigeot static inline void
i915_hotplug_interrupt_update_locked(struct drm_i915_private * dev_priv,uint32_t mask,uint32_t bits)210352ff8bdSFrançois Tigeot i915_hotplug_interrupt_update_locked(struct drm_i915_private *dev_priv,
211352ff8bdSFrançois Tigeot 				     uint32_t mask,
212352ff8bdSFrançois Tigeot 				     uint32_t bits)
213c4a9e910SFrançois Tigeot {
214352ff8bdSFrançois Tigeot 	uint32_t val;
215352ff8bdSFrançois Tigeot 
216a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
217352ff8bdSFrançois Tigeot 	WARN_ON(bits & ~mask);
218352ff8bdSFrançois Tigeot 
219352ff8bdSFrançois Tigeot 	val = I915_READ(PORT_HOTPLUG_EN);
220352ff8bdSFrançois Tigeot 	val &= ~mask;
221352ff8bdSFrançois Tigeot 	val |= bits;
222352ff8bdSFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_EN, val);
223352ff8bdSFrançois Tigeot }
224352ff8bdSFrançois Tigeot 
225352ff8bdSFrançois Tigeot /**
226352ff8bdSFrançois Tigeot  * i915_hotplug_interrupt_update - update hotplug interrupt enable
227352ff8bdSFrançois Tigeot  * @dev_priv: driver private
228352ff8bdSFrançois Tigeot  * @mask: bits to update
229352ff8bdSFrançois Tigeot  * @bits: bits to enable
230352ff8bdSFrançois Tigeot  * NOTE: the HPD enable bits are modified both inside and outside
231352ff8bdSFrançois Tigeot  * of an interrupt context. To avoid that read-modify-write cycles
232352ff8bdSFrançois Tigeot  * interfer, these bits are protected by a spinlock. Since this
233352ff8bdSFrançois Tigeot  * function is usually not called from a context where the lock is
234352ff8bdSFrançois Tigeot  * held already, this function acquires the lock itself. A non-locking
235352ff8bdSFrançois Tigeot  * version is also available.
236352ff8bdSFrançois Tigeot  */
i915_hotplug_interrupt_update(struct drm_i915_private * dev_priv,uint32_t mask,uint32_t bits)237352ff8bdSFrançois Tigeot void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
238352ff8bdSFrançois Tigeot 				   uint32_t mask,
239352ff8bdSFrançois Tigeot 				   uint32_t bits)
240352ff8bdSFrançois Tigeot {
241352ff8bdSFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
242352ff8bdSFrançois Tigeot 	i915_hotplug_interrupt_update_locked(dev_priv, mask, bits);
243352ff8bdSFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
244352ff8bdSFrançois Tigeot }
245352ff8bdSFrançois Tigeot 
246352ff8bdSFrançois Tigeot /**
247352ff8bdSFrançois Tigeot  * ilk_update_display_irq - update DEIMR
248352ff8bdSFrançois Tigeot  * @dev_priv: driver private
249352ff8bdSFrançois Tigeot  * @interrupt_mask: mask of interrupt bits to update
250352ff8bdSFrançois Tigeot  * @enabled_irq_mask: mask of interrupt bits to enable
251352ff8bdSFrançois Tigeot  */
ilk_update_display_irq(struct drm_i915_private * dev_priv,uint32_t interrupt_mask,uint32_t enabled_irq_mask)252aee94f86SFrançois Tigeot void ilk_update_display_irq(struct drm_i915_private *dev_priv,
253352ff8bdSFrançois Tigeot 			    uint32_t interrupt_mask,
254352ff8bdSFrançois Tigeot 			    uint32_t enabled_irq_mask)
255352ff8bdSFrançois Tigeot {
256352ff8bdSFrançois Tigeot 	uint32_t new_val;
257352ff8bdSFrançois Tigeot 
258a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
259352ff8bdSFrançois Tigeot 
260352ff8bdSFrançois Tigeot 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
2619edbd4a0SFrançois Tigeot 
26224edb884SFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
2639edbd4a0SFrançois Tigeot 		return;
2649edbd4a0SFrançois Tigeot 
265352ff8bdSFrançois Tigeot 	new_val = dev_priv->irq_mask;
266352ff8bdSFrançois Tigeot 	new_val &= ~interrupt_mask;
267352ff8bdSFrançois Tigeot 	new_val |= (~enabled_irq_mask & interrupt_mask);
268352ff8bdSFrançois Tigeot 
269352ff8bdSFrançois Tigeot 	if (new_val != dev_priv->irq_mask) {
270352ff8bdSFrançois Tigeot 		dev_priv->irq_mask = new_val;
271e3adcf8fSFrançois Tigeot 		I915_WRITE(DEIMR, dev_priv->irq_mask);
272e3adcf8fSFrançois Tigeot 		POSTING_READ(DEIMR);
273c4a9e910SFrançois Tigeot 	}
274c4a9e910SFrançois Tigeot }
275c4a9e910SFrançois Tigeot 
2769edbd4a0SFrançois Tigeot /**
2779edbd4a0SFrançois Tigeot  * ilk_update_gt_irq - update GTIMR
2789edbd4a0SFrançois Tigeot  * @dev_priv: driver private
2799edbd4a0SFrançois Tigeot  * @interrupt_mask: mask of interrupt bits to update
2809edbd4a0SFrançois Tigeot  * @enabled_irq_mask: mask of interrupt bits to enable
2819edbd4a0SFrançois Tigeot  */
ilk_update_gt_irq(struct drm_i915_private * dev_priv,uint32_t interrupt_mask,uint32_t enabled_irq_mask)2829edbd4a0SFrançois Tigeot static void ilk_update_gt_irq(struct drm_i915_private *dev_priv,
2839edbd4a0SFrançois Tigeot 			      uint32_t interrupt_mask,
2849edbd4a0SFrançois Tigeot 			      uint32_t enabled_irq_mask)
2859edbd4a0SFrançois Tigeot {
286a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
2879edbd4a0SFrançois Tigeot 
2882c9916cdSFrançois Tigeot 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
2892c9916cdSFrançois Tigeot 
29024edb884SFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
2919edbd4a0SFrançois Tigeot 		return;
2929edbd4a0SFrançois Tigeot 
2939edbd4a0SFrançois Tigeot 	dev_priv->gt_irq_mask &= ~interrupt_mask;
2949edbd4a0SFrançois Tigeot 	dev_priv->gt_irq_mask |= (~enabled_irq_mask & interrupt_mask);
2959edbd4a0SFrançois Tigeot 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
2969edbd4a0SFrançois Tigeot }
2979edbd4a0SFrançois Tigeot 
gen5_enable_gt_irq(struct drm_i915_private * dev_priv,uint32_t mask)29824edb884SFrançois Tigeot void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask)
2999edbd4a0SFrançois Tigeot {
3009edbd4a0SFrançois Tigeot 	ilk_update_gt_irq(dev_priv, mask, mask);
301bf017597SFrançois Tigeot 	POSTING_READ_FW(GTIMR);
3029edbd4a0SFrançois Tigeot }
3039edbd4a0SFrançois Tigeot 
gen5_disable_gt_irq(struct drm_i915_private * dev_priv,uint32_t mask)30424edb884SFrançois Tigeot void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask)
3059edbd4a0SFrançois Tigeot {
3069edbd4a0SFrançois Tigeot 	ilk_update_gt_irq(dev_priv, mask, 0);
3079edbd4a0SFrançois Tigeot }
3089edbd4a0SFrançois Tigeot 
gen6_pm_iir(struct drm_i915_private * dev_priv)309aee94f86SFrançois Tigeot static i915_reg_t gen6_pm_iir(struct drm_i915_private *dev_priv)
3102c9916cdSFrançois Tigeot {
311*3f2dd94aSFrançois Tigeot 	return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IIR(2) : GEN6_PMIIR;
3122c9916cdSFrançois Tigeot }
3132c9916cdSFrançois Tigeot 
gen6_pm_imr(struct drm_i915_private * dev_priv)314aee94f86SFrançois Tigeot static i915_reg_t gen6_pm_imr(struct drm_i915_private *dev_priv)
3152c9916cdSFrançois Tigeot {
316*3f2dd94aSFrançois Tigeot 	return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IMR(2) : GEN6_PMIMR;
3172c9916cdSFrançois Tigeot }
3182c9916cdSFrançois Tigeot 
gen6_pm_ier(struct drm_i915_private * dev_priv)319aee94f86SFrançois Tigeot static i915_reg_t gen6_pm_ier(struct drm_i915_private *dev_priv)
3202c9916cdSFrançois Tigeot {
321*3f2dd94aSFrançois Tigeot 	return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IER(2) : GEN6_PMIER;
3222c9916cdSFrançois Tigeot }
3232c9916cdSFrançois Tigeot 
3249edbd4a0SFrançois Tigeot /**
3259edbd4a0SFrançois Tigeot  * snb_update_pm_irq - update GEN6_PMIMR
3269edbd4a0SFrançois Tigeot  * @dev_priv: driver private
3279edbd4a0SFrançois Tigeot  * @interrupt_mask: mask of interrupt bits to update
3289edbd4a0SFrançois Tigeot  * @enabled_irq_mask: mask of interrupt bits to enable
3299edbd4a0SFrançois Tigeot  */
snb_update_pm_irq(struct drm_i915_private * dev_priv,uint32_t interrupt_mask,uint32_t enabled_irq_mask)3309edbd4a0SFrançois Tigeot static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
3319edbd4a0SFrançois Tigeot 			      uint32_t interrupt_mask,
3329edbd4a0SFrançois Tigeot 			      uint32_t enabled_irq_mask)
3339edbd4a0SFrançois Tigeot {
3349edbd4a0SFrançois Tigeot 	uint32_t new_val;
3359edbd4a0SFrançois Tigeot 
3362c9916cdSFrançois Tigeot 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
3379edbd4a0SFrançois Tigeot 
338a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
3399edbd4a0SFrançois Tigeot 
3404be47400SFrançois Tigeot 	new_val = dev_priv->pm_imr;
3419edbd4a0SFrançois Tigeot 	new_val &= ~interrupt_mask;
3429edbd4a0SFrançois Tigeot 	new_val |= (~enabled_irq_mask & interrupt_mask);
3439edbd4a0SFrançois Tigeot 
3444be47400SFrançois Tigeot 	if (new_val != dev_priv->pm_imr) {
3454be47400SFrançois Tigeot 		dev_priv->pm_imr = new_val;
3464be47400SFrançois Tigeot 		I915_WRITE(gen6_pm_imr(dev_priv), dev_priv->pm_imr);
3472c9916cdSFrançois Tigeot 		POSTING_READ(gen6_pm_imr(dev_priv));
3489edbd4a0SFrançois Tigeot 	}
3499edbd4a0SFrançois Tigeot }
3509edbd4a0SFrançois Tigeot 
gen6_unmask_pm_irq(struct drm_i915_private * dev_priv,u32 mask)3514be47400SFrançois Tigeot void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
3529edbd4a0SFrançois Tigeot {
3532c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
3542c9916cdSFrançois Tigeot 		return;
3552c9916cdSFrançois Tigeot 
3569edbd4a0SFrançois Tigeot 	snb_update_pm_irq(dev_priv, mask, mask);
3579edbd4a0SFrançois Tigeot }
3589edbd4a0SFrançois Tigeot 
__gen6_mask_pm_irq(struct drm_i915_private * dev_priv,u32 mask)3594be47400SFrançois Tigeot static void __gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
3609edbd4a0SFrançois Tigeot {
3619edbd4a0SFrançois Tigeot 	snb_update_pm_irq(dev_priv, mask, 0);
3629edbd4a0SFrançois Tigeot }
3639edbd4a0SFrançois Tigeot 
gen6_mask_pm_irq(struct drm_i915_private * dev_priv,u32 mask)3644be47400SFrançois Tigeot void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
3655d0b1887SFrançois Tigeot {
36624edb884SFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
367ba55f2f5SFrançois Tigeot 		return;
368ba55f2f5SFrançois Tigeot 
3694be47400SFrançois Tigeot 	__gen6_mask_pm_irq(dev_priv, mask);
3704be47400SFrançois Tigeot }
3714be47400SFrançois Tigeot 
gen6_reset_pm_iir(struct drm_i915_private * dev_priv,u32 reset_mask)372*3f2dd94aSFrançois Tigeot static void gen6_reset_pm_iir(struct drm_i915_private *dev_priv, u32 reset_mask)
3734be47400SFrançois Tigeot {
3744be47400SFrançois Tigeot 	i915_reg_t reg = gen6_pm_iir(dev_priv);
3754be47400SFrançois Tigeot 
376a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
3774be47400SFrançois Tigeot 
3784be47400SFrançois Tigeot 	I915_WRITE(reg, reset_mask);
3794be47400SFrançois Tigeot 	I915_WRITE(reg, reset_mask);
3804be47400SFrançois Tigeot 	POSTING_READ(reg);
3814be47400SFrançois Tigeot }
3824be47400SFrançois Tigeot 
gen6_enable_pm_irq(struct drm_i915_private * dev_priv,u32 enable_mask)383*3f2dd94aSFrançois Tigeot static void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, u32 enable_mask)
3844be47400SFrançois Tigeot {
385a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
3864be47400SFrançois Tigeot 
3874be47400SFrançois Tigeot 	dev_priv->pm_ier |= enable_mask;
3884be47400SFrançois Tigeot 	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier);
3894be47400SFrançois Tigeot 	gen6_unmask_pm_irq(dev_priv, enable_mask);
3904be47400SFrançois Tigeot 	/* unmask_pm_irq provides an implicit barrier (POSTING_READ) */
3914be47400SFrançois Tigeot }
3924be47400SFrançois Tigeot 
gen6_disable_pm_irq(struct drm_i915_private * dev_priv,u32 disable_mask)393*3f2dd94aSFrançois Tigeot static void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, u32 disable_mask)
3944be47400SFrançois Tigeot {
395a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
3964be47400SFrançois Tigeot 
3974be47400SFrançois Tigeot 	dev_priv->pm_ier &= ~disable_mask;
3984be47400SFrançois Tigeot 	__gen6_mask_pm_irq(dev_priv, disable_mask);
3994be47400SFrançois Tigeot 	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier);
4004be47400SFrançois Tigeot 	/* though a barrier is missing here, but don't really need a one */
401ba55f2f5SFrançois Tigeot }
402ba55f2f5SFrançois Tigeot 
gen6_reset_rps_interrupts(struct drm_i915_private * dev_priv)4031487f786SFrançois Tigeot void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv)
4045d0b1887SFrançois Tigeot {
4055e269720SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
4064be47400SFrançois Tigeot 	gen6_reset_pm_iir(dev_priv, dev_priv->pm_rps_events);
407*3f2dd94aSFrançois Tigeot 	dev_priv->gt_pm.rps.pm_iir = 0;
4085e269720SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
4095d0b1887SFrançois Tigeot }
4105d0b1887SFrançois Tigeot 
gen6_enable_rps_interrupts(struct drm_i915_private * dev_priv)4111487f786SFrançois Tigeot void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv)
412ba55f2f5SFrançois Tigeot {
413*3f2dd94aSFrançois Tigeot 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
414*3f2dd94aSFrançois Tigeot 
415*3f2dd94aSFrançois Tigeot 	if (READ_ONCE(rps->interrupts_enabled))
4161e12ee3bSFrançois Tigeot 		return;
4171e12ee3bSFrançois Tigeot 
4185e269720SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
419*3f2dd94aSFrançois Tigeot 	WARN_ON_ONCE(rps->pm_iir);
420303bf270SFrançois Tigeot 	WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events);
421*3f2dd94aSFrançois Tigeot 	rps->interrupts_enabled = true;
4222c9916cdSFrançois Tigeot 	gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
423ba55f2f5SFrançois Tigeot 
4245e269720SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
425ba55f2f5SFrançois Tigeot }
426ba55f2f5SFrançois Tigeot 
gen6_disable_rps_interrupts(struct drm_i915_private * dev_priv)4271487f786SFrançois Tigeot void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
4285d0b1887SFrançois Tigeot {
429*3f2dd94aSFrançois Tigeot 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
430*3f2dd94aSFrançois Tigeot 
431*3f2dd94aSFrançois Tigeot 	if (!READ_ONCE(rps->interrupts_enabled))
4321e12ee3bSFrançois Tigeot 		return;
4331e12ee3bSFrançois Tigeot 
4345e269720SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
435*3f2dd94aSFrançois Tigeot 	rps->interrupts_enabled = false;
4362c9916cdSFrançois Tigeot 
4371e12ee3bSFrançois Tigeot 	I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0u));
4382c9916cdSFrançois Tigeot 
4394be47400SFrançois Tigeot 	gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
4402c9916cdSFrançois Tigeot 
4415e269720SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
442303bf270SFrançois Tigeot 	synchronize_irq(dev_priv->drm.irq);
443477eb7f9SFrançois Tigeot 
444303bf270SFrançois Tigeot 	/* Now that we will not be generating any more work, flush any
445*3f2dd94aSFrançois Tigeot 	 * outstanding tasks. As we are called on the RPS idle path,
446303bf270SFrançois Tigeot 	 * we will reset the GPU to minimum frequencies, so the current
447303bf270SFrançois Tigeot 	 * state of the worker can be discarded.
448303bf270SFrançois Tigeot 	 */
449*3f2dd94aSFrançois Tigeot 	cancel_work_sync(&rps->work);
450303bf270SFrançois Tigeot 	gen6_reset_rps_interrupts(dev_priv);
4519edbd4a0SFrançois Tigeot }
4525d0b1887SFrançois Tigeot 
gen9_reset_guc_interrupts(struct drm_i915_private * dev_priv)4534be47400SFrançois Tigeot void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv)
4544be47400SFrançois Tigeot {
4554be47400SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
4564be47400SFrançois Tigeot 	gen6_reset_pm_iir(dev_priv, dev_priv->pm_guc_events);
4574be47400SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
4584be47400SFrançois Tigeot }
4594be47400SFrançois Tigeot 
gen9_enable_guc_interrupts(struct drm_i915_private * dev_priv)4604be47400SFrançois Tigeot void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv)
4614be47400SFrançois Tigeot {
4624be47400SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
4634be47400SFrançois Tigeot 	if (!dev_priv->guc.interrupts_enabled) {
4644be47400SFrançois Tigeot 		WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) &
4654be47400SFrançois Tigeot 				       dev_priv->pm_guc_events);
4664be47400SFrançois Tigeot 		dev_priv->guc.interrupts_enabled = true;
4674be47400SFrançois Tigeot 		gen6_enable_pm_irq(dev_priv, dev_priv->pm_guc_events);
4684be47400SFrançois Tigeot 	}
4694be47400SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
4704be47400SFrançois Tigeot }
4714be47400SFrançois Tigeot 
gen9_disable_guc_interrupts(struct drm_i915_private * dev_priv)4724be47400SFrançois Tigeot void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv)
4734be47400SFrançois Tigeot {
4744be47400SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
4754be47400SFrançois Tigeot 	dev_priv->guc.interrupts_enabled = false;
4764be47400SFrançois Tigeot 
4774be47400SFrançois Tigeot 	gen6_disable_pm_irq(dev_priv, dev_priv->pm_guc_events);
4784be47400SFrançois Tigeot 
4794be47400SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
4804be47400SFrançois Tigeot 	synchronize_irq(dev_priv->drm.irq);
4814be47400SFrançois Tigeot 
4824be47400SFrançois Tigeot 	gen9_reset_guc_interrupts(dev_priv);
4834be47400SFrançois Tigeot }
4844be47400SFrançois Tigeot 
4859edbd4a0SFrançois Tigeot /**
486352ff8bdSFrançois Tigeot  * bdw_update_port_irq - update DE port interrupt
487352ff8bdSFrançois Tigeot  * @dev_priv: driver private
488352ff8bdSFrançois Tigeot  * @interrupt_mask: mask of interrupt bits to update
489352ff8bdSFrançois Tigeot  * @enabled_irq_mask: mask of interrupt bits to enable
490352ff8bdSFrançois Tigeot  */
bdw_update_port_irq(struct drm_i915_private * dev_priv,uint32_t interrupt_mask,uint32_t enabled_irq_mask)491352ff8bdSFrançois Tigeot static void bdw_update_port_irq(struct drm_i915_private *dev_priv,
492352ff8bdSFrançois Tigeot 				uint32_t interrupt_mask,
493352ff8bdSFrançois Tigeot 				uint32_t enabled_irq_mask)
494352ff8bdSFrançois Tigeot {
495352ff8bdSFrançois Tigeot 	uint32_t new_val;
496352ff8bdSFrançois Tigeot 	uint32_t old_val;
497352ff8bdSFrançois Tigeot 
498a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
499352ff8bdSFrançois Tigeot 
500352ff8bdSFrançois Tigeot 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
501352ff8bdSFrançois Tigeot 
502352ff8bdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
503352ff8bdSFrançois Tigeot 		return;
504352ff8bdSFrançois Tigeot 
505352ff8bdSFrançois Tigeot 	old_val = I915_READ(GEN8_DE_PORT_IMR);
506352ff8bdSFrançois Tigeot 
507352ff8bdSFrançois Tigeot 	new_val = old_val;
508352ff8bdSFrançois Tigeot 	new_val &= ~interrupt_mask;
509352ff8bdSFrançois Tigeot 	new_val |= (~enabled_irq_mask & interrupt_mask);
510352ff8bdSFrançois Tigeot 
511352ff8bdSFrançois Tigeot 	if (new_val != old_val) {
512352ff8bdSFrançois Tigeot 		I915_WRITE(GEN8_DE_PORT_IMR, new_val);
513352ff8bdSFrançois Tigeot 		POSTING_READ(GEN8_DE_PORT_IMR);
514352ff8bdSFrançois Tigeot 	}
515352ff8bdSFrançois Tigeot }
516352ff8bdSFrançois Tigeot 
517352ff8bdSFrançois Tigeot /**
518aee94f86SFrançois Tigeot  * bdw_update_pipe_irq - update DE pipe interrupt
519aee94f86SFrançois Tigeot  * @dev_priv: driver private
520aee94f86SFrançois Tigeot  * @pipe: pipe whose interrupt to update
521aee94f86SFrançois Tigeot  * @interrupt_mask: mask of interrupt bits to update
522aee94f86SFrançois Tigeot  * @enabled_irq_mask: mask of interrupt bits to enable
523aee94f86SFrançois Tigeot  */
bdw_update_pipe_irq(struct drm_i915_private * dev_priv,enum i915_pipe pipe,uint32_t interrupt_mask,uint32_t enabled_irq_mask)524aee94f86SFrançois Tigeot void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
525aee94f86SFrançois Tigeot 			 enum i915_pipe pipe,
526aee94f86SFrançois Tigeot 			 uint32_t interrupt_mask,
527aee94f86SFrançois Tigeot 			 uint32_t enabled_irq_mask)
528aee94f86SFrançois Tigeot {
529aee94f86SFrançois Tigeot 	uint32_t new_val;
530aee94f86SFrançois Tigeot 
531a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
532aee94f86SFrançois Tigeot 
533aee94f86SFrançois Tigeot 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
534aee94f86SFrançois Tigeot 
535aee94f86SFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
536aee94f86SFrançois Tigeot 		return;
537aee94f86SFrançois Tigeot 
538aee94f86SFrançois Tigeot 	new_val = dev_priv->de_irq_mask[pipe];
539aee94f86SFrançois Tigeot 	new_val &= ~interrupt_mask;
540aee94f86SFrançois Tigeot 	new_val |= (~enabled_irq_mask & interrupt_mask);
541aee94f86SFrançois Tigeot 
542aee94f86SFrançois Tigeot 	if (new_val != dev_priv->de_irq_mask[pipe]) {
543aee94f86SFrançois Tigeot 		dev_priv->de_irq_mask[pipe] = new_val;
544aee94f86SFrançois Tigeot 		I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
545aee94f86SFrançois Tigeot 		POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
546aee94f86SFrançois Tigeot 	}
547aee94f86SFrançois Tigeot }
548aee94f86SFrançois Tigeot 
549aee94f86SFrançois Tigeot /**
5509edbd4a0SFrançois Tigeot  * ibx_display_interrupt_update - update SDEIMR
5519edbd4a0SFrançois Tigeot  * @dev_priv: driver private
5529edbd4a0SFrançois Tigeot  * @interrupt_mask: mask of interrupt bits to update
5539edbd4a0SFrançois Tigeot  * @enabled_irq_mask: mask of interrupt bits to enable
5549edbd4a0SFrançois Tigeot  */
ibx_display_interrupt_update(struct drm_i915_private * dev_priv,uint32_t interrupt_mask,uint32_t enabled_irq_mask)5552c9916cdSFrançois Tigeot void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
5569edbd4a0SFrançois Tigeot 				  uint32_t interrupt_mask,
5579edbd4a0SFrançois Tigeot 				  uint32_t enabled_irq_mask)
5589edbd4a0SFrançois Tigeot {
5599edbd4a0SFrançois Tigeot 	uint32_t sdeimr = I915_READ(SDEIMR);
5609edbd4a0SFrançois Tigeot 	sdeimr &= ~interrupt_mask;
5619edbd4a0SFrançois Tigeot 	sdeimr |= (~enabled_irq_mask & interrupt_mask);
5629edbd4a0SFrançois Tigeot 
5632c9916cdSFrançois Tigeot 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
5642c9916cdSFrançois Tigeot 
565a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
5669edbd4a0SFrançois Tigeot 
56724edb884SFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
5689edbd4a0SFrançois Tigeot 		return;
5699edbd4a0SFrançois Tigeot 
5709edbd4a0SFrançois Tigeot 	I915_WRITE(SDEIMR, sdeimr);
5715d0b1887SFrançois Tigeot 	POSTING_READ(SDEIMR);
5725d0b1887SFrançois Tigeot }
5735d0b1887SFrançois Tigeot 
i915_pipestat_enable_mask(struct drm_i915_private * dev_priv,enum i915_pipe pipe)574*3f2dd94aSFrançois Tigeot u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv,
575*3f2dd94aSFrançois Tigeot 			      enum i915_pipe pipe)
576c4a9e910SFrançois Tigeot {
577*3f2dd94aSFrançois Tigeot 	u32 status_mask = dev_priv->pipestat_irq_mask[pipe];
578ba55f2f5SFrançois Tigeot 	u32 enable_mask = status_mask << 16;
579ba55f2f5SFrançois Tigeot 
580*3f2dd94aSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
581*3f2dd94aSFrançois Tigeot 
582*3f2dd94aSFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 5)
583*3f2dd94aSFrançois Tigeot 		goto out;
584*3f2dd94aSFrançois Tigeot 
585ba55f2f5SFrançois Tigeot 	/*
586ba55f2f5SFrançois Tigeot 	 * On pipe A we don't support the PSR interrupt yet,
587ba55f2f5SFrançois Tigeot 	 * on pipe B and C the same bit MBZ.
588ba55f2f5SFrançois Tigeot 	 */
589ba55f2f5SFrançois Tigeot 	if (WARN_ON_ONCE(status_mask & PIPE_A_PSR_STATUS_VLV))
590ba55f2f5SFrançois Tigeot 		return 0;
591ba55f2f5SFrançois Tigeot 	/*
592ba55f2f5SFrançois Tigeot 	 * On pipe B and C we don't support the PSR interrupt yet, on pipe
593ba55f2f5SFrançois Tigeot 	 * A the same bit is for perf counters which we don't use either.
594ba55f2f5SFrançois Tigeot 	 */
595ba55f2f5SFrançois Tigeot 	if (WARN_ON_ONCE(status_mask & PIPE_B_PSR_STATUS_VLV))
596ba55f2f5SFrançois Tigeot 		return 0;
597ba55f2f5SFrançois Tigeot 
598ba55f2f5SFrançois Tigeot 	enable_mask &= ~(PIPE_FIFO_UNDERRUN_STATUS |
599ba55f2f5SFrançois Tigeot 			 SPRITE0_FLIP_DONE_INT_EN_VLV |
600ba55f2f5SFrançois Tigeot 			 SPRITE1_FLIP_DONE_INT_EN_VLV);
601ba55f2f5SFrançois Tigeot 	if (status_mask & SPRITE0_FLIP_DONE_INT_STATUS_VLV)
602ba55f2f5SFrançois Tigeot 		enable_mask |= SPRITE0_FLIP_DONE_INT_EN_VLV;
603ba55f2f5SFrançois Tigeot 	if (status_mask & SPRITE1_FLIP_DONE_INT_STATUS_VLV)
604ba55f2f5SFrançois Tigeot 		enable_mask |= SPRITE1_FLIP_DONE_INT_EN_VLV;
605ba55f2f5SFrançois Tigeot 
606*3f2dd94aSFrançois Tigeot out:
607*3f2dd94aSFrançois Tigeot 	WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
608*3f2dd94aSFrançois Tigeot 		  status_mask & ~PIPESTAT_INT_STATUS_MASK,
609*3f2dd94aSFrançois Tigeot 		  "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
610*3f2dd94aSFrançois Tigeot 		  pipe_name(pipe), enable_mask, status_mask);
611*3f2dd94aSFrançois Tigeot 
612ba55f2f5SFrançois Tigeot 	return enable_mask;
613ba55f2f5SFrançois Tigeot }
614ba55f2f5SFrançois Tigeot 
i915_enable_pipestat(struct drm_i915_private * dev_priv,enum i915_pipe pipe,u32 status_mask)615*3f2dd94aSFrançois Tigeot void i915_enable_pipestat(struct drm_i915_private *dev_priv,
616*3f2dd94aSFrançois Tigeot 			  enum i915_pipe pipe, u32 status_mask)
617ba55f2f5SFrançois Tigeot {
618*3f2dd94aSFrançois Tigeot 	i915_reg_t reg = PIPESTAT(pipe);
619ba55f2f5SFrançois Tigeot 	u32 enable_mask;
620ba55f2f5SFrançois Tigeot 
621*3f2dd94aSFrançois Tigeot 	WARN_ONCE(status_mask & ~PIPESTAT_INT_STATUS_MASK,
622*3f2dd94aSFrançois Tigeot 		  "pipe %c: status_mask=0x%x\n",
623*3f2dd94aSFrançois Tigeot 		  pipe_name(pipe), status_mask);
624*3f2dd94aSFrançois Tigeot 
625*3f2dd94aSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
626*3f2dd94aSFrançois Tigeot 	WARN_ON(!intel_irqs_enabled(dev_priv));
627*3f2dd94aSFrançois Tigeot 
628*3f2dd94aSFrançois Tigeot 	if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == status_mask)
629*3f2dd94aSFrançois Tigeot 		return;
630*3f2dd94aSFrançois Tigeot 
631*3f2dd94aSFrançois Tigeot 	dev_priv->pipestat_irq_mask[pipe] |= status_mask;
632*3f2dd94aSFrançois Tigeot 	enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
633*3f2dd94aSFrançois Tigeot 
634*3f2dd94aSFrançois Tigeot 	I915_WRITE(reg, enable_mask | status_mask);
635*3f2dd94aSFrançois Tigeot 	POSTING_READ(reg);
636ba55f2f5SFrançois Tigeot }
637ba55f2f5SFrançois Tigeot 
i915_disable_pipestat(struct drm_i915_private * dev_priv,enum i915_pipe pipe,u32 status_mask)638*3f2dd94aSFrançois Tigeot void i915_disable_pipestat(struct drm_i915_private *dev_priv,
639*3f2dd94aSFrançois Tigeot 			   enum i915_pipe pipe, u32 status_mask)
640ba55f2f5SFrançois Tigeot {
641*3f2dd94aSFrançois Tigeot 	i915_reg_t reg = PIPESTAT(pipe);
642ba55f2f5SFrançois Tigeot 	u32 enable_mask;
643ba55f2f5SFrançois Tigeot 
644*3f2dd94aSFrançois Tigeot 	WARN_ONCE(status_mask & ~PIPESTAT_INT_STATUS_MASK,
645*3f2dd94aSFrançois Tigeot 		  "pipe %c: status_mask=0x%x\n",
646*3f2dd94aSFrançois Tigeot 		  pipe_name(pipe), status_mask);
647*3f2dd94aSFrançois Tigeot 
648*3f2dd94aSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
649*3f2dd94aSFrançois Tigeot 	WARN_ON(!intel_irqs_enabled(dev_priv));
650*3f2dd94aSFrançois Tigeot 
651*3f2dd94aSFrançois Tigeot 	if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == 0)
652*3f2dd94aSFrançois Tigeot 		return;
653*3f2dd94aSFrançois Tigeot 
654*3f2dd94aSFrançois Tigeot 	dev_priv->pipestat_irq_mask[pipe] &= ~status_mask;
655*3f2dd94aSFrançois Tigeot 	enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
656*3f2dd94aSFrançois Tigeot 
657*3f2dd94aSFrançois Tigeot 	I915_WRITE(reg, enable_mask | status_mask);
658*3f2dd94aSFrançois Tigeot 	POSTING_READ(reg);
659ba55f2f5SFrançois Tigeot }
660ba55f2f5SFrançois Tigeot 
661c4a9e910SFrançois Tigeot /**
6625d0b1887SFrançois Tigeot  * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
6631487f786SFrançois Tigeot  * @dev_priv: i915 device private
664e3adcf8fSFrançois Tigeot  */
i915_enable_asle_pipestat(struct drm_i915_private * dev_priv)6651487f786SFrançois Tigeot static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
666e3adcf8fSFrançois Tigeot {
6671487f786SFrançois Tigeot 	if (!dev_priv->opregion.asle || !IS_MOBILE(dev_priv))
66800640ec9SFrançois Tigeot 		return;
66900640ec9SFrançois Tigeot 
6705e269720SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
671e3adcf8fSFrançois Tigeot 
672ba55f2f5SFrançois Tigeot 	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_STATUS);
6731487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 4)
6749edbd4a0SFrançois Tigeot 		i915_enable_pipestat(dev_priv, PIPE_A,
675ba55f2f5SFrançois Tigeot 				     PIPE_LEGACY_BLC_EVENT_STATUS);
676e3adcf8fSFrançois Tigeot 
6775e269720SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
678e3adcf8fSFrançois Tigeot }
679e3adcf8fSFrançois Tigeot 
680ba55f2f5SFrançois Tigeot /*
681ba55f2f5SFrançois Tigeot  * This timing diagram depicts the video signal in and
682ba55f2f5SFrançois Tigeot  * around the vertical blanking period.
683ba55f2f5SFrançois Tigeot  *
684ba55f2f5SFrançois Tigeot  * Assumptions about the fictitious mode used in this example:
685ba55f2f5SFrançois Tigeot  *  vblank_start >= 3
686ba55f2f5SFrançois Tigeot  *  vsync_start = vblank_start + 1
687ba55f2f5SFrançois Tigeot  *  vsync_end = vblank_start + 2
688ba55f2f5SFrançois Tigeot  *  vtotal = vblank_start + 3
689ba55f2f5SFrançois Tigeot  *
690ba55f2f5SFrançois Tigeot  *           start of vblank:
691ba55f2f5SFrançois Tigeot  *           latch double buffered registers
692ba55f2f5SFrançois Tigeot  *           increment frame counter (ctg+)
693ba55f2f5SFrançois Tigeot  *           generate start of vblank interrupt (gen4+)
694ba55f2f5SFrançois Tigeot  *           |
695ba55f2f5SFrançois Tigeot  *           |          frame start:
696ba55f2f5SFrançois Tigeot  *           |          generate frame start interrupt (aka. vblank interrupt) (gmch)
697ba55f2f5SFrançois Tigeot  *           |          may be shifted forward 1-3 extra lines via PIPECONF
698ba55f2f5SFrançois Tigeot  *           |          |
699ba55f2f5SFrançois Tigeot  *           |          |  start of vsync:
700ba55f2f5SFrançois Tigeot  *           |          |  generate vsync interrupt
701ba55f2f5SFrançois Tigeot  *           |          |  |
702ba55f2f5SFrançois Tigeot  * ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx
703ba55f2f5SFrançois Tigeot  *       .   \hs/   .      \hs/          \hs/          \hs/   .      \hs/
704ba55f2f5SFrançois Tigeot  * ----va---> <-----------------vb--------------------> <--------va-------------
705ba55f2f5SFrançois Tigeot  *       |          |       <----vs----->                     |
706ba55f2f5SFrançois Tigeot  * -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2)
707ba55f2f5SFrançois Tigeot  * -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+)
708ba55f2f5SFrançois Tigeot  * -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi)
709ba55f2f5SFrançois Tigeot  *       |          |                                         |
710ba55f2f5SFrançois Tigeot  *       last visible pixel                                   first visible pixel
711ba55f2f5SFrançois Tigeot  *                  |                                         increment frame counter (gen3/4)
712ba55f2f5SFrançois Tigeot  *                  pixel counter = vblank_start * htotal     pixel counter = 0 (gen3/4)
713ba55f2f5SFrançois Tigeot  *
714ba55f2f5SFrançois Tigeot  * x  = horizontal active
715ba55f2f5SFrançois Tigeot  * _  = horizontal blanking
716ba55f2f5SFrançois Tigeot  * hs = horizontal sync
717ba55f2f5SFrançois Tigeot  * va = vertical active
718ba55f2f5SFrançois Tigeot  * vb = vertical blanking
719ba55f2f5SFrançois Tigeot  * vs = vertical sync
720ba55f2f5SFrançois Tigeot  * vbs = vblank_start (number)
721ba55f2f5SFrançois Tigeot  *
722ba55f2f5SFrançois Tigeot  * Summary:
723ba55f2f5SFrançois Tigeot  * - most events happen at the start of horizontal sync
724ba55f2f5SFrançois Tigeot  * - frame start happens at the start of horizontal blank, 1-4 lines
725ba55f2f5SFrançois Tigeot  *   (depending on PIPECONF settings) after the start of vblank
726ba55f2f5SFrançois Tigeot  * - gen3/4 pixel and frame counter are synchronized with the start
727ba55f2f5SFrançois Tigeot  *   of horizontal active on the first line of vertical active
728ba55f2f5SFrançois Tigeot  */
729ba55f2f5SFrançois Tigeot 
730c4a9e910SFrançois Tigeot /* Called from drm generic code, passed a 'crtc', which
731c4a9e910SFrançois Tigeot  * we use as a pipe index
732c4a9e910SFrançois Tigeot  */
i915_get_vblank_counter(struct drm_device * dev,unsigned int pipe)733352ff8bdSFrançois Tigeot static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
734c4a9e910SFrançois Tigeot {
735303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
736aee94f86SFrançois Tigeot 	i915_reg_t high_frame, low_frame;
737ba55f2f5SFrançois Tigeot 	u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
738*3f2dd94aSFrançois Tigeot 	const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
739a85cb24fSFrançois Tigeot 	unsigned long irqflags;
7409edbd4a0SFrançois Tigeot 
741ba55f2f5SFrançois Tigeot 	htotal = mode->crtc_htotal;
742ba55f2f5SFrançois Tigeot 	hsync_start = mode->crtc_hsync_start;
743ba55f2f5SFrançois Tigeot 	vbl_start = mode->crtc_vblank_start;
744ba55f2f5SFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
745ba55f2f5SFrançois Tigeot 		vbl_start = DIV_ROUND_UP(vbl_start, 2);
7469edbd4a0SFrançois Tigeot 
747ba55f2f5SFrançois Tigeot 	/* Convert to pixel count */
748ba55f2f5SFrançois Tigeot 	vbl_start *= htotal;
749ba55f2f5SFrançois Tigeot 
750ba55f2f5SFrançois Tigeot 	/* Start of vblank event occurs at start of hsync */
751ba55f2f5SFrançois Tigeot 	vbl_start -= htotal - hsync_start;
752ba55f2f5SFrançois Tigeot 
753e3adcf8fSFrançois Tigeot 	high_frame = PIPEFRAME(pipe);
754e3adcf8fSFrançois Tigeot 	low_frame = PIPEFRAMEPIXEL(pipe);
755e3adcf8fSFrançois Tigeot 
756a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
757a85cb24fSFrançois Tigeot 
758c4a9e910SFrançois Tigeot 	/*
759c4a9e910SFrançois Tigeot 	 * High & low register fields aren't synchronized, so make sure
760c4a9e910SFrançois Tigeot 	 * we get a low value that's stable across two reads of the high
761c4a9e910SFrançois Tigeot 	 * register.
762c4a9e910SFrançois Tigeot 	 */
763c4a9e910SFrançois Tigeot 	do {
764a85cb24fSFrançois Tigeot 		high1 = I915_READ_FW(high_frame) & PIPE_FRAME_HIGH_MASK;
765a85cb24fSFrançois Tigeot 		low   = I915_READ_FW(low_frame);
766a85cb24fSFrançois Tigeot 		high2 = I915_READ_FW(high_frame) & PIPE_FRAME_HIGH_MASK;
767c4a9e910SFrançois Tigeot 	} while (high1 != high2);
768c4a9e910SFrançois Tigeot 
769a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
770a85cb24fSFrançois Tigeot 
771e3adcf8fSFrançois Tigeot 	high1 >>= PIPE_FRAME_HIGH_SHIFT;
7729edbd4a0SFrançois Tigeot 	pixel = low & PIPE_PIXEL_MASK;
773e3adcf8fSFrançois Tigeot 	low >>= PIPE_FRAME_LOW_SHIFT;
7749edbd4a0SFrançois Tigeot 
7759edbd4a0SFrançois Tigeot 	/*
7769edbd4a0SFrançois Tigeot 	 * The frame counter increments at beginning of active.
7779edbd4a0SFrançois Tigeot 	 * Cook up a vblank counter by also checking the pixel
7789edbd4a0SFrançois Tigeot 	 * counter against vblank start.
7799edbd4a0SFrançois Tigeot 	 */
7809edbd4a0SFrançois Tigeot 	return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff;
781c4a9e910SFrançois Tigeot }
782c4a9e910SFrançois Tigeot 
g4x_get_vblank_counter(struct drm_device * dev,unsigned int pipe)783352ff8bdSFrançois Tigeot static u32 g4x_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
784c4a9e910SFrançois Tigeot {
785303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
786c4a9e910SFrançois Tigeot 
787352ff8bdSFrançois Tigeot 	return I915_READ(PIPE_FRMCOUNT_G4X(pipe));
788c4a9e910SFrançois Tigeot }
789c4a9e910SFrançois Tigeot 
790*3f2dd94aSFrançois Tigeot /*
791*3f2dd94aSFrançois Tigeot  * On certain encoders on certain platforms, pipe
792*3f2dd94aSFrançois Tigeot  * scanline register will not work to get the scanline,
793*3f2dd94aSFrançois Tigeot  * since the timings are driven from the PORT or issues
794*3f2dd94aSFrançois Tigeot  * with scanline register updates.
795*3f2dd94aSFrançois Tigeot  * This function will use Framestamp and current
796*3f2dd94aSFrançois Tigeot  * timestamp registers to calculate the scanline.
797*3f2dd94aSFrançois Tigeot  */
__intel_get_crtc_scanline_from_timestamp(struct intel_crtc * crtc)798*3f2dd94aSFrançois Tigeot static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
799*3f2dd94aSFrançois Tigeot {
800*3f2dd94aSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
801*3f2dd94aSFrançois Tigeot 	struct drm_vblank_crtc *vblank =
802*3f2dd94aSFrançois Tigeot 		&crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
803*3f2dd94aSFrançois Tigeot 	const struct drm_display_mode *mode = &vblank->hwmode;
804*3f2dd94aSFrançois Tigeot 	u32 vblank_start = mode->crtc_vblank_start;
805*3f2dd94aSFrançois Tigeot 	u32 vtotal = mode->crtc_vtotal;
806*3f2dd94aSFrançois Tigeot 	u32 htotal = mode->crtc_htotal;
807*3f2dd94aSFrançois Tigeot 	u32 clock = mode->crtc_clock;
808*3f2dd94aSFrançois Tigeot 	u32 scanline, scan_prev_time, scan_curr_time, scan_post_time;
809*3f2dd94aSFrançois Tigeot 
810*3f2dd94aSFrançois Tigeot 	/*
811*3f2dd94aSFrançois Tigeot 	 * To avoid the race condition where we might cross into the
812*3f2dd94aSFrançois Tigeot 	 * next vblank just between the PIPE_FRMTMSTMP and TIMESTAMP_CTR
813*3f2dd94aSFrançois Tigeot 	 * reads. We make sure we read PIPE_FRMTMSTMP and TIMESTAMP_CTR
814*3f2dd94aSFrançois Tigeot 	 * during the same frame.
815*3f2dd94aSFrançois Tigeot 	 */
816*3f2dd94aSFrançois Tigeot 	do {
817*3f2dd94aSFrançois Tigeot 		/*
818*3f2dd94aSFrançois Tigeot 		 * This field provides read back of the display
819*3f2dd94aSFrançois Tigeot 		 * pipe frame time stamp. The time stamp value
820*3f2dd94aSFrançois Tigeot 		 * is sampled at every start of vertical blank.
821*3f2dd94aSFrançois Tigeot 		 */
822*3f2dd94aSFrançois Tigeot 		scan_prev_time = I915_READ_FW(PIPE_FRMTMSTMP(crtc->pipe));
823*3f2dd94aSFrançois Tigeot 
824*3f2dd94aSFrançois Tigeot 		/*
825*3f2dd94aSFrançois Tigeot 		 * The TIMESTAMP_CTR register has the current
826*3f2dd94aSFrançois Tigeot 		 * time stamp value.
827*3f2dd94aSFrançois Tigeot 		 */
828*3f2dd94aSFrançois Tigeot 		scan_curr_time = I915_READ_FW(IVB_TIMESTAMP_CTR);
829*3f2dd94aSFrançois Tigeot 
830*3f2dd94aSFrançois Tigeot 		scan_post_time = I915_READ_FW(PIPE_FRMTMSTMP(crtc->pipe));
831*3f2dd94aSFrançois Tigeot 	} while (scan_post_time != scan_prev_time);
832*3f2dd94aSFrançois Tigeot 
833*3f2dd94aSFrançois Tigeot 	scanline = div_u64(mul_u32_u32(scan_curr_time - scan_prev_time,
834*3f2dd94aSFrançois Tigeot 					clock), 1000 * htotal);
835*3f2dd94aSFrançois Tigeot 	scanline = min(scanline, vtotal - 1);
836*3f2dd94aSFrançois Tigeot 	scanline = (scanline + vblank_start) % vtotal;
837*3f2dd94aSFrançois Tigeot 
838*3f2dd94aSFrançois Tigeot 	return scanline;
839*3f2dd94aSFrançois Tigeot }
840*3f2dd94aSFrançois Tigeot 
841aee94f86SFrançois Tigeot /* I915_READ_FW, only for fast reads of display block, no need for forcewake etc. */
__intel_get_crtc_scanline(struct intel_crtc * crtc)842ba55f2f5SFrançois Tigeot static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
8439edbd4a0SFrançois Tigeot {
844ba55f2f5SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
845303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
846*3f2dd94aSFrançois Tigeot 	const struct drm_display_mode *mode;
847*3f2dd94aSFrançois Tigeot 	struct drm_vblank_crtc *vblank;
848ba55f2f5SFrançois Tigeot 	enum i915_pipe pipe = crtc->pipe;
849ba55f2f5SFrançois Tigeot 	int position, vtotal;
8509edbd4a0SFrançois Tigeot 
851a85cb24fSFrançois Tigeot 	if (!crtc->active)
852a85cb24fSFrançois Tigeot 		return -1;
853a85cb24fSFrançois Tigeot 
854*3f2dd94aSFrançois Tigeot 	vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
855*3f2dd94aSFrançois Tigeot 	mode = &vblank->hwmode;
856*3f2dd94aSFrançois Tigeot 
857*3f2dd94aSFrançois Tigeot 	if (mode->private_flags & I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP)
858*3f2dd94aSFrançois Tigeot 		return __intel_get_crtc_scanline_from_timestamp(crtc);
859*3f2dd94aSFrançois Tigeot 
860ba55f2f5SFrançois Tigeot 	vtotal = mode->crtc_vtotal;
861ba55f2f5SFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
862ba55f2f5SFrançois Tigeot 		vtotal /= 2;
8639edbd4a0SFrançois Tigeot 
8641487f786SFrançois Tigeot 	if (IS_GEN2(dev_priv))
865aee94f86SFrançois Tigeot 		position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
866ba55f2f5SFrançois Tigeot 	else
867aee94f86SFrançois Tigeot 		position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
868ba55f2f5SFrançois Tigeot 
869ba55f2f5SFrançois Tigeot 	/*
870a05eeebfSFrançois Tigeot 	 * On HSW, the DSL reg (0x70000) appears to return 0 if we
871a05eeebfSFrançois Tigeot 	 * read it just before the start of vblank.  So try it again
872a05eeebfSFrançois Tigeot 	 * so we don't accidentally end up spanning a vblank frame
873a05eeebfSFrançois Tigeot 	 * increment, causing the pipe_update_end() code to squak at us.
874a05eeebfSFrançois Tigeot 	 *
875a05eeebfSFrançois Tigeot 	 * The nature of this problem means we can't simply check the ISR
876a05eeebfSFrançois Tigeot 	 * bit and return the vblank start value; nor can we use the scanline
877a05eeebfSFrançois Tigeot 	 * debug register in the transcoder as it appears to have the same
878a05eeebfSFrançois Tigeot 	 * problem.  We may need to extend this to include other platforms,
879a05eeebfSFrançois Tigeot 	 * but so far testing only shows the problem on HSW.
880a05eeebfSFrançois Tigeot 	 */
8811487f786SFrançois Tigeot 	if (HAS_DDI(dev_priv) && !position) {
882a05eeebfSFrançois Tigeot 		int i, temp;
883a05eeebfSFrançois Tigeot 
884a05eeebfSFrançois Tigeot 		for (i = 0; i < 100; i++) {
885a05eeebfSFrançois Tigeot 			udelay(1);
886a85cb24fSFrançois Tigeot 			temp = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
887a05eeebfSFrançois Tigeot 			if (temp != position) {
888a05eeebfSFrançois Tigeot 				position = temp;
889a05eeebfSFrançois Tigeot 				break;
890a05eeebfSFrançois Tigeot 			}
891a05eeebfSFrançois Tigeot 		}
892a05eeebfSFrançois Tigeot 	}
893a05eeebfSFrançois Tigeot 
894a05eeebfSFrançois Tigeot 	/*
895ba55f2f5SFrançois Tigeot 	 * See update_scanline_offset() for the details on the
896ba55f2f5SFrançois Tigeot 	 * scanline_offset adjustment.
897ba55f2f5SFrançois Tigeot 	 */
898ba55f2f5SFrançois Tigeot 	return (position + crtc->scanline_offset) % vtotal;
8999edbd4a0SFrançois Tigeot }
9009edbd4a0SFrançois Tigeot 
i915_get_crtc_scanoutpos(struct drm_device * dev,unsigned int pipe,bool in_vblank_irq,int * vpos,int * hpos,ktime_t * stime,ktime_t * etime,const struct drm_display_mode * mode)901*3f2dd94aSFrançois Tigeot static bool i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
902*3f2dd94aSFrançois Tigeot 				     bool in_vblank_irq, int *vpos, int *hpos,
903352ff8bdSFrançois Tigeot 				     ktime_t *stime, ktime_t *etime,
904352ff8bdSFrançois Tigeot 				     const struct drm_display_mode *mode)
905e3adcf8fSFrançois Tigeot {
906303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
9074be47400SFrançois Tigeot 	struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv,
9084be47400SFrançois Tigeot 								pipe);
9099edbd4a0SFrançois Tigeot 	int position;
910ba55f2f5SFrançois Tigeot 	int vbl_start, vbl_end, hsync_start, htotal, vtotal;
9115e269720SFrançois Tigeot 	unsigned long irqflags;
912e3adcf8fSFrançois Tigeot 
913a05eeebfSFrançois Tigeot 	if (WARN_ON(!mode->crtc_clock)) {
91400640ec9SFrançois Tigeot 		DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
915e3adcf8fSFrançois Tigeot 				 "pipe %c\n", pipe_name(pipe));
916*3f2dd94aSFrançois Tigeot 		return false;
917e3adcf8fSFrançois Tigeot 	}
918e3adcf8fSFrançois Tigeot 
9199edbd4a0SFrançois Tigeot 	htotal = mode->crtc_htotal;
920ba55f2f5SFrançois Tigeot 	hsync_start = mode->crtc_hsync_start;
9219edbd4a0SFrançois Tigeot 	vtotal = mode->crtc_vtotal;
9229edbd4a0SFrançois Tigeot 	vbl_start = mode->crtc_vblank_start;
9239edbd4a0SFrançois Tigeot 	vbl_end = mode->crtc_vblank_end;
924e3adcf8fSFrançois Tigeot 
9259edbd4a0SFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
9269edbd4a0SFrançois Tigeot 		vbl_start = DIV_ROUND_UP(vbl_start, 2);
9279edbd4a0SFrançois Tigeot 		vbl_end /= 2;
9289edbd4a0SFrançois Tigeot 		vtotal /= 2;
9299edbd4a0SFrançois Tigeot 	}
9309edbd4a0SFrançois Tigeot 
9319edbd4a0SFrançois Tigeot 	/*
9329edbd4a0SFrançois Tigeot 	 * Lock uncore.lock, as we will do multiple timing critical raw
9339edbd4a0SFrançois Tigeot 	 * register reads, potentially with preemption disabled, so the
9349edbd4a0SFrançois Tigeot 	 * following code must not block on uncore.lock.
9359edbd4a0SFrançois Tigeot 	 */
9365e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
9379edbd4a0SFrançois Tigeot 
9389edbd4a0SFrançois Tigeot 	/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
9399edbd4a0SFrançois Tigeot 
9409edbd4a0SFrançois Tigeot 	/* Get optional system timestamp before query. */
9419edbd4a0SFrançois Tigeot 	if (stime)
9429edbd4a0SFrançois Tigeot 		*stime = ktime_get();
9439edbd4a0SFrançois Tigeot 
9441487f786SFrançois Tigeot 	if (IS_GEN2(dev_priv) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
945e3adcf8fSFrançois Tigeot 		/* No obvious pixelcount register. Only query vertical
946e3adcf8fSFrançois Tigeot 		 * scanout position from Display scan line register.
947e3adcf8fSFrançois Tigeot 		 */
948ba55f2f5SFrançois Tigeot 		position = __intel_get_crtc_scanline(intel_crtc);
949e3adcf8fSFrançois Tigeot 	} else {
950e3adcf8fSFrançois Tigeot 		/* Have access to pixelcount since start of frame.
951e3adcf8fSFrançois Tigeot 		 * We can split this into vertical and horizontal
952e3adcf8fSFrançois Tigeot 		 * scanout position.
953e3adcf8fSFrançois Tigeot 		 */
954aee94f86SFrançois Tigeot 		position = (I915_READ_FW(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
955e3adcf8fSFrançois Tigeot 
9569edbd4a0SFrançois Tigeot 		/* convert to pixel counts */
9579edbd4a0SFrançois Tigeot 		vbl_start *= htotal;
9589edbd4a0SFrançois Tigeot 		vbl_end *= htotal;
9599edbd4a0SFrançois Tigeot 		vtotal *= htotal;
960ba55f2f5SFrançois Tigeot 
961ba55f2f5SFrançois Tigeot 		/*
962ba55f2f5SFrançois Tigeot 		 * In interlaced modes, the pixel counter counts all pixels,
963ba55f2f5SFrançois Tigeot 		 * so one field will have htotal more pixels. In order to avoid
964ba55f2f5SFrançois Tigeot 		 * the reported position from jumping backwards when the pixel
965ba55f2f5SFrançois Tigeot 		 * counter is beyond the length of the shorter field, just
966ba55f2f5SFrançois Tigeot 		 * clamp the position the length of the shorter field. This
967ba55f2f5SFrançois Tigeot 		 * matches how the scanline counter based position works since
968ba55f2f5SFrançois Tigeot 		 * the scanline counter doesn't count the two half lines.
969ba55f2f5SFrançois Tigeot 		 */
970ba55f2f5SFrançois Tigeot 		if (position >= vtotal)
971ba55f2f5SFrançois Tigeot 			position = vtotal - 1;
972ba55f2f5SFrançois Tigeot 
973ba55f2f5SFrançois Tigeot 		/*
974ba55f2f5SFrançois Tigeot 		 * Start of vblank interrupt is triggered at start of hsync,
975ba55f2f5SFrançois Tigeot 		 * just prior to the first active line of vblank. However we
976ba55f2f5SFrançois Tigeot 		 * consider lines to start at the leading edge of horizontal
977ba55f2f5SFrançois Tigeot 		 * active. So, should we get here before we've crossed into
978ba55f2f5SFrançois Tigeot 		 * the horizontal active of the first line in vblank, we would
979ba55f2f5SFrançois Tigeot 		 * not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that,
980ba55f2f5SFrançois Tigeot 		 * always add htotal-hsync_start to the current pixel position.
981ba55f2f5SFrançois Tigeot 		 */
982ba55f2f5SFrançois Tigeot 		position = (position + htotal - hsync_start) % vtotal;
9839edbd4a0SFrançois Tigeot 	}
9849edbd4a0SFrançois Tigeot 
9859edbd4a0SFrançois Tigeot 	/* Get optional system timestamp after query. */
9869edbd4a0SFrançois Tigeot 	if (etime)
9879edbd4a0SFrançois Tigeot 		*etime = ktime_get();
9889edbd4a0SFrançois Tigeot 
9899edbd4a0SFrançois Tigeot 	/* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
9909edbd4a0SFrançois Tigeot 
9915e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
9929edbd4a0SFrançois Tigeot 
9939edbd4a0SFrançois Tigeot 	/*
9949edbd4a0SFrançois Tigeot 	 * While in vblank, position will be negative
9959edbd4a0SFrançois Tigeot 	 * counting up towards 0 at vbl_end. And outside
9969edbd4a0SFrançois Tigeot 	 * vblank, position will be positive counting
9979edbd4a0SFrançois Tigeot 	 * up since vbl_end.
9989edbd4a0SFrançois Tigeot 	 */
9999edbd4a0SFrançois Tigeot 	if (position >= vbl_start)
10009edbd4a0SFrançois Tigeot 		position -= vbl_end;
10019edbd4a0SFrançois Tigeot 	else
10029edbd4a0SFrançois Tigeot 		position += vtotal - vbl_end;
10039edbd4a0SFrançois Tigeot 
10041487f786SFrançois Tigeot 	if (IS_GEN2(dev_priv) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
10059edbd4a0SFrançois Tigeot 		*vpos = position;
10069edbd4a0SFrançois Tigeot 		*hpos = 0;
10079edbd4a0SFrançois Tigeot 	} else {
1008e3adcf8fSFrançois Tigeot 		*vpos = position / htotal;
1009e3adcf8fSFrançois Tigeot 		*hpos = position - (*vpos * htotal);
1010e3adcf8fSFrançois Tigeot 	}
1011e3adcf8fSFrançois Tigeot 
1012*3f2dd94aSFrançois Tigeot 	return true;
1013e3adcf8fSFrançois Tigeot }
1014e3adcf8fSFrançois Tigeot 
intel_get_crtc_scanline(struct intel_crtc * crtc)1015ba55f2f5SFrançois Tigeot int intel_get_crtc_scanline(struct intel_crtc *crtc)
1016ba55f2f5SFrançois Tigeot {
1017303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
10185e269720SFrançois Tigeot 	unsigned long irqflags;
1019ba55f2f5SFrançois Tigeot 	int position;
1020ba55f2f5SFrançois Tigeot 
10215e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
1022ba55f2f5SFrançois Tigeot 	position = __intel_get_crtc_scanline(crtc);
10235e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
1024ba55f2f5SFrançois Tigeot 
1025ba55f2f5SFrançois Tigeot 	return position;
1026ba55f2f5SFrançois Tigeot }
1027ba55f2f5SFrançois Tigeot 
ironlake_rps_change_irq_handler(struct drm_i915_private * dev_priv)10281487f786SFrançois Tigeot static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv)
1029e3adcf8fSFrançois Tigeot {
1030e3adcf8fSFrançois Tigeot 	u32 busy_up, busy_down, max_avg, min_avg;
1031a2296444SFrançois Tigeot 	u8 new_delay;
1032a2296444SFrançois Tigeot 
1033a2296444SFrançois Tigeot 	lockmgr(&mchdev_lock, LK_EXCLUSIVE);
1034a2296444SFrançois Tigeot 
1035a2296444SFrançois Tigeot 	I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
1036a2296444SFrançois Tigeot 
103700640ec9SFrançois Tigeot 	new_delay = dev_priv->ips.cur_delay;
1038e3adcf8fSFrançois Tigeot 
1039e3adcf8fSFrançois Tigeot 	I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG);
1040e3adcf8fSFrançois Tigeot 	busy_up = I915_READ(RCPREVBSYTUPAVG);
1041e3adcf8fSFrançois Tigeot 	busy_down = I915_READ(RCPREVBSYTDNAVG);
1042e3adcf8fSFrançois Tigeot 	max_avg = I915_READ(RCBMAXAVG);
1043e3adcf8fSFrançois Tigeot 	min_avg = I915_READ(RCBMINAVG);
1044e3adcf8fSFrançois Tigeot 
1045e3adcf8fSFrançois Tigeot 	/* Handle RCS change request from hw */
1046e3adcf8fSFrançois Tigeot 	if (busy_up > max_avg) {
104700640ec9SFrançois Tigeot 		if (dev_priv->ips.cur_delay != dev_priv->ips.max_delay)
104800640ec9SFrançois Tigeot 			new_delay = dev_priv->ips.cur_delay - 1;
104900640ec9SFrançois Tigeot 		if (new_delay < dev_priv->ips.max_delay)
105000640ec9SFrançois Tigeot 			new_delay = dev_priv->ips.max_delay;
1051e3adcf8fSFrançois Tigeot 	} else if (busy_down < min_avg) {
105200640ec9SFrançois Tigeot 		if (dev_priv->ips.cur_delay != dev_priv->ips.min_delay)
105300640ec9SFrançois Tigeot 			new_delay = dev_priv->ips.cur_delay + 1;
105400640ec9SFrançois Tigeot 		if (new_delay > dev_priv->ips.min_delay)
105500640ec9SFrançois Tigeot 			new_delay = dev_priv->ips.min_delay;
1056e3adcf8fSFrançois Tigeot 	}
1057e3adcf8fSFrançois Tigeot 
10581487f786SFrançois Tigeot 	if (ironlake_set_drps(dev_priv, new_delay))
105900640ec9SFrançois Tigeot 		dev_priv->ips.cur_delay = new_delay;
1060e3adcf8fSFrançois Tigeot 
1061a2296444SFrançois Tigeot 	lockmgr(&mchdev_lock, LK_RELEASE);
1062a2296444SFrançois Tigeot 
1063e3adcf8fSFrançois Tigeot 	return;
1064e3adcf8fSFrançois Tigeot }
1065e3adcf8fSFrançois Tigeot 
notify_ring(struct intel_engine_cs * engine)10668621f407SFrançois Tigeot static void notify_ring(struct intel_engine_cs *engine)
1067e3adcf8fSFrançois Tigeot {
1068a85cb24fSFrançois Tigeot 	struct drm_i915_gem_request *rq = NULL;
1069a85cb24fSFrançois Tigeot 	struct intel_wait *wait;
1070a85cb24fSFrançois Tigeot 
1071a85cb24fSFrançois Tigeot 	atomic_inc(&engine->irq_count);
1072a85cb24fSFrançois Tigeot 	set_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted);
1073a85cb24fSFrançois Tigeot 
1074a85cb24fSFrançois Tigeot 	lockmgr(&engine->breadcrumbs.irq_lock, LK_EXCLUSIVE);
1075a85cb24fSFrançois Tigeot 	wait = engine->breadcrumbs.irq_wait;
1076a85cb24fSFrançois Tigeot 	if (wait) {
1077*3f2dd94aSFrançois Tigeot 		bool wakeup = engine->irq_seqno_barrier;
1078*3f2dd94aSFrançois Tigeot 
1079a85cb24fSFrançois Tigeot 		/* We use a callback from the dma-fence to submit
1080a85cb24fSFrançois Tigeot 		 * requests after waiting on our own requests. To
1081a85cb24fSFrançois Tigeot 		 * ensure minimum delay in queuing the next request to
1082a85cb24fSFrançois Tigeot 		 * hardware, signal the fence now rather than wait for
1083a85cb24fSFrançois Tigeot 		 * the signaler to be woken up. We still wake up the
1084a85cb24fSFrançois Tigeot 		 * waiter in order to handle the irq-seqno coherency
1085a85cb24fSFrançois Tigeot 		 * issues (we may receive the interrupt before the
1086a85cb24fSFrançois Tigeot 		 * seqno is written, see __i915_request_irq_complete())
1087a85cb24fSFrançois Tigeot 		 * and to handle coalescing of multiple seqno updates
1088a85cb24fSFrançois Tigeot 		 * and many waiters.
1089a85cb24fSFrançois Tigeot 		 */
1090a85cb24fSFrançois Tigeot 		if (i915_seqno_passed(intel_engine_get_seqno(engine),
1091*3f2dd94aSFrançois Tigeot 				      wait->seqno)) {
1092*3f2dd94aSFrançois Tigeot 			struct drm_i915_gem_request *waiter = wait->request;
1093a85cb24fSFrançois Tigeot 
1094*3f2dd94aSFrançois Tigeot 			wakeup = true;
1095*3f2dd94aSFrançois Tigeot 			if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
1096*3f2dd94aSFrançois Tigeot 				      &waiter->fence.flags) &&
1097*3f2dd94aSFrançois Tigeot 			    intel_wait_check_request(wait, waiter))
1098*3f2dd94aSFrançois Tigeot 				rq = i915_gem_request_get(waiter);
1099*3f2dd94aSFrançois Tigeot 		}
1100*3f2dd94aSFrançois Tigeot 
1101*3f2dd94aSFrançois Tigeot 		if (wakeup)
1102a85cb24fSFrançois Tigeot 			wake_up_process(wait->tsk);
1103a85cb24fSFrançois Tigeot 	} else {
1104a85cb24fSFrançois Tigeot 		__intel_engine_disarm_breadcrumbs(engine);
1105a85cb24fSFrançois Tigeot 	}
1106a85cb24fSFrançois Tigeot 	lockmgr(&engine->breadcrumbs.irq_lock, LK_RELEASE);
1107a85cb24fSFrançois Tigeot 
1108a85cb24fSFrançois Tigeot 	if (rq) {
1109a85cb24fSFrançois Tigeot 		dma_fence_signal(&rq->fence);
1110a85cb24fSFrançois Tigeot 		i915_gem_request_put(rq);
1111a85cb24fSFrançois Tigeot 	}
1112a85cb24fSFrançois Tigeot 
1113a85cb24fSFrançois Tigeot 	trace_intel_engine_notify(engine, wait);
1114e3adcf8fSFrançois Tigeot }
1115e3adcf8fSFrançois Tigeot 
vlv_c0_read(struct drm_i915_private * dev_priv,struct intel_rps_ei * ei)1116477eb7f9SFrançois Tigeot static void vlv_c0_read(struct drm_i915_private *dev_priv,
1117477eb7f9SFrançois Tigeot 			struct intel_rps_ei *ei)
111824edb884SFrançois Tigeot {
1119a85cb24fSFrançois Tigeot 	ei->ktime = ktime_get_raw();
1120477eb7f9SFrançois Tigeot 	ei->render_c0 = I915_READ(VLV_RENDER_C0_COUNT);
1121477eb7f9SFrançois Tigeot 	ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT);
112224edb884SFrançois Tigeot }
112324edb884SFrançois Tigeot 
gen6_rps_reset_ei(struct drm_i915_private * dev_priv)1124477eb7f9SFrançois Tigeot void gen6_rps_reset_ei(struct drm_i915_private *dev_priv)
1125477eb7f9SFrançois Tigeot {
1126*3f2dd94aSFrançois Tigeot 	memset(&dev_priv->gt_pm.rps.ei, 0, sizeof(dev_priv->gt_pm.rps.ei));
112724edb884SFrançois Tigeot }
112824edb884SFrançois Tigeot 
vlv_wa_c0_ei(struct drm_i915_private * dev_priv,u32 pm_iir)1129477eb7f9SFrançois Tigeot static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
1130477eb7f9SFrançois Tigeot {
1131*3f2dd94aSFrançois Tigeot 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
1132*3f2dd94aSFrançois Tigeot 	const struct intel_rps_ei *prev = &rps->ei;
1133477eb7f9SFrançois Tigeot 	struct intel_rps_ei now;
1134477eb7f9SFrançois Tigeot 	u32 events = 0;
113524edb884SFrançois Tigeot 
11364be47400SFrançois Tigeot 	if ((pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) == 0)
1137477eb7f9SFrançois Tigeot 		return 0;
113824edb884SFrançois Tigeot 
1139477eb7f9SFrançois Tigeot 	vlv_c0_read(dev_priv, &now);
114024edb884SFrançois Tigeot 
1141a85cb24fSFrançois Tigeot 	if (prev->ktime) {
11424be47400SFrançois Tigeot 		u64 time, c0;
1143a85cb24fSFrançois Tigeot 		u32 render, media;
11444be47400SFrançois Tigeot 
1145a85cb24fSFrançois Tigeot 		time = ktime_us_delta(now.ktime, prev->ktime);
11464be47400SFrançois Tigeot 
11474be47400SFrançois Tigeot 		time *= dev_priv->czclk_freq;
11484be47400SFrançois Tigeot 
11494be47400SFrançois Tigeot 		/* Workload can be split between render + media,
11504be47400SFrançois Tigeot 		 * e.g. SwapBuffers being blitted in X after being rendered in
11514be47400SFrançois Tigeot 		 * mesa. To account for this we need to combine both engines
11524be47400SFrançois Tigeot 		 * into our activity counter.
11534be47400SFrançois Tigeot 		 */
1154a85cb24fSFrançois Tigeot 		render = now.render_c0 - prev->render_c0;
1155a85cb24fSFrançois Tigeot 		media = now.media_c0 - prev->media_c0;
1156a85cb24fSFrançois Tigeot 		c0 = max(render, media);
1157a85cb24fSFrançois Tigeot 		c0 *= 1000 * 100 << 8; /* to usecs and scale to threshold% */
11584be47400SFrançois Tigeot 
1159*3f2dd94aSFrançois Tigeot 		if (c0 > time * rps->up_threshold)
11604be47400SFrançois Tigeot 			events = GEN6_PM_RP_UP_THRESHOLD;
1161*3f2dd94aSFrançois Tigeot 		else if (c0 < time * rps->down_threshold)
11624be47400SFrançois Tigeot 			events = GEN6_PM_RP_DOWN_THRESHOLD;
116324edb884SFrançois Tigeot 	}
116424edb884SFrançois Tigeot 
1165*3f2dd94aSFrançois Tigeot 	rps->ei = now;
1166477eb7f9SFrançois Tigeot 	return events;
116724edb884SFrançois Tigeot }
116824edb884SFrançois Tigeot 
gen6_pm_rps_work(struct work_struct * work)1169abf1f4f4SFrançois Tigeot static void gen6_pm_rps_work(struct work_struct *work)
1170e3adcf8fSFrançois Tigeot {
1171ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv =
1172*3f2dd94aSFrançois Tigeot 		container_of(work, struct drm_i915_private, gt_pm.rps.work);
1173*3f2dd94aSFrançois Tigeot 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
1174a85cb24fSFrançois Tigeot 	bool client_boost = false;
117519c468b4SFrançois Tigeot 	int new_delay, adj, min, max;
1176a85cb24fSFrançois Tigeot 	u32 pm_iir = 0;
1177e3adcf8fSFrançois Tigeot 
11785e269720SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
1179*3f2dd94aSFrançois Tigeot 	if (rps->interrupts_enabled) {
1180*3f2dd94aSFrançois Tigeot 		pm_iir = fetch_and_zero(&rps->pm_iir);
1181*3f2dd94aSFrançois Tigeot 		client_boost = atomic_read(&rps->num_waiters);
11822c9916cdSFrançois Tigeot 	}
11835e269720SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
11849edbd4a0SFrançois Tigeot 
11859edbd4a0SFrançois Tigeot 	/* Make sure we didn't queue anything we're not going to process. */
1186ba55f2f5SFrançois Tigeot 	WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
118719c468b4SFrançois Tigeot 	if ((pm_iir & dev_priv->pm_rps_events) == 0 && !client_boost)
1188a85cb24fSFrançois Tigeot 		goto out;
1189e3adcf8fSFrançois Tigeot 
1190*3f2dd94aSFrançois Tigeot 	mutex_lock(&dev_priv->pcu_lock);
1191e3adcf8fSFrançois Tigeot 
1192477eb7f9SFrançois Tigeot 	pm_iir |= vlv_wa_c0_ei(dev_priv, pm_iir);
1193477eb7f9SFrançois Tigeot 
1194*3f2dd94aSFrançois Tigeot 	adj = rps->last_adj;
1195*3f2dd94aSFrançois Tigeot 	new_delay = rps->cur_freq;
1196*3f2dd94aSFrançois Tigeot 	min = rps->min_freq_softlimit;
1197*3f2dd94aSFrançois Tigeot 	max = rps->max_freq_softlimit;
1198*3f2dd94aSFrançois Tigeot 	if (client_boost)
1199*3f2dd94aSFrançois Tigeot 		max = rps->max_freq;
1200*3f2dd94aSFrançois Tigeot 	if (client_boost && new_delay < rps->boost_freq) {
1201*3f2dd94aSFrançois Tigeot 		new_delay = rps->boost_freq;
120219c468b4SFrançois Tigeot 		adj = 0;
120319c468b4SFrançois Tigeot 	} else if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
12049edbd4a0SFrançois Tigeot 		if (adj > 0)
12059edbd4a0SFrançois Tigeot 			adj *= 2;
120619c468b4SFrançois Tigeot 		else /* CHV needs even encode values */
120719c468b4SFrançois Tigeot 			adj = IS_CHERRYVIEW(dev_priv) ? 2 : 1;
1208a85cb24fSFrançois Tigeot 
1209*3f2dd94aSFrançois Tigeot 		if (new_delay >= rps->max_freq_softlimit)
121019c468b4SFrançois Tigeot 			adj = 0;
1211*3f2dd94aSFrançois Tigeot 	} else if (client_boost) {
121219c468b4SFrançois Tigeot 		adj = 0;
12139edbd4a0SFrançois Tigeot 	} else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) {
1214*3f2dd94aSFrançois Tigeot 		if (rps->cur_freq > rps->efficient_freq)
1215*3f2dd94aSFrançois Tigeot 			new_delay = rps->efficient_freq;
1216*3f2dd94aSFrançois Tigeot 		else if (rps->cur_freq > rps->min_freq_softlimit)
1217*3f2dd94aSFrançois Tigeot 			new_delay = rps->min_freq_softlimit;
12189edbd4a0SFrançois Tigeot 		adj = 0;
12199edbd4a0SFrançois Tigeot 	} else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
12209edbd4a0SFrançois Tigeot 		if (adj < 0)
12219edbd4a0SFrançois Tigeot 			adj *= 2;
122219c468b4SFrançois Tigeot 		else /* CHV needs even encode values */
122319c468b4SFrançois Tigeot 			adj = IS_CHERRYVIEW(dev_priv) ? -2 : -1;
1224a85cb24fSFrançois Tigeot 
1225*3f2dd94aSFrançois Tigeot 		if (new_delay <= rps->min_freq_softlimit)
1226a85cb24fSFrançois Tigeot 			adj = 0;
12279edbd4a0SFrançois Tigeot 	} else { /* unknown event */
122819c468b4SFrançois Tigeot 		adj = 0;
12299edbd4a0SFrançois Tigeot 	}
1230e3adcf8fSFrançois Tigeot 
1231*3f2dd94aSFrançois Tigeot 	rps->last_adj = adj;
123219c468b4SFrançois Tigeot 
1233abf1f4f4SFrançois Tigeot 	/* sysfs frequency interfaces may have snuck in while servicing the
1234abf1f4f4SFrançois Tigeot 	 * interrupt
1235e3adcf8fSFrançois Tigeot 	 */
123619c468b4SFrançois Tigeot 	new_delay += adj;
123719c468b4SFrançois Tigeot 	new_delay = clamp_t(int, new_delay, min, max);
12389edbd4a0SFrançois Tigeot 
1239a85cb24fSFrançois Tigeot 	if (intel_set_rps(dev_priv, new_delay)) {
1240a85cb24fSFrançois Tigeot 		DRM_DEBUG_DRIVER("Failed to set new GPU frequency\n");
1241*3f2dd94aSFrançois Tigeot 		rps->last_adj = 0;
1242a85cb24fSFrançois Tigeot 	}
12435d0b1887SFrançois Tigeot 
1244*3f2dd94aSFrançois Tigeot 	mutex_unlock(&dev_priv->pcu_lock);
1245a85cb24fSFrançois Tigeot 
1246a85cb24fSFrançois Tigeot out:
1247a85cb24fSFrançois Tigeot 	/* Make sure not to corrupt PMIMR state used by ringbuffer on GEN6 */
1248a85cb24fSFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
1249*3f2dd94aSFrançois Tigeot 	if (rps->interrupts_enabled)
1250a85cb24fSFrançois Tigeot 		gen6_unmask_pm_irq(dev_priv, dev_priv->pm_rps_events);
1251a85cb24fSFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
1252e3adcf8fSFrançois Tigeot }
1253e3adcf8fSFrançois Tigeot 
12545e269720SFrançois Tigeot 
125500640ec9SFrançois Tigeot /**
125600640ec9SFrançois Tigeot  * ivybridge_parity_work - Workqueue called when a parity error interrupt
125700640ec9SFrançois Tigeot  * occurred.
125800640ec9SFrançois Tigeot  * @work: workqueue struct
125900640ec9SFrançois Tigeot  *
126000640ec9SFrançois Tigeot  * Doesn't actually do anything except notify userspace. As a consequence of
126100640ec9SFrançois Tigeot  * this event, userspace should try to remap the bad rows since statistically
126200640ec9SFrançois Tigeot  * it is likely the same row is more likely to go bad again.
126300640ec9SFrançois Tigeot  */
ivybridge_parity_work(struct work_struct * work)126400640ec9SFrançois Tigeot static void ivybridge_parity_work(struct work_struct *work)
126500640ec9SFrançois Tigeot {
1266ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv =
1267*3f2dd94aSFrançois Tigeot 		container_of(work, typeof(*dev_priv), l3_parity.error_work);
126800640ec9SFrançois Tigeot 	u32 error_status, row, bank, subbank;
12699edbd4a0SFrançois Tigeot 	char *parity_event[6];
127000640ec9SFrançois Tigeot 	uint32_t misccpctl;
12719edbd4a0SFrançois Tigeot 	uint8_t slice = 0;
127200640ec9SFrançois Tigeot 
127300640ec9SFrançois Tigeot 	/* We must turn off DOP level clock gating to access the L3 registers.
127400640ec9SFrançois Tigeot 	 * In order to prevent a get/put style interface, acquire struct mutex
127500640ec9SFrançois Tigeot 	 * any time we access those registers.
127600640ec9SFrançois Tigeot 	 */
1277303bf270SFrançois Tigeot 	mutex_lock(&dev_priv->drm.struct_mutex);
127800640ec9SFrançois Tigeot 
12799edbd4a0SFrançois Tigeot 	/* If we've screwed up tracking, just let the interrupt fire again */
12809edbd4a0SFrançois Tigeot 	if (WARN_ON(!dev_priv->l3_parity.which_slice))
12819edbd4a0SFrançois Tigeot 		goto out;
12829edbd4a0SFrançois Tigeot 
128300640ec9SFrançois Tigeot 	misccpctl = I915_READ(GEN7_MISCCPCTL);
128400640ec9SFrançois Tigeot 	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
128500640ec9SFrançois Tigeot 	POSTING_READ(GEN7_MISCCPCTL);
128600640ec9SFrançois Tigeot 
12879edbd4a0SFrançois Tigeot 	while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
1288aee94f86SFrançois Tigeot 		i915_reg_t reg;
12899edbd4a0SFrançois Tigeot 
12909edbd4a0SFrançois Tigeot 		slice--;
12918621f407SFrançois Tigeot 		if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv)))
12929edbd4a0SFrançois Tigeot 			break;
12939edbd4a0SFrançois Tigeot 
12949edbd4a0SFrançois Tigeot 		dev_priv->l3_parity.which_slice &= ~(1<<slice);
12959edbd4a0SFrançois Tigeot 
1296aee94f86SFrançois Tigeot 		reg = GEN7_L3CDERRST1(slice);
12979edbd4a0SFrançois Tigeot 
12989edbd4a0SFrançois Tigeot 		error_status = I915_READ(reg);
129900640ec9SFrançois Tigeot 		row = GEN7_PARITY_ERROR_ROW(error_status);
130000640ec9SFrançois Tigeot 		bank = GEN7_PARITY_ERROR_BANK(error_status);
130100640ec9SFrançois Tigeot 		subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
130200640ec9SFrançois Tigeot 
13039edbd4a0SFrançois Tigeot 		I915_WRITE(reg, GEN7_PARITY_ERROR_VALID | GEN7_L3CDERRST1_ENABLE);
13049edbd4a0SFrançois Tigeot 		POSTING_READ(reg);
13059edbd4a0SFrançois Tigeot 
13069edbd4a0SFrançois Tigeot 		parity_event[0] = I915_L3_PARITY_UEVENT "=1";
1307c0e85e96SFrançois Tigeot 		parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
1308c0e85e96SFrançois Tigeot 		parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
1309c0e85e96SFrançois Tigeot 		parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
1310c0e85e96SFrançois Tigeot 		parity_event[4] = kasprintf(GFP_KERNEL, "SLICE=%d", slice);
13119edbd4a0SFrançois Tigeot 		parity_event[5] = NULL;
13129edbd4a0SFrançois Tigeot 
1313303bf270SFrançois Tigeot 		kobject_uevent_env(&dev_priv->drm.primary->kdev->kobj,
13149edbd4a0SFrançois Tigeot 				   KOBJ_CHANGE, parity_event);
13159edbd4a0SFrançois Tigeot 
13169edbd4a0SFrançois Tigeot 		DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n",
13179edbd4a0SFrançois Tigeot 			  slice, row, bank, subbank);
13189edbd4a0SFrançois Tigeot 
13199edbd4a0SFrançois Tigeot 		kfree(parity_event[4]);
13209edbd4a0SFrançois Tigeot 		kfree(parity_event[3]);
13219edbd4a0SFrançois Tigeot 		kfree(parity_event[2]);
13229edbd4a0SFrançois Tigeot 		kfree(parity_event[1]);
13239edbd4a0SFrançois Tigeot 	}
132400640ec9SFrançois Tigeot 
132500640ec9SFrançois Tigeot 	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
132600640ec9SFrançois Tigeot 
13279edbd4a0SFrançois Tigeot out:
13289edbd4a0SFrançois Tigeot 	WARN_ON(dev_priv->l3_parity.which_slice);
13295e269720SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
13308621f407SFrançois Tigeot 	gen5_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv));
13315e269720SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
133200640ec9SFrançois Tigeot 
1333303bf270SFrançois Tigeot 	mutex_unlock(&dev_priv->drm.struct_mutex);
133400640ec9SFrançois Tigeot }
133500640ec9SFrançois Tigeot 
ivybridge_parity_error_irq_handler(struct drm_i915_private * dev_priv,u32 iir)13368621f407SFrançois Tigeot static void ivybridge_parity_error_irq_handler(struct drm_i915_private *dev_priv,
13378621f407SFrançois Tigeot 					       u32 iir)
133800640ec9SFrançois Tigeot {
13398621f407SFrançois Tigeot 	if (!HAS_L3_DPF(dev_priv))
134000640ec9SFrançois Tigeot 		return;
134100640ec9SFrançois Tigeot 
134200640ec9SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
13438621f407SFrançois Tigeot 	gen5_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv));
134400640ec9SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
134500640ec9SFrançois Tigeot 
13468621f407SFrançois Tigeot 	iir &= GT_PARITY_ERROR(dev_priv);
13479edbd4a0SFrançois Tigeot 	if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1)
13489edbd4a0SFrançois Tigeot 		dev_priv->l3_parity.which_slice |= 1 << 1;
13499edbd4a0SFrançois Tigeot 
13509edbd4a0SFrançois Tigeot 	if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
13519edbd4a0SFrançois Tigeot 		dev_priv->l3_parity.which_slice |= 1 << 0;
13529edbd4a0SFrançois Tigeot 
135300640ec9SFrançois Tigeot 	queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
135400640ec9SFrançois Tigeot }
135500640ec9SFrançois Tigeot 
ilk_gt_irq_handler(struct drm_i915_private * dev_priv,u32 gt_iir)13568621f407SFrançois Tigeot static void ilk_gt_irq_handler(struct drm_i915_private *dev_priv,
13579edbd4a0SFrançois Tigeot 			       u32 gt_iir)
13589edbd4a0SFrançois Tigeot {
1359303bf270SFrançois Tigeot 	if (gt_iir & GT_RENDER_USER_INTERRUPT)
13601e12ee3bSFrançois Tigeot 		notify_ring(dev_priv->engine[RCS]);
13619edbd4a0SFrançois Tigeot 	if (gt_iir & ILK_BSD_USER_INTERRUPT)
13621e12ee3bSFrançois Tigeot 		notify_ring(dev_priv->engine[VCS]);
13639edbd4a0SFrançois Tigeot }
13649edbd4a0SFrançois Tigeot 
snb_gt_irq_handler(struct drm_i915_private * dev_priv,u32 gt_iir)13658621f407SFrançois Tigeot static void snb_gt_irq_handler(struct drm_i915_private *dev_priv,
1366a2296444SFrançois Tigeot 			       u32 gt_iir)
1367a2296444SFrançois Tigeot {
1368303bf270SFrançois Tigeot 	if (gt_iir & GT_RENDER_USER_INTERRUPT)
13691e12ee3bSFrançois Tigeot 		notify_ring(dev_priv->engine[RCS]);
13705d0b1887SFrançois Tigeot 	if (gt_iir & GT_BSD_USER_INTERRUPT)
13711e12ee3bSFrançois Tigeot 		notify_ring(dev_priv->engine[VCS]);
13725d0b1887SFrançois Tigeot 	if (gt_iir & GT_BLT_USER_INTERRUPT)
13731e12ee3bSFrançois Tigeot 		notify_ring(dev_priv->engine[BCS]);
1374a2296444SFrançois Tigeot 
13755d0b1887SFrançois Tigeot 	if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
13765d0b1887SFrançois Tigeot 		      GT_BSD_CS_ERROR_INTERRUPT |
13772c9916cdSFrançois Tigeot 		      GT_RENDER_CS_MASTER_ERROR_INTERRUPT))
13782c9916cdSFrançois Tigeot 		DRM_DEBUG("Command parser error, gt_iir 0x%08x\n", gt_iir);
1379a2296444SFrançois Tigeot 
13808621f407SFrançois Tigeot 	if (gt_iir & GT_PARITY_ERROR(dev_priv))
13818621f407SFrançois Tigeot 		ivybridge_parity_error_irq_handler(dev_priv, gt_iir);
1382a2296444SFrançois Tigeot }
1383a2296444SFrançois Tigeot 
1384*3f2dd94aSFrançois Tigeot static void
gen8_cs_irq_handler(struct intel_engine_cs * engine,u32 iir,int test_shift)13858621f407SFrançois Tigeot gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift)
1386aee94f86SFrançois Tigeot {
1387*3f2dd94aSFrançois Tigeot 	struct intel_engine_execlists * const execlists = &engine->execlists;
1388a85cb24fSFrançois Tigeot 	bool tasklet = false;
1389a85cb24fSFrançois Tigeot 
1390a85cb24fSFrançois Tigeot 	if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift)) {
1391*3f2dd94aSFrançois Tigeot 		if (READ_ONCE(engine->execlists.active)) {
1392*3f2dd94aSFrançois Tigeot 			__set_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
1393a85cb24fSFrançois Tigeot 			tasklet = true;
1394a85cb24fSFrançois Tigeot 		}
1395*3f2dd94aSFrançois Tigeot 	}
1396a85cb24fSFrançois Tigeot 
1397a85cb24fSFrançois Tigeot 	if (iir & (GT_RENDER_USER_INTERRUPT << test_shift)) {
13988621f407SFrançois Tigeot 		notify_ring(engine);
1399*3f2dd94aSFrançois Tigeot 		tasklet |= i915_modparams.enable_guc_submission;
1400a85cb24fSFrançois Tigeot 	}
1401a85cb24fSFrançois Tigeot 
1402a85cb24fSFrançois Tigeot 	if (tasklet)
1403*3f2dd94aSFrançois Tigeot 		tasklet_hi_schedule(&execlists->irq_tasklet);
1404aee94f86SFrançois Tigeot }
1405aee94f86SFrançois Tigeot 
gen8_gt_irq_ack(struct drm_i915_private * dev_priv,u32 master_ctl,u32 gt_iir[4])14068621f407SFrançois Tigeot static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
14078621f407SFrançois Tigeot 				   u32 master_ctl,
14088621f407SFrançois Tigeot 				   u32 gt_iir[4])
1409a2296444SFrançois Tigeot {
1410183e2373SFrançois Tigeot 	irqreturn_t ret = IRQ_NONE;
1411a2296444SFrançois Tigeot 
14129edbd4a0SFrançois Tigeot 	if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
14138621f407SFrançois Tigeot 		gt_iir[0] = I915_READ_FW(GEN8_GT_IIR(0));
14148621f407SFrançois Tigeot 		if (gt_iir[0]) {
14158621f407SFrançois Tigeot 			I915_WRITE_FW(GEN8_GT_IIR(0), gt_iir[0]);
1416183e2373SFrançois Tigeot 			ret = IRQ_HANDLED;
14179edbd4a0SFrançois Tigeot 		} else
14189edbd4a0SFrançois Tigeot 			DRM_ERROR("The master control interrupt lied (GT0)!\n");
14199edbd4a0SFrançois Tigeot 	}
1420a2296444SFrançois Tigeot 
1421ba55f2f5SFrançois Tigeot 	if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
14228621f407SFrançois Tigeot 		gt_iir[1] = I915_READ_FW(GEN8_GT_IIR(1));
14238621f407SFrançois Tigeot 		if (gt_iir[1]) {
14248621f407SFrançois Tigeot 			I915_WRITE_FW(GEN8_GT_IIR(1), gt_iir[1]);
1425183e2373SFrançois Tigeot 			ret = IRQ_HANDLED;
14269edbd4a0SFrançois Tigeot 		} else
14279edbd4a0SFrançois Tigeot 			DRM_ERROR("The master control interrupt lied (GT1)!\n");
14289edbd4a0SFrançois Tigeot 	}
1429a2296444SFrançois Tigeot 
143019c468b4SFrançois Tigeot 	if (master_ctl & GEN8_GT_VECS_IRQ) {
14318621f407SFrançois Tigeot 		gt_iir[3] = I915_READ_FW(GEN8_GT_IIR(3));
14328621f407SFrançois Tigeot 		if (gt_iir[3]) {
14338621f407SFrançois Tigeot 			I915_WRITE_FW(GEN8_GT_IIR(3), gt_iir[3]);
1434183e2373SFrançois Tigeot 			ret = IRQ_HANDLED;
143519c468b4SFrançois Tigeot 		} else
143619c468b4SFrançois Tigeot 			DRM_ERROR("The master control interrupt lied (GT3)!\n");
143719c468b4SFrançois Tigeot 	}
143819c468b4SFrançois Tigeot 
14394be47400SFrançois Tigeot 	if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
14408621f407SFrançois Tigeot 		gt_iir[2] = I915_READ_FW(GEN8_GT_IIR(2));
14414be47400SFrançois Tigeot 		if (gt_iir[2] & (dev_priv->pm_rps_events |
14424be47400SFrançois Tigeot 				 dev_priv->pm_guc_events)) {
144319c468b4SFrançois Tigeot 			I915_WRITE_FW(GEN8_GT_IIR(2),
14444be47400SFrançois Tigeot 				      gt_iir[2] & (dev_priv->pm_rps_events |
14454be47400SFrançois Tigeot 						   dev_priv->pm_guc_events));
1446183e2373SFrançois Tigeot 			ret = IRQ_HANDLED;
1447ba55f2f5SFrançois Tigeot 		} else
1448ba55f2f5SFrançois Tigeot 			DRM_ERROR("The master control interrupt lied (PM)!\n");
1449ba55f2f5SFrançois Tigeot 	}
1450ba55f2f5SFrançois Tigeot 
1451183e2373SFrançois Tigeot 	return ret;
1452a2296444SFrançois Tigeot }
1453a2296444SFrançois Tigeot 
gen8_gt_irq_handler(struct drm_i915_private * dev_priv,u32 gt_iir[4])14548621f407SFrançois Tigeot static void gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
14558621f407SFrançois Tigeot 				u32 gt_iir[4])
14568621f407SFrançois Tigeot {
14578621f407SFrançois Tigeot 	if (gt_iir[0]) {
14581e12ee3bSFrançois Tigeot 		gen8_cs_irq_handler(dev_priv->engine[RCS],
14598621f407SFrançois Tigeot 				    gt_iir[0], GEN8_RCS_IRQ_SHIFT);
14601e12ee3bSFrançois Tigeot 		gen8_cs_irq_handler(dev_priv->engine[BCS],
14618621f407SFrançois Tigeot 				    gt_iir[0], GEN8_BCS_IRQ_SHIFT);
14628621f407SFrançois Tigeot 	}
14638621f407SFrançois Tigeot 
14648621f407SFrançois Tigeot 	if (gt_iir[1]) {
14651e12ee3bSFrançois Tigeot 		gen8_cs_irq_handler(dev_priv->engine[VCS],
14668621f407SFrançois Tigeot 				    gt_iir[1], GEN8_VCS1_IRQ_SHIFT);
14671e12ee3bSFrançois Tigeot 		gen8_cs_irq_handler(dev_priv->engine[VCS2],
14688621f407SFrançois Tigeot 				    gt_iir[1], GEN8_VCS2_IRQ_SHIFT);
14698621f407SFrançois Tigeot 	}
14708621f407SFrançois Tigeot 
14718621f407SFrançois Tigeot 	if (gt_iir[3])
14721e12ee3bSFrançois Tigeot 		gen8_cs_irq_handler(dev_priv->engine[VECS],
14738621f407SFrançois Tigeot 				    gt_iir[3], GEN8_VECS_IRQ_SHIFT);
14748621f407SFrançois Tigeot 
14758621f407SFrançois Tigeot 	if (gt_iir[2] & dev_priv->pm_rps_events)
14768621f407SFrançois Tigeot 		gen6_rps_irq_handler(dev_priv, gt_iir[2]);
14774be47400SFrançois Tigeot 
14784be47400SFrançois Tigeot 	if (gt_iir[2] & dev_priv->pm_guc_events)
14794be47400SFrançois Tigeot 		gen9_guc_irq_handler(dev_priv, gt_iir[2]);
14808621f407SFrançois Tigeot }
14818621f407SFrançois Tigeot 
bxt_port_hotplug_long_detect(enum port port,u32 val)1482a05eeebfSFrançois Tigeot static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
148324edb884SFrançois Tigeot {
148424edb884SFrançois Tigeot 	switch (port) {
148524edb884SFrançois Tigeot 	case PORT_A:
1486352ff8bdSFrançois Tigeot 		return val & PORTA_HOTPLUG_LONG_DETECT;
1487352ff8bdSFrançois Tigeot 	case PORT_B:
1488352ff8bdSFrançois Tigeot 		return val & PORTB_HOTPLUG_LONG_DETECT;
1489352ff8bdSFrançois Tigeot 	case PORT_C:
1490352ff8bdSFrançois Tigeot 		return val & PORTC_HOTPLUG_LONG_DETECT;
1491352ff8bdSFrançois Tigeot 	default:
1492352ff8bdSFrançois Tigeot 		return false;
1493352ff8bdSFrançois Tigeot 	}
1494352ff8bdSFrançois Tigeot }
1495352ff8bdSFrançois Tigeot 
spt_port_hotplug2_long_detect(enum port port,u32 val)1496352ff8bdSFrançois Tigeot static bool spt_port_hotplug2_long_detect(enum port port, u32 val)
1497352ff8bdSFrançois Tigeot {
1498352ff8bdSFrançois Tigeot 	switch (port) {
1499352ff8bdSFrançois Tigeot 	case PORT_E:
1500352ff8bdSFrançois Tigeot 		return val & PORTE_HOTPLUG_LONG_DETECT;
1501352ff8bdSFrançois Tigeot 	default:
1502352ff8bdSFrançois Tigeot 		return false;
1503352ff8bdSFrançois Tigeot 	}
1504352ff8bdSFrançois Tigeot }
1505352ff8bdSFrançois Tigeot 
spt_port_hotplug_long_detect(enum port port,u32 val)1506352ff8bdSFrançois Tigeot static bool spt_port_hotplug_long_detect(enum port port, u32 val)
1507352ff8bdSFrançois Tigeot {
1508352ff8bdSFrançois Tigeot 	switch (port) {
1509352ff8bdSFrançois Tigeot 	case PORT_A:
1510352ff8bdSFrançois Tigeot 		return val & PORTA_HOTPLUG_LONG_DETECT;
151124edb884SFrançois Tigeot 	case PORT_B:
1512a05eeebfSFrançois Tigeot 		return val & PORTB_HOTPLUG_LONG_DETECT;
151324edb884SFrançois Tigeot 	case PORT_C:
1514a05eeebfSFrançois Tigeot 		return val & PORTC_HOTPLUG_LONG_DETECT;
151524edb884SFrançois Tigeot 	case PORT_D:
1516a05eeebfSFrançois Tigeot 		return val & PORTD_HOTPLUG_LONG_DETECT;
1517a05eeebfSFrançois Tigeot 	default:
1518a05eeebfSFrançois Tigeot 		return false;
151924edb884SFrançois Tigeot 	}
152024edb884SFrançois Tigeot }
152124edb884SFrançois Tigeot 
ilk_port_hotplug_long_detect(enum port port,u32 val)1522352ff8bdSFrançois Tigeot static bool ilk_port_hotplug_long_detect(enum port port, u32 val)
1523352ff8bdSFrançois Tigeot {
1524352ff8bdSFrançois Tigeot 	switch (port) {
1525352ff8bdSFrançois Tigeot 	case PORT_A:
1526352ff8bdSFrançois Tigeot 		return val & DIGITAL_PORTA_HOTPLUG_LONG_DETECT;
1527352ff8bdSFrançois Tigeot 	default:
1528352ff8bdSFrançois Tigeot 		return false;
1529352ff8bdSFrançois Tigeot 	}
1530352ff8bdSFrançois Tigeot }
1531352ff8bdSFrançois Tigeot 
pch_port_hotplug_long_detect(enum port port,u32 val)1532a05eeebfSFrançois Tigeot static bool pch_port_hotplug_long_detect(enum port port, u32 val)
153324edb884SFrançois Tigeot {
153424edb884SFrançois Tigeot 	switch (port) {
153524edb884SFrançois Tigeot 	case PORT_B:
1536a05eeebfSFrançois Tigeot 		return val & PORTB_HOTPLUG_LONG_DETECT;
153724edb884SFrançois Tigeot 	case PORT_C:
1538a05eeebfSFrançois Tigeot 		return val & PORTC_HOTPLUG_LONG_DETECT;
153924edb884SFrançois Tigeot 	case PORT_D:
1540a05eeebfSFrançois Tigeot 		return val & PORTD_HOTPLUG_LONG_DETECT;
154124edb884SFrançois Tigeot 	default:
1542a05eeebfSFrançois Tigeot 		return false;
154324edb884SFrançois Tigeot 	}
154424edb884SFrançois Tigeot }
154524edb884SFrançois Tigeot 
i9xx_port_hotplug_long_detect(enum port port,u32 val)1546a05eeebfSFrançois Tigeot static bool i9xx_port_hotplug_long_detect(enum port port, u32 val)
15478e26cdf6SFrançois Tigeot {
1548a05eeebfSFrançois Tigeot 	switch (port) {
1549a05eeebfSFrançois Tigeot 	case PORT_B:
1550a05eeebfSFrançois Tigeot 		return val & PORTB_HOTPLUG_INT_LONG_PULSE;
1551a05eeebfSFrançois Tigeot 	case PORT_C:
1552a05eeebfSFrançois Tigeot 		return val & PORTC_HOTPLUG_INT_LONG_PULSE;
1553a05eeebfSFrançois Tigeot 	case PORT_D:
1554a05eeebfSFrançois Tigeot 		return val & PORTD_HOTPLUG_INT_LONG_PULSE;
1555a05eeebfSFrançois Tigeot 	default:
1556a05eeebfSFrançois Tigeot 		return false;
1557a05eeebfSFrançois Tigeot 	}
1558a05eeebfSFrançois Tigeot }
1559a05eeebfSFrançois Tigeot 
1560352ff8bdSFrançois Tigeot /*
1561352ff8bdSFrançois Tigeot  * Get a bit mask of pins that have triggered, and which ones may be long.
1562352ff8bdSFrançois Tigeot  * This can be called multiple times with the same masks to accumulate
1563352ff8bdSFrançois Tigeot  * hotplug detection results from several registers.
1564352ff8bdSFrançois Tigeot  *
1565352ff8bdSFrançois Tigeot  * Note that the caller is expected to zero out the masks initially.
1566352ff8bdSFrançois Tigeot  */
intel_get_hpd_pins(u32 * pin_mask,u32 * long_mask,u32 hotplug_trigger,u32 dig_hotplug_reg,const u32 hpd[HPD_NUM_PINS],bool long_pulse_detect (enum port port,u32 val))1567a05eeebfSFrançois Tigeot static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
1568a05eeebfSFrançois Tigeot 			     u32 hotplug_trigger, u32 dig_hotplug_reg,
1569a05eeebfSFrançois Tigeot 			     const u32 hpd[HPD_NUM_PINS],
1570a05eeebfSFrançois Tigeot 			     bool long_pulse_detect(enum port port, u32 val))
1571a05eeebfSFrançois Tigeot {
157224edb884SFrançois Tigeot 	enum port port;
1573a05eeebfSFrançois Tigeot 	int i;
15745d0b1887SFrançois Tigeot 
1575a05eeebfSFrançois Tigeot 	for_each_hpd_pin(i) {
1576a05eeebfSFrançois Tigeot 		if ((hpd[i] & hotplug_trigger) == 0)
157724edb884SFrançois Tigeot 			continue;
15788e26cdf6SFrançois Tigeot 
1579a05eeebfSFrançois Tigeot 		*pin_mask |= BIT(i);
158024edb884SFrançois Tigeot 
1581*3f2dd94aSFrançois Tigeot 		port = intel_hpd_pin_to_port(i);
1582*3f2dd94aSFrançois Tigeot 		if (port == PORT_NONE)
15838e26cdf6SFrançois Tigeot 			continue;
15848e26cdf6SFrançois Tigeot 
1585a05eeebfSFrançois Tigeot 		if (long_pulse_detect(port, dig_hotplug_reg))
1586a05eeebfSFrançois Tigeot 			*long_mask |= BIT(i);
158724edb884SFrançois Tigeot 	}
158824edb884SFrançois Tigeot 
1589a05eeebfSFrançois Tigeot 	DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x\n",
1590a05eeebfSFrançois Tigeot 			 hotplug_trigger, dig_hotplug_reg, *pin_mask);
15918e26cdf6SFrançois Tigeot 
15928e26cdf6SFrançois Tigeot }
15938e26cdf6SFrançois Tigeot 
gmbus_irq_handler(struct drm_i915_private * dev_priv)15941487f786SFrançois Tigeot static void gmbus_irq_handler(struct drm_i915_private *dev_priv)
1595a2fdbec6SFrançois Tigeot {
1596a2fdbec6SFrançois Tigeot 	wake_up_all(&dev_priv->gmbus_wait_queue);
1597a2fdbec6SFrançois Tigeot }
1598a2fdbec6SFrançois Tigeot 
dp_aux_irq_handler(struct drm_i915_private * dev_priv)15991487f786SFrançois Tigeot static void dp_aux_irq_handler(struct drm_i915_private *dev_priv)
1600a2fdbec6SFrançois Tigeot {
1601a2fdbec6SFrançois Tigeot 	wake_up_all(&dev_priv->gmbus_wait_queue);
1602a2fdbec6SFrançois Tigeot }
1603a2fdbec6SFrançois Tigeot 
16049edbd4a0SFrançois Tigeot #if defined(CONFIG_DEBUG_FS)
display_pipe_crc_irq_handler(struct drm_i915_private * dev_priv,enum i915_pipe pipe,uint32_t crc0,uint32_t crc1,uint32_t crc2,uint32_t crc3,uint32_t crc4)16051487f786SFrançois Tigeot static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
16061487f786SFrançois Tigeot 					 enum i915_pipe pipe,
16079edbd4a0SFrançois Tigeot 					 uint32_t crc0, uint32_t crc1,
16089edbd4a0SFrançois Tigeot 					 uint32_t crc2, uint32_t crc3,
16099edbd4a0SFrançois Tigeot 					 uint32_t crc4)
16105d0b1887SFrançois Tigeot {
16119edbd4a0SFrançois Tigeot 	struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
16129edbd4a0SFrançois Tigeot 	struct intel_pipe_crc_entry *entry;
1613a85cb24fSFrançois Tigeot 	struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
1614a85cb24fSFrançois Tigeot 	struct drm_driver *driver = dev_priv->drm.driver;
1615a85cb24fSFrançois Tigeot 	uint32_t crcs[5];
16169edbd4a0SFrançois Tigeot 	int head, tail;
16179edbd4a0SFrançois Tigeot 
16181e12ee3bSFrançois Tigeot 	lockmgr(&pipe_crc->lock, LK_EXCLUSIVE);
1619a85cb24fSFrançois Tigeot 	if (pipe_crc->source) {
16209edbd4a0SFrançois Tigeot 		if (!pipe_crc->entries) {
16211e12ee3bSFrançois Tigeot 			lockmgr(&pipe_crc->lock, LK_RELEASE);
16222c9916cdSFrançois Tigeot 			DRM_DEBUG_KMS("spurious interrupt\n");
16239edbd4a0SFrançois Tigeot 			return;
16249edbd4a0SFrançois Tigeot 		}
16259edbd4a0SFrançois Tigeot 
16269edbd4a0SFrançois Tigeot 		head = pipe_crc->head;
16279edbd4a0SFrançois Tigeot 		tail = pipe_crc->tail;
16289edbd4a0SFrançois Tigeot 
16299edbd4a0SFrançois Tigeot 		if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) {
16301e12ee3bSFrançois Tigeot 			lockmgr(&pipe_crc->lock, LK_RELEASE);
16319edbd4a0SFrançois Tigeot 			DRM_ERROR("CRC buffer overflowing\n");
16329edbd4a0SFrançois Tigeot 			return;
16339edbd4a0SFrançois Tigeot 		}
16349edbd4a0SFrançois Tigeot 
16359edbd4a0SFrançois Tigeot 		entry = &pipe_crc->entries[head];
16369edbd4a0SFrançois Tigeot 
1637a85cb24fSFrançois Tigeot 		entry->frame = driver->get_vblank_counter(&dev_priv->drm, pipe);
16389edbd4a0SFrançois Tigeot 		entry->crc[0] = crc0;
16399edbd4a0SFrançois Tigeot 		entry->crc[1] = crc1;
16409edbd4a0SFrançois Tigeot 		entry->crc[2] = crc2;
16419edbd4a0SFrançois Tigeot 		entry->crc[3] = crc3;
16429edbd4a0SFrançois Tigeot 		entry->crc[4] = crc4;
16439edbd4a0SFrançois Tigeot 
16449edbd4a0SFrançois Tigeot 		head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
16459edbd4a0SFrançois Tigeot 		pipe_crc->head = head;
16469edbd4a0SFrançois Tigeot 
16471e12ee3bSFrançois Tigeot 		lockmgr(&pipe_crc->lock, LK_RELEASE);
16489edbd4a0SFrançois Tigeot 
16499edbd4a0SFrançois Tigeot 		wake_up_interruptible(&pipe_crc->wq);
1650a85cb24fSFrançois Tigeot 	} else {
1651a85cb24fSFrançois Tigeot 		/*
1652a85cb24fSFrançois Tigeot 		 * For some not yet identified reason, the first CRC is
1653a85cb24fSFrançois Tigeot 		 * bonkers. So let's just wait for the next vblank and read
1654a85cb24fSFrançois Tigeot 		 * out the buggy result.
1655a85cb24fSFrançois Tigeot 		 *
1656*3f2dd94aSFrançois Tigeot 		 * On GEN8+ sometimes the second CRC is bonkers as well, so
1657a85cb24fSFrançois Tigeot 		 * don't trust that one either.
1658a85cb24fSFrançois Tigeot 		 */
1659a85cb24fSFrançois Tigeot 		if (pipe_crc->skipped == 0 ||
1660*3f2dd94aSFrançois Tigeot 		    (INTEL_GEN(dev_priv) >= 8 && pipe_crc->skipped == 1)) {
1661a85cb24fSFrançois Tigeot 			pipe_crc->skipped++;
1662a85cb24fSFrançois Tigeot 			lockmgr(&pipe_crc->lock, LK_RELEASE);
1663a85cb24fSFrançois Tigeot 			return;
1664a85cb24fSFrançois Tigeot 		}
1665a85cb24fSFrançois Tigeot 		lockmgr(&pipe_crc->lock, LK_RELEASE);
1666a85cb24fSFrançois Tigeot 		crcs[0] = crc0;
1667a85cb24fSFrançois Tigeot 		crcs[1] = crc1;
1668a85cb24fSFrançois Tigeot 		crcs[2] = crc2;
1669a85cb24fSFrançois Tigeot 		crcs[3] = crc3;
1670a85cb24fSFrançois Tigeot 		crcs[4] = crc4;
1671a85cb24fSFrançois Tigeot 		drm_crtc_add_crc_entry(&crtc->base, true,
1672*3f2dd94aSFrançois Tigeot 				       drm_crtc_accurate_vblank_count(&crtc->base),
1673a85cb24fSFrançois Tigeot 				       crcs);
1674a85cb24fSFrançois Tigeot 	}
16759edbd4a0SFrançois Tigeot }
16769edbd4a0SFrançois Tigeot #else
16779edbd4a0SFrançois Tigeot static inline void
display_pipe_crc_irq_handler(struct drm_i915_private * dev_priv,enum i915_pipe pipe,uint32_t crc0,uint32_t crc1,uint32_t crc2,uint32_t crc3,uint32_t crc4)16781487f786SFrançois Tigeot display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
16791487f786SFrançois Tigeot 			     enum i915_pipe pipe,
16809edbd4a0SFrançois Tigeot 			     uint32_t crc0, uint32_t crc1,
16819edbd4a0SFrançois Tigeot 			     uint32_t crc2, uint32_t crc3,
16829edbd4a0SFrançois Tigeot 			     uint32_t crc4) {}
16839edbd4a0SFrançois Tigeot #endif
16849edbd4a0SFrançois Tigeot 
16859edbd4a0SFrançois Tigeot 
hsw_pipe_crc_irq_handler(struct drm_i915_private * dev_priv,enum i915_pipe pipe)16861487f786SFrançois Tigeot static void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
16871487f786SFrançois Tigeot 				     enum i915_pipe pipe)
16889edbd4a0SFrançois Tigeot {
16891487f786SFrançois Tigeot 	display_pipe_crc_irq_handler(dev_priv, pipe,
16909edbd4a0SFrançois Tigeot 				     I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
16919edbd4a0SFrançois Tigeot 				     0, 0, 0, 0);
16929edbd4a0SFrançois Tigeot }
16939edbd4a0SFrançois Tigeot 
ivb_pipe_crc_irq_handler(struct drm_i915_private * dev_priv,enum i915_pipe pipe)16941487f786SFrançois Tigeot static void ivb_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
16951487f786SFrançois Tigeot 				     enum i915_pipe pipe)
16969edbd4a0SFrançois Tigeot {
16971487f786SFrançois Tigeot 	display_pipe_crc_irq_handler(dev_priv, pipe,
16989edbd4a0SFrançois Tigeot 				     I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
16999edbd4a0SFrançois Tigeot 				     I915_READ(PIPE_CRC_RES_2_IVB(pipe)),
17009edbd4a0SFrançois Tigeot 				     I915_READ(PIPE_CRC_RES_3_IVB(pipe)),
17019edbd4a0SFrançois Tigeot 				     I915_READ(PIPE_CRC_RES_4_IVB(pipe)),
17029edbd4a0SFrançois Tigeot 				     I915_READ(PIPE_CRC_RES_5_IVB(pipe)));
17039edbd4a0SFrançois Tigeot }
17049edbd4a0SFrançois Tigeot 
i9xx_pipe_crc_irq_handler(struct drm_i915_private * dev_priv,enum i915_pipe pipe)17051487f786SFrançois Tigeot static void i9xx_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
17061487f786SFrançois Tigeot 				      enum i915_pipe pipe)
17079edbd4a0SFrançois Tigeot {
17089edbd4a0SFrançois Tigeot 	uint32_t res1, res2;
17099edbd4a0SFrançois Tigeot 
17101487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 3)
17119edbd4a0SFrançois Tigeot 		res1 = I915_READ(PIPE_CRC_RES_RES1_I915(pipe));
17129edbd4a0SFrançois Tigeot 	else
17139edbd4a0SFrançois Tigeot 		res1 = 0;
17149edbd4a0SFrançois Tigeot 
17151487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
17169edbd4a0SFrançois Tigeot 		res2 = I915_READ(PIPE_CRC_RES_RES2_G4X(pipe));
17179edbd4a0SFrançois Tigeot 	else
17189edbd4a0SFrançois Tigeot 		res2 = 0;
17199edbd4a0SFrançois Tigeot 
17201487f786SFrançois Tigeot 	display_pipe_crc_irq_handler(dev_priv, pipe,
17219edbd4a0SFrançois Tigeot 				     I915_READ(PIPE_CRC_RES_RED(pipe)),
17229edbd4a0SFrançois Tigeot 				     I915_READ(PIPE_CRC_RES_GREEN(pipe)),
17239edbd4a0SFrançois Tigeot 				     I915_READ(PIPE_CRC_RES_BLUE(pipe)),
17249edbd4a0SFrançois Tigeot 				     res1, res2);
17259edbd4a0SFrançois Tigeot }
17269edbd4a0SFrançois Tigeot 
17279edbd4a0SFrançois Tigeot /* The RPS events need forcewake, so we add them to a work queue and mask their
17289edbd4a0SFrançois Tigeot  * IMR bits until the work is done. Other interrupts can be processed without
17299edbd4a0SFrançois Tigeot  * the work queue. */
gen6_rps_irq_handler(struct drm_i915_private * dev_priv,u32 pm_iir)17309edbd4a0SFrançois Tigeot static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
17319edbd4a0SFrançois Tigeot {
1732*3f2dd94aSFrançois Tigeot 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
1733*3f2dd94aSFrançois Tigeot 
1734ba55f2f5SFrançois Tigeot 	if (pm_iir & dev_priv->pm_rps_events) {
17359edbd4a0SFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
17364be47400SFrançois Tigeot 		gen6_mask_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
1737*3f2dd94aSFrançois Tigeot 		if (rps->interrupts_enabled) {
1738*3f2dd94aSFrançois Tigeot 			rps->pm_iir |= pm_iir & dev_priv->pm_rps_events;
1739*3f2dd94aSFrançois Tigeot 			schedule_work(&rps->work);
17405d0b1887SFrançois Tigeot 		}
17412c9916cdSFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_RELEASE);
17422c9916cdSFrançois Tigeot 	}
17432c9916cdSFrançois Tigeot 
1744*3f2dd94aSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8)
17452c9916cdSFrançois Tigeot 		return;
17465d0b1887SFrançois Tigeot 
17478621f407SFrançois Tigeot 	if (HAS_VEBOX(dev_priv)) {
17485d0b1887SFrançois Tigeot 		if (pm_iir & PM_VEBOX_USER_INTERRUPT)
17491e12ee3bSFrançois Tigeot 			notify_ring(dev_priv->engine[VECS]);
17505d0b1887SFrançois Tigeot 
17512c9916cdSFrançois Tigeot 		if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT)
17522c9916cdSFrançois Tigeot 			DRM_DEBUG("Command parser error, pm_iir 0x%08x\n", pm_iir);
17535d0b1887SFrançois Tigeot 	}
17545d0b1887SFrançois Tigeot }
17555d0b1887SFrançois Tigeot 
gen9_guc_irq_handler(struct drm_i915_private * dev_priv,u32 gt_iir)17564be47400SFrançois Tigeot static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
17574be47400SFrançois Tigeot {
17584be47400SFrançois Tigeot 	if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) {
17594be47400SFrançois Tigeot 		/* Sample the log buffer flush related bits & clear them out now
17604be47400SFrançois Tigeot 		 * itself from the message identity register to minimize the
17614be47400SFrançois Tigeot 		 * probability of losing a flush interrupt, when there are back
17624be47400SFrançois Tigeot 		 * to back flush interrupts.
17634be47400SFrançois Tigeot 		 * There can be a new flush interrupt, for different log buffer
17644be47400SFrançois Tigeot 		 * type (like for ISR), whilst Host is handling one (for DPC).
17654be47400SFrançois Tigeot 		 * Since same bit is used in message register for ISR & DPC, it
17664be47400SFrançois Tigeot 		 * could happen that GuC sets the bit for 2nd interrupt but Host
17674be47400SFrançois Tigeot 		 * clears out the bit on handling the 1st interrupt.
17684be47400SFrançois Tigeot 		 */
17694be47400SFrançois Tigeot 		u32 msg, flush;
17704be47400SFrançois Tigeot 
17714be47400SFrançois Tigeot 		msg = I915_READ(SOFT_SCRATCH(15));
1772a85cb24fSFrançois Tigeot 		flush = msg & (INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED |
1773a85cb24fSFrançois Tigeot 			       INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER);
17744be47400SFrançois Tigeot 		if (flush) {
17754be47400SFrançois Tigeot 			/* Clear the message bits that are handled */
17764be47400SFrançois Tigeot 			I915_WRITE(SOFT_SCRATCH(15), msg & ~flush);
17774be47400SFrançois Tigeot 
17784be47400SFrançois Tigeot 			/* Handle flush interrupt in bottom half */
1779a85cb24fSFrançois Tigeot 			queue_work(dev_priv->guc.log.runtime.flush_wq,
1780a85cb24fSFrançois Tigeot 				   &dev_priv->guc.log.runtime.flush_work);
17814be47400SFrançois Tigeot 
17824be47400SFrançois Tigeot 			dev_priv->guc.log.flush_interrupt_count++;
17834be47400SFrançois Tigeot 		} else {
17844be47400SFrançois Tigeot 			/* Not clearing of unhandled event bits won't result in
17854be47400SFrançois Tigeot 			 * re-triggering of the interrupt.
17864be47400SFrançois Tigeot 			 */
17874be47400SFrançois Tigeot 		}
17884be47400SFrançois Tigeot 	}
17894be47400SFrançois Tigeot }
17904be47400SFrançois Tigeot 
i9xx_pipestat_irq_reset(struct drm_i915_private * dev_priv)1791*3f2dd94aSFrançois Tigeot static void i9xx_pipestat_irq_reset(struct drm_i915_private *dev_priv)
1792ba55f2f5SFrançois Tigeot {
1793*3f2dd94aSFrançois Tigeot 	enum i915_pipe pipe;
1794ba55f2f5SFrançois Tigeot 
1795*3f2dd94aSFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
1796*3f2dd94aSFrançois Tigeot 		I915_WRITE(PIPESTAT(pipe),
1797*3f2dd94aSFrançois Tigeot 			   PIPESTAT_INT_STATUS_MASK |
1798*3f2dd94aSFrançois Tigeot 			   PIPE_FIFO_UNDERRUN_STATUS);
17991487f786SFrançois Tigeot 
1800*3f2dd94aSFrançois Tigeot 		dev_priv->pipestat_irq_mask[pipe] = 0;
1801*3f2dd94aSFrançois Tigeot 	}
1802ba55f2f5SFrançois Tigeot }
1803ba55f2f5SFrançois Tigeot 
i9xx_pipestat_irq_ack(struct drm_i915_private * dev_priv,u32 iir,u32 pipe_stats[I915_MAX_PIPES])1804*3f2dd94aSFrançois Tigeot static void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv,
18051487f786SFrançois Tigeot 				  u32 iir, u32 pipe_stats[I915_MAX_PIPES])
1806ba55f2f5SFrançois Tigeot {
1807ba55f2f5SFrançois Tigeot 	int pipe;
1808ba55f2f5SFrançois Tigeot 
1809ba55f2f5SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1810c0e85e96SFrançois Tigeot 
1811c0e85e96SFrançois Tigeot 	if (!dev_priv->display_irqs_enabled) {
1812c0e85e96SFrançois Tigeot 		lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1813c0e85e96SFrançois Tigeot 		return;
1814c0e85e96SFrançois Tigeot 	}
1815c0e85e96SFrançois Tigeot 
18161b13d190SFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
1817aee94f86SFrançois Tigeot 		i915_reg_t reg;
1818*3f2dd94aSFrançois Tigeot 		u32 status_mask, enable_mask, iir_bit = 0;
1819ba55f2f5SFrançois Tigeot 
1820ba55f2f5SFrançois Tigeot 		/*
1821ba55f2f5SFrançois Tigeot 		 * PIPESTAT bits get signalled even when the interrupt is
1822ba55f2f5SFrançois Tigeot 		 * disabled with the mask bits, and some of the status bits do
1823ba55f2f5SFrançois Tigeot 		 * not generate interrupts at all (like the underrun bit). Hence
1824ba55f2f5SFrançois Tigeot 		 * we need to be careful that we only handle what we want to
1825ba55f2f5SFrançois Tigeot 		 * handle.
1826ba55f2f5SFrançois Tigeot 		 */
18272c9916cdSFrançois Tigeot 
18282c9916cdSFrançois Tigeot 		/* fifo underruns are filterered in the underrun handler. */
1829*3f2dd94aSFrançois Tigeot 		status_mask = PIPE_FIFO_UNDERRUN_STATUS;
1830ba55f2f5SFrançois Tigeot 
1831ba55f2f5SFrançois Tigeot 		switch (pipe) {
1832ba55f2f5SFrançois Tigeot 		case PIPE_A:
1833ba55f2f5SFrançois Tigeot 			iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
1834ba55f2f5SFrançois Tigeot 			break;
1835ba55f2f5SFrançois Tigeot 		case PIPE_B:
1836ba55f2f5SFrançois Tigeot 			iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
1837ba55f2f5SFrançois Tigeot 			break;
1838ba55f2f5SFrançois Tigeot 		case PIPE_C:
1839ba55f2f5SFrançois Tigeot 			iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
1840ba55f2f5SFrançois Tigeot 			break;
1841ba55f2f5SFrançois Tigeot 		}
1842ba55f2f5SFrançois Tigeot 		if (iir & iir_bit)
1843*3f2dd94aSFrançois Tigeot 			status_mask |= dev_priv->pipestat_irq_mask[pipe];
1844ba55f2f5SFrançois Tigeot 
1845*3f2dd94aSFrançois Tigeot 		if (!status_mask)
1846ba55f2f5SFrançois Tigeot 			continue;
1847ba55f2f5SFrançois Tigeot 
1848ba55f2f5SFrançois Tigeot 		reg = PIPESTAT(pipe);
1849*3f2dd94aSFrançois Tigeot 		pipe_stats[pipe] = I915_READ(reg) & status_mask;
1850*3f2dd94aSFrançois Tigeot 		enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
1851ba55f2f5SFrançois Tigeot 
1852ba55f2f5SFrançois Tigeot 		/*
1853ba55f2f5SFrançois Tigeot 		 * Clear the PIPE*STAT regs before the IIR
1854ba55f2f5SFrançois Tigeot 		 */
1855*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe])
1856*3f2dd94aSFrançois Tigeot 			I915_WRITE(reg, enable_mask | pipe_stats[pipe]);
1857ba55f2f5SFrançois Tigeot 	}
1858ba55f2f5SFrançois Tigeot 	lockmgr(&dev_priv->irq_lock, LK_RELEASE);
18598621f407SFrançois Tigeot }
18608621f407SFrançois Tigeot 
i8xx_pipestat_irq_handler(struct drm_i915_private * dev_priv,u16 iir,u32 pipe_stats[I915_MAX_PIPES])1861*3f2dd94aSFrançois Tigeot static void i8xx_pipestat_irq_handler(struct drm_i915_private *dev_priv,
1862*3f2dd94aSFrançois Tigeot 				      u16 iir, u32 pipe_stats[I915_MAX_PIPES])
1863*3f2dd94aSFrançois Tigeot {
1864*3f2dd94aSFrançois Tigeot 	enum i915_pipe pipe;
1865*3f2dd94aSFrançois Tigeot 
1866*3f2dd94aSFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
1867*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
1868*3f2dd94aSFrançois Tigeot 			drm_handle_vblank(&dev_priv->drm, pipe);
1869*3f2dd94aSFrançois Tigeot 
1870*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
1871*3f2dd94aSFrançois Tigeot 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
1872*3f2dd94aSFrançois Tigeot 
1873*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
1874*3f2dd94aSFrançois Tigeot 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
1875*3f2dd94aSFrançois Tigeot 	}
1876*3f2dd94aSFrançois Tigeot }
1877*3f2dd94aSFrançois Tigeot 
i915_pipestat_irq_handler(struct drm_i915_private * dev_priv,u32 iir,u32 pipe_stats[I915_MAX_PIPES])1878*3f2dd94aSFrançois Tigeot static void i915_pipestat_irq_handler(struct drm_i915_private *dev_priv,
1879*3f2dd94aSFrançois Tigeot 				      u32 iir, u32 pipe_stats[I915_MAX_PIPES])
1880*3f2dd94aSFrançois Tigeot {
1881*3f2dd94aSFrançois Tigeot 	bool blc_event = false;
1882*3f2dd94aSFrançois Tigeot 	enum i915_pipe pipe;
1883*3f2dd94aSFrançois Tigeot 
1884*3f2dd94aSFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
1885*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
1886*3f2dd94aSFrançois Tigeot 			drm_handle_vblank(&dev_priv->drm, pipe);
1887*3f2dd94aSFrançois Tigeot 
1888*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
1889*3f2dd94aSFrançois Tigeot 			blc_event = true;
1890*3f2dd94aSFrançois Tigeot 
1891*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
1892*3f2dd94aSFrançois Tigeot 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
1893*3f2dd94aSFrançois Tigeot 
1894*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
1895*3f2dd94aSFrançois Tigeot 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
1896*3f2dd94aSFrançois Tigeot 	}
1897*3f2dd94aSFrançois Tigeot 
1898*3f2dd94aSFrançois Tigeot 	if (blc_event || (iir & I915_ASLE_INTERRUPT))
1899*3f2dd94aSFrançois Tigeot 		intel_opregion_asle_intr(dev_priv);
1900*3f2dd94aSFrançois Tigeot }
1901*3f2dd94aSFrançois Tigeot 
i965_pipestat_irq_handler(struct drm_i915_private * dev_priv,u32 iir,u32 pipe_stats[I915_MAX_PIPES])1902*3f2dd94aSFrançois Tigeot static void i965_pipestat_irq_handler(struct drm_i915_private *dev_priv,
1903*3f2dd94aSFrançois Tigeot 				      u32 iir, u32 pipe_stats[I915_MAX_PIPES])
1904*3f2dd94aSFrançois Tigeot {
1905*3f2dd94aSFrançois Tigeot 	bool blc_event = false;
1906*3f2dd94aSFrançois Tigeot 	enum i915_pipe pipe;
1907*3f2dd94aSFrançois Tigeot 
1908*3f2dd94aSFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
1909*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
1910*3f2dd94aSFrançois Tigeot 			drm_handle_vblank(&dev_priv->drm, pipe);
1911*3f2dd94aSFrançois Tigeot 
1912*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
1913*3f2dd94aSFrançois Tigeot 			blc_event = true;
1914*3f2dd94aSFrançois Tigeot 
1915*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
1916*3f2dd94aSFrançois Tigeot 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
1917*3f2dd94aSFrançois Tigeot 
1918*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
1919*3f2dd94aSFrançois Tigeot 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
1920*3f2dd94aSFrançois Tigeot 	}
1921*3f2dd94aSFrançois Tigeot 
1922*3f2dd94aSFrançois Tigeot 	if (blc_event || (iir & I915_ASLE_INTERRUPT))
1923*3f2dd94aSFrançois Tigeot 		intel_opregion_asle_intr(dev_priv);
1924*3f2dd94aSFrançois Tigeot 
1925*3f2dd94aSFrançois Tigeot 	if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
1926*3f2dd94aSFrançois Tigeot 		gmbus_irq_handler(dev_priv);
1927*3f2dd94aSFrançois Tigeot }
1928*3f2dd94aSFrançois Tigeot 
valleyview_pipestat_irq_handler(struct drm_i915_private * dev_priv,u32 pipe_stats[I915_MAX_PIPES])19291487f786SFrançois Tigeot static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
19308621f407SFrançois Tigeot 					    u32 pipe_stats[I915_MAX_PIPES])
19318621f407SFrançois Tigeot {
19328621f407SFrançois Tigeot 	enum i915_pipe pipe;
1933ba55f2f5SFrançois Tigeot 
19341b13d190SFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
1935*3f2dd94aSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
1936*3f2dd94aSFrançois Tigeot 			drm_handle_vblank(&dev_priv->drm, pipe);
1937ba55f2f5SFrançois Tigeot 
1938ba55f2f5SFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
19391487f786SFrançois Tigeot 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
1940ba55f2f5SFrançois Tigeot 
19412c9916cdSFrançois Tigeot 		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
19422c9916cdSFrançois Tigeot 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
1943ba55f2f5SFrançois Tigeot 	}
1944ba55f2f5SFrançois Tigeot 
1945ba55f2f5SFrançois Tigeot 	if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
19461487f786SFrançois Tigeot 		gmbus_irq_handler(dev_priv);
1947ba55f2f5SFrançois Tigeot }
1948ba55f2f5SFrançois Tigeot 
i9xx_hpd_irq_ack(struct drm_i915_private * dev_priv)19498621f407SFrançois Tigeot static u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv)
1950ba55f2f5SFrançois Tigeot {
1951ba55f2f5SFrançois Tigeot 	u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
1952ba55f2f5SFrançois Tigeot 
19538621f407SFrançois Tigeot 	if (hotplug_status)
1954ba55f2f5SFrançois Tigeot 		I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
19558621f407SFrançois Tigeot 
19568621f407SFrançois Tigeot 	return hotplug_status;
19578621f407SFrançois Tigeot }
19588621f407SFrançois Tigeot 
i9xx_hpd_irq_handler(struct drm_i915_private * dev_priv,u32 hotplug_status)19591487f786SFrançois Tigeot static void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv,
19608621f407SFrançois Tigeot 				 u32 hotplug_status)
19618621f407SFrançois Tigeot {
19628621f407SFrançois Tigeot 	u32 pin_mask = 0, long_mask = 0;
196324edb884SFrançois Tigeot 
19641487f786SFrançois Tigeot 	if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) ||
19651487f786SFrançois Tigeot 	    IS_CHERRYVIEW(dev_priv)) {
196624edb884SFrançois Tigeot 		u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
196724edb884SFrançois Tigeot 
1968352ff8bdSFrançois Tigeot 		if (hotplug_trigger) {
1969a05eeebfSFrançois Tigeot 			intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
1970a05eeebfSFrançois Tigeot 					   hotplug_trigger, hpd_status_g4x,
1971a05eeebfSFrançois Tigeot 					   i9xx_port_hotplug_long_detect);
1972352ff8bdSFrançois Tigeot 
19731487f786SFrançois Tigeot 			intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
1974352ff8bdSFrançois Tigeot 		}
1975a05eeebfSFrançois Tigeot 
1976a05eeebfSFrançois Tigeot 		if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
19771487f786SFrançois Tigeot 			dp_aux_irq_handler(dev_priv);
197824edb884SFrançois Tigeot 	} else {
197924edb884SFrançois Tigeot 		u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
198024edb884SFrançois Tigeot 
1981352ff8bdSFrançois Tigeot 		if (hotplug_trigger) {
1982a05eeebfSFrançois Tigeot 			intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
1983a05eeebfSFrançois Tigeot 					   hotplug_trigger, hpd_status_i915,
1984a05eeebfSFrançois Tigeot 					   i9xx_port_hotplug_long_detect);
19851487f786SFrançois Tigeot 			intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
198624edb884SFrançois Tigeot 		}
1987ba55f2f5SFrançois Tigeot 	}
1988352ff8bdSFrançois Tigeot }
1989ba55f2f5SFrançois Tigeot 
valleyview_irq_handler(int irq,void * arg)1990183e2373SFrançois Tigeot static irqreturn_t valleyview_irq_handler(int irq, void *arg)
1991e9243325SFrançois Tigeot {
1992ba55f2f5SFrançois Tigeot 	struct drm_device *dev = arg;
1993303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1994183e2373SFrançois Tigeot 	irqreturn_t ret = IRQ_NONE;
1995ba55f2f5SFrançois Tigeot 
19962c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
19972c9916cdSFrançois Tigeot 		return IRQ_NONE;
19982c9916cdSFrançois Tigeot 
1999aee94f86SFrançois Tigeot 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
2000aee94f86SFrançois Tigeot 	disable_rpm_wakeref_asserts(dev_priv);
2001aee94f86SFrançois Tigeot 
2002c0e85e96SFrançois Tigeot 	do {
20038621f407SFrançois Tigeot 		u32 iir, gt_iir, pm_iir;
20048621f407SFrançois Tigeot 		u32 pipe_stats[I915_MAX_PIPES] = {};
20058621f407SFrançois Tigeot 		u32 hotplug_status = 0;
20068621f407SFrançois Tigeot 		u32 ier = 0;
20078621f407SFrançois Tigeot 
20088621f407SFrançois Tigeot 		gt_iir = I915_READ(GTIIR);
20098621f407SFrançois Tigeot 		pm_iir = I915_READ(GEN6_PMIIR);
20108621f407SFrançois Tigeot 		iir = I915_READ(VLV_IIR);
20118621f407SFrançois Tigeot 
20128621f407SFrançois Tigeot 		if (gt_iir == 0 && pm_iir == 0 && iir == 0)
20138621f407SFrançois Tigeot 			break;
20148621f407SFrançois Tigeot 
2015183e2373SFrançois Tigeot 		ret = IRQ_HANDLED;
20168621f407SFrançois Tigeot 
20178621f407SFrançois Tigeot 		/*
20188621f407SFrançois Tigeot 		 * Theory on interrupt generation, based on empirical evidence:
20198621f407SFrançois Tigeot 		 *
20208621f407SFrançois Tigeot 		 * x = ((VLV_IIR & VLV_IER) ||
20218621f407SFrançois Tigeot 		 *      (((GT_IIR & GT_IER) || (GEN6_PMIIR & GEN6_PMIER)) &&
20228621f407SFrançois Tigeot 		 *       (VLV_MASTER_IER & MASTER_INTERRUPT_ENABLE)));
20238621f407SFrançois Tigeot 		 *
20248621f407SFrançois Tigeot 		 * A CPU interrupt will only be raised when 'x' has a 0->1 edge.
20258621f407SFrançois Tigeot 		 * Hence we clear MASTER_INTERRUPT_ENABLE and VLV_IER to
20268621f407SFrançois Tigeot 		 * guarantee the CPU interrupt will be raised again even if we
20278621f407SFrançois Tigeot 		 * don't end up clearing all the VLV_IIR, GT_IIR, GEN6_PMIIR
20288621f407SFrançois Tigeot 		 * bits this time around.
20298621f407SFrançois Tigeot 		 */
20308621f407SFrançois Tigeot 		I915_WRITE(VLV_MASTER_IER, 0);
20318621f407SFrançois Tigeot 		ier = I915_READ(VLV_IER);
20328621f407SFrançois Tigeot 		I915_WRITE(VLV_IER, 0);
20338621f407SFrançois Tigeot 
20348621f407SFrançois Tigeot 		if (gt_iir)
20358621f407SFrançois Tigeot 			I915_WRITE(GTIIR, gt_iir);
20368621f407SFrançois Tigeot 		if (pm_iir)
20378621f407SFrançois Tigeot 			I915_WRITE(GEN6_PMIIR, pm_iir);
20388621f407SFrançois Tigeot 
20398621f407SFrançois Tigeot 		if (iir & I915_DISPLAY_PORT_INTERRUPT)
20408621f407SFrançois Tigeot 			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
20418621f407SFrançois Tigeot 
20428621f407SFrançois Tigeot 		/* Call regardless, as some status bits might not be
20438621f407SFrançois Tigeot 		 * signalled in iir */
2044*3f2dd94aSFrançois Tigeot 		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
20458621f407SFrançois Tigeot 
2046a85cb24fSFrançois Tigeot 		if (iir & (I915_LPE_PIPE_A_INTERRUPT |
2047a85cb24fSFrançois Tigeot 			   I915_LPE_PIPE_B_INTERRUPT))
2048a85cb24fSFrançois Tigeot 			intel_lpe_audio_irq_handler(dev_priv);
2049a85cb24fSFrançois Tigeot 
20508621f407SFrançois Tigeot 		/*
20518621f407SFrançois Tigeot 		 * VLV_IIR is single buffered, and reflects the level
20528621f407SFrançois Tigeot 		 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
20538621f407SFrançois Tigeot 		 */
20548621f407SFrançois Tigeot 		if (iir)
20558621f407SFrançois Tigeot 			I915_WRITE(VLV_IIR, iir);
20568621f407SFrançois Tigeot 
20578621f407SFrançois Tigeot 		I915_WRITE(VLV_IER, ier);
20588621f407SFrançois Tigeot 		I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
20598621f407SFrançois Tigeot 		POSTING_READ(VLV_MASTER_IER);
20608621f407SFrançois Tigeot 
20618621f407SFrançois Tigeot 		if (gt_iir)
20628621f407SFrançois Tigeot 			snb_gt_irq_handler(dev_priv, gt_iir);
20638621f407SFrançois Tigeot 		if (pm_iir)
20648621f407SFrançois Tigeot 			gen6_rps_irq_handler(dev_priv, pm_iir);
20658621f407SFrançois Tigeot 
20668621f407SFrançois Tigeot 		if (hotplug_status)
20671487f786SFrançois Tigeot 			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
20688621f407SFrançois Tigeot 
20691487f786SFrançois Tigeot 		valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
20708621f407SFrançois Tigeot 	} while (0);
20718621f407SFrançois Tigeot 
20728621f407SFrançois Tigeot 	enable_rpm_wakeref_asserts(dev_priv);
20738621f407SFrançois Tigeot 
2074183e2373SFrançois Tigeot 	return ret;
20758621f407SFrançois Tigeot }
20768621f407SFrançois Tigeot 
cherryview_irq_handler(int irq,void * arg)2077183e2373SFrançois Tigeot static irqreturn_t cherryview_irq_handler(int irq, void *arg)
20788621f407SFrançois Tigeot {
20798621f407SFrançois Tigeot 	struct drm_device *dev = arg;
2080303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2081183e2373SFrançois Tigeot 	irqreturn_t ret = IRQ_NONE;
20828621f407SFrançois Tigeot 
20838621f407SFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
20848621f407SFrançois Tigeot 		return IRQ_NONE;
20858621f407SFrançois Tigeot 
20868621f407SFrançois Tigeot 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
20878621f407SFrançois Tigeot 	disable_rpm_wakeref_asserts(dev_priv);
20888621f407SFrançois Tigeot 
20898621f407SFrançois Tigeot 	do {
20908621f407SFrançois Tigeot 		u32 master_ctl, iir;
20918621f407SFrançois Tigeot 		u32 gt_iir[4] = {};
20928621f407SFrançois Tigeot 		u32 pipe_stats[I915_MAX_PIPES] = {};
20938621f407SFrançois Tigeot 		u32 hotplug_status = 0;
20948621f407SFrançois Tigeot 		u32 ier = 0;
20958621f407SFrançois Tigeot 
2096ba55f2f5SFrançois Tigeot 		master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
2097ba55f2f5SFrançois Tigeot 		iir = I915_READ(VLV_IIR);
2098ba55f2f5SFrançois Tigeot 
2099ba55f2f5SFrançois Tigeot 		if (master_ctl == 0 && iir == 0)
2100ba55f2f5SFrançois Tigeot 			break;
2101ba55f2f5SFrançois Tigeot 
2102183e2373SFrançois Tigeot 		ret = IRQ_HANDLED;
210324edb884SFrançois Tigeot 
21048621f407SFrançois Tigeot 		/*
21058621f407SFrançois Tigeot 		 * Theory on interrupt generation, based on empirical evidence:
21068621f407SFrançois Tigeot 		 *
21078621f407SFrançois Tigeot 		 * x = ((VLV_IIR & VLV_IER) ||
21088621f407SFrançois Tigeot 		 *      ((GEN8_MASTER_IRQ & ~GEN8_MASTER_IRQ_CONTROL) &&
21098621f407SFrançois Tigeot 		 *       (GEN8_MASTER_IRQ & GEN8_MASTER_IRQ_CONTROL)));
21108621f407SFrançois Tigeot 		 *
21118621f407SFrançois Tigeot 		 * A CPU interrupt will only be raised when 'x' has a 0->1 edge.
21128621f407SFrançois Tigeot 		 * Hence we clear GEN8_MASTER_IRQ_CONTROL and VLV_IER to
21138621f407SFrançois Tigeot 		 * guarantee the CPU interrupt will be raised again even if we
21148621f407SFrançois Tigeot 		 * don't end up clearing all the VLV_IIR and GEN8_MASTER_IRQ_CONTROL
21158621f407SFrançois Tigeot 		 * bits this time around.
21168621f407SFrançois Tigeot 		 */
2117ba55f2f5SFrançois Tigeot 		I915_WRITE(GEN8_MASTER_IRQ, 0);
21188621f407SFrançois Tigeot 		ier = I915_READ(VLV_IER);
21198621f407SFrançois Tigeot 		I915_WRITE(VLV_IER, 0);
2120ba55f2f5SFrançois Tigeot 
21218621f407SFrançois Tigeot 		gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
212224edb884SFrançois Tigeot 
212324edb884SFrançois Tigeot 		if (iir & I915_DISPLAY_PORT_INTERRUPT)
21248621f407SFrançois Tigeot 			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
2125ba55f2f5SFrançois Tigeot 
212624edb884SFrançois Tigeot 		/* Call regardless, as some status bits might not be
212724edb884SFrançois Tigeot 		 * signalled in iir */
2128*3f2dd94aSFrançois Tigeot 		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
2129ba55f2f5SFrançois Tigeot 
2130a85cb24fSFrançois Tigeot 		if (iir & (I915_LPE_PIPE_A_INTERRUPT |
2131a85cb24fSFrançois Tigeot 			   I915_LPE_PIPE_B_INTERRUPT |
2132a85cb24fSFrançois Tigeot 			   I915_LPE_PIPE_C_INTERRUPT))
2133a85cb24fSFrançois Tigeot 			intel_lpe_audio_irq_handler(dev_priv);
2134a85cb24fSFrançois Tigeot 
21358621f407SFrançois Tigeot 		/*
21368621f407SFrançois Tigeot 		 * VLV_IIR is single buffered, and reflects the level
21378621f407SFrançois Tigeot 		 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
21388621f407SFrançois Tigeot 		 */
21398621f407SFrançois Tigeot 		if (iir)
21408621f407SFrançois Tigeot 			I915_WRITE(VLV_IIR, iir);
21418621f407SFrançois Tigeot 
21428621f407SFrançois Tigeot 		I915_WRITE(VLV_IER, ier);
21438621f407SFrançois Tigeot 		I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
2144ba55f2f5SFrançois Tigeot 		POSTING_READ(GEN8_MASTER_IRQ);
21458621f407SFrançois Tigeot 
21468621f407SFrançois Tigeot 		gen8_gt_irq_handler(dev_priv, gt_iir);
21478621f407SFrançois Tigeot 
21488621f407SFrançois Tigeot 		if (hotplug_status)
21491487f786SFrançois Tigeot 			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
21508621f407SFrançois Tigeot 
21511487f786SFrançois Tigeot 		valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
2152c0e85e96SFrançois Tigeot 	} while (0);
215324edb884SFrançois Tigeot 
2154aee94f86SFrançois Tigeot 	enable_rpm_wakeref_asserts(dev_priv);
2155c0e85e96SFrançois Tigeot 
2156183e2373SFrançois Tigeot 	return ret;
2157ba55f2f5SFrançois Tigeot }
2158ba55f2f5SFrançois Tigeot 
ibx_hpd_irq_handler(struct drm_i915_private * dev_priv,u32 hotplug_trigger,const u32 hpd[HPD_NUM_PINS])21591487f786SFrançois Tigeot static void ibx_hpd_irq_handler(struct drm_i915_private *dev_priv,
21601487f786SFrançois Tigeot 				u32 hotplug_trigger,
2161352ff8bdSFrançois Tigeot 				const u32 hpd[HPD_NUM_PINS])
2162352ff8bdSFrançois Tigeot {
2163352ff8bdSFrançois Tigeot 	u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
2164352ff8bdSFrançois Tigeot 
2165aee94f86SFrançois Tigeot 	/*
2166aee94f86SFrançois Tigeot 	 * Somehow the PCH doesn't seem to really ack the interrupt to the CPU
2167aee94f86SFrançois Tigeot 	 * unless we touch the hotplug register, even if hotplug_trigger is
2168aee94f86SFrançois Tigeot 	 * zero. Not acking leads to "The master control interrupt lied (SDE)!"
2169aee94f86SFrançois Tigeot 	 * errors.
2170aee94f86SFrançois Tigeot 	 */
2171352ff8bdSFrançois Tigeot 	dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
2172aee94f86SFrançois Tigeot 	if (!hotplug_trigger) {
2173aee94f86SFrançois Tigeot 		u32 mask = PORTA_HOTPLUG_STATUS_MASK |
2174aee94f86SFrançois Tigeot 			PORTD_HOTPLUG_STATUS_MASK |
2175aee94f86SFrançois Tigeot 			PORTC_HOTPLUG_STATUS_MASK |
2176aee94f86SFrançois Tigeot 			PORTB_HOTPLUG_STATUS_MASK;
2177aee94f86SFrançois Tigeot 		dig_hotplug_reg &= ~mask;
2178aee94f86SFrançois Tigeot 	}
2179aee94f86SFrançois Tigeot 
2180352ff8bdSFrançois Tigeot 	I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
2181aee94f86SFrançois Tigeot 	if (!hotplug_trigger)
2182aee94f86SFrançois Tigeot 		return;
2183352ff8bdSFrançois Tigeot 
2184352ff8bdSFrançois Tigeot 	intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
2185352ff8bdSFrançois Tigeot 			   dig_hotplug_reg, hpd,
2186352ff8bdSFrançois Tigeot 			   pch_port_hotplug_long_detect);
2187352ff8bdSFrançois Tigeot 
21881487f786SFrançois Tigeot 	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
2189352ff8bdSFrançois Tigeot }
2190352ff8bdSFrançois Tigeot 
ibx_irq_handler(struct drm_i915_private * dev_priv,u32 pch_iir)21911487f786SFrançois Tigeot static void ibx_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
2192e3adcf8fSFrançois Tigeot {
2193e3adcf8fSFrançois Tigeot 	int pipe;
21948e26cdf6SFrançois Tigeot 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
2195a05eeebfSFrançois Tigeot 
21961487f786SFrançois Tigeot 	ibx_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ibx);
21975d0b1887SFrançois Tigeot 
21985d0b1887SFrançois Tigeot 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
21995d0b1887SFrançois Tigeot 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
2200e3adcf8fSFrançois Tigeot 			       SDE_AUDIO_POWER_SHIFT);
22015d0b1887SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
22025d0b1887SFrançois Tigeot 				 port_name(port));
22035d0b1887SFrançois Tigeot 	}
2204e3adcf8fSFrançois Tigeot 
2205a2fdbec6SFrançois Tigeot 	if (pch_iir & SDE_AUX_MASK)
22061487f786SFrançois Tigeot 		dp_aux_irq_handler(dev_priv);
2207a2fdbec6SFrançois Tigeot 
2208e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_GMBUS)
22091487f786SFrançois Tigeot 		gmbus_irq_handler(dev_priv);
2210e3adcf8fSFrançois Tigeot 
2211e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_AUDIO_HDCP_MASK)
2212a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n");
2213e3adcf8fSFrançois Tigeot 
2214e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_AUDIO_TRANS_MASK)
2215a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH transcoder audio interrupt\n");
2216e3adcf8fSFrançois Tigeot 
2217e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_POISON)
2218a2296444SFrançois Tigeot 		DRM_ERROR("PCH poison interrupt\n");
2219e3adcf8fSFrançois Tigeot 
2220e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_FDI_MASK)
22211b13d190SFrançois Tigeot 		for_each_pipe(dev_priv, pipe)
2222a2296444SFrançois Tigeot 			DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
2223e3adcf8fSFrançois Tigeot 					 pipe_name(pipe),
2224e3adcf8fSFrançois Tigeot 					 I915_READ(FDI_RX_IIR(pipe)));
2225e3adcf8fSFrançois Tigeot 
2226e3adcf8fSFrançois Tigeot 	if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE))
2227a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n");
2228e3adcf8fSFrançois Tigeot 
2229e3adcf8fSFrançois Tigeot 	if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR))
2230a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
2231e3adcf8fSFrançois Tigeot 
2232e3adcf8fSFrançois Tigeot 	if (pch_iir & SDE_TRANSA_FIFO_UNDER)
2233*3f2dd94aSFrançois Tigeot 		intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_A);
22345d0b1887SFrançois Tigeot 
22355d0b1887SFrançois Tigeot 	if (pch_iir & SDE_TRANSB_FIFO_UNDER)
2236*3f2dd94aSFrançois Tigeot 		intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_B);
22375d0b1887SFrançois Tigeot }
22385d0b1887SFrançois Tigeot 
ivb_err_int_handler(struct drm_i915_private * dev_priv)22391487f786SFrançois Tigeot static void ivb_err_int_handler(struct drm_i915_private *dev_priv)
22405d0b1887SFrançois Tigeot {
22415d0b1887SFrançois Tigeot 	u32 err_int = I915_READ(GEN7_ERR_INT);
22429edbd4a0SFrançois Tigeot 	enum i915_pipe pipe;
22435d0b1887SFrançois Tigeot 
22445d0b1887SFrançois Tigeot 	if (err_int & ERR_INT_POISON)
22455d0b1887SFrançois Tigeot 		DRM_ERROR("Poison interrupt\n");
22465d0b1887SFrançois Tigeot 
22471b13d190SFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
22482c9916cdSFrançois Tigeot 		if (err_int & ERR_INT_FIFO_UNDERRUN(pipe))
22492c9916cdSFrançois Tigeot 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
22505d0b1887SFrançois Tigeot 
22519edbd4a0SFrançois Tigeot 		if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
22521487f786SFrançois Tigeot 			if (IS_IVYBRIDGE(dev_priv))
22531487f786SFrançois Tigeot 				ivb_pipe_crc_irq_handler(dev_priv, pipe);
22549edbd4a0SFrançois Tigeot 			else
22551487f786SFrançois Tigeot 				hsw_pipe_crc_irq_handler(dev_priv, pipe);
22569edbd4a0SFrançois Tigeot 		}
22579edbd4a0SFrançois Tigeot 	}
22585d0b1887SFrançois Tigeot 
22595d0b1887SFrançois Tigeot 	I915_WRITE(GEN7_ERR_INT, err_int);
22605d0b1887SFrançois Tigeot }
22615d0b1887SFrançois Tigeot 
cpt_serr_int_handler(struct drm_i915_private * dev_priv)22621487f786SFrançois Tigeot static void cpt_serr_int_handler(struct drm_i915_private *dev_priv)
22635d0b1887SFrançois Tigeot {
22645d0b1887SFrançois Tigeot 	u32 serr_int = I915_READ(SERR_INT);
2265*3f2dd94aSFrançois Tigeot 	enum i915_pipe pipe;
22665d0b1887SFrançois Tigeot 
22675d0b1887SFrançois Tigeot 	if (serr_int & SERR_INT_POISON)
22685d0b1887SFrançois Tigeot 		DRM_ERROR("PCH poison interrupt\n");
22695d0b1887SFrançois Tigeot 
2270*3f2dd94aSFrançois Tigeot 	for_each_pipe(dev_priv, pipe)
2271*3f2dd94aSFrançois Tigeot 		if (serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pipe))
2272*3f2dd94aSFrançois Tigeot 			intel_pch_fifo_underrun_irq_handler(dev_priv, pipe);
22735d0b1887SFrançois Tigeot 
22745d0b1887SFrançois Tigeot 	I915_WRITE(SERR_INT, serr_int);
2275a2296444SFrançois Tigeot }
2276a2296444SFrançois Tigeot 
cpt_irq_handler(struct drm_i915_private * dev_priv,u32 pch_iir)22771487f786SFrançois Tigeot static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
2278a2296444SFrançois Tigeot {
2279a2296444SFrançois Tigeot 	int pipe;
2280352ff8bdSFrançois Tigeot 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
2281a05eeebfSFrançois Tigeot 
22821487f786SFrançois Tigeot 	ibx_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_cpt);
22835d0b1887SFrançois Tigeot 
22845d0b1887SFrançois Tigeot 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
22855d0b1887SFrançois Tigeot 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
2286a2296444SFrançois Tigeot 			       SDE_AUDIO_POWER_SHIFT_CPT);
22875d0b1887SFrançois Tigeot 		DRM_DEBUG_DRIVER("PCH audio power change on port %c\n",
22885d0b1887SFrançois Tigeot 				 port_name(port));
22895d0b1887SFrançois Tigeot 	}
2290a2296444SFrançois Tigeot 
2291a2296444SFrançois Tigeot 	if (pch_iir & SDE_AUX_MASK_CPT)
22921487f786SFrançois Tigeot 		dp_aux_irq_handler(dev_priv);
2293a2296444SFrançois Tigeot 
2294a2296444SFrançois Tigeot 	if (pch_iir & SDE_GMBUS_CPT)
22951487f786SFrançois Tigeot 		gmbus_irq_handler(dev_priv);
2296a2296444SFrançois Tigeot 
2297a2296444SFrançois Tigeot 	if (pch_iir & SDE_AUDIO_CP_REQ_CPT)
2298a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("Audio CP request interrupt\n");
2299a2296444SFrançois Tigeot 
2300a2296444SFrançois Tigeot 	if (pch_iir & SDE_AUDIO_CP_CHG_CPT)
2301a2296444SFrançois Tigeot 		DRM_DEBUG_DRIVER("Audio CP change interrupt\n");
2302a2296444SFrançois Tigeot 
2303a2296444SFrançois Tigeot 	if (pch_iir & SDE_FDI_MASK_CPT)
23041b13d190SFrançois Tigeot 		for_each_pipe(dev_priv, pipe)
2305a2296444SFrançois Tigeot 			DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
2306a2296444SFrançois Tigeot 					 pipe_name(pipe),
2307a2296444SFrançois Tigeot 					 I915_READ(FDI_RX_IIR(pipe)));
23085d0b1887SFrançois Tigeot 
23095d0b1887SFrançois Tigeot 	if (pch_iir & SDE_ERROR_CPT)
23101487f786SFrançois Tigeot 		cpt_serr_int_handler(dev_priv);
2311e3adcf8fSFrançois Tigeot }
2312e3adcf8fSFrançois Tigeot 
spt_irq_handler(struct drm_i915_private * dev_priv,u32 pch_iir)23131487f786SFrançois Tigeot static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
2314352ff8bdSFrançois Tigeot {
2315352ff8bdSFrançois Tigeot 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT &
2316352ff8bdSFrançois Tigeot 		~SDE_PORTE_HOTPLUG_SPT;
2317352ff8bdSFrançois Tigeot 	u32 hotplug2_trigger = pch_iir & SDE_PORTE_HOTPLUG_SPT;
2318352ff8bdSFrançois Tigeot 	u32 pin_mask = 0, long_mask = 0;
2319352ff8bdSFrançois Tigeot 
2320352ff8bdSFrançois Tigeot 	if (hotplug_trigger) {
2321352ff8bdSFrançois Tigeot 		u32 dig_hotplug_reg;
2322352ff8bdSFrançois Tigeot 
2323352ff8bdSFrançois Tigeot 		dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
2324352ff8bdSFrançois Tigeot 		I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
2325352ff8bdSFrançois Tigeot 
2326352ff8bdSFrançois Tigeot 		intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
2327352ff8bdSFrançois Tigeot 				   dig_hotplug_reg, hpd_spt,
2328352ff8bdSFrançois Tigeot 				   spt_port_hotplug_long_detect);
2329352ff8bdSFrançois Tigeot 	}
2330352ff8bdSFrançois Tigeot 
2331352ff8bdSFrançois Tigeot 	if (hotplug2_trigger) {
2332352ff8bdSFrançois Tigeot 		u32 dig_hotplug_reg;
2333352ff8bdSFrançois Tigeot 
2334352ff8bdSFrançois Tigeot 		dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2);
2335352ff8bdSFrançois Tigeot 		I915_WRITE(PCH_PORT_HOTPLUG2, dig_hotplug_reg);
2336352ff8bdSFrançois Tigeot 
2337352ff8bdSFrançois Tigeot 		intel_get_hpd_pins(&pin_mask, &long_mask, hotplug2_trigger,
2338352ff8bdSFrançois Tigeot 				   dig_hotplug_reg, hpd_spt,
2339352ff8bdSFrançois Tigeot 				   spt_port_hotplug2_long_detect);
2340352ff8bdSFrançois Tigeot 	}
2341352ff8bdSFrançois Tigeot 
2342352ff8bdSFrançois Tigeot 	if (pin_mask)
23431487f786SFrançois Tigeot 		intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
2344352ff8bdSFrançois Tigeot 
2345352ff8bdSFrançois Tigeot 	if (pch_iir & SDE_GMBUS_CPT)
23461487f786SFrançois Tigeot 		gmbus_irq_handler(dev_priv);
2347352ff8bdSFrançois Tigeot }
2348352ff8bdSFrançois Tigeot 
ilk_hpd_irq_handler(struct drm_i915_private * dev_priv,u32 hotplug_trigger,const u32 hpd[HPD_NUM_PINS])23491487f786SFrançois Tigeot static void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv,
23501487f786SFrançois Tigeot 				u32 hotplug_trigger,
2351352ff8bdSFrançois Tigeot 				const u32 hpd[HPD_NUM_PINS])
2352352ff8bdSFrançois Tigeot {
2353352ff8bdSFrançois Tigeot 	u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
2354352ff8bdSFrançois Tigeot 
2355352ff8bdSFrançois Tigeot 	dig_hotplug_reg = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
2356352ff8bdSFrançois Tigeot 	I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, dig_hotplug_reg);
2357352ff8bdSFrançois Tigeot 
2358352ff8bdSFrançois Tigeot 	intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
2359352ff8bdSFrançois Tigeot 			   dig_hotplug_reg, hpd,
2360352ff8bdSFrançois Tigeot 			   ilk_port_hotplug_long_detect);
2361352ff8bdSFrançois Tigeot 
23621487f786SFrançois Tigeot 	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
2363352ff8bdSFrançois Tigeot }
2364352ff8bdSFrançois Tigeot 
ilk_display_irq_handler(struct drm_i915_private * dev_priv,u32 de_iir)23651487f786SFrançois Tigeot static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
23661487f786SFrançois Tigeot 				    u32 de_iir)
2367c4a9e910SFrançois Tigeot {
23689edbd4a0SFrançois Tigeot 	enum i915_pipe pipe;
2369352ff8bdSFrançois Tigeot 	u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG;
2370352ff8bdSFrançois Tigeot 
2371352ff8bdSFrançois Tigeot 	if (hotplug_trigger)
23721487f786SFrançois Tigeot 		ilk_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ilk);
2373e3adcf8fSFrançois Tigeot 
2374a2fdbec6SFrançois Tigeot 	if (de_iir & DE_AUX_CHANNEL_A)
23751487f786SFrançois Tigeot 		dp_aux_irq_handler(dev_priv);
2376a2fdbec6SFrançois Tigeot 
237700640ec9SFrançois Tigeot 	if (de_iir & DE_GSE)
23781487f786SFrançois Tigeot 		intel_opregion_asle_intr(dev_priv);
2379e3adcf8fSFrançois Tigeot 
23805d0b1887SFrançois Tigeot 	if (de_iir & DE_POISON)
23815d0b1887SFrançois Tigeot 		DRM_ERROR("Poison interrupt\n");
23825d0b1887SFrançois Tigeot 
23831b13d190SFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
2384*3f2dd94aSFrançois Tigeot 		if (de_iir & DE_PIPE_VBLANK(pipe))
2385*3f2dd94aSFrançois Tigeot 			drm_handle_vblank(&dev_priv->drm, pipe);
23865d0b1887SFrançois Tigeot 
23879edbd4a0SFrançois Tigeot 		if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
23882c9916cdSFrançois Tigeot 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
23895d0b1887SFrançois Tigeot 
23909edbd4a0SFrançois Tigeot 		if (de_iir & DE_PIPE_CRC_DONE(pipe))
23911487f786SFrançois Tigeot 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
2392e3adcf8fSFrançois Tigeot 	}
2393e3adcf8fSFrançois Tigeot 
2394e3adcf8fSFrançois Tigeot 	/* check event from PCH */
2395e3adcf8fSFrançois Tigeot 	if (de_iir & DE_PCH_EVENT) {
2396a2fdbec6SFrançois Tigeot 		u32 pch_iir = I915_READ(SDEIIR);
2397a2fdbec6SFrançois Tigeot 
23981487f786SFrançois Tigeot 		if (HAS_PCH_CPT(dev_priv))
23991487f786SFrançois Tigeot 			cpt_irq_handler(dev_priv, pch_iir);
2400a2296444SFrançois Tigeot 		else
24011487f786SFrançois Tigeot 			ibx_irq_handler(dev_priv, pch_iir);
2402a2fdbec6SFrançois Tigeot 
2403a2fdbec6SFrançois Tigeot 		/* should clear PCH hotplug event before clear CPU irq */
2404a2fdbec6SFrançois Tigeot 		I915_WRITE(SDEIIR, pch_iir);
2405e3adcf8fSFrançois Tigeot 	}
2406e3adcf8fSFrançois Tigeot 
24071487f786SFrançois Tigeot 	if (IS_GEN5(dev_priv) && de_iir & DE_PCU_EVENT)
24081487f786SFrançois Tigeot 		ironlake_rps_change_irq_handler(dev_priv);
24099edbd4a0SFrançois Tigeot }
2410e3adcf8fSFrançois Tigeot 
ivb_display_irq_handler(struct drm_i915_private * dev_priv,u32 de_iir)24111487f786SFrançois Tigeot static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
24121487f786SFrançois Tigeot 				    u32 de_iir)
24139edbd4a0SFrançois Tigeot {
2414ba55f2f5SFrançois Tigeot 	enum i915_pipe pipe;
2415352ff8bdSFrançois Tigeot 	u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB;
2416352ff8bdSFrançois Tigeot 
2417352ff8bdSFrançois Tigeot 	if (hotplug_trigger)
24181487f786SFrançois Tigeot 		ilk_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ivb);
2419e3adcf8fSFrançois Tigeot 
24209edbd4a0SFrançois Tigeot 	if (de_iir & DE_ERR_INT_IVB)
24211487f786SFrançois Tigeot 		ivb_err_int_handler(dev_priv);
24229edbd4a0SFrançois Tigeot 
24239edbd4a0SFrançois Tigeot 	if (de_iir & DE_AUX_CHANNEL_A_IVB)
24241487f786SFrançois Tigeot 		dp_aux_irq_handler(dev_priv);
24259edbd4a0SFrançois Tigeot 
24269edbd4a0SFrançois Tigeot 	if (de_iir & DE_GSE_IVB)
24271487f786SFrançois Tigeot 		intel_opregion_asle_intr(dev_priv);
24289edbd4a0SFrançois Tigeot 
24291b13d190SFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
2430*3f2dd94aSFrançois Tigeot 		if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
2431*3f2dd94aSFrançois Tigeot 			drm_handle_vblank(&dev_priv->drm, pipe);
24329edbd4a0SFrançois Tigeot 	}
24339edbd4a0SFrançois Tigeot 
24349edbd4a0SFrançois Tigeot 	/* check event from PCH */
24351487f786SFrançois Tigeot 	if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) {
24369edbd4a0SFrançois Tigeot 		u32 pch_iir = I915_READ(SDEIIR);
24379edbd4a0SFrançois Tigeot 
24381487f786SFrançois Tigeot 		cpt_irq_handler(dev_priv, pch_iir);
24399edbd4a0SFrançois Tigeot 
24409edbd4a0SFrançois Tigeot 		/* clear PCH hotplug event before clear CPU irq */
24419edbd4a0SFrançois Tigeot 		I915_WRITE(SDEIIR, pch_iir);
24429edbd4a0SFrançois Tigeot 	}
24439edbd4a0SFrançois Tigeot }
24449edbd4a0SFrançois Tigeot 
244524edb884SFrançois Tigeot /*
244624edb884SFrançois Tigeot  * To handle irqs with the minimum potential races with fresh interrupts, we:
244724edb884SFrançois Tigeot  * 1 - Disable Master Interrupt Control.
244824edb884SFrançois Tigeot  * 2 - Find the source(s) of the interrupt.
244924edb884SFrançois Tigeot  * 3 - Clear the Interrupt Identity bits (IIR).
245024edb884SFrançois Tigeot  * 4 - Process the interrupt(s) that had bits set in the IIRs.
245124edb884SFrançois Tigeot  * 5 - Re-enable Master Interrupt Control.
245224edb884SFrançois Tigeot  */
ironlake_irq_handler(int irq,void * arg)2453183e2373SFrançois Tigeot static irqreturn_t ironlake_irq_handler(int irq, void *arg)
24549edbd4a0SFrançois Tigeot {
2455ba55f2f5SFrançois Tigeot 	struct drm_device *dev = arg;
2456303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
24579edbd4a0SFrançois Tigeot 	u32 de_iir, gt_iir, de_ier, sde_ier = 0;
2458183e2373SFrançois Tigeot 	irqreturn_t ret = IRQ_NONE;
24599edbd4a0SFrançois Tigeot 
24602c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
24612c9916cdSFrançois Tigeot 		return IRQ_NONE;
24622c9916cdSFrançois Tigeot 
2463aee94f86SFrançois Tigeot 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
2464aee94f86SFrançois Tigeot 	disable_rpm_wakeref_asserts(dev_priv);
2465aee94f86SFrançois Tigeot 
24669edbd4a0SFrançois Tigeot 	/* disable master interrupt before clearing iir  */
24679edbd4a0SFrançois Tigeot 	de_ier = I915_READ(DEIER);
24689edbd4a0SFrançois Tigeot 	I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
24699edbd4a0SFrançois Tigeot 	POSTING_READ(DEIER);
24709edbd4a0SFrançois Tigeot 
24719edbd4a0SFrançois Tigeot 	/* Disable south interrupts. We'll only write to SDEIIR once, so further
24729edbd4a0SFrançois Tigeot 	 * interrupts will will be stored on its back queue, and then we'll be
24739edbd4a0SFrançois Tigeot 	 * able to process them after we restore SDEIER (as soon as we restore
24749edbd4a0SFrançois Tigeot 	 * it, we'll get an interrupt if SDEIIR still has something to process
24759edbd4a0SFrançois Tigeot 	 * due to its back queue). */
24761487f786SFrançois Tigeot 	if (!HAS_PCH_NOP(dev_priv)) {
24779edbd4a0SFrançois Tigeot 		sde_ier = I915_READ(SDEIER);
24789edbd4a0SFrançois Tigeot 		I915_WRITE(SDEIER, 0);
24799edbd4a0SFrançois Tigeot 		POSTING_READ(SDEIER);
24809edbd4a0SFrançois Tigeot 	}
24819edbd4a0SFrançois Tigeot 
248224edb884SFrançois Tigeot 	/* Find, clear, then process each source of interrupt */
248324edb884SFrançois Tigeot 
24849edbd4a0SFrançois Tigeot 	gt_iir = I915_READ(GTIIR);
24859edbd4a0SFrançois Tigeot 	if (gt_iir) {
248624edb884SFrançois Tigeot 		I915_WRITE(GTIIR, gt_iir);
2487183e2373SFrançois Tigeot 		ret = IRQ_HANDLED;
24881487f786SFrançois Tigeot 		if (INTEL_GEN(dev_priv) >= 6)
24898621f407SFrançois Tigeot 			snb_gt_irq_handler(dev_priv, gt_iir);
24909edbd4a0SFrançois Tigeot 		else
24918621f407SFrançois Tigeot 			ilk_gt_irq_handler(dev_priv, gt_iir);
24929edbd4a0SFrançois Tigeot 	}
2493e3adcf8fSFrançois Tigeot 
24949edbd4a0SFrançois Tigeot 	de_iir = I915_READ(DEIIR);
24959edbd4a0SFrançois Tigeot 	if (de_iir) {
249624edb884SFrançois Tigeot 		I915_WRITE(DEIIR, de_iir);
2497183e2373SFrançois Tigeot 		ret = IRQ_HANDLED;
24981487f786SFrançois Tigeot 		if (INTEL_GEN(dev_priv) >= 7)
24991487f786SFrançois Tigeot 			ivb_display_irq_handler(dev_priv, de_iir);
25009edbd4a0SFrançois Tigeot 		else
25011487f786SFrançois Tigeot 			ilk_display_irq_handler(dev_priv, de_iir);
25029edbd4a0SFrançois Tigeot 	}
25039edbd4a0SFrançois Tigeot 
25041487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 6) {
25059edbd4a0SFrançois Tigeot 		u32 pm_iir = I915_READ(GEN6_PMIIR);
25069edbd4a0SFrançois Tigeot 		if (pm_iir) {
25079edbd4a0SFrançois Tigeot 			I915_WRITE(GEN6_PMIIR, pm_iir);
2508183e2373SFrançois Tigeot 			ret = IRQ_HANDLED;
250924edb884SFrançois Tigeot 			gen6_rps_irq_handler(dev_priv, pm_iir);
25109edbd4a0SFrançois Tigeot 		}
25119edbd4a0SFrançois Tigeot 	}
25129edbd4a0SFrançois Tigeot 
2513e3adcf8fSFrançois Tigeot 	I915_WRITE(DEIER, de_ier);
2514e3adcf8fSFrançois Tigeot 	POSTING_READ(DEIER);
25151487f786SFrançois Tigeot 	if (!HAS_PCH_NOP(dev_priv)) {
2516a2fdbec6SFrançois Tigeot 		I915_WRITE(SDEIER, sde_ier);
2517a2fdbec6SFrançois Tigeot 		POSTING_READ(SDEIER);
2518e3adcf8fSFrançois Tigeot 	}
2519e3adcf8fSFrançois Tigeot 
2520aee94f86SFrançois Tigeot 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
2521aee94f86SFrançois Tigeot 	enable_rpm_wakeref_asserts(dev_priv);
2522aee94f86SFrançois Tigeot 
2523183e2373SFrançois Tigeot 	return ret;
25249edbd4a0SFrançois Tigeot }
25259edbd4a0SFrançois Tigeot 
bxt_hpd_irq_handler(struct drm_i915_private * dev_priv,u32 hotplug_trigger,const u32 hpd[HPD_NUM_PINS])25261487f786SFrançois Tigeot static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv,
25271487f786SFrançois Tigeot 				u32 hotplug_trigger,
2528352ff8bdSFrançois Tigeot 				const u32 hpd[HPD_NUM_PINS])
252919c468b4SFrançois Tigeot {
2530352ff8bdSFrançois Tigeot 	u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
253119c468b4SFrançois Tigeot 
2532352ff8bdSFrançois Tigeot 	dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
2533352ff8bdSFrançois Tigeot 	I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
253419c468b4SFrançois Tigeot 
2535352ff8bdSFrançois Tigeot 	intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
2536352ff8bdSFrançois Tigeot 			   dig_hotplug_reg, hpd,
2537352ff8bdSFrançois Tigeot 			   bxt_port_hotplug_long_detect);
253819c468b4SFrançois Tigeot 
25391487f786SFrançois Tigeot 	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
254019c468b4SFrançois Tigeot }
254119c468b4SFrançois Tigeot 
2542c0e85e96SFrançois Tigeot static irqreturn_t
gen8_de_irq_handler(struct drm_i915_private * dev_priv,u32 master_ctl)2543c0e85e96SFrançois Tigeot gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
25449edbd4a0SFrançois Tigeot {
2545183e2373SFrançois Tigeot 	irqreturn_t ret = IRQ_NONE;
2546c0e85e96SFrançois Tigeot 	u32 iir;
25479edbd4a0SFrançois Tigeot 	enum i915_pipe pipe;
25489edbd4a0SFrançois Tigeot 
25499edbd4a0SFrançois Tigeot 	if (master_ctl & GEN8_DE_MISC_IRQ) {
2550c0e85e96SFrançois Tigeot 		iir = I915_READ(GEN8_DE_MISC_IIR);
2551c0e85e96SFrançois Tigeot 		if (iir) {
2552c0e85e96SFrançois Tigeot 			I915_WRITE(GEN8_DE_MISC_IIR, iir);
2553183e2373SFrançois Tigeot 			ret = IRQ_HANDLED;
2554c0e85e96SFrançois Tigeot 			if (iir & GEN8_DE_MISC_GSE)
25551487f786SFrançois Tigeot 				intel_opregion_asle_intr(dev_priv);
255624edb884SFrançois Tigeot 			else
255724edb884SFrançois Tigeot 				DRM_ERROR("Unexpected DE Misc interrupt\n");
25589edbd4a0SFrançois Tigeot 		}
255924edb884SFrançois Tigeot 		else
256024edb884SFrançois Tigeot 			DRM_ERROR("The master control interrupt lied (DE MISC)!\n");
25619edbd4a0SFrançois Tigeot 	}
25629edbd4a0SFrançois Tigeot 
25639edbd4a0SFrançois Tigeot 	if (master_ctl & GEN8_DE_PORT_IRQ) {
2564c0e85e96SFrançois Tigeot 		iir = I915_READ(GEN8_DE_PORT_IIR);
2565c0e85e96SFrançois Tigeot 		if (iir) {
2566c0e85e96SFrançois Tigeot 			u32 tmp_mask;
256719c468b4SFrançois Tigeot 			bool found = false;
2568352ff8bdSFrançois Tigeot 
2569c0e85e96SFrançois Tigeot 			I915_WRITE(GEN8_DE_PORT_IIR, iir);
2570183e2373SFrançois Tigeot 			ret = IRQ_HANDLED;
257119c468b4SFrançois Tigeot 
2572c0e85e96SFrançois Tigeot 			tmp_mask = GEN8_AUX_CHANNEL_A;
2573*3f2dd94aSFrançois Tigeot 			if (INTEL_GEN(dev_priv) >= 9)
2574c0e85e96SFrançois Tigeot 				tmp_mask |= GEN9_AUX_CHANNEL_B |
2575c0e85e96SFrançois Tigeot 					    GEN9_AUX_CHANNEL_C |
2576c0e85e96SFrançois Tigeot 					    GEN9_AUX_CHANNEL_D;
257719c468b4SFrançois Tigeot 
2578c0e85e96SFrançois Tigeot 			if (iir & tmp_mask) {
25791487f786SFrançois Tigeot 				dp_aux_irq_handler(dev_priv);
258019c468b4SFrançois Tigeot 				found = true;
258119c468b4SFrançois Tigeot 			}
258219c468b4SFrançois Tigeot 
2583a85cb24fSFrançois Tigeot 			if (IS_GEN9_LP(dev_priv)) {
2584c0e85e96SFrançois Tigeot 				tmp_mask = iir & BXT_DE_PORT_HOTPLUG_MASK;
2585c0e85e96SFrançois Tigeot 				if (tmp_mask) {
25861487f786SFrançois Tigeot 					bxt_hpd_irq_handler(dev_priv, tmp_mask,
25871487f786SFrançois Tigeot 							    hpd_bxt);
258819c468b4SFrançois Tigeot 					found = true;
258919c468b4SFrançois Tigeot 				}
2590c0e85e96SFrançois Tigeot 			} else if (IS_BROADWELL(dev_priv)) {
2591c0e85e96SFrançois Tigeot 				tmp_mask = iir & GEN8_PORT_DP_A_HOTPLUG;
2592c0e85e96SFrançois Tigeot 				if (tmp_mask) {
25931487f786SFrançois Tigeot 					ilk_hpd_irq_handler(dev_priv,
25941487f786SFrançois Tigeot 							    tmp_mask, hpd_bdw);
2595c0e85e96SFrançois Tigeot 					found = true;
2596c0e85e96SFrançois Tigeot 				}
2597c0e85e96SFrançois Tigeot 			}
259819c468b4SFrançois Tigeot 
2599a85cb24fSFrançois Tigeot 			if (IS_GEN9_LP(dev_priv) && (iir & BXT_DE_PORT_GMBUS)) {
26001487f786SFrançois Tigeot 				gmbus_irq_handler(dev_priv);
260119c468b4SFrançois Tigeot 				found = true;
260219c468b4SFrançois Tigeot 			}
260319c468b4SFrançois Tigeot 
260419c468b4SFrançois Tigeot 			if (!found)
260524edb884SFrançois Tigeot 				DRM_ERROR("Unexpected DE Port interrupt\n");
26069edbd4a0SFrançois Tigeot 		}
260724edb884SFrançois Tigeot 		else
260824edb884SFrançois Tigeot 			DRM_ERROR("The master control interrupt lied (DE PORT)!\n");
26099edbd4a0SFrançois Tigeot 	}
26109edbd4a0SFrançois Tigeot 
26111b13d190SFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
2612*3f2dd94aSFrançois Tigeot 		u32 fault_errors;
26139edbd4a0SFrançois Tigeot 
26149edbd4a0SFrançois Tigeot 		if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
26159edbd4a0SFrançois Tigeot 			continue;
26169edbd4a0SFrançois Tigeot 
2617c0e85e96SFrançois Tigeot 		iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
2618c0e85e96SFrançois Tigeot 		if (!iir) {
2619c0e85e96SFrançois Tigeot 			DRM_ERROR("The master control interrupt lied (DE PIPE)!\n");
2620c0e85e96SFrançois Tigeot 			continue;
2621c0e85e96SFrançois Tigeot 		}
26222c9916cdSFrançois Tigeot 
2623183e2373SFrançois Tigeot 		ret = IRQ_HANDLED;
2624c0e85e96SFrançois Tigeot 		I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir);
2625c0e85e96SFrançois Tigeot 
2626*3f2dd94aSFrançois Tigeot 		if (iir & GEN8_PIPE_VBLANK)
2627*3f2dd94aSFrançois Tigeot 			drm_handle_vblank(&dev_priv->drm, pipe);
26289edbd4a0SFrançois Tigeot 
2629c0e85e96SFrançois Tigeot 		if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
26301487f786SFrançois Tigeot 			hsw_pipe_crc_irq_handler(dev_priv, pipe);
26319edbd4a0SFrançois Tigeot 
2632c0e85e96SFrançois Tigeot 		if (iir & GEN8_PIPE_FIFO_UNDERRUN)
2633c0e85e96SFrançois Tigeot 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
26349edbd4a0SFrançois Tigeot 
2635c0e85e96SFrançois Tigeot 		fault_errors = iir;
2636*3f2dd94aSFrançois Tigeot 		if (INTEL_GEN(dev_priv) >= 9)
2637c0e85e96SFrançois Tigeot 			fault_errors &= GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
26382c9916cdSFrançois Tigeot 		else
2639c0e85e96SFrançois Tigeot 			fault_errors &= GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
26402c9916cdSFrançois Tigeot 
26412c9916cdSFrançois Tigeot 		if (fault_errors)
26424be47400SFrançois Tigeot 			DRM_ERROR("Fault errors on pipe %c: 0x%08x\n",
26439edbd4a0SFrançois Tigeot 				  pipe_name(pipe),
2644c0e85e96SFrançois Tigeot 				  fault_errors);
26459edbd4a0SFrançois Tigeot 	}
26469edbd4a0SFrançois Tigeot 
26471487f786SFrançois Tigeot 	if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) &&
264819c468b4SFrançois Tigeot 	    master_ctl & GEN8_DE_PCH_IRQ) {
26499edbd4a0SFrançois Tigeot 		/*
26509edbd4a0SFrançois Tigeot 		 * FIXME(BDW): Assume for now that the new interrupt handling
26519edbd4a0SFrançois Tigeot 		 * scheme also closed the SDE interrupt handling race we've seen
26529edbd4a0SFrançois Tigeot 		 * on older pch-split platforms. But this needs testing.
26539edbd4a0SFrançois Tigeot 		 */
2654c0e85e96SFrançois Tigeot 		iir = I915_READ(SDEIIR);
2655c0e85e96SFrançois Tigeot 		if (iir) {
2656c0e85e96SFrançois Tigeot 			I915_WRITE(SDEIIR, iir);
2657183e2373SFrançois Tigeot 			ret = IRQ_HANDLED;
2658352ff8bdSFrançois Tigeot 
2659*3f2dd94aSFrançois Tigeot 			if (HAS_PCH_SPT(dev_priv) || HAS_PCH_KBP(dev_priv) ||
2660*3f2dd94aSFrançois Tigeot 			    HAS_PCH_CNP(dev_priv))
26611487f786SFrançois Tigeot 				spt_irq_handler(dev_priv, iir);
2662352ff8bdSFrançois Tigeot 			else
26631487f786SFrançois Tigeot 				cpt_irq_handler(dev_priv, iir);
2664aee94f86SFrançois Tigeot 		} else {
2665aee94f86SFrançois Tigeot 			/*
2666aee94f86SFrançois Tigeot 			 * Like on previous PCH there seems to be something
2667aee94f86SFrançois Tigeot 			 * fishy going on with forwarding PCH interrupts.
2668aee94f86SFrançois Tigeot 			 */
2669aee94f86SFrançois Tigeot 			DRM_DEBUG_DRIVER("The master control interrupt lied (SDE)!\n");
2670aee94f86SFrançois Tigeot 		}
26719edbd4a0SFrançois Tigeot 	}
26729edbd4a0SFrançois Tigeot 
2673183e2373SFrançois Tigeot 	return ret;
2674c0e85e96SFrançois Tigeot }
2675c0e85e96SFrançois Tigeot 
gen8_irq_handler(int irq,void * arg)2676183e2373SFrançois Tigeot static irqreturn_t gen8_irq_handler(int irq, void *arg)
2677c0e85e96SFrançois Tigeot {
2678c0e85e96SFrançois Tigeot 	struct drm_device *dev = arg;
2679303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2680c0e85e96SFrançois Tigeot 	u32 master_ctl;
26818621f407SFrançois Tigeot 	u32 gt_iir[4] = {};
2682183e2373SFrançois Tigeot 	irqreturn_t ret;
2683c0e85e96SFrançois Tigeot 
2684c0e85e96SFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
2685c0e85e96SFrançois Tigeot 		return IRQ_NONE;
2686c0e85e96SFrançois Tigeot 
2687c0e85e96SFrançois Tigeot 	master_ctl = I915_READ_FW(GEN8_MASTER_IRQ);
2688c0e85e96SFrançois Tigeot 	master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
2689c0e85e96SFrançois Tigeot 	if (!master_ctl)
2690c0e85e96SFrançois Tigeot 		return IRQ_NONE;
2691c0e85e96SFrançois Tigeot 
2692c0e85e96SFrançois Tigeot 	I915_WRITE_FW(GEN8_MASTER_IRQ, 0);
2693c0e85e96SFrançois Tigeot 
2694c0e85e96SFrançois Tigeot 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
2695c0e85e96SFrançois Tigeot 	disable_rpm_wakeref_asserts(dev_priv);
2696c0e85e96SFrançois Tigeot 
2697c0e85e96SFrançois Tigeot 	/* Find, clear, then process each source of interrupt */
2698183e2373SFrançois Tigeot 	ret = gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
26998621f407SFrançois Tigeot 	gen8_gt_irq_handler(dev_priv, gt_iir);
2700183e2373SFrançois Tigeot 	ret |= gen8_de_irq_handler(dev_priv, master_ctl);
2701c0e85e96SFrançois Tigeot 
270219c468b4SFrançois Tigeot 	I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
270319c468b4SFrançois Tigeot 	POSTING_READ_FW(GEN8_MASTER_IRQ);
27049edbd4a0SFrançois Tigeot 
2705aee94f86SFrançois Tigeot 	enable_rpm_wakeref_asserts(dev_priv);
2706aee94f86SFrançois Tigeot 
2707183e2373SFrançois Tigeot 	return ret;
27089edbd4a0SFrançois Tigeot }
27099edbd4a0SFrançois Tigeot 
2710*3f2dd94aSFrançois Tigeot struct wedge_me {
2711*3f2dd94aSFrançois Tigeot 	struct delayed_work work;
2712*3f2dd94aSFrançois Tigeot 	struct drm_i915_private *i915;
2713*3f2dd94aSFrançois Tigeot 	const char *name;
2714*3f2dd94aSFrançois Tigeot };
2715*3f2dd94aSFrançois Tigeot 
wedge_me(struct work_struct * work)2716*3f2dd94aSFrançois Tigeot static void wedge_me(struct work_struct *work)
2717*3f2dd94aSFrançois Tigeot {
2718*3f2dd94aSFrançois Tigeot 	struct wedge_me *w = container_of(work, typeof(*w), work.work);
2719*3f2dd94aSFrançois Tigeot 
2720*3f2dd94aSFrançois Tigeot 	dev_err(w->i915->drm.dev,
2721*3f2dd94aSFrançois Tigeot 		"%s timed out, cancelling all in-flight rendering.\n",
2722*3f2dd94aSFrançois Tigeot 		w->name);
2723*3f2dd94aSFrançois Tigeot 	i915_gem_set_wedged(w->i915);
2724*3f2dd94aSFrançois Tigeot }
2725*3f2dd94aSFrançois Tigeot 
__init_wedge(struct wedge_me * w,struct drm_i915_private * i915,long timeout,const char * name)2726*3f2dd94aSFrançois Tigeot static void __init_wedge(struct wedge_me *w,
2727*3f2dd94aSFrançois Tigeot 			 struct drm_i915_private *i915,
2728*3f2dd94aSFrançois Tigeot 			 long timeout,
2729*3f2dd94aSFrançois Tigeot 			 const char *name)
2730*3f2dd94aSFrançois Tigeot {
2731*3f2dd94aSFrançois Tigeot 	w->i915 = i915;
2732*3f2dd94aSFrançois Tigeot 	w->name = name;
2733*3f2dd94aSFrançois Tigeot 
2734*3f2dd94aSFrançois Tigeot 	INIT_DELAYED_WORK_ONSTACK(&w->work, wedge_me);
2735*3f2dd94aSFrançois Tigeot 	schedule_delayed_work(&w->work, timeout);
2736*3f2dd94aSFrançois Tigeot }
2737*3f2dd94aSFrançois Tigeot 
__fini_wedge(struct wedge_me * w)2738*3f2dd94aSFrançois Tigeot static void __fini_wedge(struct wedge_me *w)
2739*3f2dd94aSFrançois Tigeot {
2740*3f2dd94aSFrançois Tigeot 	cancel_delayed_work_sync(&w->work);
2741*3f2dd94aSFrançois Tigeot 	destroy_delayed_work_on_stack(&w->work);
2742*3f2dd94aSFrançois Tigeot 	w->i915 = NULL;
2743*3f2dd94aSFrançois Tigeot }
2744*3f2dd94aSFrançois Tigeot 
2745*3f2dd94aSFrançois Tigeot #define i915_wedge_on_timeout(W, DEV, TIMEOUT)				\
2746*3f2dd94aSFrançois Tigeot 	for (__init_wedge((W), (DEV), (TIMEOUT), __func__);		\
2747*3f2dd94aSFrançois Tigeot 	     (W)->i915;							\
2748*3f2dd94aSFrançois Tigeot 	     __fini_wedge((W)))
2749*3f2dd94aSFrançois Tigeot 
2750e3adcf8fSFrançois Tigeot /**
2751*3f2dd94aSFrançois Tigeot  * i915_reset_device - do process context error handling work
27521487f786SFrançois Tigeot  * @dev_priv: i915 device private
2753e3adcf8fSFrançois Tigeot  *
2754e3adcf8fSFrançois Tigeot  * Fire an error uevent so userspace can see that a hang or error
2755e3adcf8fSFrançois Tigeot  * was detected.
2756e3adcf8fSFrançois Tigeot  */
i915_reset_device(struct drm_i915_private * dev_priv)2757*3f2dd94aSFrançois Tigeot static void i915_reset_device(struct drm_i915_private *dev_priv)
2758e3adcf8fSFrançois Tigeot {
2759303bf270SFrançois Tigeot 	struct kobject *kobj = &dev_priv->drm.primary->kdev->kobj;
27609edbd4a0SFrançois Tigeot 	char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
27619edbd4a0SFrançois Tigeot 	char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
27629edbd4a0SFrançois Tigeot 	char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
2763*3f2dd94aSFrançois Tigeot 	struct wedge_me w;
2764e3adcf8fSFrançois Tigeot 
27651487f786SFrançois Tigeot 	kobject_uevent_env(kobj, KOBJ_CHANGE, error_event);
2766e3adcf8fSFrançois Tigeot 
2767abf1f4f4SFrançois Tigeot 	DRM_DEBUG_DRIVER("resetting chip\n");
27681487f786SFrançois Tigeot 	kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event);
2769a2fdbec6SFrançois Tigeot 
2770*3f2dd94aSFrançois Tigeot 	/* Use a watchdog to ensure that our reset completes */
2771*3f2dd94aSFrançois Tigeot 	i915_wedge_on_timeout(&w, dev_priv, 5*HZ) {
27721487f786SFrançois Tigeot 		intel_prepare_reset(dev_priv);
27732c9916cdSFrançois Tigeot 
2774*3f2dd94aSFrançois Tigeot 		/* Signal that locked waiters should reset the GPU */
2775a85cb24fSFrançois Tigeot 		set_bit(I915_RESET_HANDOFF, &dev_priv->gpu_error.flags);
2776a85cb24fSFrançois Tigeot 		wake_up_all(&dev_priv->gpu_error.wait_queue);
2777a85cb24fSFrançois Tigeot 
2778*3f2dd94aSFrançois Tigeot 		/* Wait for anyone holding the lock to wakeup, without
2779*3f2dd94aSFrançois Tigeot 		 * blocking indefinitely on struct_mutex.
27809edbd4a0SFrançois Tigeot 		 */
2781*3f2dd94aSFrançois Tigeot 		do {
27821e12ee3bSFrançois Tigeot 			if (mutex_trylock(&dev_priv->drm.struct_mutex)) {
2783*3f2dd94aSFrançois Tigeot 				i915_reset(dev_priv, 0);
27841e12ee3bSFrançois Tigeot 				mutex_unlock(&dev_priv->drm.struct_mutex);
27851e12ee3bSFrançois Tigeot 			}
27861e12ee3bSFrançois Tigeot 		} while (wait_on_bit_timeout(&dev_priv->gpu_error.flags,
2787a85cb24fSFrançois Tigeot 					     I915_RESET_HANDOFF,
27881e12ee3bSFrançois Tigeot 					     TASK_UNINTERRUPTIBLE,
2789*3f2dd94aSFrançois Tigeot 					     1));
2790a2fdbec6SFrançois Tigeot 
27911487f786SFrançois Tigeot 		intel_finish_reset(dev_priv);
2792*3f2dd94aSFrançois Tigeot 	}
2793ba55f2f5SFrançois Tigeot 
27941e12ee3bSFrançois Tigeot 	if (!test_bit(I915_WEDGED, &dev_priv->gpu_error.flags))
27951487f786SFrançois Tigeot 		kobject_uevent_env(kobj,
2796a2fdbec6SFrançois Tigeot 				   KOBJ_CHANGE, reset_done_event);
2797e9243325SFrançois Tigeot }
2798e9243325SFrançois Tigeot 
i915_clear_error_registers(struct drm_i915_private * dev_priv)27991e12ee3bSFrançois Tigeot static void i915_clear_error_registers(struct drm_i915_private *dev_priv)
28001e12ee3bSFrançois Tigeot {
28011e12ee3bSFrançois Tigeot 	u32 eir;
2802e9243325SFrançois Tigeot 
28031e12ee3bSFrançois Tigeot 	if (!IS_GEN2(dev_priv))
28041e12ee3bSFrançois Tigeot 		I915_WRITE(PGTBL_ER, I915_READ(PGTBL_ER));
2805e9243325SFrançois Tigeot 
28061e12ee3bSFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 4)
28071e12ee3bSFrançois Tigeot 		I915_WRITE(IPEIR, I915_READ(IPEIR));
28081e12ee3bSFrançois Tigeot 	else
28091e12ee3bSFrançois Tigeot 		I915_WRITE(IPEIR_I965, I915_READ(IPEIR_I965));
2810e9243325SFrançois Tigeot 
28111e12ee3bSFrançois Tigeot 	I915_WRITE(EIR, I915_READ(EIR));
2812e9243325SFrançois Tigeot 	eir = I915_READ(EIR);
2813e9243325SFrançois Tigeot 	if (eir) {
2814e9243325SFrançois Tigeot 		/*
2815e9243325SFrançois Tigeot 		 * some errors might have become stuck,
2816e9243325SFrançois Tigeot 		 * mask them.
2817e9243325SFrançois Tigeot 		 */
28181e12ee3bSFrançois Tigeot 		DRM_DEBUG_DRIVER("EIR stuck: 0x%08x, masking\n", eir);
2819e9243325SFrançois Tigeot 		I915_WRITE(EMR, I915_READ(EMR) | eir);
2820e9243325SFrançois Tigeot 		I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
2821e9243325SFrançois Tigeot 	}
2822e9243325SFrançois Tigeot }
2823e9243325SFrançois Tigeot 
2824e9243325SFrançois Tigeot /**
28252c9916cdSFrançois Tigeot  * i915_handle_error - handle a gpu error
28261487f786SFrançois Tigeot  * @dev_priv: i915 device private
28278621f407SFrançois Tigeot  * @engine_mask: mask representing engines that are hung
2828a85cb24fSFrançois Tigeot  * @fmt: Error message format string
2829a85cb24fSFrançois Tigeot  *
2830352ff8bdSFrançois Tigeot  * Do some basic checking of register state at error time and
2831e9243325SFrançois Tigeot  * dump it to the syslog.  Also call i915_capture_error_state() to make
2832e9243325SFrançois Tigeot  * sure we get a record and make it available in debugfs.  Fire a uevent
2833e9243325SFrançois Tigeot  * so userspace knows something bad happened (should trigger collection
2834e9243325SFrançois Tigeot  * of a ring dump etc.).
2835e9243325SFrançois Tigeot  */
i915_handle_error(struct drm_i915_private * dev_priv,u32 engine_mask,const char * fmt,...)28361487f786SFrançois Tigeot void i915_handle_error(struct drm_i915_private *dev_priv,
28371487f786SFrançois Tigeot 		       u32 engine_mask,
2838ba55f2f5SFrançois Tigeot 		       const char *fmt, ...)
2839e9243325SFrançois Tigeot {
2840*3f2dd94aSFrançois Tigeot 	struct intel_engine_cs *engine;
2841*3f2dd94aSFrançois Tigeot 	unsigned int tmp;
2842ba55f2f5SFrançois Tigeot 	va_list args;
2843ba55f2f5SFrançois Tigeot 	char error_msg[80];
2844ba55f2f5SFrançois Tigeot 
2845ba55f2f5SFrançois Tigeot 	va_start(args, fmt);
2846ba55f2f5SFrançois Tigeot 	vscnprintf(error_msg, sizeof(error_msg), fmt, args);
2847ba55f2f5SFrançois Tigeot 	va_end(args);
2848ba55f2f5SFrançois Tigeot 
2849a85cb24fSFrançois Tigeot 	/*
2850a85cb24fSFrançois Tigeot 	 * In most cases it's guaranteed that we get here with an RPM
2851a85cb24fSFrançois Tigeot 	 * reference held, for example because there is a pending GPU
2852a85cb24fSFrançois Tigeot 	 * request that won't finish until the reset is done. This
2853a85cb24fSFrançois Tigeot 	 * isn't the case at least when we get here by doing a
2854a85cb24fSFrançois Tigeot 	 * simulated reset via debugfs, so get an RPM reference.
2855a85cb24fSFrançois Tigeot 	 */
2856a85cb24fSFrançois Tigeot 	intel_runtime_pm_get(dev_priv);
2857a85cb24fSFrançois Tigeot 
28581487f786SFrançois Tigeot 	i915_capture_error_state(dev_priv, engine_mask, error_msg);
28591e12ee3bSFrançois Tigeot 	i915_clear_error_registers(dev_priv);
2860e9243325SFrançois Tigeot 
2861*3f2dd94aSFrançois Tigeot 	/*
2862*3f2dd94aSFrançois Tigeot 	 * Try engine reset when available. We fall back to full reset if
2863*3f2dd94aSFrançois Tigeot 	 * single reset fails.
2864*3f2dd94aSFrançois Tigeot 	 */
2865*3f2dd94aSFrançois Tigeot 	if (intel_has_reset_engine(dev_priv)) {
2866*3f2dd94aSFrançois Tigeot 		for_each_engine_masked(engine, dev_priv, engine_mask, tmp) {
2867*3f2dd94aSFrançois Tigeot 			BUILD_BUG_ON(I915_RESET_MODESET >= I915_RESET_ENGINE);
2868*3f2dd94aSFrançois Tigeot 			if (test_and_set_bit(I915_RESET_ENGINE + engine->id,
2869*3f2dd94aSFrançois Tigeot 					     &dev_priv->gpu_error.flags))
2870*3f2dd94aSFrançois Tigeot 				continue;
2871*3f2dd94aSFrançois Tigeot 
2872*3f2dd94aSFrançois Tigeot 			if (i915_reset_engine(engine, 0) == 0)
2873*3f2dd94aSFrançois Tigeot 				engine_mask &= ~intel_engine_flag(engine);
2874*3f2dd94aSFrançois Tigeot 
2875*3f2dd94aSFrançois Tigeot 			clear_bit(I915_RESET_ENGINE + engine->id,
2876*3f2dd94aSFrançois Tigeot 				  &dev_priv->gpu_error.flags);
2877*3f2dd94aSFrançois Tigeot 			wake_up_bit(&dev_priv->gpu_error.flags,
2878*3f2dd94aSFrançois Tigeot 				    I915_RESET_ENGINE + engine->id);
2879*3f2dd94aSFrançois Tigeot 		}
2880*3f2dd94aSFrançois Tigeot 	}
2881*3f2dd94aSFrançois Tigeot 
28821e12ee3bSFrançois Tigeot 	if (!engine_mask)
2883a85cb24fSFrançois Tigeot 		goto out;
28841e12ee3bSFrançois Tigeot 
2885*3f2dd94aSFrançois Tigeot 	/* Full reset needs the mutex, stop any other user trying to do so. */
2886*3f2dd94aSFrançois Tigeot 	if (test_and_set_bit(I915_RESET_BACKOFF, &dev_priv->gpu_error.flags)) {
2887*3f2dd94aSFrançois Tigeot 		wait_event(dev_priv->gpu_error.reset_queue,
2888*3f2dd94aSFrançois Tigeot 			   !test_bit(I915_RESET_BACKOFF,
2889*3f2dd94aSFrançois Tigeot 				     &dev_priv->gpu_error.flags));
2890a85cb24fSFrançois Tigeot 		goto out;
2891*3f2dd94aSFrançois Tigeot 	}
2892e9243325SFrançois Tigeot 
2893*3f2dd94aSFrançois Tigeot 	/* Prevent any other reset-engine attempt. */
2894*3f2dd94aSFrançois Tigeot 	for_each_engine(engine, dev_priv, tmp) {
2895*3f2dd94aSFrançois Tigeot 		while (test_and_set_bit(I915_RESET_ENGINE + engine->id,
2896*3f2dd94aSFrançois Tigeot 					&dev_priv->gpu_error.flags))
2897*3f2dd94aSFrançois Tigeot 			wait_on_bit(&dev_priv->gpu_error.flags,
2898*3f2dd94aSFrançois Tigeot 				    I915_RESET_ENGINE + engine->id,
2899*3f2dd94aSFrançois Tigeot 				    TASK_UNINTERRUPTIBLE);
2900*3f2dd94aSFrançois Tigeot 	}
2901*3f2dd94aSFrançois Tigeot 
2902*3f2dd94aSFrançois Tigeot 	i915_reset_device(dev_priv);
2903*3f2dd94aSFrançois Tigeot 
2904*3f2dd94aSFrançois Tigeot 	for_each_engine(engine, dev_priv, tmp) {
2905*3f2dd94aSFrançois Tigeot 		clear_bit(I915_RESET_ENGINE + engine->id,
2906*3f2dd94aSFrançois Tigeot 			  &dev_priv->gpu_error.flags);
2907*3f2dd94aSFrançois Tigeot 	}
2908*3f2dd94aSFrançois Tigeot 
2909*3f2dd94aSFrançois Tigeot 	clear_bit(I915_RESET_BACKOFF, &dev_priv->gpu_error.flags);
2910*3f2dd94aSFrançois Tigeot 	wake_up_all(&dev_priv->gpu_error.reset_queue);
2911a85cb24fSFrançois Tigeot 
2912a85cb24fSFrançois Tigeot out:
2913a85cb24fSFrançois Tigeot 	intel_runtime_pm_put(dev_priv);
2914e9243325SFrançois Tigeot }
2915e9243325SFrançois Tigeot 
2916e9243325SFrançois Tigeot /* Called from drm generic code, passed 'crtc' which
2917e9243325SFrançois Tigeot  * we use as a pipe index
2918e9243325SFrançois Tigeot  */
i8xx_enable_vblank(struct drm_device * dev,unsigned int pipe)29191e12ee3bSFrançois Tigeot static int i8xx_enable_vblank(struct drm_device *dev, unsigned int pipe)
2920e9243325SFrançois Tigeot {
2921303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
29225e269720SFrançois Tigeot 	unsigned long irqflags;
2923e9243325SFrançois Tigeot 
29245e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
29251e12ee3bSFrançois Tigeot 	i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS);
29261e12ee3bSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
29271e12ee3bSFrançois Tigeot 
29281e12ee3bSFrançois Tigeot 	return 0;
29291e12ee3bSFrançois Tigeot }
29301e12ee3bSFrançois Tigeot 
i965_enable_vblank(struct drm_device * dev,unsigned int pipe)29311e12ee3bSFrançois Tigeot static int i965_enable_vblank(struct drm_device *dev, unsigned int pipe)
29321e12ee3bSFrançois Tigeot {
29331e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
29341e12ee3bSFrançois Tigeot 	unsigned long irqflags;
29351e12ee3bSFrançois Tigeot 
29361e12ee3bSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
2937e9243325SFrançois Tigeot 	i915_enable_pipestat(dev_priv, pipe,
2938ba55f2f5SFrançois Tigeot 			     PIPE_START_VBLANK_INTERRUPT_STATUS);
29395e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
2940e9243325SFrançois Tigeot 
2941e9243325SFrançois Tigeot 	return 0;
2942e9243325SFrançois Tigeot }
2943e9243325SFrançois Tigeot 
ironlake_enable_vblank(struct drm_device * dev,unsigned int pipe)2944352ff8bdSFrançois Tigeot static int ironlake_enable_vblank(struct drm_device *dev, unsigned int pipe)
2945e9243325SFrançois Tigeot {
2946303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
29475e269720SFrançois Tigeot 	unsigned long irqflags;
29481e12ee3bSFrançois Tigeot 	uint32_t bit = INTEL_GEN(dev_priv) >= 7 ?
29491e12ee3bSFrançois Tigeot 		DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe);
2950e9243325SFrançois Tigeot 
29515e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
2952aee94f86SFrançois Tigeot 	ilk_enable_display_irq(dev_priv, bit);
29535e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
2954e9243325SFrançois Tigeot 
2955e9243325SFrançois Tigeot 	return 0;
2956e9243325SFrançois Tigeot }
2957e9243325SFrançois Tigeot 
gen8_enable_vblank(struct drm_device * dev,unsigned int pipe)2958352ff8bdSFrançois Tigeot static int gen8_enable_vblank(struct drm_device *dev, unsigned int pipe)
29599edbd4a0SFrançois Tigeot {
2960303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
29615e269720SFrançois Tigeot 	unsigned long irqflags;
29629edbd4a0SFrançois Tigeot 
29635e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
2964aee94f86SFrançois Tigeot 	bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
29655e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
2966aee94f86SFrançois Tigeot 
29679edbd4a0SFrançois Tigeot 	return 0;
29689edbd4a0SFrançois Tigeot }
29699edbd4a0SFrançois Tigeot 
2970e9243325SFrançois Tigeot /* Called from drm generic code, passed 'crtc' which
2971e9243325SFrançois Tigeot  * we use as a pipe index
2972e9243325SFrançois Tigeot  */
i8xx_disable_vblank(struct drm_device * dev,unsigned int pipe)29731e12ee3bSFrançois Tigeot static void i8xx_disable_vblank(struct drm_device *dev, unsigned int pipe)
29741e12ee3bSFrançois Tigeot {
29751e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
29761e12ee3bSFrançois Tigeot 	unsigned long irqflags;
29771e12ee3bSFrançois Tigeot 
29781e12ee3bSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
29791e12ee3bSFrançois Tigeot 	i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS);
29801e12ee3bSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
29811e12ee3bSFrançois Tigeot }
29821e12ee3bSFrançois Tigeot 
i965_disable_vblank(struct drm_device * dev,unsigned int pipe)29831e12ee3bSFrançois Tigeot static void i965_disable_vblank(struct drm_device *dev, unsigned int pipe)
2984e9243325SFrançois Tigeot {
2985303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
29865e269720SFrançois Tigeot 	unsigned long irqflags;
2987e9243325SFrançois Tigeot 
29885e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
2989e9243325SFrançois Tigeot 	i915_disable_pipestat(dev_priv, pipe,
2990ba55f2f5SFrançois Tigeot 			      PIPE_START_VBLANK_INTERRUPT_STATUS);
29915e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
2992e9243325SFrançois Tigeot }
2993e9243325SFrançois Tigeot 
ironlake_disable_vblank(struct drm_device * dev,unsigned int pipe)2994352ff8bdSFrançois Tigeot static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe)
2995e9243325SFrançois Tigeot {
2996303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
29975e269720SFrançois Tigeot 	unsigned long irqflags;
29981e12ee3bSFrançois Tigeot 	uint32_t bit = INTEL_GEN(dev_priv) >= 7 ?
29991e12ee3bSFrançois Tigeot 		DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe);
3000e9243325SFrançois Tigeot 
30015e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
3002aee94f86SFrançois Tigeot 	ilk_disable_display_irq(dev_priv, bit);
30035e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
3004e9243325SFrançois Tigeot }
3005e9243325SFrançois Tigeot 
gen8_disable_vblank(struct drm_device * dev,unsigned int pipe)3006352ff8bdSFrançois Tigeot static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
30079edbd4a0SFrançois Tigeot {
3008303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
30095e269720SFrançois Tigeot 	unsigned long irqflags;
30109edbd4a0SFrançois Tigeot 
30115e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
3012aee94f86SFrançois Tigeot 	bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
30135e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
30149edbd4a0SFrançois Tigeot }
30159edbd4a0SFrançois Tigeot 
ibx_irq_reset(struct drm_i915_private * dev_priv)30164be47400SFrançois Tigeot static void ibx_irq_reset(struct drm_i915_private *dev_priv)
3017ba55f2f5SFrançois Tigeot {
30181e12ee3bSFrançois Tigeot 	if (HAS_PCH_NOP(dev_priv))
30195d0b1887SFrançois Tigeot 		return;
30205d0b1887SFrançois Tigeot 
3021*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_RESET(SDE);
3022ba55f2f5SFrançois Tigeot 
30231e12ee3bSFrançois Tigeot 	if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv))
3024ba55f2f5SFrançois Tigeot 		I915_WRITE(SERR_INT, 0xffffffff);
3025ba55f2f5SFrançois Tigeot }
3026ba55f2f5SFrançois Tigeot 
30275d0b1887SFrançois Tigeot /*
3028ba55f2f5SFrançois Tigeot  * SDEIER is also touched by the interrupt handler to work around missed PCH
3029ba55f2f5SFrançois Tigeot  * interrupts. Hence we can't update it after the interrupt handler is enabled -
3030ba55f2f5SFrançois Tigeot  * instead we unconditionally enable all PCH interrupt sources here, but then
3031ba55f2f5SFrançois Tigeot  * only unmask them as needed with SDEIMR.
3032ba55f2f5SFrançois Tigeot  *
3033ba55f2f5SFrançois Tigeot  * This function needs to be called before interrupts are enabled.
30345d0b1887SFrançois Tigeot  */
ibx_irq_pre_postinstall(struct drm_device * dev)3035ba55f2f5SFrançois Tigeot static void ibx_irq_pre_postinstall(struct drm_device *dev)
3036ba55f2f5SFrançois Tigeot {
3037303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3038ba55f2f5SFrançois Tigeot 
30391e12ee3bSFrançois Tigeot 	if (HAS_PCH_NOP(dev_priv))
3040ba55f2f5SFrançois Tigeot 		return;
3041ba55f2f5SFrançois Tigeot 
3042ba55f2f5SFrançois Tigeot 	WARN_ON(I915_READ(SDEIER) != 0);
30435d0b1887SFrançois Tigeot 	I915_WRITE(SDEIER, 0xffffffff);
30445d0b1887SFrançois Tigeot 	POSTING_READ(SDEIER);
3045e9243325SFrançois Tigeot }
3046e9243325SFrançois Tigeot 
gen5_gt_irq_reset(struct drm_i915_private * dev_priv)30474be47400SFrançois Tigeot static void gen5_gt_irq_reset(struct drm_i915_private *dev_priv)
30489edbd4a0SFrançois Tigeot {
3049*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_RESET(GT);
30504be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 6)
3051*3f2dd94aSFrançois Tigeot 		GEN3_IRQ_RESET(GEN6_PM);
30529edbd4a0SFrançois Tigeot }
30539edbd4a0SFrançois Tigeot 
vlv_display_irq_reset(struct drm_i915_private * dev_priv)30548621f407SFrançois Tigeot static void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
30558621f407SFrançois Tigeot {
30568621f407SFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv))
30578621f407SFrançois Tigeot 		I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV);
30588621f407SFrançois Tigeot 	else
30598621f407SFrançois Tigeot 		I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK);
30608621f407SFrançois Tigeot 
30618621f407SFrançois Tigeot 	i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0);
30628621f407SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
30638621f407SFrançois Tigeot 
3064*3f2dd94aSFrançois Tigeot 	i9xx_pipestat_irq_reset(dev_priv);
30658621f407SFrançois Tigeot 
3066*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_RESET(VLV_);
30678621f407SFrançois Tigeot 	dev_priv->irq_mask = ~0;
30688621f407SFrançois Tigeot }
30698621f407SFrançois Tigeot 
vlv_display_irq_postinstall(struct drm_i915_private * dev_priv)30708621f407SFrançois Tigeot static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
30718621f407SFrançois Tigeot {
30728621f407SFrançois Tigeot 	u32 pipestat_mask;
30738621f407SFrançois Tigeot 	u32 enable_mask;
30748621f407SFrançois Tigeot 	enum i915_pipe pipe;
30758621f407SFrançois Tigeot 
3076*3f2dd94aSFrançois Tigeot 	pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS;
30778621f407SFrançois Tigeot 
30788621f407SFrançois Tigeot 	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
30798621f407SFrançois Tigeot 	for_each_pipe(dev_priv, pipe)
30808621f407SFrançois Tigeot 		i915_enable_pipestat(dev_priv, pipe, pipestat_mask);
30818621f407SFrançois Tigeot 
30828621f407SFrançois Tigeot 	enable_mask = I915_DISPLAY_PORT_INTERRUPT |
30838621f407SFrançois Tigeot 		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
3084a85cb24fSFrançois Tigeot 		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
3085a85cb24fSFrançois Tigeot 		I915_LPE_PIPE_A_INTERRUPT |
3086a85cb24fSFrançois Tigeot 		I915_LPE_PIPE_B_INTERRUPT;
3087a85cb24fSFrançois Tigeot 
30888621f407SFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv))
3089a85cb24fSFrançois Tigeot 		enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT |
3090a85cb24fSFrançois Tigeot 			I915_LPE_PIPE_C_INTERRUPT;
30918621f407SFrançois Tigeot 
30928621f407SFrançois Tigeot 	WARN_ON(dev_priv->irq_mask != ~0);
30938621f407SFrançois Tigeot 
30948621f407SFrançois Tigeot 	dev_priv->irq_mask = ~enable_mask;
30958621f407SFrançois Tigeot 
3096*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask);
30978621f407SFrançois Tigeot }
30988621f407SFrançois Tigeot 
3099e9243325SFrançois Tigeot /* drm_dma.h hooks
3100e9243325SFrançois Tigeot */
ironlake_irq_reset(struct drm_device * dev)3101ba55f2f5SFrançois Tigeot static void ironlake_irq_reset(struct drm_device *dev)
3102e9243325SFrançois Tigeot {
3103303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3104e9243325SFrançois Tigeot 
3105*3f2dd94aSFrançois Tigeot 	if (IS_GEN5(dev_priv))
3106ba55f2f5SFrançois Tigeot 		I915_WRITE(HWSTAM, 0xffffffff);
3107e9243325SFrançois Tigeot 
3108*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_RESET(DE);
31091e12ee3bSFrançois Tigeot 	if (IS_GEN7(dev_priv))
3110ba55f2f5SFrançois Tigeot 		I915_WRITE(GEN7_ERR_INT, 0xffffffff);
3111e9243325SFrançois Tigeot 
31124be47400SFrançois Tigeot 	gen5_gt_irq_reset(dev_priv);
3113e9243325SFrançois Tigeot 
31144be47400SFrançois Tigeot 	ibx_irq_reset(dev_priv);
3115e9243325SFrançois Tigeot }
3116e9243325SFrançois Tigeot 
valleyview_irq_reset(struct drm_device * dev)3117*3f2dd94aSFrançois Tigeot static void valleyview_irq_reset(struct drm_device *dev)
3118e9243325SFrançois Tigeot {
3119303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3120e9243325SFrançois Tigeot 
31218621f407SFrançois Tigeot 	I915_WRITE(VLV_MASTER_IER, 0);
31228621f407SFrançois Tigeot 	POSTING_READ(VLV_MASTER_IER);
3123e9243325SFrançois Tigeot 
31244be47400SFrançois Tigeot 	gen5_gt_irq_reset(dev_priv);
3125e9243325SFrançois Tigeot 
31268621f407SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
31278621f407SFrançois Tigeot 	if (dev_priv->display_irqs_enabled)
31282c9916cdSFrançois Tigeot 		vlv_display_irq_reset(dev_priv);
31298621f407SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
3130e9243325SFrançois Tigeot }
3131e9243325SFrançois Tigeot 
gen8_gt_irq_reset(struct drm_i915_private * dev_priv)3132ba55f2f5SFrançois Tigeot static void gen8_gt_irq_reset(struct drm_i915_private *dev_priv)
3133ba55f2f5SFrançois Tigeot {
3134ba55f2f5SFrançois Tigeot 	GEN8_IRQ_RESET_NDX(GT, 0);
3135ba55f2f5SFrançois Tigeot 	GEN8_IRQ_RESET_NDX(GT, 1);
3136ba55f2f5SFrançois Tigeot 	GEN8_IRQ_RESET_NDX(GT, 2);
3137ba55f2f5SFrançois Tigeot 	GEN8_IRQ_RESET_NDX(GT, 3);
3138ba55f2f5SFrançois Tigeot }
3139ba55f2f5SFrançois Tigeot 
gen8_irq_reset(struct drm_device * dev)3140ba55f2f5SFrançois Tigeot static void gen8_irq_reset(struct drm_device *dev)
31419edbd4a0SFrançois Tigeot {
3142303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
31439edbd4a0SFrançois Tigeot 	int pipe;
31449edbd4a0SFrançois Tigeot 
3145ba55f2f5SFrançois Tigeot 	I915_WRITE(GEN8_MASTER_IRQ, 0);
3146ba55f2f5SFrançois Tigeot 	POSTING_READ(GEN8_MASTER_IRQ);
3147ba55f2f5SFrançois Tigeot 
3148ba55f2f5SFrançois Tigeot 	gen8_gt_irq_reset(dev_priv);
3149ba55f2f5SFrançois Tigeot 
31501b13d190SFrançois Tigeot 	for_each_pipe(dev_priv, pipe)
31512c9916cdSFrançois Tigeot 		if (intel_display_power_is_enabled(dev_priv,
315224edb884SFrançois Tigeot 						   POWER_DOMAIN_PIPE(pipe)))
3153ba55f2f5SFrançois Tigeot 			GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
3154ba55f2f5SFrançois Tigeot 
3155*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_RESET(GEN8_DE_PORT_);
3156*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_RESET(GEN8_DE_MISC_);
3157*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_RESET(GEN8_PCU_);
3158ba55f2f5SFrançois Tigeot 
31591e12ee3bSFrançois Tigeot 	if (HAS_PCH_SPLIT(dev_priv))
31604be47400SFrançois Tigeot 		ibx_irq_reset(dev_priv);
3161ba55f2f5SFrançois Tigeot }
3162ba55f2f5SFrançois Tigeot 
gen8_irq_power_well_post_enable(struct drm_i915_private * dev_priv,u8 pipe_mask)3163477eb7f9SFrançois Tigeot void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
3164*3f2dd94aSFrançois Tigeot 				     u8 pipe_mask)
316524edb884SFrançois Tigeot {
3166acf467cbSFrançois Tigeot 	uint32_t extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN;
3167c0e85e96SFrançois Tigeot 	enum i915_pipe pipe;
316824edb884SFrançois Tigeot 
31695e269720SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
3170*3f2dd94aSFrançois Tigeot 
3171*3f2dd94aSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv)) {
3172*3f2dd94aSFrançois Tigeot 		spin_unlock_irq(&dev_priv->irq_lock);
3173*3f2dd94aSFrançois Tigeot 		return;
3174*3f2dd94aSFrançois Tigeot 	}
3175*3f2dd94aSFrançois Tigeot 
3176c0e85e96SFrançois Tigeot 	for_each_pipe_masked(dev_priv, pipe, pipe_mask)
3177c0e85e96SFrançois Tigeot 		GEN8_IRQ_INIT_NDX(DE_PIPE, pipe,
3178c0e85e96SFrançois Tigeot 				  dev_priv->de_irq_mask[pipe],
3179c0e85e96SFrançois Tigeot 				  ~dev_priv->de_irq_mask[pipe] | extra_ier);
3180*3f2dd94aSFrançois Tigeot 
31815e269720SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
318224edb884SFrançois Tigeot }
318324edb884SFrançois Tigeot 
gen8_irq_power_well_pre_disable(struct drm_i915_private * dev_priv,u8 pipe_mask)3184c0e85e96SFrançois Tigeot void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
3185*3f2dd94aSFrançois Tigeot 				     u8 pipe_mask)
3186c0e85e96SFrançois Tigeot {
3187c0e85e96SFrançois Tigeot 	enum i915_pipe pipe;
3188c0e85e96SFrançois Tigeot 
3189c0e85e96SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
3190*3f2dd94aSFrançois Tigeot 
3191*3f2dd94aSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv)) {
3192*3f2dd94aSFrançois Tigeot 		spin_unlock_irq(&dev_priv->irq_lock);
3193*3f2dd94aSFrançois Tigeot 		return;
3194*3f2dd94aSFrançois Tigeot 	}
3195*3f2dd94aSFrançois Tigeot 
3196c0e85e96SFrançois Tigeot 	for_each_pipe_masked(dev_priv, pipe, pipe_mask)
3197c0e85e96SFrançois Tigeot 		GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
3198*3f2dd94aSFrançois Tigeot 
3199c0e85e96SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
3200c0e85e96SFrançois Tigeot 
3201c0e85e96SFrançois Tigeot 	/* make sure we're done processing display irqs */
3202303bf270SFrançois Tigeot 	synchronize_irq(dev_priv->drm.irq);
3203c0e85e96SFrançois Tigeot }
3204c0e85e96SFrançois Tigeot 
cherryview_irq_reset(struct drm_device * dev)3205*3f2dd94aSFrançois Tigeot static void cherryview_irq_reset(struct drm_device *dev)
3206ba55f2f5SFrançois Tigeot {
3207303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
32089edbd4a0SFrançois Tigeot 
32099edbd4a0SFrançois Tigeot 	I915_WRITE(GEN8_MASTER_IRQ, 0);
32109edbd4a0SFrançois Tigeot 	POSTING_READ(GEN8_MASTER_IRQ);
32119edbd4a0SFrançois Tigeot 
3212ba55f2f5SFrançois Tigeot 	gen8_gt_irq_reset(dev_priv);
32139edbd4a0SFrançois Tigeot 
3214*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_RESET(GEN8_PCU_);
32159edbd4a0SFrançois Tigeot 
32168621f407SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
32178621f407SFrançois Tigeot 	if (dev_priv->display_irqs_enabled)
32182c9916cdSFrançois Tigeot 		vlv_display_irq_reset(dev_priv);
32198621f407SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
32209edbd4a0SFrançois Tigeot }
32219edbd4a0SFrançois Tigeot 
intel_hpd_enabled_irqs(struct drm_i915_private * dev_priv,const u32 hpd[HPD_NUM_PINS])32221487f786SFrançois Tigeot static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
3223352ff8bdSFrançois Tigeot 				  const u32 hpd[HPD_NUM_PINS])
3224352ff8bdSFrançois Tigeot {
3225352ff8bdSFrançois Tigeot 	struct intel_encoder *encoder;
3226352ff8bdSFrançois Tigeot 	u32 enabled_irqs = 0;
3227352ff8bdSFrançois Tigeot 
3228303bf270SFrançois Tigeot 	for_each_intel_encoder(&dev_priv->drm, encoder)
3229352ff8bdSFrançois Tigeot 		if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED)
3230352ff8bdSFrançois Tigeot 			enabled_irqs |= hpd[encoder->hpd_pin];
3231352ff8bdSFrançois Tigeot 
3232352ff8bdSFrançois Tigeot 	return enabled_irqs;
3233352ff8bdSFrançois Tigeot }
3234352ff8bdSFrançois Tigeot 
ibx_hpd_detection_setup(struct drm_i915_private * dev_priv)3235a85cb24fSFrançois Tigeot static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv)
3236a85cb24fSFrançois Tigeot {
3237a85cb24fSFrançois Tigeot 	u32 hotplug;
3238a85cb24fSFrançois Tigeot 
3239a85cb24fSFrançois Tigeot 	/*
3240a85cb24fSFrançois Tigeot 	 * Enable digital hotplug on the PCH, and configure the DP short pulse
3241a85cb24fSFrançois Tigeot 	 * duration to 2ms (which is the minimum in the Display Port spec).
3242a85cb24fSFrançois Tigeot 	 * The pulse duration bits are reserved on LPT+.
3243a85cb24fSFrançois Tigeot 	 */
3244a85cb24fSFrançois Tigeot 	hotplug = I915_READ(PCH_PORT_HOTPLUG);
3245a85cb24fSFrançois Tigeot 	hotplug &= ~(PORTB_PULSE_DURATION_MASK |
3246a85cb24fSFrançois Tigeot 		     PORTC_PULSE_DURATION_MASK |
3247a85cb24fSFrançois Tigeot 		     PORTD_PULSE_DURATION_MASK);
3248a85cb24fSFrançois Tigeot 	hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms;
3249a85cb24fSFrançois Tigeot 	hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms;
3250a85cb24fSFrançois Tigeot 	hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
3251a85cb24fSFrançois Tigeot 	/*
3252a85cb24fSFrançois Tigeot 	 * When CPU and PCH are on the same package, port A
3253a85cb24fSFrançois Tigeot 	 * HPD must be enabled in both north and south.
3254a85cb24fSFrançois Tigeot 	 */
3255a85cb24fSFrançois Tigeot 	if (HAS_PCH_LPT_LP(dev_priv))
3256a85cb24fSFrançois Tigeot 		hotplug |= PORTA_HOTPLUG_ENABLE;
3257a85cb24fSFrançois Tigeot 	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
3258a85cb24fSFrançois Tigeot }
3259a85cb24fSFrançois Tigeot 
ibx_hpd_irq_setup(struct drm_i915_private * dev_priv)32601487f786SFrançois Tigeot static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
32618e26cdf6SFrançois Tigeot {
3262a85cb24fSFrançois Tigeot 	u32 hotplug_irqs, enabled_irqs;
32638e26cdf6SFrançois Tigeot 
32641487f786SFrançois Tigeot 	if (HAS_PCH_IBX(dev_priv)) {
32659edbd4a0SFrançois Tigeot 		hotplug_irqs = SDE_HOTPLUG_MASK;
32661487f786SFrançois Tigeot 		enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ibx);
32678e26cdf6SFrançois Tigeot 	} else {
32689edbd4a0SFrançois Tigeot 		hotplug_irqs = SDE_HOTPLUG_MASK_CPT;
32691487f786SFrançois Tigeot 		enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_cpt);
32708e26cdf6SFrançois Tigeot 	}
32718e26cdf6SFrançois Tigeot 
32729edbd4a0SFrançois Tigeot 	ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
32738e26cdf6SFrançois Tigeot 
3274a85cb24fSFrançois Tigeot 	ibx_hpd_detection_setup(dev_priv);
3275352ff8bdSFrançois Tigeot }
3276352ff8bdSFrançois Tigeot 
spt_hpd_detection_setup(struct drm_i915_private * dev_priv)32774be47400SFrançois Tigeot static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv)
32784be47400SFrançois Tigeot {
3279*3f2dd94aSFrançois Tigeot 	u32 val, hotplug;
3280*3f2dd94aSFrançois Tigeot 
3281*3f2dd94aSFrançois Tigeot 	/* Display WA #1179 WaHardHangonHotPlug: cnp */
3282*3f2dd94aSFrançois Tigeot 	if (HAS_PCH_CNP(dev_priv)) {
3283*3f2dd94aSFrançois Tigeot 		val = I915_READ(SOUTH_CHICKEN1);
3284*3f2dd94aSFrançois Tigeot 		val &= ~CHASSIS_CLK_REQ_DURATION_MASK;
3285*3f2dd94aSFrançois Tigeot 		val |= CHASSIS_CLK_REQ_DURATION(0xf);
3286*3f2dd94aSFrançois Tigeot 		I915_WRITE(SOUTH_CHICKEN1, val);
3287*3f2dd94aSFrançois Tigeot 	}
32884be47400SFrançois Tigeot 
32894be47400SFrançois Tigeot 	/* Enable digital hotplug on the PCH */
32904be47400SFrançois Tigeot 	hotplug = I915_READ(PCH_PORT_HOTPLUG);
32914be47400SFrançois Tigeot 	hotplug |= PORTA_HOTPLUG_ENABLE |
32924be47400SFrançois Tigeot 		   PORTB_HOTPLUG_ENABLE |
32934be47400SFrançois Tigeot 		   PORTC_HOTPLUG_ENABLE |
32944be47400SFrançois Tigeot 		   PORTD_HOTPLUG_ENABLE;
32954be47400SFrançois Tigeot 	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
32964be47400SFrançois Tigeot 
32974be47400SFrançois Tigeot 	hotplug = I915_READ(PCH_PORT_HOTPLUG2);
32984be47400SFrançois Tigeot 	hotplug |= PORTE_HOTPLUG_ENABLE;
32994be47400SFrançois Tigeot 	I915_WRITE(PCH_PORT_HOTPLUG2, hotplug);
33004be47400SFrançois Tigeot }
33014be47400SFrançois Tigeot 
spt_hpd_irq_setup(struct drm_i915_private * dev_priv)33021487f786SFrançois Tigeot static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv)
3303352ff8bdSFrançois Tigeot {
33044be47400SFrançois Tigeot 	u32 hotplug_irqs, enabled_irqs;
3305352ff8bdSFrançois Tigeot 
3306352ff8bdSFrançois Tigeot 	hotplug_irqs = SDE_HOTPLUG_MASK_SPT;
33071487f786SFrançois Tigeot 	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_spt);
3308352ff8bdSFrançois Tigeot 
3309352ff8bdSFrançois Tigeot 	ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
3310352ff8bdSFrançois Tigeot 
33114be47400SFrançois Tigeot 	spt_hpd_detection_setup(dev_priv);
3312a05eeebfSFrançois Tigeot }
3313352ff8bdSFrançois Tigeot 
ilk_hpd_detection_setup(struct drm_i915_private * dev_priv)3314a85cb24fSFrançois Tigeot static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv)
3315a85cb24fSFrançois Tigeot {
3316a85cb24fSFrançois Tigeot 	u32 hotplug;
3317a85cb24fSFrançois Tigeot 
3318a85cb24fSFrançois Tigeot 	/*
3319a85cb24fSFrançois Tigeot 	 * Enable digital hotplug on the CPU, and configure the DP short pulse
3320a85cb24fSFrançois Tigeot 	 * duration to 2ms (which is the minimum in the Display Port spec)
3321a85cb24fSFrançois Tigeot 	 * The pulse duration bits are reserved on HSW+.
3322a85cb24fSFrançois Tigeot 	 */
3323a85cb24fSFrançois Tigeot 	hotplug = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
3324a85cb24fSFrançois Tigeot 	hotplug &= ~DIGITAL_PORTA_PULSE_DURATION_MASK;
3325a85cb24fSFrançois Tigeot 	hotplug |= DIGITAL_PORTA_HOTPLUG_ENABLE |
3326a85cb24fSFrançois Tigeot 		   DIGITAL_PORTA_PULSE_DURATION_2ms;
3327a85cb24fSFrançois Tigeot 	I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, hotplug);
3328a85cb24fSFrançois Tigeot }
3329a85cb24fSFrançois Tigeot 
ilk_hpd_irq_setup(struct drm_i915_private * dev_priv)33301487f786SFrançois Tigeot static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv)
3331352ff8bdSFrançois Tigeot {
3332a85cb24fSFrançois Tigeot 	u32 hotplug_irqs, enabled_irqs;
3333352ff8bdSFrançois Tigeot 
33341487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8) {
3335352ff8bdSFrançois Tigeot 		hotplug_irqs = GEN8_PORT_DP_A_HOTPLUG;
33361487f786SFrançois Tigeot 		enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_bdw);
3337352ff8bdSFrançois Tigeot 
3338352ff8bdSFrançois Tigeot 		bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
33391487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 7) {
3340352ff8bdSFrançois Tigeot 		hotplug_irqs = DE_DP_A_HOTPLUG_IVB;
33411487f786SFrançois Tigeot 		enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ivb);
3342352ff8bdSFrançois Tigeot 
3343352ff8bdSFrançois Tigeot 		ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
3344352ff8bdSFrançois Tigeot 	} else {
3345352ff8bdSFrançois Tigeot 		hotplug_irqs = DE_DP_A_HOTPLUG;
33461487f786SFrançois Tigeot 		enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ilk);
3347352ff8bdSFrançois Tigeot 
3348352ff8bdSFrançois Tigeot 		ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
3349352ff8bdSFrançois Tigeot 	}
3350352ff8bdSFrançois Tigeot 
3351a85cb24fSFrançois Tigeot 	ilk_hpd_detection_setup(dev_priv);
3352352ff8bdSFrançois Tigeot 
33531487f786SFrançois Tigeot 	ibx_hpd_irq_setup(dev_priv);
3354e9243325SFrançois Tigeot }
3355e9243325SFrançois Tigeot 
__bxt_hpd_detection_setup(struct drm_i915_private * dev_priv,u32 enabled_irqs)33564be47400SFrançois Tigeot static void __bxt_hpd_detection_setup(struct drm_i915_private *dev_priv,
33574be47400SFrançois Tigeot 				      u32 enabled_irqs)
335819c468b4SFrançois Tigeot {
33594be47400SFrançois Tigeot 	u32 hotplug;
336019c468b4SFrançois Tigeot 
3361352ff8bdSFrançois Tigeot 	hotplug = I915_READ(PCH_PORT_HOTPLUG);
33624be47400SFrançois Tigeot 	hotplug |= PORTA_HOTPLUG_ENABLE |
33634be47400SFrançois Tigeot 		   PORTB_HOTPLUG_ENABLE |
33644be47400SFrançois Tigeot 		   PORTC_HOTPLUG_ENABLE;
33658621f407SFrançois Tigeot 
33668621f407SFrançois Tigeot 	DRM_DEBUG_KMS("Invert bit setting: hp_ctl:%x hp_port:%x\n",
33678621f407SFrançois Tigeot 		      hotplug, enabled_irqs);
33688621f407SFrançois Tigeot 	hotplug &= ~BXT_DDI_HPD_INVERT_MASK;
33698621f407SFrançois Tigeot 
33708621f407SFrançois Tigeot 	/*
33718621f407SFrançois Tigeot 	 * For BXT invert bit has to be set based on AOB design
33728621f407SFrançois Tigeot 	 * for HPD detection logic, update it based on VBT fields.
33738621f407SFrançois Tigeot 	 */
33748621f407SFrançois Tigeot 	if ((enabled_irqs & BXT_DE_PORT_HP_DDIA) &&
33758621f407SFrançois Tigeot 	    intel_bios_is_port_hpd_inverted(dev_priv, PORT_A))
33768621f407SFrançois Tigeot 		hotplug |= BXT_DDIA_HPD_INVERT;
33778621f407SFrançois Tigeot 	if ((enabled_irqs & BXT_DE_PORT_HP_DDIB) &&
33788621f407SFrançois Tigeot 	    intel_bios_is_port_hpd_inverted(dev_priv, PORT_B))
33798621f407SFrançois Tigeot 		hotplug |= BXT_DDIB_HPD_INVERT;
33808621f407SFrançois Tigeot 	if ((enabled_irqs & BXT_DE_PORT_HP_DDIC) &&
33818621f407SFrançois Tigeot 	    intel_bios_is_port_hpd_inverted(dev_priv, PORT_C))
33828621f407SFrançois Tigeot 		hotplug |= BXT_DDIC_HPD_INVERT;
33838621f407SFrançois Tigeot 
3384352ff8bdSFrançois Tigeot 	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
338519c468b4SFrançois Tigeot }
338619c468b4SFrançois Tigeot 
bxt_hpd_detection_setup(struct drm_i915_private * dev_priv)33874be47400SFrançois Tigeot static void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv)
33884be47400SFrançois Tigeot {
33894be47400SFrançois Tigeot 	__bxt_hpd_detection_setup(dev_priv, BXT_DE_PORT_HOTPLUG_MASK);
33904be47400SFrançois Tigeot }
33914be47400SFrançois Tigeot 
bxt_hpd_irq_setup(struct drm_i915_private * dev_priv)33924be47400SFrançois Tigeot static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv)
33934be47400SFrançois Tigeot {
33944be47400SFrançois Tigeot 	u32 hotplug_irqs, enabled_irqs;
33954be47400SFrançois Tigeot 
33964be47400SFrançois Tigeot 	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_bxt);
33974be47400SFrançois Tigeot 	hotplug_irqs = BXT_DE_PORT_HOTPLUG_MASK;
33984be47400SFrançois Tigeot 
33994be47400SFrançois Tigeot 	bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
34004be47400SFrançois Tigeot 
34014be47400SFrançois Tigeot 	__bxt_hpd_detection_setup(dev_priv, enabled_irqs);
34024be47400SFrançois Tigeot }
34034be47400SFrançois Tigeot 
ibx_irq_postinstall(struct drm_device * dev)3404a2fdbec6SFrançois Tigeot static void ibx_irq_postinstall(struct drm_device *dev)
3405a2fdbec6SFrançois Tigeot {
3406303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3407a2fdbec6SFrançois Tigeot 	u32 mask;
3408a2fdbec6SFrançois Tigeot 
34091e12ee3bSFrançois Tigeot 	if (HAS_PCH_NOP(dev_priv))
34108e26cdf6SFrançois Tigeot 		return;
3411a2fdbec6SFrançois Tigeot 
34121e12ee3bSFrançois Tigeot 	if (HAS_PCH_IBX(dev_priv))
34139edbd4a0SFrançois Tigeot 		mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
3414*3f2dd94aSFrançois Tigeot 	else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv))
34159edbd4a0SFrançois Tigeot 		mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
3416*3f2dd94aSFrançois Tigeot 	else
3417*3f2dd94aSFrançois Tigeot 		mask = SDE_GMBUS_CPT;
34185d0b1887SFrançois Tigeot 
3419*3f2dd94aSFrançois Tigeot 	gen3_assert_iir_is_zero(dev_priv, SDEIIR);
3420a2fdbec6SFrançois Tigeot 	I915_WRITE(SDEIMR, ~mask);
34214be47400SFrançois Tigeot 
34224be47400SFrançois Tigeot 	if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) ||
34234be47400SFrançois Tigeot 	    HAS_PCH_LPT(dev_priv))
3424a85cb24fSFrançois Tigeot 		ibx_hpd_detection_setup(dev_priv);
34254be47400SFrançois Tigeot 	else
34264be47400SFrançois Tigeot 		spt_hpd_detection_setup(dev_priv);
3427a2fdbec6SFrançois Tigeot }
3428a2fdbec6SFrançois Tigeot 
gen5_gt_irq_postinstall(struct drm_device * dev)34299edbd4a0SFrançois Tigeot static void gen5_gt_irq_postinstall(struct drm_device *dev)
34309edbd4a0SFrançois Tigeot {
3431303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
34329edbd4a0SFrançois Tigeot 	u32 pm_irqs, gt_irqs;
34339edbd4a0SFrançois Tigeot 
34349edbd4a0SFrançois Tigeot 	pm_irqs = gt_irqs = 0;
34359edbd4a0SFrançois Tigeot 
34369edbd4a0SFrançois Tigeot 	dev_priv->gt_irq_mask = ~0;
34371e12ee3bSFrançois Tigeot 	if (HAS_L3_DPF(dev_priv)) {
34389edbd4a0SFrançois Tigeot 		/* L3 parity interrupt is always unmasked. */
34391e12ee3bSFrançois Tigeot 		dev_priv->gt_irq_mask = ~GT_PARITY_ERROR(dev_priv);
34401e12ee3bSFrançois Tigeot 		gt_irqs |= GT_PARITY_ERROR(dev_priv);
34419edbd4a0SFrançois Tigeot 	}
34429edbd4a0SFrançois Tigeot 
34439edbd4a0SFrançois Tigeot 	gt_irqs |= GT_RENDER_USER_INTERRUPT;
34441e12ee3bSFrançois Tigeot 	if (IS_GEN5(dev_priv)) {
3445303bf270SFrançois Tigeot 		gt_irqs |= ILK_BSD_USER_INTERRUPT;
34469edbd4a0SFrançois Tigeot 	} else {
34479edbd4a0SFrançois Tigeot 		gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
34489edbd4a0SFrançois Tigeot 	}
34499edbd4a0SFrançois Tigeot 
3450*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs);
34519edbd4a0SFrançois Tigeot 
34524be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 6) {
34532c9916cdSFrançois Tigeot 		/*
34542c9916cdSFrançois Tigeot 		 * RPS interrupts will get enabled/disabled on demand when RPS
34552c9916cdSFrançois Tigeot 		 * itself is enabled/disabled.
34562c9916cdSFrançois Tigeot 		 */
34574be47400SFrançois Tigeot 		if (HAS_VEBOX(dev_priv)) {
34589edbd4a0SFrançois Tigeot 			pm_irqs |= PM_VEBOX_USER_INTERRUPT;
34594be47400SFrançois Tigeot 			dev_priv->pm_ier |= PM_VEBOX_USER_INTERRUPT;
34604be47400SFrançois Tigeot 		}
34619edbd4a0SFrançois Tigeot 
34624be47400SFrançois Tigeot 		dev_priv->pm_imr = 0xffffffff;
3463*3f2dd94aSFrançois Tigeot 		GEN3_IRQ_INIT(GEN6_PM, dev_priv->pm_imr, pm_irqs);
34649edbd4a0SFrançois Tigeot 	}
34659edbd4a0SFrançois Tigeot }
34669edbd4a0SFrançois Tigeot 
ironlake_irq_postinstall(struct drm_device * dev)3467e9243325SFrançois Tigeot static int ironlake_irq_postinstall(struct drm_device *dev)
3468e9243325SFrançois Tigeot {
3469303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
34709edbd4a0SFrançois Tigeot 	u32 display_mask, extra_mask;
34719edbd4a0SFrançois Tigeot 
34724be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 7) {
34739edbd4a0SFrançois Tigeot 		display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
3474*3f2dd94aSFrançois Tigeot 				DE_PCH_EVENT_IVB | DE_AUX_CHANNEL_A_IVB);
34759edbd4a0SFrançois Tigeot 		extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
3476352ff8bdSFrançois Tigeot 			      DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB |
3477352ff8bdSFrançois Tigeot 			      DE_DP_A_HOTPLUG_IVB);
34789edbd4a0SFrançois Tigeot 	} else {
34799edbd4a0SFrançois Tigeot 		display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
3480*3f2dd94aSFrançois Tigeot 				DE_AUX_CHANNEL_A | DE_PIPEB_CRC_DONE |
3481*3f2dd94aSFrançois Tigeot 				DE_PIPEA_CRC_DONE | DE_POISON);
3482352ff8bdSFrançois Tigeot 		extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
3483352ff8bdSFrançois Tigeot 			      DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
3484352ff8bdSFrançois Tigeot 			      DE_DP_A_HOTPLUG);
34859edbd4a0SFrançois Tigeot 	}
3486e9243325SFrançois Tigeot 
3487e9243325SFrançois Tigeot 	dev_priv->irq_mask = ~display_mask;
3488e9243325SFrançois Tigeot 
3489ba55f2f5SFrançois Tigeot 	ibx_irq_pre_postinstall(dev);
3490ba55f2f5SFrançois Tigeot 
3491*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_INIT(DE, dev_priv->irq_mask, display_mask | extra_mask);
3492e9243325SFrançois Tigeot 
34939edbd4a0SFrançois Tigeot 	gen5_gt_irq_postinstall(dev);
3494e9243325SFrançois Tigeot 
3495a85cb24fSFrançois Tigeot 	ilk_hpd_detection_setup(dev_priv);
3496a85cb24fSFrançois Tigeot 
3497a2fdbec6SFrançois Tigeot 	ibx_irq_postinstall(dev);
3498e9243325SFrançois Tigeot 
34991e12ee3bSFrançois Tigeot 	if (IS_IRONLAKE_M(dev_priv)) {
35005d0b1887SFrançois Tigeot 		/* Enable PCU event interrupts
35015d0b1887SFrançois Tigeot 		 *
35025d0b1887SFrançois Tigeot 		 * spinlocking not required here for correctness since interrupt
35035d0b1887SFrançois Tigeot 		 * setup is guaranteed to run in single-threaded context. But we
35045d0b1887SFrançois Tigeot 		 * need it to make the assert_spin_locked happy. */
35055e269720SFrançois Tigeot 		spin_lock_irq(&dev_priv->irq_lock);
3506aee94f86SFrançois Tigeot 		ilk_enable_display_irq(dev_priv, DE_PCU_EVENT);
35075e269720SFrançois Tigeot 		spin_unlock_irq(&dev_priv->irq_lock);
3508e9243325SFrançois Tigeot 	}
3509e9243325SFrançois Tigeot 
3510e9243325SFrançois Tigeot 	return 0;
3511e9243325SFrançois Tigeot }
3512e9243325SFrançois Tigeot 
valleyview_enable_display_irqs(struct drm_i915_private * dev_priv)3513ba55f2f5SFrançois Tigeot void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv)
3514ba55f2f5SFrançois Tigeot {
3515a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
3516ba55f2f5SFrançois Tigeot 
3517ba55f2f5SFrançois Tigeot 	if (dev_priv->display_irqs_enabled)
3518ba55f2f5SFrançois Tigeot 		return;
3519ba55f2f5SFrançois Tigeot 
3520ba55f2f5SFrançois Tigeot 	dev_priv->display_irqs_enabled = true;
3521ba55f2f5SFrançois Tigeot 
35228621f407SFrançois Tigeot 	if (intel_irqs_enabled(dev_priv)) {
35238621f407SFrançois Tigeot 		vlv_display_irq_reset(dev_priv);
35248621f407SFrançois Tigeot 		vlv_display_irq_postinstall(dev_priv);
35258621f407SFrançois Tigeot 	}
3526ba55f2f5SFrançois Tigeot }
3527ba55f2f5SFrançois Tigeot 
valleyview_disable_display_irqs(struct drm_i915_private * dev_priv)3528ba55f2f5SFrançois Tigeot void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv)
3529ba55f2f5SFrançois Tigeot {
3530a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
3531ba55f2f5SFrançois Tigeot 
3532ba55f2f5SFrançois Tigeot 	if (!dev_priv->display_irqs_enabled)
3533ba55f2f5SFrançois Tigeot 		return;
3534ba55f2f5SFrançois Tigeot 
3535ba55f2f5SFrançois Tigeot 	dev_priv->display_irqs_enabled = false;
3536ba55f2f5SFrançois Tigeot 
35372c9916cdSFrançois Tigeot 	if (intel_irqs_enabled(dev_priv))
35388621f407SFrançois Tigeot 		vlv_display_irq_reset(dev_priv);
3539ba55f2f5SFrançois Tigeot }
3540ba55f2f5SFrançois Tigeot 
3541e9243325SFrançois Tigeot 
valleyview_irq_postinstall(struct drm_device * dev)35422c9916cdSFrançois Tigeot static int valleyview_irq_postinstall(struct drm_device *dev)
35432c9916cdSFrançois Tigeot {
3544303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
35452c9916cdSFrançois Tigeot 
35469edbd4a0SFrançois Tigeot 	gen5_gt_irq_postinstall(dev);
3547e9243325SFrançois Tigeot 
35488621f407SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
35498621f407SFrançois Tigeot 	if (dev_priv->display_irqs_enabled)
35508621f407SFrançois Tigeot 		vlv_display_irq_postinstall(dev_priv);
35518621f407SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
3552e9243325SFrançois Tigeot 
3553e9243325SFrançois Tigeot 	I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
35548621f407SFrançois Tigeot 	POSTING_READ(VLV_MASTER_IER);
3555a2fdbec6SFrançois Tigeot 
3556a2fdbec6SFrançois Tigeot 	return 0;
3557a2fdbec6SFrançois Tigeot }
3558a2fdbec6SFrançois Tigeot 
gen8_gt_irq_postinstall(struct drm_i915_private * dev_priv)35599edbd4a0SFrançois Tigeot static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
35609edbd4a0SFrançois Tigeot {
35619edbd4a0SFrançois Tigeot 	/* These are interrupts we'll toggle with the ring mask register */
35629edbd4a0SFrançois Tigeot 	uint32_t gt_interrupts[] = {
35639edbd4a0SFrançois Tigeot 		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
35641b13d190SFrançois Tigeot 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
35651b13d190SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
35661b13d190SFrançois Tigeot 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
35679edbd4a0SFrançois Tigeot 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
35681b13d190SFrançois Tigeot 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
35691b13d190SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT |
35701b13d190SFrançois Tigeot 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
35719edbd4a0SFrançois Tigeot 		0,
35721b13d190SFrançois Tigeot 		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT |
35731b13d190SFrançois Tigeot 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT
35749edbd4a0SFrançois Tigeot 		};
35759edbd4a0SFrançois Tigeot 
35768621f407SFrançois Tigeot 	if (HAS_L3_DPF(dev_priv))
35778621f407SFrançois Tigeot 		gt_interrupts[0] |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
35788621f407SFrançois Tigeot 
35794be47400SFrançois Tigeot 	dev_priv->pm_ier = 0x0;
35804be47400SFrançois Tigeot 	dev_priv->pm_imr = ~dev_priv->pm_ier;
35811b13d190SFrançois Tigeot 	GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
35821b13d190SFrançois Tigeot 	GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
35832c9916cdSFrançois Tigeot 	/*
35842c9916cdSFrançois Tigeot 	 * RPS interrupts will get enabled/disabled on demand when RPS itself
35854be47400SFrançois Tigeot 	 * is enabled/disabled. Same wil be the case for GuC interrupts.
35862c9916cdSFrançois Tigeot 	 */
35874be47400SFrançois Tigeot 	GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier);
35881b13d190SFrançois Tigeot 	GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
35899edbd4a0SFrançois Tigeot }
35909edbd4a0SFrançois Tigeot 
gen8_de_irq_postinstall(struct drm_i915_private * dev_priv)35919edbd4a0SFrançois Tigeot static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
35929edbd4a0SFrançois Tigeot {
35932c9916cdSFrançois Tigeot 	uint32_t de_pipe_masked = GEN8_PIPE_CDCLK_CRC_DONE;
35942c9916cdSFrançois Tigeot 	uint32_t de_pipe_enables;
3595352ff8bdSFrançois Tigeot 	u32 de_port_masked = GEN8_AUX_CHANNEL_A;
3596352ff8bdSFrançois Tigeot 	u32 de_port_enables;
35971487f786SFrançois Tigeot 	u32 de_misc_masked = GEN8_DE_MISC_GSE;
3598352ff8bdSFrançois Tigeot 	enum i915_pipe pipe;
35992c9916cdSFrançois Tigeot 
3600*3f2dd94aSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9) {
3601*3f2dd94aSFrançois Tigeot 		de_pipe_masked |= GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
3602352ff8bdSFrançois Tigeot 		de_port_masked |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
36032c9916cdSFrançois Tigeot 				  GEN9_AUX_CHANNEL_D;
3604a85cb24fSFrançois Tigeot 		if (IS_GEN9_LP(dev_priv))
3605352ff8bdSFrançois Tigeot 			de_port_masked |= BXT_DE_PORT_GMBUS;
3606352ff8bdSFrançois Tigeot 	} else {
3607*3f2dd94aSFrançois Tigeot 		de_pipe_masked |= GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
3608352ff8bdSFrançois Tigeot 	}
36092c9916cdSFrançois Tigeot 
36102c9916cdSFrançois Tigeot 	de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
36112c9916cdSFrançois Tigeot 					   GEN8_PIPE_FIFO_UNDERRUN;
36122c9916cdSFrançois Tigeot 
3613352ff8bdSFrançois Tigeot 	de_port_enables = de_port_masked;
3614a85cb24fSFrançois Tigeot 	if (IS_GEN9_LP(dev_priv))
3615352ff8bdSFrançois Tigeot 		de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK;
3616352ff8bdSFrançois Tigeot 	else if (IS_BROADWELL(dev_priv))
3617352ff8bdSFrançois Tigeot 		de_port_enables |= GEN8_PORT_DP_A_HOTPLUG;
3618352ff8bdSFrançois Tigeot 
3619*3f2dd94aSFrançois Tigeot 	for_each_pipe(dev_priv, pipe) {
3620*3f2dd94aSFrançois Tigeot 		dev_priv->de_irq_mask[pipe] = ~de_pipe_masked;
36219edbd4a0SFrançois Tigeot 
36222c9916cdSFrançois Tigeot 		if (intel_display_power_is_enabled(dev_priv,
362324edb884SFrançois Tigeot 				POWER_DOMAIN_PIPE(pipe)))
362424edb884SFrançois Tigeot 			GEN8_IRQ_INIT_NDX(DE_PIPE, pipe,
362524edb884SFrançois Tigeot 					  dev_priv->de_irq_mask[pipe],
3626ba55f2f5SFrançois Tigeot 					  de_pipe_enables);
3627*3f2dd94aSFrançois Tigeot 	}
36289edbd4a0SFrançois Tigeot 
3629*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_INIT(GEN8_DE_PORT_, ~de_port_masked, de_port_enables);
3630*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_INIT(GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked);
36314be47400SFrançois Tigeot 
3632a85cb24fSFrançois Tigeot 	if (IS_GEN9_LP(dev_priv))
36334be47400SFrançois Tigeot 		bxt_hpd_detection_setup(dev_priv);
3634a85cb24fSFrançois Tigeot 	else if (IS_BROADWELL(dev_priv))
3635a85cb24fSFrançois Tigeot 		ilk_hpd_detection_setup(dev_priv);
36369edbd4a0SFrançois Tigeot }
36379edbd4a0SFrançois Tigeot 
gen8_irq_postinstall(struct drm_device * dev)36389edbd4a0SFrançois Tigeot static int gen8_irq_postinstall(struct drm_device *dev)
36399edbd4a0SFrançois Tigeot {
3640303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
36419edbd4a0SFrançois Tigeot 
36421e12ee3bSFrançois Tigeot 	if (HAS_PCH_SPLIT(dev_priv))
3643ba55f2f5SFrançois Tigeot 		ibx_irq_pre_postinstall(dev);
3644ba55f2f5SFrançois Tigeot 
36459edbd4a0SFrançois Tigeot 	gen8_gt_irq_postinstall(dev_priv);
36469edbd4a0SFrançois Tigeot 	gen8_de_irq_postinstall(dev_priv);
36479edbd4a0SFrançois Tigeot 
36481e12ee3bSFrançois Tigeot 	if (HAS_PCH_SPLIT(dev_priv))
36499edbd4a0SFrançois Tigeot 		ibx_irq_postinstall(dev);
36509edbd4a0SFrançois Tigeot 
36518621f407SFrançois Tigeot 	I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
36529edbd4a0SFrançois Tigeot 	POSTING_READ(GEN8_MASTER_IRQ);
36539edbd4a0SFrançois Tigeot 
36549edbd4a0SFrançois Tigeot 	return 0;
36559edbd4a0SFrançois Tigeot }
36569edbd4a0SFrançois Tigeot 
cherryview_irq_postinstall(struct drm_device * dev)3657ba55f2f5SFrançois Tigeot static int cherryview_irq_postinstall(struct drm_device *dev)
3658ba55f2f5SFrançois Tigeot {
3659303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3660ba55f2f5SFrançois Tigeot 
3661ba55f2f5SFrançois Tigeot 	gen8_gt_irq_postinstall(dev_priv);
3662ba55f2f5SFrançois Tigeot 
36638621f407SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
36648621f407SFrançois Tigeot 	if (dev_priv->display_irqs_enabled)
36658621f407SFrançois Tigeot 		vlv_display_irq_postinstall(dev_priv);
36668621f407SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
36678621f407SFrançois Tigeot 
36688621f407SFrançois Tigeot 	I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
3669ba55f2f5SFrançois Tigeot 	POSTING_READ(GEN8_MASTER_IRQ);
3670ba55f2f5SFrançois Tigeot 
3671ba55f2f5SFrançois Tigeot 	return 0;
3672ba55f2f5SFrançois Tigeot }
3673ba55f2f5SFrançois Tigeot 
i8xx_irq_reset(struct drm_device * dev)3674*3f2dd94aSFrançois Tigeot static void i8xx_irq_reset(struct drm_device *dev)
36759edbd4a0SFrançois Tigeot {
3676303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3677ba55f2f5SFrançois Tigeot 
3678*3f2dd94aSFrançois Tigeot 	i9xx_pipestat_irq_reset(dev_priv);
3679ba55f2f5SFrançois Tigeot 
3680*3f2dd94aSFrançois Tigeot 	I915_WRITE16(HWSTAM, 0xffff);
3681ba55f2f5SFrançois Tigeot 
3682*3f2dd94aSFrançois Tigeot 	GEN2_IRQ_RESET();
3683e9243325SFrançois Tigeot }
3684e9243325SFrançois Tigeot 
i8xx_irq_postinstall(struct drm_device * dev)3685e9243325SFrançois Tigeot static int i8xx_irq_postinstall(struct drm_device *dev)
3686e9243325SFrançois Tigeot {
3687303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3688*3f2dd94aSFrançois Tigeot 	u16 enable_mask;
3689e9243325SFrançois Tigeot 
3690*3f2dd94aSFrançois Tigeot 	I915_WRITE16(EMR, ~(I915_ERROR_PAGE_TABLE |
3691*3f2dd94aSFrançois Tigeot 			    I915_ERROR_MEMORY_REFRESH));
3692e9243325SFrançois Tigeot 
3693e9243325SFrançois Tigeot 	/* Unmask the interrupts that we always want on. */
3694e9243325SFrançois Tigeot 	dev_priv->irq_mask =
3695e9243325SFrançois Tigeot 		~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
3696*3f2dd94aSFrançois Tigeot 		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
3697e9243325SFrançois Tigeot 
3698*3f2dd94aSFrançois Tigeot 	enable_mask =
3699e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
3700e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
3701*3f2dd94aSFrançois Tigeot 		I915_USER_INTERRUPT;
3702*3f2dd94aSFrançois Tigeot 
3703*3f2dd94aSFrançois Tigeot 	GEN2_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
3704e9243325SFrançois Tigeot 
37059edbd4a0SFrançois Tigeot 	/* Interrupt setup is already guaranteed to be single-threaded, this is
37069edbd4a0SFrançois Tigeot 	 * just to make the assert_spin_locked check happy. */
37075e269720SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
3708ba55f2f5SFrançois Tigeot 	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
3709ba55f2f5SFrançois Tigeot 	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
37105e269720SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
37119edbd4a0SFrançois Tigeot 
3712e9243325SFrançois Tigeot 	return 0;
3713e9243325SFrançois Tigeot }
3714e9243325SFrançois Tigeot 
i8xx_irq_handler(int irq,void * arg)3715183e2373SFrançois Tigeot static irqreturn_t i8xx_irq_handler(int irq, void *arg)
3716e9243325SFrançois Tigeot {
3717ba55f2f5SFrançois Tigeot 	struct drm_device *dev = arg;
3718303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3719*3f2dd94aSFrançois Tigeot 	irqreturn_t ret = IRQ_NONE;
3720e9243325SFrançois Tigeot 
37212c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
37222c9916cdSFrançois Tigeot 		return IRQ_NONE;
37232c9916cdSFrançois Tigeot 
3724aee94f86SFrançois Tigeot 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
3725aee94f86SFrançois Tigeot 	disable_rpm_wakeref_asserts(dev_priv);
3726aee94f86SFrançois Tigeot 
3727*3f2dd94aSFrançois Tigeot 	do {
3728*3f2dd94aSFrançois Tigeot 		u32 pipe_stats[I915_MAX_PIPES] = {};
3729*3f2dd94aSFrançois Tigeot 		u16 iir;
3730*3f2dd94aSFrançois Tigeot 
3731e9243325SFrançois Tigeot 		iir = I915_READ16(IIR);
3732e9243325SFrançois Tigeot 		if (iir == 0)
3733*3f2dd94aSFrançois Tigeot 			break;
3734e9243325SFrançois Tigeot 
3735*3f2dd94aSFrançois Tigeot 		ret = IRQ_HANDLED;
3736e9243325SFrançois Tigeot 
3737*3f2dd94aSFrançois Tigeot 		/* Call regardless, as some status bits might not be
3738*3f2dd94aSFrançois Tigeot 		 * signalled in iir */
3739*3f2dd94aSFrançois Tigeot 		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
3740e9243325SFrançois Tigeot 
3741*3f2dd94aSFrançois Tigeot 		I915_WRITE16(IIR, iir);
3742e9243325SFrançois Tigeot 
3743e9243325SFrançois Tigeot 		if (iir & I915_USER_INTERRUPT)
37441e12ee3bSFrançois Tigeot 			notify_ring(dev_priv->engine[RCS]);
3745e9243325SFrançois Tigeot 
3746*3f2dd94aSFrançois Tigeot 		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
3747*3f2dd94aSFrançois Tigeot 			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
3748e9243325SFrançois Tigeot 
3749*3f2dd94aSFrançois Tigeot 		i8xx_pipestat_irq_handler(dev_priv, iir, pipe_stats);
3750*3f2dd94aSFrançois Tigeot 	} while (0);
37519edbd4a0SFrançois Tigeot 
3752aee94f86SFrançois Tigeot 	enable_rpm_wakeref_asserts(dev_priv);
3753aee94f86SFrançois Tigeot 
3754183e2373SFrançois Tigeot 	return ret;
3755e9243325SFrançois Tigeot }
3756e9243325SFrançois Tigeot 
i915_irq_reset(struct drm_device * dev)3757*3f2dd94aSFrançois Tigeot static void i915_irq_reset(struct drm_device *dev)
3758e9243325SFrançois Tigeot {
3759303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3760e9243325SFrançois Tigeot 
37614be47400SFrançois Tigeot 	if (I915_HAS_HOTPLUG(dev_priv)) {
3762352ff8bdSFrançois Tigeot 		i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
3763e9243325SFrançois Tigeot 		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
3764e9243325SFrançois Tigeot 	}
3765e9243325SFrançois Tigeot 
3766*3f2dd94aSFrançois Tigeot 	i9xx_pipestat_irq_reset(dev_priv);
3767*3f2dd94aSFrançois Tigeot 
3768*3f2dd94aSFrançois Tigeot 	I915_WRITE(HWSTAM, 0xffffffff);
3769*3f2dd94aSFrançois Tigeot 
3770*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_RESET();
3771e9243325SFrançois Tigeot }
3772e9243325SFrançois Tigeot 
i915_irq_postinstall(struct drm_device * dev)3773e9243325SFrançois Tigeot static int i915_irq_postinstall(struct drm_device *dev)
3774e9243325SFrançois Tigeot {
3775303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3776e9243325SFrançois Tigeot 	u32 enable_mask;
3777e9243325SFrançois Tigeot 
3778*3f2dd94aSFrançois Tigeot 	I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE |
3779*3f2dd94aSFrançois Tigeot 			  I915_ERROR_MEMORY_REFRESH));
3780e9243325SFrançois Tigeot 
3781e9243325SFrançois Tigeot 	/* Unmask the interrupts that we always want on. */
3782e9243325SFrançois Tigeot 	dev_priv->irq_mask =
3783e9243325SFrançois Tigeot 		~(I915_ASLE_INTERRUPT |
3784e9243325SFrançois Tigeot 		  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
3785*3f2dd94aSFrançois Tigeot 		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
3786e9243325SFrançois Tigeot 
3787e9243325SFrançois Tigeot 	enable_mask =
3788e9243325SFrançois Tigeot 		I915_ASLE_INTERRUPT |
3789e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
3790e9243325SFrançois Tigeot 		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
3791e9243325SFrançois Tigeot 		I915_USER_INTERRUPT;
3792e9243325SFrançois Tigeot 
37934be47400SFrançois Tigeot 	if (I915_HAS_HOTPLUG(dev_priv)) {
3794e9243325SFrançois Tigeot 		/* Enable in IER... */
3795e9243325SFrançois Tigeot 		enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
3796e9243325SFrançois Tigeot 		/* and unmask in IMR */
3797e9243325SFrançois Tigeot 		dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT;
3798e9243325SFrançois Tigeot 	}
3799e9243325SFrançois Tigeot 
3800*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
3801e9243325SFrançois Tigeot 
38029edbd4a0SFrançois Tigeot 	/* Interrupt setup is already guaranteed to be single-threaded, this is
38039edbd4a0SFrançois Tigeot 	 * just to make the assert_spin_locked check happy. */
38045e269720SFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
3805ba55f2f5SFrançois Tigeot 	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
3806ba55f2f5SFrançois Tigeot 	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
38075e269720SFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
38089edbd4a0SFrançois Tigeot 
3809*3f2dd94aSFrançois Tigeot 	i915_enable_asle_pipestat(dev_priv);
3810*3f2dd94aSFrançois Tigeot 
3811a2fdbec6SFrançois Tigeot 	return 0;
3812a2fdbec6SFrançois Tigeot }
3813a2fdbec6SFrançois Tigeot 
i915_irq_handler(int irq,void * arg)3814183e2373SFrançois Tigeot static irqreturn_t i915_irq_handler(int irq, void *arg)
3815e9243325SFrançois Tigeot {
3816ba55f2f5SFrançois Tigeot 	struct drm_device *dev = arg;
3817303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3818*3f2dd94aSFrançois Tigeot 	irqreturn_t ret = IRQ_NONE;
3819e9243325SFrançois Tigeot 
38202c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
38212c9916cdSFrançois Tigeot 		return IRQ_NONE;
38222c9916cdSFrançois Tigeot 
3823aee94f86SFrançois Tigeot 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
3824aee94f86SFrançois Tigeot 	disable_rpm_wakeref_asserts(dev_priv);
3825aee94f86SFrançois Tigeot 
3826e9243325SFrançois Tigeot 	do {
3827*3f2dd94aSFrançois Tigeot 		u32 pipe_stats[I915_MAX_PIPES] = {};
3828*3f2dd94aSFrançois Tigeot 		u32 hotplug_status = 0;
3829*3f2dd94aSFrançois Tigeot 		u32 iir;
3830e9243325SFrançois Tigeot 
3831*3f2dd94aSFrançois Tigeot 		iir = I915_READ(IIR);
3832*3f2dd94aSFrançois Tigeot 		if (iir == 0)
3833e9243325SFrançois Tigeot 			break;
3834e9243325SFrançois Tigeot 
3835*3f2dd94aSFrançois Tigeot 		ret = IRQ_HANDLED;
3836e9243325SFrançois Tigeot 
3837*3f2dd94aSFrançois Tigeot 		if (I915_HAS_HOTPLUG(dev_priv) &&
3838*3f2dd94aSFrançois Tigeot 		    iir & I915_DISPLAY_PORT_INTERRUPT)
3839*3f2dd94aSFrançois Tigeot 			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
3840*3f2dd94aSFrançois Tigeot 
3841*3f2dd94aSFrançois Tigeot 		/* Call regardless, as some status bits might not be
3842*3f2dd94aSFrançois Tigeot 		 * signalled in iir */
3843*3f2dd94aSFrançois Tigeot 		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
3844*3f2dd94aSFrançois Tigeot 
3845*3f2dd94aSFrançois Tigeot 		I915_WRITE(IIR, iir);
3846e9243325SFrançois Tigeot 
3847e9243325SFrançois Tigeot 		if (iir & I915_USER_INTERRUPT)
38481e12ee3bSFrançois Tigeot 			notify_ring(dev_priv->engine[RCS]);
3849e9243325SFrançois Tigeot 
3850*3f2dd94aSFrançois Tigeot 		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
3851*3f2dd94aSFrançois Tigeot 			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
38528e26cdf6SFrançois Tigeot 
3853*3f2dd94aSFrançois Tigeot 		if (hotplug_status)
3854*3f2dd94aSFrançois Tigeot 			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
3855e9243325SFrançois Tigeot 
3856*3f2dd94aSFrançois Tigeot 		i915_pipestat_irq_handler(dev_priv, iir, pipe_stats);
3857*3f2dd94aSFrançois Tigeot 	} while (0);
3858e9243325SFrançois Tigeot 
3859aee94f86SFrançois Tigeot 	enable_rpm_wakeref_asserts(dev_priv);
3860aee94f86SFrançois Tigeot 
3861183e2373SFrançois Tigeot 	return ret;
3862e9243325SFrançois Tigeot }
3863e9243325SFrançois Tigeot 
i965_irq_reset(struct drm_device * dev)3864*3f2dd94aSFrançois Tigeot static void i965_irq_reset(struct drm_device *dev)
3865e9243325SFrançois Tigeot {
3866303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3867e9243325SFrançois Tigeot 
3868352ff8bdSFrançois Tigeot 	i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
3869e9243325SFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
3870e9243325SFrançois Tigeot 
3871*3f2dd94aSFrançois Tigeot 	i9xx_pipestat_irq_reset(dev_priv);
3872*3f2dd94aSFrançois Tigeot 
3873*3f2dd94aSFrançois Tigeot 	I915_WRITE(HWSTAM, 0xffffffff);
3874*3f2dd94aSFrançois Tigeot 
3875*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_RESET();
3876e9243325SFrançois Tigeot }
3877e9243325SFrançois Tigeot 
i965_irq_postinstall(struct drm_device * dev)3878e9243325SFrançois Tigeot static int i965_irq_postinstall(struct drm_device *dev)
3879e9243325SFrançois Tigeot {
3880303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3881e9243325SFrançois Tigeot 	u32 enable_mask;
3882e9243325SFrançois Tigeot 	u32 error_mask;
3883e9243325SFrançois Tigeot 
3884e9243325SFrançois Tigeot 	/*
3885e9243325SFrançois Tigeot 	 * Enable some error detection, note the instruction error mask
3886e9243325SFrançois Tigeot 	 * bit is reserved, so we leave it masked.
3887e9243325SFrançois Tigeot 	 */
38881487f786SFrançois Tigeot 	if (IS_G4X(dev_priv)) {
3889e9243325SFrançois Tigeot 		error_mask = ~(GM45_ERROR_PAGE_TABLE |
3890e9243325SFrançois Tigeot 			       GM45_ERROR_MEM_PRIV |
3891e9243325SFrançois Tigeot 			       GM45_ERROR_CP_PRIV |
3892e9243325SFrançois Tigeot 			       I915_ERROR_MEMORY_REFRESH);
3893e9243325SFrançois Tigeot 	} else {
3894e9243325SFrançois Tigeot 		error_mask = ~(I915_ERROR_PAGE_TABLE |
3895e9243325SFrançois Tigeot 			       I915_ERROR_MEMORY_REFRESH);
3896e9243325SFrançois Tigeot 	}
3897e9243325SFrançois Tigeot 	I915_WRITE(EMR, error_mask);
3898e9243325SFrançois Tigeot 
3899*3f2dd94aSFrançois Tigeot 	/* Unmask the interrupts that we always want on. */
3900*3f2dd94aSFrançois Tigeot 	dev_priv->irq_mask =
3901*3f2dd94aSFrançois Tigeot 		~(I915_ASLE_INTERRUPT |
3902*3f2dd94aSFrançois Tigeot 		  I915_DISPLAY_PORT_INTERRUPT |
3903*3f2dd94aSFrançois Tigeot 		  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
3904*3f2dd94aSFrançois Tigeot 		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
3905*3f2dd94aSFrançois Tigeot 		  I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
3906e9243325SFrançois Tigeot 
3907*3f2dd94aSFrançois Tigeot 	enable_mask =
3908*3f2dd94aSFrançois Tigeot 		I915_ASLE_INTERRUPT |
3909*3f2dd94aSFrançois Tigeot 		I915_DISPLAY_PORT_INTERRUPT |
3910*3f2dd94aSFrançois Tigeot 		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
3911*3f2dd94aSFrançois Tigeot 		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
3912*3f2dd94aSFrançois Tigeot 		I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
3913*3f2dd94aSFrançois Tigeot 		I915_USER_INTERRUPT;
3914*3f2dd94aSFrançois Tigeot 
3915*3f2dd94aSFrançois Tigeot 	if (IS_G4X(dev_priv))
3916*3f2dd94aSFrançois Tigeot 		enable_mask |= I915_BSD_USER_INTERRUPT;
3917*3f2dd94aSFrançois Tigeot 
3918*3f2dd94aSFrançois Tigeot 	GEN3_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
3919*3f2dd94aSFrançois Tigeot 
3920*3f2dd94aSFrançois Tigeot 	/* Interrupt setup is already guaranteed to be single-threaded, this is
3921*3f2dd94aSFrançois Tigeot 	 * just to make the assert_spin_locked check happy. */
3922*3f2dd94aSFrançois Tigeot 	spin_lock_irq(&dev_priv->irq_lock);
3923*3f2dd94aSFrançois Tigeot 	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
3924*3f2dd94aSFrançois Tigeot 	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
3925*3f2dd94aSFrançois Tigeot 	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
3926*3f2dd94aSFrançois Tigeot 	spin_unlock_irq(&dev_priv->irq_lock);
3927a2fdbec6SFrançois Tigeot 
39281487f786SFrançois Tigeot 	i915_enable_asle_pipestat(dev_priv);
3929a2fdbec6SFrançois Tigeot 
3930a2fdbec6SFrançois Tigeot 	return 0;
3931a2fdbec6SFrançois Tigeot }
3932a2fdbec6SFrançois Tigeot 
i915_hpd_irq_setup(struct drm_i915_private * dev_priv)39331487f786SFrançois Tigeot static void i915_hpd_irq_setup(struct drm_i915_private *dev_priv)
3934a2fdbec6SFrançois Tigeot {
3935a2fdbec6SFrançois Tigeot 	u32 hotplug_en;
3936a2fdbec6SFrançois Tigeot 
3937a85cb24fSFrançois Tigeot 	lockdep_assert_held(&dev_priv->irq_lock);
39389edbd4a0SFrançois Tigeot 
3939e9243325SFrançois Tigeot 	/* Note HDMI and DP share hotplug bits */
39408e26cdf6SFrançois Tigeot 	/* enable bits are the same for all generations */
39411487f786SFrançois Tigeot 	hotplug_en = intel_hpd_enabled_irqs(dev_priv, hpd_mask_i915);
3942e9243325SFrançois Tigeot 	/* Programming the CRT detection parameters tends
3943e9243325SFrançois Tigeot 	   to generate a spurious hotplug event about three
3944e9243325SFrançois Tigeot 	   seconds later.  So just do it once.
3945e9243325SFrançois Tigeot 	*/
39461487f786SFrançois Tigeot 	if (IS_G4X(dev_priv))
3947e9243325SFrançois Tigeot 		hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
3948e9243325SFrançois Tigeot 	hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
3949e9243325SFrançois Tigeot 
3950e9243325SFrançois Tigeot 	/* Ignore TV since it's buggy */
3951352ff8bdSFrançois Tigeot 	i915_hotplug_interrupt_update_locked(dev_priv,
3952352ff8bdSFrançois Tigeot 					     HOTPLUG_INT_EN_MASK |
3953352ff8bdSFrançois Tigeot 					     CRT_HOTPLUG_VOLTAGE_COMPARE_MASK |
3954352ff8bdSFrançois Tigeot 					     CRT_HOTPLUG_ACTIVATION_PERIOD_64,
3955352ff8bdSFrançois Tigeot 					     hotplug_en);
3956e9243325SFrançois Tigeot }
3957e9243325SFrançois Tigeot 
i965_irq_handler(int irq,void * arg)3958183e2373SFrançois Tigeot static irqreturn_t i965_irq_handler(int irq, void *arg)
3959e9243325SFrançois Tigeot {
3960ba55f2f5SFrançois Tigeot 	struct drm_device *dev = arg;
3961303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
3962*3f2dd94aSFrançois Tigeot 	irqreturn_t ret = IRQ_NONE;
3963e9243325SFrançois Tigeot 
39642c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
39652c9916cdSFrançois Tigeot 		return IRQ_NONE;
39662c9916cdSFrançois Tigeot 
3967aee94f86SFrançois Tigeot 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
3968aee94f86SFrançois Tigeot 	disable_rpm_wakeref_asserts(dev_priv);
3969aee94f86SFrançois Tigeot 
3970*3f2dd94aSFrançois Tigeot 	do {
3971*3f2dd94aSFrançois Tigeot 		u32 pipe_stats[I915_MAX_PIPES] = {};
3972*3f2dd94aSFrançois Tigeot 		u32 hotplug_status = 0;
3973*3f2dd94aSFrançois Tigeot 		u32 iir;
3974*3f2dd94aSFrançois Tigeot 
3975e9243325SFrançois Tigeot 		iir = I915_READ(IIR);
3976*3f2dd94aSFrançois Tigeot 		if (iir == 0)
3977e9243325SFrançois Tigeot 			break;
3978e9243325SFrançois Tigeot 
3979183e2373SFrançois Tigeot 		ret = IRQ_HANDLED;
3980c0e85e96SFrançois Tigeot 
3981*3f2dd94aSFrançois Tigeot 		if (iir & I915_DISPLAY_PORT_INTERRUPT)
3982*3f2dd94aSFrançois Tigeot 			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
3983e9243325SFrançois Tigeot 
3984*3f2dd94aSFrançois Tigeot 		/* Call regardless, as some status bits might not be
3985*3f2dd94aSFrançois Tigeot 		 * signalled in iir */
3986*3f2dd94aSFrançois Tigeot 		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
3987*3f2dd94aSFrançois Tigeot 
3988*3f2dd94aSFrançois Tigeot 		I915_WRITE(IIR, iir);
3989e9243325SFrançois Tigeot 
3990e9243325SFrançois Tigeot 		if (iir & I915_USER_INTERRUPT)
39911e12ee3bSFrançois Tigeot 			notify_ring(dev_priv->engine[RCS]);
3992*3f2dd94aSFrançois Tigeot 
3993e9243325SFrançois Tigeot 		if (iir & I915_BSD_USER_INTERRUPT)
39941e12ee3bSFrançois Tigeot 			notify_ring(dev_priv->engine[VCS]);
3995e9243325SFrançois Tigeot 
3996*3f2dd94aSFrançois Tigeot 		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
3997*3f2dd94aSFrançois Tigeot 			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
3998e9243325SFrançois Tigeot 
3999*3f2dd94aSFrançois Tigeot 		if (hotplug_status)
4000*3f2dd94aSFrançois Tigeot 			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
40019edbd4a0SFrançois Tigeot 
4002*3f2dd94aSFrançois Tigeot 		i965_pipestat_irq_handler(dev_priv, iir, pipe_stats);
4003*3f2dd94aSFrançois Tigeot 	} while (0);
4004e9243325SFrançois Tigeot 
4005aee94f86SFrançois Tigeot 	enable_rpm_wakeref_asserts(dev_priv);
4006aee94f86SFrançois Tigeot 
4007183e2373SFrançois Tigeot 	return ret;
4008e9243325SFrançois Tigeot }
4009e9243325SFrançois Tigeot 
40102c9916cdSFrançois Tigeot /**
40112c9916cdSFrançois Tigeot  * intel_irq_init - initializes irq support
40122c9916cdSFrançois Tigeot  * @dev_priv: i915 device instance
40132c9916cdSFrançois Tigeot  *
40142c9916cdSFrançois Tigeot  * This function initializes all the irq support including work items, timers
40152c9916cdSFrançois Tigeot  * and all the vtables. It does not setup the interrupt itself though.
40162c9916cdSFrançois Tigeot  */
intel_irq_init(struct drm_i915_private * dev_priv)40172c9916cdSFrançois Tigeot void intel_irq_init(struct drm_i915_private *dev_priv)
4018e9243325SFrançois Tigeot {
4019303bf270SFrançois Tigeot 	struct drm_device *dev = &dev_priv->drm;
4020*3f2dd94aSFrançois Tigeot 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
4021*3f2dd94aSFrançois Tigeot 	int i;
4022e9243325SFrançois Tigeot 
4023a05eeebfSFrançois Tigeot 	intel_hpd_init_work(dev_priv);
4024a05eeebfSFrançois Tigeot 
4025*3f2dd94aSFrançois Tigeot 	INIT_WORK(&rps->work, gen6_pm_rps_work);
4026*3f2dd94aSFrançois Tigeot 
402700640ec9SFrançois Tigeot 	INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
4028*3f2dd94aSFrançois Tigeot 	for (i = 0; i < MAX_L3_SLICES; ++i)
4029*3f2dd94aSFrançois Tigeot 		dev_priv->l3_parity.remap_info[i] = NULL;
4030e9243325SFrançois Tigeot 
40314be47400SFrançois Tigeot 	if (HAS_GUC_SCHED(dev_priv))
40324be47400SFrançois Tigeot 		dev_priv->pm_guc_events = GEN9_GUC_TO_HOST_INT_EVENT;
40334be47400SFrançois Tigeot 
4034ba55f2f5SFrançois Tigeot 	/* Let's track the enabled rps events */
4035aee94f86SFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv))
40361b13d190SFrançois Tigeot 		/* WaGsvRC0ResidencyMethod:vlv */
40374be47400SFrançois Tigeot 		dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
403824edb884SFrançois Tigeot 	else
4039ba55f2f5SFrançois Tigeot 		dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
4040ba55f2f5SFrançois Tigeot 
4041*3f2dd94aSFrançois Tigeot 	rps->pm_intrmsk_mbz = 0;
40421487f786SFrançois Tigeot 
40431487f786SFrançois Tigeot 	/*
4044a85cb24fSFrançois Tigeot 	 * SNB,IVB,HSW can while VLV,CHV may hard hang on looping batchbuffer
40451487f786SFrançois Tigeot 	 * if GEN6_PM_UP_EI_EXPIRED is masked.
40461487f786SFrançois Tigeot 	 *
40471487f786SFrançois Tigeot 	 * TODO: verify if this can be reproduced on VLV,CHV.
40481487f786SFrançois Tigeot 	 */
4049*3f2dd94aSFrançois Tigeot 	if (INTEL_GEN(dev_priv) <= 7)
4050*3f2dd94aSFrançois Tigeot 		rps->pm_intrmsk_mbz |= GEN6_PM_RP_UP_EI_EXPIRED;
40511487f786SFrançois Tigeot 
4052*3f2dd94aSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8)
4053*3f2dd94aSFrançois Tigeot 		rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
40541487f786SFrançois Tigeot 
40552c9916cdSFrançois Tigeot 	if (IS_GEN2(dev_priv)) {
405671f41f3eSFrançois Tigeot 		/* Gen2 doesn't have a hardware frame counter */
40579edbd4a0SFrançois Tigeot 		dev->max_vblank_count = 0;
4058*3f2dd94aSFrançois Tigeot 	} else if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
4059e9243325SFrançois Tigeot 		dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
4060352ff8bdSFrançois Tigeot 		dev->driver->get_vblank_counter = g4x_get_vblank_counter;
40619edbd4a0SFrançois Tigeot 	} else {
40629edbd4a0SFrançois Tigeot 		dev->driver->get_vblank_counter = i915_get_vblank_counter;
40639edbd4a0SFrançois Tigeot 		dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
4064e9243325SFrançois Tigeot 	}
4065e9243325SFrançois Tigeot 
40661b13d190SFrançois Tigeot 	/*
40671b13d190SFrançois Tigeot 	 * Opt out of the vblank disable timer on everything except gen2.
40681b13d190SFrançois Tigeot 	 * Gen2 doesn't have a hardware frame counter and so depends on
40691b13d190SFrançois Tigeot 	 * vblank interrupts to produce sane vblank seuquence numbers.
40701b13d190SFrançois Tigeot 	 */
40712c9916cdSFrançois Tigeot 	if (!IS_GEN2(dev_priv))
40721b13d190SFrançois Tigeot 		dev->vblank_disable_immediate = true;
40731b13d190SFrançois Tigeot 
40744be47400SFrançois Tigeot 	/* Most platforms treat the display irq block as an always-on
40754be47400SFrançois Tigeot 	 * power domain. vlv/chv can disable it at runtime and need
40764be47400SFrançois Tigeot 	 * special care to avoid writing any of the display block registers
40774be47400SFrançois Tigeot 	 * outside of the power domain. We defer setting up the display irqs
40784be47400SFrançois Tigeot 	 * in this case to the runtime pm.
40794be47400SFrançois Tigeot 	 */
40804be47400SFrançois Tigeot 	dev_priv->display_irqs_enabled = true;
40814be47400SFrançois Tigeot 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
40824be47400SFrançois Tigeot 		dev_priv->display_irqs_enabled = false;
40834be47400SFrançois Tigeot 
4084a85cb24fSFrançois Tigeot 	dev_priv->hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD;
4085a85cb24fSFrançois Tigeot 
4086*3f2dd94aSFrançois Tigeot 	dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos;
4087e9243325SFrançois Tigeot 	dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
4088e9243325SFrançois Tigeot 
40892c9916cdSFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv)) {
4090ba55f2f5SFrançois Tigeot 		dev->driver->irq_handler = cherryview_irq_handler;
4091*3f2dd94aSFrançois Tigeot 		dev->driver->irq_preinstall = cherryview_irq_reset;
4092ba55f2f5SFrançois Tigeot 		dev->driver->irq_postinstall = cherryview_irq_postinstall;
4093*3f2dd94aSFrançois Tigeot 		dev->driver->irq_uninstall = cherryview_irq_reset;
40941e12ee3bSFrançois Tigeot 		dev->driver->enable_vblank = i965_enable_vblank;
40951e12ee3bSFrançois Tigeot 		dev->driver->disable_vblank = i965_disable_vblank;
4096ba55f2f5SFrançois Tigeot 		dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
40972c9916cdSFrançois Tigeot 	} else if (IS_VALLEYVIEW(dev_priv)) {
4098e9243325SFrançois Tigeot 		dev->driver->irq_handler = valleyview_irq_handler;
4099*3f2dd94aSFrançois Tigeot 		dev->driver->irq_preinstall = valleyview_irq_reset;
4100e9243325SFrançois Tigeot 		dev->driver->irq_postinstall = valleyview_irq_postinstall;
4101*3f2dd94aSFrançois Tigeot 		dev->driver->irq_uninstall = valleyview_irq_reset;
41021e12ee3bSFrançois Tigeot 		dev->driver->enable_vblank = i965_enable_vblank;
41031e12ee3bSFrançois Tigeot 		dev->driver->disable_vblank = i965_disable_vblank;
41048e26cdf6SFrançois Tigeot 		dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
4105*3f2dd94aSFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 8) {
41069edbd4a0SFrançois Tigeot 		dev->driver->irq_handler = gen8_irq_handler;
4107ba55f2f5SFrançois Tigeot 		dev->driver->irq_preinstall = gen8_irq_reset;
41089edbd4a0SFrançois Tigeot 		dev->driver->irq_postinstall = gen8_irq_postinstall;
4109*3f2dd94aSFrançois Tigeot 		dev->driver->irq_uninstall = gen8_irq_reset;
41109edbd4a0SFrançois Tigeot 		dev->driver->enable_vblank = gen8_enable_vblank;
41119edbd4a0SFrançois Tigeot 		dev->driver->disable_vblank = gen8_disable_vblank;
4112a85cb24fSFrançois Tigeot 		if (IS_GEN9_LP(dev_priv))
411319c468b4SFrançois Tigeot 			dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup;
4114*3f2dd94aSFrançois Tigeot 		else if (HAS_PCH_SPT(dev_priv) || HAS_PCH_KBP(dev_priv) ||
4115*3f2dd94aSFrançois Tigeot 			 HAS_PCH_CNP(dev_priv))
4116352ff8bdSFrançois Tigeot 			dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup;
4117352ff8bdSFrançois Tigeot 		else
4118352ff8bdSFrançois Tigeot 			dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
41191e12ee3bSFrançois Tigeot 	} else if (HAS_PCH_SPLIT(dev_priv)) {
4120e9243325SFrançois Tigeot 		dev->driver->irq_handler = ironlake_irq_handler;
4121ba55f2f5SFrançois Tigeot 		dev->driver->irq_preinstall = ironlake_irq_reset;
4122e9243325SFrançois Tigeot 		dev->driver->irq_postinstall = ironlake_irq_postinstall;
4123*3f2dd94aSFrançois Tigeot 		dev->driver->irq_uninstall = ironlake_irq_reset;
4124e9243325SFrançois Tigeot 		dev->driver->enable_vblank = ironlake_enable_vblank;
4125e9243325SFrançois Tigeot 		dev->driver->disable_vblank = ironlake_disable_vblank;
4126352ff8bdSFrançois Tigeot 		dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
4127e9243325SFrançois Tigeot 	} else {
41281487f786SFrançois Tigeot 		if (IS_GEN2(dev_priv)) {
4129*3f2dd94aSFrançois Tigeot 			dev->driver->irq_preinstall = i8xx_irq_reset;
4130e9243325SFrançois Tigeot 			dev->driver->irq_postinstall = i8xx_irq_postinstall;
4131e9243325SFrançois Tigeot 			dev->driver->irq_handler = i8xx_irq_handler;
4132*3f2dd94aSFrançois Tigeot 			dev->driver->irq_uninstall = i8xx_irq_reset;
41331e12ee3bSFrançois Tigeot 			dev->driver->enable_vblank = i8xx_enable_vblank;
41341e12ee3bSFrançois Tigeot 			dev->driver->disable_vblank = i8xx_disable_vblank;
41351487f786SFrançois Tigeot 		} else if (IS_GEN3(dev_priv)) {
4136*3f2dd94aSFrançois Tigeot 			dev->driver->irq_preinstall = i915_irq_reset;
4137e9243325SFrançois Tigeot 			dev->driver->irq_postinstall = i915_irq_postinstall;
4138*3f2dd94aSFrançois Tigeot 			dev->driver->irq_uninstall = i915_irq_reset;
4139e9243325SFrançois Tigeot 			dev->driver->irq_handler = i915_irq_handler;
41401e12ee3bSFrançois Tigeot 			dev->driver->enable_vblank = i8xx_enable_vblank;
41411e12ee3bSFrançois Tigeot 			dev->driver->disable_vblank = i8xx_disable_vblank;
4142e9243325SFrançois Tigeot 		} else {
4143*3f2dd94aSFrançois Tigeot 			dev->driver->irq_preinstall = i965_irq_reset;
4144e9243325SFrançois Tigeot 			dev->driver->irq_postinstall = i965_irq_postinstall;
4145*3f2dd94aSFrançois Tigeot 			dev->driver->irq_uninstall = i965_irq_reset;
4146e9243325SFrançois Tigeot 			dev->driver->irq_handler = i965_irq_handler;
41471e12ee3bSFrançois Tigeot 			dev->driver->enable_vblank = i965_enable_vblank;
41481e12ee3bSFrançois Tigeot 			dev->driver->disable_vblank = i965_disable_vblank;
4149e9243325SFrançois Tigeot 		}
41502c9916cdSFrançois Tigeot 		if (I915_HAS_HOTPLUG(dev_priv))
41512c9916cdSFrançois Tigeot 			dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
4152e9243325SFrançois Tigeot 	}
4153e9243325SFrançois Tigeot }
4154a2fdbec6SFrançois Tigeot 
41552c9916cdSFrançois Tigeot /**
4156*3f2dd94aSFrançois Tigeot  * intel_irq_fini - deinitializes IRQ support
4157*3f2dd94aSFrançois Tigeot  * @i915: i915 device instance
4158*3f2dd94aSFrançois Tigeot  *
4159*3f2dd94aSFrançois Tigeot  * This function deinitializes all the IRQ support.
4160*3f2dd94aSFrançois Tigeot  */
intel_irq_fini(struct drm_i915_private * i915)4161*3f2dd94aSFrançois Tigeot void intel_irq_fini(struct drm_i915_private *i915)
4162*3f2dd94aSFrançois Tigeot {
4163*3f2dd94aSFrançois Tigeot 	int i;
4164*3f2dd94aSFrançois Tigeot 
4165*3f2dd94aSFrançois Tigeot 	for (i = 0; i < MAX_L3_SLICES; ++i)
4166*3f2dd94aSFrançois Tigeot 		kfree(i915->l3_parity.remap_info[i]);
4167*3f2dd94aSFrançois Tigeot }
4168*3f2dd94aSFrançois Tigeot 
4169*3f2dd94aSFrançois Tigeot /**
41702c9916cdSFrançois Tigeot  * intel_irq_install - enables the hardware interrupt
41712c9916cdSFrançois Tigeot  * @dev_priv: i915 device instance
41722c9916cdSFrançois Tigeot  *
41732c9916cdSFrançois Tigeot  * This function enables the hardware interrupt handling, but leaves the hotplug
41742c9916cdSFrançois Tigeot  * handling still disabled. It is called after intel_irq_init().
41752c9916cdSFrançois Tigeot  *
41762c9916cdSFrançois Tigeot  * In the driver load and resume code we need working interrupts in a few places
41772c9916cdSFrançois Tigeot  * but don't want to deal with the hassle of concurrent probe and hotplug
41782c9916cdSFrançois Tigeot  * workers. Hence the split into this two-stage approach.
41792c9916cdSFrançois Tigeot  */
intel_irq_install(struct drm_i915_private * dev_priv)41802c9916cdSFrançois Tigeot int intel_irq_install(struct drm_i915_private *dev_priv)
41819edbd4a0SFrançois Tigeot {
41822c9916cdSFrançois Tigeot 	/*
41832c9916cdSFrançois Tigeot 	 * We enable some interrupt sources in our postinstall hooks, so mark
41842c9916cdSFrançois Tigeot 	 * interrupts as enabled _before_ actually enabling them to avoid
41852c9916cdSFrançois Tigeot 	 * special cases in our ordering checks.
41862c9916cdSFrançois Tigeot 	 */
4187*3f2dd94aSFrançois Tigeot 	dev_priv->runtime_pm.irqs_enabled = true;
41889edbd4a0SFrançois Tigeot 
4189303bf270SFrançois Tigeot 	return drm_irq_install(&dev_priv->drm, dev_priv->drm.pdev->irq);
41909edbd4a0SFrançois Tigeot }
41919edbd4a0SFrançois Tigeot 
41922c9916cdSFrançois Tigeot /**
41932c9916cdSFrançois Tigeot  * intel_irq_uninstall - finilizes all irq handling
41942c9916cdSFrançois Tigeot  * @dev_priv: i915 device instance
41952c9916cdSFrançois Tigeot  *
41962c9916cdSFrançois Tigeot  * This stops interrupt and hotplug handling and unregisters and frees all
41972c9916cdSFrançois Tigeot  * resources acquired in the init functions.
41982c9916cdSFrançois Tigeot  */
intel_irq_uninstall(struct drm_i915_private * dev_priv)41992c9916cdSFrançois Tigeot void intel_irq_uninstall(struct drm_i915_private *dev_priv)
42009edbd4a0SFrançois Tigeot {
4201303bf270SFrançois Tigeot 	drm_irq_uninstall(&dev_priv->drm);
42022c9916cdSFrançois Tigeot 	intel_hpd_cancel_work(dev_priv);
4203*3f2dd94aSFrançois Tigeot 	dev_priv->runtime_pm.irqs_enabled = false;
42042c9916cdSFrançois Tigeot }
42059edbd4a0SFrançois Tigeot 
42062c9916cdSFrançois Tigeot /**
42072c9916cdSFrançois Tigeot  * intel_runtime_pm_disable_interrupts - runtime interrupt disabling
42082c9916cdSFrançois Tigeot  * @dev_priv: i915 device instance
42092c9916cdSFrançois Tigeot  *
42102c9916cdSFrançois Tigeot  * This function is used to disable interrupts at runtime, both in the runtime
42112c9916cdSFrançois Tigeot  * pm and the system suspend/resume code.
42122c9916cdSFrançois Tigeot  */
intel_runtime_pm_disable_interrupts(struct drm_i915_private * dev_priv)42132c9916cdSFrançois Tigeot void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
42142c9916cdSFrançois Tigeot {
4215303bf270SFrançois Tigeot 	dev_priv->drm.driver->irq_uninstall(&dev_priv->drm);
4216*3f2dd94aSFrançois Tigeot 	dev_priv->runtime_pm.irqs_enabled = false;
4217303bf270SFrançois Tigeot 	synchronize_irq(dev_priv->drm.irq);
42182c9916cdSFrançois Tigeot }
42192c9916cdSFrançois Tigeot 
42202c9916cdSFrançois Tigeot /**
42212c9916cdSFrançois Tigeot  * intel_runtime_pm_enable_interrupts - runtime interrupt enabling
42222c9916cdSFrançois Tigeot  * @dev_priv: i915 device instance
42232c9916cdSFrançois Tigeot  *
42242c9916cdSFrançois Tigeot  * This function is used to enable interrupts at runtime, both in the runtime
42252c9916cdSFrançois Tigeot  * pm and the system suspend/resume code.
42262c9916cdSFrançois Tigeot  */
intel_runtime_pm_enable_interrupts(struct drm_i915_private * dev_priv)42272c9916cdSFrançois Tigeot void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv)
42282c9916cdSFrançois Tigeot {
4229*3f2dd94aSFrançois Tigeot 	dev_priv->runtime_pm.irqs_enabled = true;
4230303bf270SFrançois Tigeot 	dev_priv->drm.driver->irq_preinstall(&dev_priv->drm);
4231303bf270SFrançois Tigeot 	dev_priv->drm.driver->irq_postinstall(&dev_priv->drm);
42329edbd4a0SFrançois Tigeot }
4233