xref: /openbmc/linux/drivers/gpu/drm/i915/i915_irq.c (revision b796b9710fd52d7f406f606697322fb5c7f562f3)
1c0e09200SDave Airlie /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
2c0e09200SDave Airlie  */
3c0e09200SDave Airlie /*
4c0e09200SDave Airlie  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
5c0e09200SDave Airlie  * All Rights Reserved.
6c0e09200SDave Airlie  *
7c0e09200SDave Airlie  * Permission is hereby granted, free of charge, to any person obtaining a
8c0e09200SDave Airlie  * copy of this software and associated documentation files (the
9c0e09200SDave Airlie  * "Software"), to deal in the Software without restriction, including
10c0e09200SDave Airlie  * without limitation the rights to use, copy, modify, merge, publish,
11c0e09200SDave Airlie  * distribute, sub license, and/or sell copies of the Software, and to
12c0e09200SDave Airlie  * permit persons to whom the Software is furnished to do so, subject to
13c0e09200SDave Airlie  * the following conditions:
14c0e09200SDave Airlie  *
15c0e09200SDave Airlie  * The above copyright notice and this permission notice (including the
16c0e09200SDave Airlie  * next paragraph) shall be included in all copies or substantial portions
17c0e09200SDave Airlie  * of the Software.
18c0e09200SDave Airlie  *
19c0e09200SDave Airlie  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20c0e09200SDave Airlie  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21c0e09200SDave Airlie  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22c0e09200SDave Airlie  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23c0e09200SDave Airlie  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24c0e09200SDave Airlie  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25c0e09200SDave Airlie  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26c0e09200SDave Airlie  *
27c0e09200SDave Airlie  */
28c0e09200SDave Airlie 
29a70491ccSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30a70491ccSJoe Perches 
3163eeaf38SJesse Barnes #include <linux/sysrq.h>
325a0e3ad6STejun Heo #include <linux/slab.h>
33b2c88f5bSDamien Lespiau #include <linux/circ_buf.h>
34760285e7SDavid Howells #include <drm/drmP.h>
35760285e7SDavid Howells #include <drm/i915_drm.h>
36c0e09200SDave Airlie #include "i915_drv.h"
371c5d22f7SChris Wilson #include "i915_trace.h"
3879e53945SJesse Barnes #include "intel_drv.h"
39c0e09200SDave Airlie 
40fca52a55SDaniel Vetter /**
41fca52a55SDaniel Vetter  * DOC: interrupt handling
42fca52a55SDaniel Vetter  *
43fca52a55SDaniel Vetter  * These functions provide the basic support for enabling and disabling the
44fca52a55SDaniel Vetter  * interrupt handling support. There's a lot more functionality in i915_irq.c
45fca52a55SDaniel Vetter  * and related files, but that will be described in separate chapters.
46fca52a55SDaniel Vetter  */
47fca52a55SDaniel Vetter 
48e4ce95aaSVille Syrjälä static const u32 hpd_ilk[HPD_NUM_PINS] = {
49e4ce95aaSVille Syrjälä 	[HPD_PORT_A] = DE_DP_A_HOTPLUG,
50e4ce95aaSVille Syrjälä };
51e4ce95aaSVille Syrjälä 
5223bb4cb5SVille Syrjälä static const u32 hpd_ivb[HPD_NUM_PINS] = {
5323bb4cb5SVille Syrjälä 	[HPD_PORT_A] = DE_DP_A_HOTPLUG_IVB,
5423bb4cb5SVille Syrjälä };
5523bb4cb5SVille Syrjälä 
563a3b3c7dSVille Syrjälä static const u32 hpd_bdw[HPD_NUM_PINS] = {
573a3b3c7dSVille Syrjälä 	[HPD_PORT_A] = GEN8_PORT_DP_A_HOTPLUG,
583a3b3c7dSVille Syrjälä };
593a3b3c7dSVille Syrjälä 
607c7e10dbSVille Syrjälä static const u32 hpd_ibx[HPD_NUM_PINS] = {
61e5868a31SEgbert Eich 	[HPD_CRT] = SDE_CRT_HOTPLUG,
62e5868a31SEgbert Eich 	[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
63e5868a31SEgbert Eich 	[HPD_PORT_B] = SDE_PORTB_HOTPLUG,
64e5868a31SEgbert Eich 	[HPD_PORT_C] = SDE_PORTC_HOTPLUG,
65e5868a31SEgbert Eich 	[HPD_PORT_D] = SDE_PORTD_HOTPLUG
66e5868a31SEgbert Eich };
67e5868a31SEgbert Eich 
687c7e10dbSVille Syrjälä static const u32 hpd_cpt[HPD_NUM_PINS] = {
69e5868a31SEgbert Eich 	[HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
7073c352a2SDaniel Vetter 	[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT,
71e5868a31SEgbert Eich 	[HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
72e5868a31SEgbert Eich 	[HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
73e5868a31SEgbert Eich 	[HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT
74e5868a31SEgbert Eich };
75e5868a31SEgbert Eich 
7626951cafSXiong Zhang static const u32 hpd_spt[HPD_NUM_PINS] = {
7774c0b395SVille Syrjälä 	[HPD_PORT_A] = SDE_PORTA_HOTPLUG_SPT,
7826951cafSXiong Zhang 	[HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
7926951cafSXiong Zhang 	[HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
8026951cafSXiong Zhang 	[HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT,
8126951cafSXiong Zhang 	[HPD_PORT_E] = SDE_PORTE_HOTPLUG_SPT
8226951cafSXiong Zhang };
8326951cafSXiong Zhang 
847c7e10dbSVille Syrjälä static const u32 hpd_mask_i915[HPD_NUM_PINS] = {
85e5868a31SEgbert Eich 	[HPD_CRT] = CRT_HOTPLUG_INT_EN,
86e5868a31SEgbert Eich 	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
87e5868a31SEgbert Eich 	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
88e5868a31SEgbert Eich 	[HPD_PORT_B] = PORTB_HOTPLUG_INT_EN,
89e5868a31SEgbert Eich 	[HPD_PORT_C] = PORTC_HOTPLUG_INT_EN,
90e5868a31SEgbert Eich 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
91e5868a31SEgbert Eich };
92e5868a31SEgbert Eich 
937c7e10dbSVille Syrjälä static const u32 hpd_status_g4x[HPD_NUM_PINS] = {
94e5868a31SEgbert Eich 	[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
95e5868a31SEgbert Eich 	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
96e5868a31SEgbert Eich 	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
97e5868a31SEgbert Eich 	[HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
98e5868a31SEgbert Eich 	[HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
99e5868a31SEgbert Eich 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
100e5868a31SEgbert Eich };
101e5868a31SEgbert Eich 
1024bca26d0SVille Syrjälä static const u32 hpd_status_i915[HPD_NUM_PINS] = {
103e5868a31SEgbert Eich 	[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
104e5868a31SEgbert Eich 	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
105e5868a31SEgbert Eich 	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
106e5868a31SEgbert Eich 	[HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
107e5868a31SEgbert Eich 	[HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
108e5868a31SEgbert Eich 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
109e5868a31SEgbert Eich };
110e5868a31SEgbert Eich 
111e0a20ad7SShashank Sharma /* BXT hpd list */
112e0a20ad7SShashank Sharma static const u32 hpd_bxt[HPD_NUM_PINS] = {
1137f3561beSSonika Jindal 	[HPD_PORT_A] = BXT_DE_PORT_HP_DDIA,
114e0a20ad7SShashank Sharma 	[HPD_PORT_B] = BXT_DE_PORT_HP_DDIB,
115e0a20ad7SShashank Sharma 	[HPD_PORT_C] = BXT_DE_PORT_HP_DDIC
116e0a20ad7SShashank Sharma };
117e0a20ad7SShashank Sharma 
118*b796b971SDhinakaran Pandiyan static const u32 hpd_gen11[HPD_NUM_PINS] = {
119*b796b971SDhinakaran Pandiyan 	[HPD_PORT_C] = GEN11_TC1_HOTPLUG | GEN11_TBT1_HOTPLUG,
120*b796b971SDhinakaran Pandiyan 	[HPD_PORT_D] = GEN11_TC2_HOTPLUG | GEN11_TBT2_HOTPLUG,
121*b796b971SDhinakaran Pandiyan 	[HPD_PORT_E] = GEN11_TC3_HOTPLUG | GEN11_TBT3_HOTPLUG,
122*b796b971SDhinakaran Pandiyan 	[HPD_PORT_F] = GEN11_TC4_HOTPLUG | GEN11_TBT4_HOTPLUG
123121e758eSDhinakaran Pandiyan };
124121e758eSDhinakaran Pandiyan 
1255c502442SPaulo Zanoni /* IIR can theoretically queue up two events. Be paranoid. */
126f86f3fb0SPaulo Zanoni #define GEN8_IRQ_RESET_NDX(type, which) do { \
1275c502442SPaulo Zanoni 	I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
1285c502442SPaulo Zanoni 	POSTING_READ(GEN8_##type##_IMR(which)); \
1295c502442SPaulo Zanoni 	I915_WRITE(GEN8_##type##_IER(which), 0); \
1305c502442SPaulo Zanoni 	I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
1315c502442SPaulo Zanoni 	POSTING_READ(GEN8_##type##_IIR(which)); \
1325c502442SPaulo Zanoni 	I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
1335c502442SPaulo Zanoni 	POSTING_READ(GEN8_##type##_IIR(which)); \
1345c502442SPaulo Zanoni } while (0)
1355c502442SPaulo Zanoni 
1363488d4ebSVille Syrjälä #define GEN3_IRQ_RESET(type) do { \
137a9d356a6SPaulo Zanoni 	I915_WRITE(type##IMR, 0xffffffff); \
1385c502442SPaulo Zanoni 	POSTING_READ(type##IMR); \
139a9d356a6SPaulo Zanoni 	I915_WRITE(type##IER, 0); \
1405c502442SPaulo Zanoni 	I915_WRITE(type##IIR, 0xffffffff); \
1415c502442SPaulo Zanoni 	POSTING_READ(type##IIR); \
1425c502442SPaulo Zanoni 	I915_WRITE(type##IIR, 0xffffffff); \
1435c502442SPaulo Zanoni 	POSTING_READ(type##IIR); \
144a9d356a6SPaulo Zanoni } while (0)
145a9d356a6SPaulo Zanoni 
146e9e9848aSVille Syrjälä #define GEN2_IRQ_RESET(type) do { \
147e9e9848aSVille Syrjälä 	I915_WRITE16(type##IMR, 0xffff); \
148e9e9848aSVille Syrjälä 	POSTING_READ16(type##IMR); \
149e9e9848aSVille Syrjälä 	I915_WRITE16(type##IER, 0); \
150e9e9848aSVille Syrjälä 	I915_WRITE16(type##IIR, 0xffff); \
151e9e9848aSVille Syrjälä 	POSTING_READ16(type##IIR); \
152e9e9848aSVille Syrjälä 	I915_WRITE16(type##IIR, 0xffff); \
153e9e9848aSVille Syrjälä 	POSTING_READ16(type##IIR); \
154e9e9848aSVille Syrjälä } while (0)
155e9e9848aSVille Syrjälä 
156337ba017SPaulo Zanoni /*
157337ba017SPaulo Zanoni  * We should clear IMR at preinstall/uninstall, and just check at postinstall.
158337ba017SPaulo Zanoni  */
1593488d4ebSVille Syrjälä static void gen3_assert_iir_is_zero(struct drm_i915_private *dev_priv,
160f0f59a00SVille Syrjälä 				    i915_reg_t reg)
161b51a2842SVille Syrjälä {
162b51a2842SVille Syrjälä 	u32 val = I915_READ(reg);
163b51a2842SVille Syrjälä 
164b51a2842SVille Syrjälä 	if (val == 0)
165b51a2842SVille Syrjälä 		return;
166b51a2842SVille Syrjälä 
167b51a2842SVille Syrjälä 	WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n",
168f0f59a00SVille Syrjälä 	     i915_mmio_reg_offset(reg), val);
169b51a2842SVille Syrjälä 	I915_WRITE(reg, 0xffffffff);
170b51a2842SVille Syrjälä 	POSTING_READ(reg);
171b51a2842SVille Syrjälä 	I915_WRITE(reg, 0xffffffff);
172b51a2842SVille Syrjälä 	POSTING_READ(reg);
173b51a2842SVille Syrjälä }
174337ba017SPaulo Zanoni 
175e9e9848aSVille Syrjälä static void gen2_assert_iir_is_zero(struct drm_i915_private *dev_priv,
176e9e9848aSVille Syrjälä 				    i915_reg_t reg)
177e9e9848aSVille Syrjälä {
178e9e9848aSVille Syrjälä 	u16 val = I915_READ16(reg);
179e9e9848aSVille Syrjälä 
180e9e9848aSVille Syrjälä 	if (val == 0)
181e9e9848aSVille Syrjälä 		return;
182e9e9848aSVille Syrjälä 
183e9e9848aSVille Syrjälä 	WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n",
184e9e9848aSVille Syrjälä 	     i915_mmio_reg_offset(reg), val);
185e9e9848aSVille Syrjälä 	I915_WRITE16(reg, 0xffff);
186e9e9848aSVille Syrjälä 	POSTING_READ16(reg);
187e9e9848aSVille Syrjälä 	I915_WRITE16(reg, 0xffff);
188e9e9848aSVille Syrjälä 	POSTING_READ16(reg);
189e9e9848aSVille Syrjälä }
190e9e9848aSVille Syrjälä 
19135079899SPaulo Zanoni #define GEN8_IRQ_INIT_NDX(type, which, imr_val, ier_val) do { \
1923488d4ebSVille Syrjälä 	gen3_assert_iir_is_zero(dev_priv, GEN8_##type##_IIR(which)); \
19335079899SPaulo Zanoni 	I915_WRITE(GEN8_##type##_IER(which), (ier_val)); \
1947d1bd539SVille Syrjälä 	I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \
1957d1bd539SVille Syrjälä 	POSTING_READ(GEN8_##type##_IMR(which)); \
19635079899SPaulo Zanoni } while (0)
19735079899SPaulo Zanoni 
1983488d4ebSVille Syrjälä #define GEN3_IRQ_INIT(type, imr_val, ier_val) do { \
1993488d4ebSVille Syrjälä 	gen3_assert_iir_is_zero(dev_priv, type##IIR); \
20035079899SPaulo Zanoni 	I915_WRITE(type##IER, (ier_val)); \
2017d1bd539SVille Syrjälä 	I915_WRITE(type##IMR, (imr_val)); \
2027d1bd539SVille Syrjälä 	POSTING_READ(type##IMR); \
20335079899SPaulo Zanoni } while (0)
20435079899SPaulo Zanoni 
205e9e9848aSVille Syrjälä #define GEN2_IRQ_INIT(type, imr_val, ier_val) do { \
206e9e9848aSVille Syrjälä 	gen2_assert_iir_is_zero(dev_priv, type##IIR); \
207e9e9848aSVille Syrjälä 	I915_WRITE16(type##IER, (ier_val)); \
208e9e9848aSVille Syrjälä 	I915_WRITE16(type##IMR, (imr_val)); \
209e9e9848aSVille Syrjälä 	POSTING_READ16(type##IMR); \
210e9e9848aSVille Syrjälä } while (0)
211e9e9848aSVille Syrjälä 
212c9a9a268SImre Deak static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
21326705e20SSagar Arun Kamble static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
214c9a9a268SImre Deak 
2150706f17cSEgbert Eich /* For display hotplug interrupt */
2160706f17cSEgbert Eich static inline void
2170706f17cSEgbert Eich i915_hotplug_interrupt_update_locked(struct drm_i915_private *dev_priv,
2180706f17cSEgbert Eich 				     uint32_t mask,
2190706f17cSEgbert Eich 				     uint32_t bits)
2200706f17cSEgbert Eich {
2210706f17cSEgbert Eich 	uint32_t val;
2220706f17cSEgbert Eich 
22367520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
2240706f17cSEgbert Eich 	WARN_ON(bits & ~mask);
2250706f17cSEgbert Eich 
2260706f17cSEgbert Eich 	val = I915_READ(PORT_HOTPLUG_EN);
2270706f17cSEgbert Eich 	val &= ~mask;
2280706f17cSEgbert Eich 	val |= bits;
2290706f17cSEgbert Eich 	I915_WRITE(PORT_HOTPLUG_EN, val);
2300706f17cSEgbert Eich }
2310706f17cSEgbert Eich 
2320706f17cSEgbert Eich /**
2330706f17cSEgbert Eich  * i915_hotplug_interrupt_update - update hotplug interrupt enable
2340706f17cSEgbert Eich  * @dev_priv: driver private
2350706f17cSEgbert Eich  * @mask: bits to update
2360706f17cSEgbert Eich  * @bits: bits to enable
2370706f17cSEgbert Eich  * NOTE: the HPD enable bits are modified both inside and outside
2380706f17cSEgbert Eich  * of an interrupt context. To avoid that read-modify-write cycles
2390706f17cSEgbert Eich  * interfer, these bits are protected by a spinlock. Since this
2400706f17cSEgbert Eich  * function is usually not called from a context where the lock is
2410706f17cSEgbert Eich  * held already, this function acquires the lock itself. A non-locking
2420706f17cSEgbert Eich  * version is also available.
2430706f17cSEgbert Eich  */
2440706f17cSEgbert Eich void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
2450706f17cSEgbert Eich 				   uint32_t mask,
2460706f17cSEgbert Eich 				   uint32_t bits)
2470706f17cSEgbert Eich {
2480706f17cSEgbert Eich 	spin_lock_irq(&dev_priv->irq_lock);
2490706f17cSEgbert Eich 	i915_hotplug_interrupt_update_locked(dev_priv, mask, bits);
2500706f17cSEgbert Eich 	spin_unlock_irq(&dev_priv->irq_lock);
2510706f17cSEgbert Eich }
2520706f17cSEgbert Eich 
25396606f3bSOscar Mateo static u32
25496606f3bSOscar Mateo gen11_gt_engine_identity(struct drm_i915_private * const i915,
25596606f3bSOscar Mateo 			 const unsigned int bank, const unsigned int bit);
25696606f3bSOscar Mateo 
257ff047a87SOscar Mateo bool gen11_reset_one_iir(struct drm_i915_private * const i915,
25896606f3bSOscar Mateo 			 const unsigned int bank,
25996606f3bSOscar Mateo 			 const unsigned int bit)
26096606f3bSOscar Mateo {
26196606f3bSOscar Mateo 	void __iomem * const regs = i915->regs;
26296606f3bSOscar Mateo 	u32 dw;
26396606f3bSOscar Mateo 
26496606f3bSOscar Mateo 	lockdep_assert_held(&i915->irq_lock);
26596606f3bSOscar Mateo 
26696606f3bSOscar Mateo 	dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank));
26796606f3bSOscar Mateo 	if (dw & BIT(bit)) {
26896606f3bSOscar Mateo 		/*
26996606f3bSOscar Mateo 		 * According to the BSpec, DW_IIR bits cannot be cleared without
27096606f3bSOscar Mateo 		 * first servicing the Selector & Shared IIR registers.
27196606f3bSOscar Mateo 		 */
27296606f3bSOscar Mateo 		gen11_gt_engine_identity(i915, bank, bit);
27396606f3bSOscar Mateo 
27496606f3bSOscar Mateo 		/*
27596606f3bSOscar Mateo 		 * We locked GT INT DW by reading it. If we want to (try
27696606f3bSOscar Mateo 		 * to) recover from this succesfully, we need to clear
27796606f3bSOscar Mateo 		 * our bit, otherwise we are locking the register for
27896606f3bSOscar Mateo 		 * everybody.
27996606f3bSOscar Mateo 		 */
28096606f3bSOscar Mateo 		raw_reg_write(regs, GEN11_GT_INTR_DW(bank), BIT(bit));
28196606f3bSOscar Mateo 
28296606f3bSOscar Mateo 		return true;
28396606f3bSOscar Mateo 	}
28496606f3bSOscar Mateo 
28596606f3bSOscar Mateo 	return false;
28696606f3bSOscar Mateo }
28796606f3bSOscar Mateo 
288d9dc34f1SVille Syrjälä /**
289d9dc34f1SVille Syrjälä  * ilk_update_display_irq - update DEIMR
290d9dc34f1SVille Syrjälä  * @dev_priv: driver private
291d9dc34f1SVille Syrjälä  * @interrupt_mask: mask of interrupt bits to update
292d9dc34f1SVille Syrjälä  * @enabled_irq_mask: mask of interrupt bits to enable
293d9dc34f1SVille Syrjälä  */
294fbdedaeaSVille Syrjälä void ilk_update_display_irq(struct drm_i915_private *dev_priv,
295d9dc34f1SVille Syrjälä 			    uint32_t interrupt_mask,
296d9dc34f1SVille Syrjälä 			    uint32_t enabled_irq_mask)
297036a4a7dSZhenyu Wang {
298d9dc34f1SVille Syrjälä 	uint32_t new_val;
299d9dc34f1SVille Syrjälä 
30067520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
3014bc9d430SDaniel Vetter 
302d9dc34f1SVille Syrjälä 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
303d9dc34f1SVille Syrjälä 
3049df7575fSJesse Barnes 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
305c67a470bSPaulo Zanoni 		return;
306c67a470bSPaulo Zanoni 
307d9dc34f1SVille Syrjälä 	new_val = dev_priv->irq_mask;
308d9dc34f1SVille Syrjälä 	new_val &= ~interrupt_mask;
309d9dc34f1SVille Syrjälä 	new_val |= (~enabled_irq_mask & interrupt_mask);
310d9dc34f1SVille Syrjälä 
311d9dc34f1SVille Syrjälä 	if (new_val != dev_priv->irq_mask) {
312d9dc34f1SVille Syrjälä 		dev_priv->irq_mask = new_val;
3131ec14ad3SChris Wilson 		I915_WRITE(DEIMR, dev_priv->irq_mask);
3143143a2bfSChris Wilson 		POSTING_READ(DEIMR);
315036a4a7dSZhenyu Wang 	}
316036a4a7dSZhenyu Wang }
317036a4a7dSZhenyu Wang 
31843eaea13SPaulo Zanoni /**
31943eaea13SPaulo Zanoni  * ilk_update_gt_irq - update GTIMR
32043eaea13SPaulo Zanoni  * @dev_priv: driver private
32143eaea13SPaulo Zanoni  * @interrupt_mask: mask of interrupt bits to update
32243eaea13SPaulo Zanoni  * @enabled_irq_mask: mask of interrupt bits to enable
32343eaea13SPaulo Zanoni  */
32443eaea13SPaulo Zanoni static void ilk_update_gt_irq(struct drm_i915_private *dev_priv,
32543eaea13SPaulo Zanoni 			      uint32_t interrupt_mask,
32643eaea13SPaulo Zanoni 			      uint32_t enabled_irq_mask)
32743eaea13SPaulo Zanoni {
32867520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
32943eaea13SPaulo Zanoni 
33015a17aaeSDaniel Vetter 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
33115a17aaeSDaniel Vetter 
3329df7575fSJesse Barnes 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
333c67a470bSPaulo Zanoni 		return;
334c67a470bSPaulo Zanoni 
33543eaea13SPaulo Zanoni 	dev_priv->gt_irq_mask &= ~interrupt_mask;
33643eaea13SPaulo Zanoni 	dev_priv->gt_irq_mask |= (~enabled_irq_mask & interrupt_mask);
33743eaea13SPaulo Zanoni 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
33843eaea13SPaulo Zanoni }
33943eaea13SPaulo Zanoni 
340480c8033SDaniel Vetter void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask)
34143eaea13SPaulo Zanoni {
34243eaea13SPaulo Zanoni 	ilk_update_gt_irq(dev_priv, mask, mask);
34331bb59ccSChris Wilson 	POSTING_READ_FW(GTIMR);
34443eaea13SPaulo Zanoni }
34543eaea13SPaulo Zanoni 
346480c8033SDaniel Vetter void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask)
34743eaea13SPaulo Zanoni {
34843eaea13SPaulo Zanoni 	ilk_update_gt_irq(dev_priv, mask, 0);
34943eaea13SPaulo Zanoni }
35043eaea13SPaulo Zanoni 
351f0f59a00SVille Syrjälä static i915_reg_t gen6_pm_iir(struct drm_i915_private *dev_priv)
352b900b949SImre Deak {
353d02b98b8SOscar Mateo 	WARN_ON_ONCE(INTEL_GEN(dev_priv) >= 11);
354d02b98b8SOscar Mateo 
355bca2bf2aSPandiyan, Dhinakaran 	return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IIR(2) : GEN6_PMIIR;
356b900b949SImre Deak }
357b900b949SImre Deak 
358f0f59a00SVille Syrjälä static i915_reg_t gen6_pm_imr(struct drm_i915_private *dev_priv)
359a72fbc3aSImre Deak {
360d02b98b8SOscar Mateo 	if (INTEL_GEN(dev_priv) >= 11)
361d02b98b8SOscar Mateo 		return GEN11_GPM_WGBOXPERF_INTR_MASK;
362d02b98b8SOscar Mateo 	else if (INTEL_GEN(dev_priv) >= 8)
363d02b98b8SOscar Mateo 		return GEN8_GT_IMR(2);
364d02b98b8SOscar Mateo 	else
365d02b98b8SOscar Mateo 		return GEN6_PMIMR;
366a72fbc3aSImre Deak }
367a72fbc3aSImre Deak 
368f0f59a00SVille Syrjälä static i915_reg_t gen6_pm_ier(struct drm_i915_private *dev_priv)
369b900b949SImre Deak {
370d02b98b8SOscar Mateo 	if (INTEL_GEN(dev_priv) >= 11)
371d02b98b8SOscar Mateo 		return GEN11_GPM_WGBOXPERF_INTR_ENABLE;
372d02b98b8SOscar Mateo 	else if (INTEL_GEN(dev_priv) >= 8)
373d02b98b8SOscar Mateo 		return GEN8_GT_IER(2);
374d02b98b8SOscar Mateo 	else
375d02b98b8SOscar Mateo 		return GEN6_PMIER;
376b900b949SImre Deak }
377b900b949SImre Deak 
378edbfdb45SPaulo Zanoni /**
379edbfdb45SPaulo Zanoni  * snb_update_pm_irq - update GEN6_PMIMR
380edbfdb45SPaulo Zanoni  * @dev_priv: driver private
381edbfdb45SPaulo Zanoni  * @interrupt_mask: mask of interrupt bits to update
382edbfdb45SPaulo Zanoni  * @enabled_irq_mask: mask of interrupt bits to enable
383edbfdb45SPaulo Zanoni  */
384edbfdb45SPaulo Zanoni static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
385edbfdb45SPaulo Zanoni 			      uint32_t interrupt_mask,
386edbfdb45SPaulo Zanoni 			      uint32_t enabled_irq_mask)
387edbfdb45SPaulo Zanoni {
388605cd25bSPaulo Zanoni 	uint32_t new_val;
389edbfdb45SPaulo Zanoni 
39015a17aaeSDaniel Vetter 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
39115a17aaeSDaniel Vetter 
39267520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
393edbfdb45SPaulo Zanoni 
394f4e9af4fSAkash Goel 	new_val = dev_priv->pm_imr;
395f52ecbcfSPaulo Zanoni 	new_val &= ~interrupt_mask;
396f52ecbcfSPaulo Zanoni 	new_val |= (~enabled_irq_mask & interrupt_mask);
397f52ecbcfSPaulo Zanoni 
398f4e9af4fSAkash Goel 	if (new_val != dev_priv->pm_imr) {
399f4e9af4fSAkash Goel 		dev_priv->pm_imr = new_val;
400f4e9af4fSAkash Goel 		I915_WRITE(gen6_pm_imr(dev_priv), dev_priv->pm_imr);
401a72fbc3aSImre Deak 		POSTING_READ(gen6_pm_imr(dev_priv));
402edbfdb45SPaulo Zanoni 	}
403f52ecbcfSPaulo Zanoni }
404edbfdb45SPaulo Zanoni 
405f4e9af4fSAkash Goel void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
406edbfdb45SPaulo Zanoni {
4079939fba2SImre Deak 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
4089939fba2SImre Deak 		return;
4099939fba2SImre Deak 
410edbfdb45SPaulo Zanoni 	snb_update_pm_irq(dev_priv, mask, mask);
411edbfdb45SPaulo Zanoni }
412edbfdb45SPaulo Zanoni 
413f4e9af4fSAkash Goel static void __gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
4149939fba2SImre Deak {
4159939fba2SImre Deak 	snb_update_pm_irq(dev_priv, mask, 0);
4169939fba2SImre Deak }
4179939fba2SImre Deak 
418f4e9af4fSAkash Goel void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
419edbfdb45SPaulo Zanoni {
4209939fba2SImre Deak 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
4219939fba2SImre Deak 		return;
4229939fba2SImre Deak 
423f4e9af4fSAkash Goel 	__gen6_mask_pm_irq(dev_priv, mask);
424f4e9af4fSAkash Goel }
425f4e9af4fSAkash Goel 
4263814fd77SOscar Mateo static void gen6_reset_pm_iir(struct drm_i915_private *dev_priv, u32 reset_mask)
427f4e9af4fSAkash Goel {
428f4e9af4fSAkash Goel 	i915_reg_t reg = gen6_pm_iir(dev_priv);
429f4e9af4fSAkash Goel 
43067520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
431f4e9af4fSAkash Goel 
432f4e9af4fSAkash Goel 	I915_WRITE(reg, reset_mask);
433f4e9af4fSAkash Goel 	I915_WRITE(reg, reset_mask);
434f4e9af4fSAkash Goel 	POSTING_READ(reg);
435f4e9af4fSAkash Goel }
436f4e9af4fSAkash Goel 
4373814fd77SOscar Mateo static void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, u32 enable_mask)
438f4e9af4fSAkash Goel {
43967520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
440f4e9af4fSAkash Goel 
441f4e9af4fSAkash Goel 	dev_priv->pm_ier |= enable_mask;
442f4e9af4fSAkash Goel 	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier);
443f4e9af4fSAkash Goel 	gen6_unmask_pm_irq(dev_priv, enable_mask);
444f4e9af4fSAkash Goel 	/* unmask_pm_irq provides an implicit barrier (POSTING_READ) */
445f4e9af4fSAkash Goel }
446f4e9af4fSAkash Goel 
4473814fd77SOscar Mateo static void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, u32 disable_mask)
448f4e9af4fSAkash Goel {
44967520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
450f4e9af4fSAkash Goel 
451f4e9af4fSAkash Goel 	dev_priv->pm_ier &= ~disable_mask;
452f4e9af4fSAkash Goel 	__gen6_mask_pm_irq(dev_priv, disable_mask);
453f4e9af4fSAkash Goel 	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier);
454f4e9af4fSAkash Goel 	/* though a barrier is missing here, but don't really need a one */
455edbfdb45SPaulo Zanoni }
456edbfdb45SPaulo Zanoni 
457d02b98b8SOscar Mateo void gen11_reset_rps_interrupts(struct drm_i915_private *dev_priv)
458d02b98b8SOscar Mateo {
459d02b98b8SOscar Mateo 	spin_lock_irq(&dev_priv->irq_lock);
460d02b98b8SOscar Mateo 
46196606f3bSOscar Mateo 	while (gen11_reset_one_iir(dev_priv, 0, GEN11_GTPM))
46296606f3bSOscar Mateo 		;
463d02b98b8SOscar Mateo 
464d02b98b8SOscar Mateo 	dev_priv->gt_pm.rps.pm_iir = 0;
465d02b98b8SOscar Mateo 
466d02b98b8SOscar Mateo 	spin_unlock_irq(&dev_priv->irq_lock);
467d02b98b8SOscar Mateo }
468d02b98b8SOscar Mateo 
469dc97997aSChris Wilson void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv)
4703cc134e3SImre Deak {
4713cc134e3SImre Deak 	spin_lock_irq(&dev_priv->irq_lock);
472f4e9af4fSAkash Goel 	gen6_reset_pm_iir(dev_priv, dev_priv->pm_rps_events);
473562d9baeSSagar Arun Kamble 	dev_priv->gt_pm.rps.pm_iir = 0;
4743cc134e3SImre Deak 	spin_unlock_irq(&dev_priv->irq_lock);
4753cc134e3SImre Deak }
4763cc134e3SImre Deak 
47791d14251STvrtko Ursulin void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv)
478b900b949SImre Deak {
479562d9baeSSagar Arun Kamble 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
480562d9baeSSagar Arun Kamble 
481562d9baeSSagar Arun Kamble 	if (READ_ONCE(rps->interrupts_enabled))
482f2a91d1aSChris Wilson 		return;
483f2a91d1aSChris Wilson 
484b900b949SImre Deak 	spin_lock_irq(&dev_priv->irq_lock);
485562d9baeSSagar Arun Kamble 	WARN_ON_ONCE(rps->pm_iir);
48696606f3bSOscar Mateo 
487d02b98b8SOscar Mateo 	if (INTEL_GEN(dev_priv) >= 11)
48896606f3bSOscar Mateo 		WARN_ON_ONCE(gen11_reset_one_iir(dev_priv, 0, GEN11_GTPM));
489d02b98b8SOscar Mateo 	else
490c33d247dSChris Wilson 		WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events);
49196606f3bSOscar Mateo 
492562d9baeSSagar Arun Kamble 	rps->interrupts_enabled = true;
493b900b949SImre Deak 	gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
49478e68d36SImre Deak 
495b900b949SImre Deak 	spin_unlock_irq(&dev_priv->irq_lock);
496b900b949SImre Deak }
497b900b949SImre Deak 
49891d14251STvrtko Ursulin void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
499b900b949SImre Deak {
500562d9baeSSagar Arun Kamble 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
501562d9baeSSagar Arun Kamble 
502562d9baeSSagar Arun Kamble 	if (!READ_ONCE(rps->interrupts_enabled))
503f2a91d1aSChris Wilson 		return;
504f2a91d1aSChris Wilson 
505d4d70aa5SImre Deak 	spin_lock_irq(&dev_priv->irq_lock);
506562d9baeSSagar Arun Kamble 	rps->interrupts_enabled = false;
5079939fba2SImre Deak 
508b20e3cfeSDave Gordon 	I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0u));
5099939fba2SImre Deak 
510f4e9af4fSAkash Goel 	gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
51158072ccbSImre Deak 
51258072ccbSImre Deak 	spin_unlock_irq(&dev_priv->irq_lock);
51391c8a326SChris Wilson 	synchronize_irq(dev_priv->drm.irq);
514c33d247dSChris Wilson 
515c33d247dSChris Wilson 	/* Now that we will not be generating any more work, flush any
5163814fd77SOscar Mateo 	 * outstanding tasks. As we are called on the RPS idle path,
517c33d247dSChris Wilson 	 * we will reset the GPU to minimum frequencies, so the current
518c33d247dSChris Wilson 	 * state of the worker can be discarded.
519c33d247dSChris Wilson 	 */
520562d9baeSSagar Arun Kamble 	cancel_work_sync(&rps->work);
521d02b98b8SOscar Mateo 	if (INTEL_GEN(dev_priv) >= 11)
522d02b98b8SOscar Mateo 		gen11_reset_rps_interrupts(dev_priv);
523d02b98b8SOscar Mateo 	else
524c33d247dSChris Wilson 		gen6_reset_rps_interrupts(dev_priv);
525b900b949SImre Deak }
526b900b949SImre Deak 
52726705e20SSagar Arun Kamble void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv)
52826705e20SSagar Arun Kamble {
5291be333d3SSagar Arun Kamble 	assert_rpm_wakelock_held(dev_priv);
5301be333d3SSagar Arun Kamble 
53126705e20SSagar Arun Kamble 	spin_lock_irq(&dev_priv->irq_lock);
53226705e20SSagar Arun Kamble 	gen6_reset_pm_iir(dev_priv, dev_priv->pm_guc_events);
53326705e20SSagar Arun Kamble 	spin_unlock_irq(&dev_priv->irq_lock);
53426705e20SSagar Arun Kamble }
53526705e20SSagar Arun Kamble 
53626705e20SSagar Arun Kamble void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv)
53726705e20SSagar Arun Kamble {
5381be333d3SSagar Arun Kamble 	assert_rpm_wakelock_held(dev_priv);
5391be333d3SSagar Arun Kamble 
54026705e20SSagar Arun Kamble 	spin_lock_irq(&dev_priv->irq_lock);
54126705e20SSagar Arun Kamble 	if (!dev_priv->guc.interrupts_enabled) {
54226705e20SSagar Arun Kamble 		WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) &
54326705e20SSagar Arun Kamble 				       dev_priv->pm_guc_events);
54426705e20SSagar Arun Kamble 		dev_priv->guc.interrupts_enabled = true;
54526705e20SSagar Arun Kamble 		gen6_enable_pm_irq(dev_priv, dev_priv->pm_guc_events);
54626705e20SSagar Arun Kamble 	}
54726705e20SSagar Arun Kamble 	spin_unlock_irq(&dev_priv->irq_lock);
54826705e20SSagar Arun Kamble }
54926705e20SSagar Arun Kamble 
55026705e20SSagar Arun Kamble void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv)
55126705e20SSagar Arun Kamble {
5521be333d3SSagar Arun Kamble 	assert_rpm_wakelock_held(dev_priv);
5531be333d3SSagar Arun Kamble 
55426705e20SSagar Arun Kamble 	spin_lock_irq(&dev_priv->irq_lock);
55526705e20SSagar Arun Kamble 	dev_priv->guc.interrupts_enabled = false;
55626705e20SSagar Arun Kamble 
55726705e20SSagar Arun Kamble 	gen6_disable_pm_irq(dev_priv, dev_priv->pm_guc_events);
55826705e20SSagar Arun Kamble 
55926705e20SSagar Arun Kamble 	spin_unlock_irq(&dev_priv->irq_lock);
56026705e20SSagar Arun Kamble 	synchronize_irq(dev_priv->drm.irq);
56126705e20SSagar Arun Kamble 
56226705e20SSagar Arun Kamble 	gen9_reset_guc_interrupts(dev_priv);
56326705e20SSagar Arun Kamble }
56426705e20SSagar Arun Kamble 
5650961021aSBen Widawsky /**
5663a3b3c7dSVille Syrjälä  * bdw_update_port_irq - update DE port interrupt
5673a3b3c7dSVille Syrjälä  * @dev_priv: driver private
5683a3b3c7dSVille Syrjälä  * @interrupt_mask: mask of interrupt bits to update
5693a3b3c7dSVille Syrjälä  * @enabled_irq_mask: mask of interrupt bits to enable
5703a3b3c7dSVille Syrjälä  */
5713a3b3c7dSVille Syrjälä static void bdw_update_port_irq(struct drm_i915_private *dev_priv,
5723a3b3c7dSVille Syrjälä 				uint32_t interrupt_mask,
5733a3b3c7dSVille Syrjälä 				uint32_t enabled_irq_mask)
5743a3b3c7dSVille Syrjälä {
5753a3b3c7dSVille Syrjälä 	uint32_t new_val;
5763a3b3c7dSVille Syrjälä 	uint32_t old_val;
5773a3b3c7dSVille Syrjälä 
57867520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
5793a3b3c7dSVille Syrjälä 
5803a3b3c7dSVille Syrjälä 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
5813a3b3c7dSVille Syrjälä 
5823a3b3c7dSVille Syrjälä 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
5833a3b3c7dSVille Syrjälä 		return;
5843a3b3c7dSVille Syrjälä 
5853a3b3c7dSVille Syrjälä 	old_val = I915_READ(GEN8_DE_PORT_IMR);
5863a3b3c7dSVille Syrjälä 
5873a3b3c7dSVille Syrjälä 	new_val = old_val;
5883a3b3c7dSVille Syrjälä 	new_val &= ~interrupt_mask;
5893a3b3c7dSVille Syrjälä 	new_val |= (~enabled_irq_mask & interrupt_mask);
5903a3b3c7dSVille Syrjälä 
5913a3b3c7dSVille Syrjälä 	if (new_val != old_val) {
5923a3b3c7dSVille Syrjälä 		I915_WRITE(GEN8_DE_PORT_IMR, new_val);
5933a3b3c7dSVille Syrjälä 		POSTING_READ(GEN8_DE_PORT_IMR);
5943a3b3c7dSVille Syrjälä 	}
5953a3b3c7dSVille Syrjälä }
5963a3b3c7dSVille Syrjälä 
5973a3b3c7dSVille Syrjälä /**
598013d3752SVille Syrjälä  * bdw_update_pipe_irq - update DE pipe interrupt
599013d3752SVille Syrjälä  * @dev_priv: driver private
600013d3752SVille Syrjälä  * @pipe: pipe whose interrupt to update
601013d3752SVille Syrjälä  * @interrupt_mask: mask of interrupt bits to update
602013d3752SVille Syrjälä  * @enabled_irq_mask: mask of interrupt bits to enable
603013d3752SVille Syrjälä  */
604013d3752SVille Syrjälä void bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
605013d3752SVille Syrjälä 			 enum pipe pipe,
606013d3752SVille Syrjälä 			 uint32_t interrupt_mask,
607013d3752SVille Syrjälä 			 uint32_t enabled_irq_mask)
608013d3752SVille Syrjälä {
609013d3752SVille Syrjälä 	uint32_t new_val;
610013d3752SVille Syrjälä 
61167520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
612013d3752SVille Syrjälä 
613013d3752SVille Syrjälä 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
614013d3752SVille Syrjälä 
615013d3752SVille Syrjälä 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
616013d3752SVille Syrjälä 		return;
617013d3752SVille Syrjälä 
618013d3752SVille Syrjälä 	new_val = dev_priv->de_irq_mask[pipe];
619013d3752SVille Syrjälä 	new_val &= ~interrupt_mask;
620013d3752SVille Syrjälä 	new_val |= (~enabled_irq_mask & interrupt_mask);
621013d3752SVille Syrjälä 
622013d3752SVille Syrjälä 	if (new_val != dev_priv->de_irq_mask[pipe]) {
623013d3752SVille Syrjälä 		dev_priv->de_irq_mask[pipe] = new_val;
624013d3752SVille Syrjälä 		I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
625013d3752SVille Syrjälä 		POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
626013d3752SVille Syrjälä 	}
627013d3752SVille Syrjälä }
628013d3752SVille Syrjälä 
629013d3752SVille Syrjälä /**
630fee884edSDaniel Vetter  * ibx_display_interrupt_update - update SDEIMR
631fee884edSDaniel Vetter  * @dev_priv: driver private
632fee884edSDaniel Vetter  * @interrupt_mask: mask of interrupt bits to update
633fee884edSDaniel Vetter  * @enabled_irq_mask: mask of interrupt bits to enable
634fee884edSDaniel Vetter  */
63547339cd9SDaniel Vetter void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
636fee884edSDaniel Vetter 				  uint32_t interrupt_mask,
637fee884edSDaniel Vetter 				  uint32_t enabled_irq_mask)
638fee884edSDaniel Vetter {
639fee884edSDaniel Vetter 	uint32_t sdeimr = I915_READ(SDEIMR);
640fee884edSDaniel Vetter 	sdeimr &= ~interrupt_mask;
641fee884edSDaniel Vetter 	sdeimr |= (~enabled_irq_mask & interrupt_mask);
642fee884edSDaniel Vetter 
64315a17aaeSDaniel Vetter 	WARN_ON(enabled_irq_mask & ~interrupt_mask);
64415a17aaeSDaniel Vetter 
64567520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
646fee884edSDaniel Vetter 
6479df7575fSJesse Barnes 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
648c67a470bSPaulo Zanoni 		return;
649c67a470bSPaulo Zanoni 
650fee884edSDaniel Vetter 	I915_WRITE(SDEIMR, sdeimr);
651fee884edSDaniel Vetter 	POSTING_READ(SDEIMR);
652fee884edSDaniel Vetter }
6538664281bSPaulo Zanoni 
6546b12ca56SVille Syrjälä u32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv,
6556b12ca56SVille Syrjälä 			      enum pipe pipe)
6567c463586SKeith Packard {
6576b12ca56SVille Syrjälä 	u32 status_mask = dev_priv->pipestat_irq_mask[pipe];
65810c59c51SImre Deak 	u32 enable_mask = status_mask << 16;
65910c59c51SImre Deak 
6606b12ca56SVille Syrjälä 	lockdep_assert_held(&dev_priv->irq_lock);
6616b12ca56SVille Syrjälä 
6626b12ca56SVille Syrjälä 	if (INTEL_GEN(dev_priv) < 5)
6636b12ca56SVille Syrjälä 		goto out;
6646b12ca56SVille Syrjälä 
66510c59c51SImre Deak 	/*
666724a6905SVille Syrjälä 	 * On pipe A we don't support the PSR interrupt yet,
667724a6905SVille Syrjälä 	 * on pipe B and C the same bit MBZ.
66810c59c51SImre Deak 	 */
66910c59c51SImre Deak 	if (WARN_ON_ONCE(status_mask & PIPE_A_PSR_STATUS_VLV))
67010c59c51SImre Deak 		return 0;
671724a6905SVille Syrjälä 	/*
672724a6905SVille Syrjälä 	 * On pipe B and C we don't support the PSR interrupt yet, on pipe
673724a6905SVille Syrjälä 	 * A the same bit is for perf counters which we don't use either.
674724a6905SVille Syrjälä 	 */
675724a6905SVille Syrjälä 	if (WARN_ON_ONCE(status_mask & PIPE_B_PSR_STATUS_VLV))
676724a6905SVille Syrjälä 		return 0;
67710c59c51SImre Deak 
67810c59c51SImre Deak 	enable_mask &= ~(PIPE_FIFO_UNDERRUN_STATUS |
67910c59c51SImre Deak 			 SPRITE0_FLIP_DONE_INT_EN_VLV |
68010c59c51SImre Deak 			 SPRITE1_FLIP_DONE_INT_EN_VLV);
68110c59c51SImre Deak 	if (status_mask & SPRITE0_FLIP_DONE_INT_STATUS_VLV)
68210c59c51SImre Deak 		enable_mask |= SPRITE0_FLIP_DONE_INT_EN_VLV;
68310c59c51SImre Deak 	if (status_mask & SPRITE1_FLIP_DONE_INT_STATUS_VLV)
68410c59c51SImre Deak 		enable_mask |= SPRITE1_FLIP_DONE_INT_EN_VLV;
68510c59c51SImre Deak 
6866b12ca56SVille Syrjälä out:
6876b12ca56SVille Syrjälä 	WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
6886b12ca56SVille Syrjälä 		  status_mask & ~PIPESTAT_INT_STATUS_MASK,
6896b12ca56SVille Syrjälä 		  "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
6906b12ca56SVille Syrjälä 		  pipe_name(pipe), enable_mask, status_mask);
6916b12ca56SVille Syrjälä 
69210c59c51SImre Deak 	return enable_mask;
69310c59c51SImre Deak }
69410c59c51SImre Deak 
6956b12ca56SVille Syrjälä void i915_enable_pipestat(struct drm_i915_private *dev_priv,
6966b12ca56SVille Syrjälä 			  enum pipe pipe, u32 status_mask)
697755e9019SImre Deak {
6986b12ca56SVille Syrjälä 	i915_reg_t reg = PIPESTAT(pipe);
699755e9019SImre Deak 	u32 enable_mask;
700755e9019SImre Deak 
7016b12ca56SVille Syrjälä 	WARN_ONCE(status_mask & ~PIPESTAT_INT_STATUS_MASK,
7026b12ca56SVille Syrjälä 		  "pipe %c: status_mask=0x%x\n",
7036b12ca56SVille Syrjälä 		  pipe_name(pipe), status_mask);
7046b12ca56SVille Syrjälä 
7056b12ca56SVille Syrjälä 	lockdep_assert_held(&dev_priv->irq_lock);
7066b12ca56SVille Syrjälä 	WARN_ON(!intel_irqs_enabled(dev_priv));
7076b12ca56SVille Syrjälä 
7086b12ca56SVille Syrjälä 	if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == status_mask)
7096b12ca56SVille Syrjälä 		return;
7106b12ca56SVille Syrjälä 
7116b12ca56SVille Syrjälä 	dev_priv->pipestat_irq_mask[pipe] |= status_mask;
7126b12ca56SVille Syrjälä 	enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
7136b12ca56SVille Syrjälä 
7146b12ca56SVille Syrjälä 	I915_WRITE(reg, enable_mask | status_mask);
7156b12ca56SVille Syrjälä 	POSTING_READ(reg);
716755e9019SImre Deak }
717755e9019SImre Deak 
7186b12ca56SVille Syrjälä void i915_disable_pipestat(struct drm_i915_private *dev_priv,
7196b12ca56SVille Syrjälä 			   enum pipe pipe, u32 status_mask)
720755e9019SImre Deak {
7216b12ca56SVille Syrjälä 	i915_reg_t reg = PIPESTAT(pipe);
722755e9019SImre Deak 	u32 enable_mask;
723755e9019SImre Deak 
7246b12ca56SVille Syrjälä 	WARN_ONCE(status_mask & ~PIPESTAT_INT_STATUS_MASK,
7256b12ca56SVille Syrjälä 		  "pipe %c: status_mask=0x%x\n",
7266b12ca56SVille Syrjälä 		  pipe_name(pipe), status_mask);
7276b12ca56SVille Syrjälä 
7286b12ca56SVille Syrjälä 	lockdep_assert_held(&dev_priv->irq_lock);
7296b12ca56SVille Syrjälä 	WARN_ON(!intel_irqs_enabled(dev_priv));
7306b12ca56SVille Syrjälä 
7316b12ca56SVille Syrjälä 	if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == 0)
7326b12ca56SVille Syrjälä 		return;
7336b12ca56SVille Syrjälä 
7346b12ca56SVille Syrjälä 	dev_priv->pipestat_irq_mask[pipe] &= ~status_mask;
7356b12ca56SVille Syrjälä 	enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
7366b12ca56SVille Syrjälä 
7376b12ca56SVille Syrjälä 	I915_WRITE(reg, enable_mask | status_mask);
7386b12ca56SVille Syrjälä 	POSTING_READ(reg);
739755e9019SImre Deak }
740755e9019SImre Deak 
741c0e09200SDave Airlie /**
742f49e38ddSJani Nikula  * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
74314bb2c11STvrtko Ursulin  * @dev_priv: i915 device private
74401c66889SZhao Yakui  */
74591d14251STvrtko Ursulin static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
74601c66889SZhao Yakui {
74791d14251STvrtko Ursulin 	if (!dev_priv->opregion.asle || !IS_MOBILE(dev_priv))
748f49e38ddSJani Nikula 		return;
749f49e38ddSJani Nikula 
75013321786SDaniel Vetter 	spin_lock_irq(&dev_priv->irq_lock);
75101c66889SZhao Yakui 
752755e9019SImre Deak 	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_STATUS);
75391d14251STvrtko Ursulin 	if (INTEL_GEN(dev_priv) >= 4)
7543b6c42e8SDaniel Vetter 		i915_enable_pipestat(dev_priv, PIPE_A,
755755e9019SImre Deak 				     PIPE_LEGACY_BLC_EVENT_STATUS);
7561ec14ad3SChris Wilson 
75713321786SDaniel Vetter 	spin_unlock_irq(&dev_priv->irq_lock);
75801c66889SZhao Yakui }
75901c66889SZhao Yakui 
760f75f3746SVille Syrjälä /*
761f75f3746SVille Syrjälä  * This timing diagram depicts the video signal in and
762f75f3746SVille Syrjälä  * around the vertical blanking period.
763f75f3746SVille Syrjälä  *
764f75f3746SVille Syrjälä  * Assumptions about the fictitious mode used in this example:
765f75f3746SVille Syrjälä  *  vblank_start >= 3
766f75f3746SVille Syrjälä  *  vsync_start = vblank_start + 1
767f75f3746SVille Syrjälä  *  vsync_end = vblank_start + 2
768f75f3746SVille Syrjälä  *  vtotal = vblank_start + 3
769f75f3746SVille Syrjälä  *
770f75f3746SVille Syrjälä  *           start of vblank:
771f75f3746SVille Syrjälä  *           latch double buffered registers
772f75f3746SVille Syrjälä  *           increment frame counter (ctg+)
773f75f3746SVille Syrjälä  *           generate start of vblank interrupt (gen4+)
774f75f3746SVille Syrjälä  *           |
775f75f3746SVille Syrjälä  *           |          frame start:
776f75f3746SVille Syrjälä  *           |          generate frame start interrupt (aka. vblank interrupt) (gmch)
777f75f3746SVille Syrjälä  *           |          may be shifted forward 1-3 extra lines via PIPECONF
778f75f3746SVille Syrjälä  *           |          |
779f75f3746SVille Syrjälä  *           |          |  start of vsync:
780f75f3746SVille Syrjälä  *           |          |  generate vsync interrupt
781f75f3746SVille Syrjälä  *           |          |  |
782f75f3746SVille Syrjälä  * ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx
783f75f3746SVille Syrjälä  *       .   \hs/   .      \hs/          \hs/          \hs/   .      \hs/
784f75f3746SVille Syrjälä  * ----va---> <-----------------vb--------------------> <--------va-------------
785f75f3746SVille Syrjälä  *       |          |       <----vs----->                     |
786f75f3746SVille Syrjälä  * -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2)
787f75f3746SVille Syrjälä  * -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+)
788f75f3746SVille Syrjälä  * -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi)
789f75f3746SVille Syrjälä  *       |          |                                         |
790f75f3746SVille Syrjälä  *       last visible pixel                                   first visible pixel
791f75f3746SVille Syrjälä  *                  |                                         increment frame counter (gen3/4)
792f75f3746SVille Syrjälä  *                  pixel counter = vblank_start * htotal     pixel counter = 0 (gen3/4)
793f75f3746SVille Syrjälä  *
794f75f3746SVille Syrjälä  * x  = horizontal active
795f75f3746SVille Syrjälä  * _  = horizontal blanking
796f75f3746SVille Syrjälä  * hs = horizontal sync
797f75f3746SVille Syrjälä  * va = vertical active
798f75f3746SVille Syrjälä  * vb = vertical blanking
799f75f3746SVille Syrjälä  * vs = vertical sync
800f75f3746SVille Syrjälä  * vbs = vblank_start (number)
801f75f3746SVille Syrjälä  *
802f75f3746SVille Syrjälä  * Summary:
803f75f3746SVille Syrjälä  * - most events happen at the start of horizontal sync
804f75f3746SVille Syrjälä  * - frame start happens at the start of horizontal blank, 1-4 lines
805f75f3746SVille Syrjälä  *   (depending on PIPECONF settings) after the start of vblank
806f75f3746SVille Syrjälä  * - gen3/4 pixel and frame counter are synchronized with the start
807f75f3746SVille Syrjälä  *   of horizontal active on the first line of vertical active
808f75f3746SVille Syrjälä  */
809f75f3746SVille Syrjälä 
81042f52ef8SKeith Packard /* Called from drm generic code, passed a 'crtc', which
81142f52ef8SKeith Packard  * we use as a pipe index
81242f52ef8SKeith Packard  */
81388e72717SThierry Reding static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
8140a3e67a4SJesse Barnes {
815fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
816f0f59a00SVille Syrjälä 	i915_reg_t high_frame, low_frame;
8170b2a8e09SVille Syrjälä 	u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
8185caa0feaSDaniel Vetter 	const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
819694e409dSVille Syrjälä 	unsigned long irqflags;
820391f75e2SVille Syrjälä 
8210b2a8e09SVille Syrjälä 	htotal = mode->crtc_htotal;
8220b2a8e09SVille Syrjälä 	hsync_start = mode->crtc_hsync_start;
8230b2a8e09SVille Syrjälä 	vbl_start = mode->crtc_vblank_start;
8240b2a8e09SVille Syrjälä 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
8250b2a8e09SVille Syrjälä 		vbl_start = DIV_ROUND_UP(vbl_start, 2);
826391f75e2SVille Syrjälä 
8270b2a8e09SVille Syrjälä 	/* Convert to pixel count */
8280b2a8e09SVille Syrjälä 	vbl_start *= htotal;
8290b2a8e09SVille Syrjälä 
8300b2a8e09SVille Syrjälä 	/* Start of vblank event occurs at start of hsync */
8310b2a8e09SVille Syrjälä 	vbl_start -= htotal - hsync_start;
8320b2a8e09SVille Syrjälä 
8339db4a9c7SJesse Barnes 	high_frame = PIPEFRAME(pipe);
8349db4a9c7SJesse Barnes 	low_frame = PIPEFRAMEPIXEL(pipe);
8355eddb70bSChris Wilson 
836694e409dSVille Syrjälä 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
837694e409dSVille Syrjälä 
8380a3e67a4SJesse Barnes 	/*
8390a3e67a4SJesse Barnes 	 * High & low register fields aren't synchronized, so make sure
8400a3e67a4SJesse Barnes 	 * we get a low value that's stable across two reads of the high
8410a3e67a4SJesse Barnes 	 * register.
8420a3e67a4SJesse Barnes 	 */
8430a3e67a4SJesse Barnes 	do {
844694e409dSVille Syrjälä 		high1 = I915_READ_FW(high_frame) & PIPE_FRAME_HIGH_MASK;
845694e409dSVille Syrjälä 		low   = I915_READ_FW(low_frame);
846694e409dSVille Syrjälä 		high2 = I915_READ_FW(high_frame) & PIPE_FRAME_HIGH_MASK;
8470a3e67a4SJesse Barnes 	} while (high1 != high2);
8480a3e67a4SJesse Barnes 
849694e409dSVille Syrjälä 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
850694e409dSVille Syrjälä 
8515eddb70bSChris Wilson 	high1 >>= PIPE_FRAME_HIGH_SHIFT;
852391f75e2SVille Syrjälä 	pixel = low & PIPE_PIXEL_MASK;
8535eddb70bSChris Wilson 	low >>= PIPE_FRAME_LOW_SHIFT;
854391f75e2SVille Syrjälä 
855391f75e2SVille Syrjälä 	/*
856391f75e2SVille Syrjälä 	 * The frame counter increments at beginning of active.
857391f75e2SVille Syrjälä 	 * Cook up a vblank counter by also checking the pixel
858391f75e2SVille Syrjälä 	 * counter against vblank start.
859391f75e2SVille Syrjälä 	 */
860edc08d0aSVille Syrjälä 	return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff;
8610a3e67a4SJesse Barnes }
8620a3e67a4SJesse Barnes 
863974e59baSDave Airlie static u32 g4x_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
8649880b7a5SJesse Barnes {
865fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
8669880b7a5SJesse Barnes 
867649636efSVille Syrjälä 	return I915_READ(PIPE_FRMCOUNT_G4X(pipe));
8689880b7a5SJesse Barnes }
8699880b7a5SJesse Barnes 
870aec0246fSUma Shankar /*
871aec0246fSUma Shankar  * On certain encoders on certain platforms, pipe
872aec0246fSUma Shankar  * scanline register will not work to get the scanline,
873aec0246fSUma Shankar  * since the timings are driven from the PORT or issues
874aec0246fSUma Shankar  * with scanline register updates.
875aec0246fSUma Shankar  * This function will use Framestamp and current
876aec0246fSUma Shankar  * timestamp registers to calculate the scanline.
877aec0246fSUma Shankar  */
878aec0246fSUma Shankar static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
879aec0246fSUma Shankar {
880aec0246fSUma Shankar 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
881aec0246fSUma Shankar 	struct drm_vblank_crtc *vblank =
882aec0246fSUma Shankar 		&crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
883aec0246fSUma Shankar 	const struct drm_display_mode *mode = &vblank->hwmode;
884aec0246fSUma Shankar 	u32 vblank_start = mode->crtc_vblank_start;
885aec0246fSUma Shankar 	u32 vtotal = mode->crtc_vtotal;
886aec0246fSUma Shankar 	u32 htotal = mode->crtc_htotal;
887aec0246fSUma Shankar 	u32 clock = mode->crtc_clock;
888aec0246fSUma Shankar 	u32 scanline, scan_prev_time, scan_curr_time, scan_post_time;
889aec0246fSUma Shankar 
890aec0246fSUma Shankar 	/*
891aec0246fSUma Shankar 	 * To avoid the race condition where we might cross into the
892aec0246fSUma Shankar 	 * next vblank just between the PIPE_FRMTMSTMP and TIMESTAMP_CTR
893aec0246fSUma Shankar 	 * reads. We make sure we read PIPE_FRMTMSTMP and TIMESTAMP_CTR
894aec0246fSUma Shankar 	 * during the same frame.
895aec0246fSUma Shankar 	 */
896aec0246fSUma Shankar 	do {
897aec0246fSUma Shankar 		/*
898aec0246fSUma Shankar 		 * This field provides read back of the display
899aec0246fSUma Shankar 		 * pipe frame time stamp. The time stamp value
900aec0246fSUma Shankar 		 * is sampled at every start of vertical blank.
901aec0246fSUma Shankar 		 */
902aec0246fSUma Shankar 		scan_prev_time = I915_READ_FW(PIPE_FRMTMSTMP(crtc->pipe));
903aec0246fSUma Shankar 
904aec0246fSUma Shankar 		/*
905aec0246fSUma Shankar 		 * The TIMESTAMP_CTR register has the current
906aec0246fSUma Shankar 		 * time stamp value.
907aec0246fSUma Shankar 		 */
908aec0246fSUma Shankar 		scan_curr_time = I915_READ_FW(IVB_TIMESTAMP_CTR);
909aec0246fSUma Shankar 
910aec0246fSUma Shankar 		scan_post_time = I915_READ_FW(PIPE_FRMTMSTMP(crtc->pipe));
911aec0246fSUma Shankar 	} while (scan_post_time != scan_prev_time);
912aec0246fSUma Shankar 
913aec0246fSUma Shankar 	scanline = div_u64(mul_u32_u32(scan_curr_time - scan_prev_time,
914aec0246fSUma Shankar 					clock), 1000 * htotal);
915aec0246fSUma Shankar 	scanline = min(scanline, vtotal - 1);
916aec0246fSUma Shankar 	scanline = (scanline + vblank_start) % vtotal;
917aec0246fSUma Shankar 
918aec0246fSUma Shankar 	return scanline;
919aec0246fSUma Shankar }
920aec0246fSUma Shankar 
92175aa3f63SVille Syrjälä /* I915_READ_FW, only for fast reads of display block, no need for forcewake etc. */
922a225f079SVille Syrjälä static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
923a225f079SVille Syrjälä {
924a225f079SVille Syrjälä 	struct drm_device *dev = crtc->base.dev;
925fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
9265caa0feaSDaniel Vetter 	const struct drm_display_mode *mode;
9275caa0feaSDaniel Vetter 	struct drm_vblank_crtc *vblank;
928a225f079SVille Syrjälä 	enum pipe pipe = crtc->pipe;
92980715b2fSVille Syrjälä 	int position, vtotal;
930a225f079SVille Syrjälä 
93172259536SVille Syrjälä 	if (!crtc->active)
93272259536SVille Syrjälä 		return -1;
93372259536SVille Syrjälä 
9345caa0feaSDaniel Vetter 	vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
9355caa0feaSDaniel Vetter 	mode = &vblank->hwmode;
9365caa0feaSDaniel Vetter 
937aec0246fSUma Shankar 	if (mode->private_flags & I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP)
938aec0246fSUma Shankar 		return __intel_get_crtc_scanline_from_timestamp(crtc);
939aec0246fSUma Shankar 
94080715b2fSVille Syrjälä 	vtotal = mode->crtc_vtotal;
941a225f079SVille Syrjälä 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
942a225f079SVille Syrjälä 		vtotal /= 2;
943a225f079SVille Syrjälä 
94491d14251STvrtko Ursulin 	if (IS_GEN2(dev_priv))
94575aa3f63SVille Syrjälä 		position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
946a225f079SVille Syrjälä 	else
94775aa3f63SVille Syrjälä 		position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
948a225f079SVille Syrjälä 
949a225f079SVille Syrjälä 	/*
95041b578fbSJesse Barnes 	 * On HSW, the DSL reg (0x70000) appears to return 0 if we
95141b578fbSJesse Barnes 	 * read it just before the start of vblank.  So try it again
95241b578fbSJesse Barnes 	 * so we don't accidentally end up spanning a vblank frame
95341b578fbSJesse Barnes 	 * increment, causing the pipe_update_end() code to squak at us.
95441b578fbSJesse Barnes 	 *
95541b578fbSJesse Barnes 	 * The nature of this problem means we can't simply check the ISR
95641b578fbSJesse Barnes 	 * bit and return the vblank start value; nor can we use the scanline
95741b578fbSJesse Barnes 	 * debug register in the transcoder as it appears to have the same
95841b578fbSJesse Barnes 	 * problem.  We may need to extend this to include other platforms,
95941b578fbSJesse Barnes 	 * but so far testing only shows the problem on HSW.
96041b578fbSJesse Barnes 	 */
96191d14251STvrtko Ursulin 	if (HAS_DDI(dev_priv) && !position) {
96241b578fbSJesse Barnes 		int i, temp;
96341b578fbSJesse Barnes 
96441b578fbSJesse Barnes 		for (i = 0; i < 100; i++) {
96541b578fbSJesse Barnes 			udelay(1);
966707bdd3fSVille Syrjälä 			temp = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
96741b578fbSJesse Barnes 			if (temp != position) {
96841b578fbSJesse Barnes 				position = temp;
96941b578fbSJesse Barnes 				break;
97041b578fbSJesse Barnes 			}
97141b578fbSJesse Barnes 		}
97241b578fbSJesse Barnes 	}
97341b578fbSJesse Barnes 
97441b578fbSJesse Barnes 	/*
97580715b2fSVille Syrjälä 	 * See update_scanline_offset() for the details on the
97680715b2fSVille Syrjälä 	 * scanline_offset adjustment.
977a225f079SVille Syrjälä 	 */
97880715b2fSVille Syrjälä 	return (position + crtc->scanline_offset) % vtotal;
979a225f079SVille Syrjälä }
980a225f079SVille Syrjälä 
9811bf6ad62SDaniel Vetter static bool i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
9821bf6ad62SDaniel Vetter 				     bool in_vblank_irq, int *vpos, int *hpos,
9833bb403bfSVille Syrjälä 				     ktime_t *stime, ktime_t *etime,
9843bb403bfSVille Syrjälä 				     const struct drm_display_mode *mode)
9850af7e4dfSMario Kleiner {
986fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
98798187836SVille Syrjälä 	struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv,
98898187836SVille Syrjälä 								pipe);
9893aa18df8SVille Syrjälä 	int position;
99078e8fc6bSVille Syrjälä 	int vbl_start, vbl_end, hsync_start, htotal, vtotal;
991ad3543edSMario Kleiner 	unsigned long irqflags;
9920af7e4dfSMario Kleiner 
993fc467a22SMaarten Lankhorst 	if (WARN_ON(!mode->crtc_clock)) {
9940af7e4dfSMario Kleiner 		DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
9959db4a9c7SJesse Barnes 				 "pipe %c\n", pipe_name(pipe));
9961bf6ad62SDaniel Vetter 		return false;
9970af7e4dfSMario Kleiner 	}
9980af7e4dfSMario Kleiner 
999c2baf4b7SVille Syrjälä 	htotal = mode->crtc_htotal;
100078e8fc6bSVille Syrjälä 	hsync_start = mode->crtc_hsync_start;
1001c2baf4b7SVille Syrjälä 	vtotal = mode->crtc_vtotal;
1002c2baf4b7SVille Syrjälä 	vbl_start = mode->crtc_vblank_start;
1003c2baf4b7SVille Syrjälä 	vbl_end = mode->crtc_vblank_end;
10040af7e4dfSMario Kleiner 
1005d31faf65SVille Syrjälä 	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
1006d31faf65SVille Syrjälä 		vbl_start = DIV_ROUND_UP(vbl_start, 2);
1007d31faf65SVille Syrjälä 		vbl_end /= 2;
1008d31faf65SVille Syrjälä 		vtotal /= 2;
1009d31faf65SVille Syrjälä 	}
1010d31faf65SVille Syrjälä 
1011ad3543edSMario Kleiner 	/*
1012ad3543edSMario Kleiner 	 * Lock uncore.lock, as we will do multiple timing critical raw
1013ad3543edSMario Kleiner 	 * register reads, potentially with preemption disabled, so the
1014ad3543edSMario Kleiner 	 * following code must not block on uncore.lock.
1015ad3543edSMario Kleiner 	 */
1016ad3543edSMario Kleiner 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
1017ad3543edSMario Kleiner 
1018ad3543edSMario Kleiner 	/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
1019ad3543edSMario Kleiner 
1020ad3543edSMario Kleiner 	/* Get optional system timestamp before query. */
1021ad3543edSMario Kleiner 	if (stime)
1022ad3543edSMario Kleiner 		*stime = ktime_get();
1023ad3543edSMario Kleiner 
102491d14251STvrtko Ursulin 	if (IS_GEN2(dev_priv) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
10250af7e4dfSMario Kleiner 		/* No obvious pixelcount register. Only query vertical
10260af7e4dfSMario Kleiner 		 * scanout position from Display scan line register.
10270af7e4dfSMario Kleiner 		 */
1028a225f079SVille Syrjälä 		position = __intel_get_crtc_scanline(intel_crtc);
10290af7e4dfSMario Kleiner 	} else {
10300af7e4dfSMario Kleiner 		/* Have access to pixelcount since start of frame.
10310af7e4dfSMario Kleiner 		 * We can split this into vertical and horizontal
10320af7e4dfSMario Kleiner 		 * scanout position.
10330af7e4dfSMario Kleiner 		 */
103475aa3f63SVille Syrjälä 		position = (I915_READ_FW(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
10350af7e4dfSMario Kleiner 
10363aa18df8SVille Syrjälä 		/* convert to pixel counts */
10373aa18df8SVille Syrjälä 		vbl_start *= htotal;
10383aa18df8SVille Syrjälä 		vbl_end *= htotal;
10393aa18df8SVille Syrjälä 		vtotal *= htotal;
104078e8fc6bSVille Syrjälä 
104178e8fc6bSVille Syrjälä 		/*
10427e78f1cbSVille Syrjälä 		 * In interlaced modes, the pixel counter counts all pixels,
10437e78f1cbSVille Syrjälä 		 * so one field will have htotal more pixels. In order to avoid
10447e78f1cbSVille Syrjälä 		 * the reported position from jumping backwards when the pixel
10457e78f1cbSVille Syrjälä 		 * counter is beyond the length of the shorter field, just
10467e78f1cbSVille Syrjälä 		 * clamp the position the length of the shorter field. This
10477e78f1cbSVille Syrjälä 		 * matches how the scanline counter based position works since
10487e78f1cbSVille Syrjälä 		 * the scanline counter doesn't count the two half lines.
10497e78f1cbSVille Syrjälä 		 */
10507e78f1cbSVille Syrjälä 		if (position >= vtotal)
10517e78f1cbSVille Syrjälä 			position = vtotal - 1;
10527e78f1cbSVille Syrjälä 
10537e78f1cbSVille Syrjälä 		/*
105478e8fc6bSVille Syrjälä 		 * Start of vblank interrupt is triggered at start of hsync,
105578e8fc6bSVille Syrjälä 		 * just prior to the first active line of vblank. However we
105678e8fc6bSVille Syrjälä 		 * consider lines to start at the leading edge of horizontal
105778e8fc6bSVille Syrjälä 		 * active. So, should we get here before we've crossed into
105878e8fc6bSVille Syrjälä 		 * the horizontal active of the first line in vblank, we would
105978e8fc6bSVille Syrjälä 		 * not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that,
106078e8fc6bSVille Syrjälä 		 * always add htotal-hsync_start to the current pixel position.
106178e8fc6bSVille Syrjälä 		 */
106278e8fc6bSVille Syrjälä 		position = (position + htotal - hsync_start) % vtotal;
10633aa18df8SVille Syrjälä 	}
10643aa18df8SVille Syrjälä 
1065ad3543edSMario Kleiner 	/* Get optional system timestamp after query. */
1066ad3543edSMario Kleiner 	if (etime)
1067ad3543edSMario Kleiner 		*etime = ktime_get();
1068ad3543edSMario Kleiner 
1069ad3543edSMario Kleiner 	/* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
1070ad3543edSMario Kleiner 
1071ad3543edSMario Kleiner 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
1072ad3543edSMario Kleiner 
10733aa18df8SVille Syrjälä 	/*
10743aa18df8SVille Syrjälä 	 * While in vblank, position will be negative
10753aa18df8SVille Syrjälä 	 * counting up towards 0 at vbl_end. And outside
10763aa18df8SVille Syrjälä 	 * vblank, position will be positive counting
10773aa18df8SVille Syrjälä 	 * up since vbl_end.
10783aa18df8SVille Syrjälä 	 */
10793aa18df8SVille Syrjälä 	if (position >= vbl_start)
10803aa18df8SVille Syrjälä 		position -= vbl_end;
10813aa18df8SVille Syrjälä 	else
10823aa18df8SVille Syrjälä 		position += vtotal - vbl_end;
10833aa18df8SVille Syrjälä 
108491d14251STvrtko Ursulin 	if (IS_GEN2(dev_priv) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
10853aa18df8SVille Syrjälä 		*vpos = position;
10863aa18df8SVille Syrjälä 		*hpos = 0;
10873aa18df8SVille Syrjälä 	} else {
10880af7e4dfSMario Kleiner 		*vpos = position / htotal;
10890af7e4dfSMario Kleiner 		*hpos = position - (*vpos * htotal);
10900af7e4dfSMario Kleiner 	}
10910af7e4dfSMario Kleiner 
10921bf6ad62SDaniel Vetter 	return true;
10930af7e4dfSMario Kleiner }
10940af7e4dfSMario Kleiner 
1095a225f079SVille Syrjälä int intel_get_crtc_scanline(struct intel_crtc *crtc)
1096a225f079SVille Syrjälä {
1097fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
1098a225f079SVille Syrjälä 	unsigned long irqflags;
1099a225f079SVille Syrjälä 	int position;
1100a225f079SVille Syrjälä 
1101a225f079SVille Syrjälä 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
1102a225f079SVille Syrjälä 	position = __intel_get_crtc_scanline(crtc);
1103a225f079SVille Syrjälä 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
1104a225f079SVille Syrjälä 
1105a225f079SVille Syrjälä 	return position;
1106a225f079SVille Syrjälä }
1107a225f079SVille Syrjälä 
110891d14251STvrtko Ursulin static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv)
1109f97108d1SJesse Barnes {
1110b5b72e89SMatthew Garrett 	u32 busy_up, busy_down, max_avg, min_avg;
11119270388eSDaniel Vetter 	u8 new_delay;
11129270388eSDaniel Vetter 
1113d0ecd7e2SDaniel Vetter 	spin_lock(&mchdev_lock);
1114f97108d1SJesse Barnes 
111573edd18fSDaniel Vetter 	I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
111673edd18fSDaniel Vetter 
111720e4d407SDaniel Vetter 	new_delay = dev_priv->ips.cur_delay;
11189270388eSDaniel Vetter 
11197648fa99SJesse Barnes 	I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG);
1120b5b72e89SMatthew Garrett 	busy_up = I915_READ(RCPREVBSYTUPAVG);
1121b5b72e89SMatthew Garrett 	busy_down = I915_READ(RCPREVBSYTDNAVG);
1122f97108d1SJesse Barnes 	max_avg = I915_READ(RCBMAXAVG);
1123f97108d1SJesse Barnes 	min_avg = I915_READ(RCBMINAVG);
1124f97108d1SJesse Barnes 
1125f97108d1SJesse Barnes 	/* Handle RCS change request from hw */
1126b5b72e89SMatthew Garrett 	if (busy_up > max_avg) {
112720e4d407SDaniel Vetter 		if (dev_priv->ips.cur_delay != dev_priv->ips.max_delay)
112820e4d407SDaniel Vetter 			new_delay = dev_priv->ips.cur_delay - 1;
112920e4d407SDaniel Vetter 		if (new_delay < dev_priv->ips.max_delay)
113020e4d407SDaniel Vetter 			new_delay = dev_priv->ips.max_delay;
1131b5b72e89SMatthew Garrett 	} else if (busy_down < min_avg) {
113220e4d407SDaniel Vetter 		if (dev_priv->ips.cur_delay != dev_priv->ips.min_delay)
113320e4d407SDaniel Vetter 			new_delay = dev_priv->ips.cur_delay + 1;
113420e4d407SDaniel Vetter 		if (new_delay > dev_priv->ips.min_delay)
113520e4d407SDaniel Vetter 			new_delay = dev_priv->ips.min_delay;
1136f97108d1SJesse Barnes 	}
1137f97108d1SJesse Barnes 
113891d14251STvrtko Ursulin 	if (ironlake_set_drps(dev_priv, new_delay))
113920e4d407SDaniel Vetter 		dev_priv->ips.cur_delay = new_delay;
1140f97108d1SJesse Barnes 
1141d0ecd7e2SDaniel Vetter 	spin_unlock(&mchdev_lock);
11429270388eSDaniel Vetter 
1143f97108d1SJesse Barnes 	return;
1144f97108d1SJesse Barnes }
1145f97108d1SJesse Barnes 
11460bc40be8STvrtko Ursulin static void notify_ring(struct intel_engine_cs *engine)
1147549f7365SChris Wilson {
1148e61e0f51SChris Wilson 	struct i915_request *rq = NULL;
114956299fb7SChris Wilson 	struct intel_wait *wait;
1150dffabc8fSTvrtko Ursulin 
1151bcbd5c33SChris Wilson 	if (!engine->breadcrumbs.irq_armed)
1152bcbd5c33SChris Wilson 		return;
1153bcbd5c33SChris Wilson 
11542246bea6SChris Wilson 	atomic_inc(&engine->irq_count);
1155538b257dSChris Wilson 	set_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted);
115656299fb7SChris Wilson 
115761d3dc70SChris Wilson 	spin_lock(&engine->breadcrumbs.irq_lock);
115861d3dc70SChris Wilson 	wait = engine->breadcrumbs.irq_wait;
115956299fb7SChris Wilson 	if (wait) {
116017b51ad8SChris Wilson 		bool wakeup = engine->irq_seqno_barrier;
116117b51ad8SChris Wilson 
116256299fb7SChris Wilson 		/* We use a callback from the dma-fence to submit
116356299fb7SChris Wilson 		 * requests after waiting on our own requests. To
116456299fb7SChris Wilson 		 * ensure minimum delay in queuing the next request to
116556299fb7SChris Wilson 		 * hardware, signal the fence now rather than wait for
116656299fb7SChris Wilson 		 * the signaler to be woken up. We still wake up the
116756299fb7SChris Wilson 		 * waiter in order to handle the irq-seqno coherency
116856299fb7SChris Wilson 		 * issues (we may receive the interrupt before the
116956299fb7SChris Wilson 		 * seqno is written, see __i915_request_irq_complete())
117056299fb7SChris Wilson 		 * and to handle coalescing of multiple seqno updates
117156299fb7SChris Wilson 		 * and many waiters.
117256299fb7SChris Wilson 		 */
117356299fb7SChris Wilson 		if (i915_seqno_passed(intel_engine_get_seqno(engine),
117417b51ad8SChris Wilson 				      wait->seqno)) {
1175e61e0f51SChris Wilson 			struct i915_request *waiter = wait->request;
1176de4d2106SChris Wilson 
117717b51ad8SChris Wilson 			wakeup = true;
117817b51ad8SChris Wilson 			if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
1179de4d2106SChris Wilson 				      &waiter->fence.flags) &&
1180de4d2106SChris Wilson 			    intel_wait_check_request(wait, waiter))
1181e61e0f51SChris Wilson 				rq = i915_request_get(waiter);
118217b51ad8SChris Wilson 		}
118356299fb7SChris Wilson 
118417b51ad8SChris Wilson 		if (wakeup)
118556299fb7SChris Wilson 			wake_up_process(wait->tsk);
118667b807a8SChris Wilson 	} else {
1187bcbd5c33SChris Wilson 		if (engine->breadcrumbs.irq_armed)
118867b807a8SChris Wilson 			__intel_engine_disarm_breadcrumbs(engine);
118956299fb7SChris Wilson 	}
119061d3dc70SChris Wilson 	spin_unlock(&engine->breadcrumbs.irq_lock);
119156299fb7SChris Wilson 
119224754d75SChris Wilson 	if (rq) {
119356299fb7SChris Wilson 		dma_fence_signal(&rq->fence);
11944e9a8befSChris Wilson 		GEM_BUG_ON(!i915_request_completed(rq));
1195e61e0f51SChris Wilson 		i915_request_put(rq);
119624754d75SChris Wilson 	}
119756299fb7SChris Wilson 
119856299fb7SChris Wilson 	trace_intel_engine_notify(engine, wait);
1199549f7365SChris Wilson }
1200549f7365SChris Wilson 
120143cf3bf0SChris Wilson static void vlv_c0_read(struct drm_i915_private *dev_priv,
120243cf3bf0SChris Wilson 			struct intel_rps_ei *ei)
120331685c25SDeepak S {
1204679cb6c1SMika Kuoppala 	ei->ktime = ktime_get_raw();
120543cf3bf0SChris Wilson 	ei->render_c0 = I915_READ(VLV_RENDER_C0_COUNT);
120643cf3bf0SChris Wilson 	ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT);
120731685c25SDeepak S }
120831685c25SDeepak S 
120943cf3bf0SChris Wilson void gen6_rps_reset_ei(struct drm_i915_private *dev_priv)
121043cf3bf0SChris Wilson {
1211562d9baeSSagar Arun Kamble 	memset(&dev_priv->gt_pm.rps.ei, 0, sizeof(dev_priv->gt_pm.rps.ei));
121243cf3bf0SChris Wilson }
121343cf3bf0SChris Wilson 
121443cf3bf0SChris Wilson static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
121543cf3bf0SChris Wilson {
1216562d9baeSSagar Arun Kamble 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
1217562d9baeSSagar Arun Kamble 	const struct intel_rps_ei *prev = &rps->ei;
121843cf3bf0SChris Wilson 	struct intel_rps_ei now;
121943cf3bf0SChris Wilson 	u32 events = 0;
122043cf3bf0SChris Wilson 
1221e0e8c7cbSChris Wilson 	if ((pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) == 0)
122243cf3bf0SChris Wilson 		return 0;
122343cf3bf0SChris Wilson 
122443cf3bf0SChris Wilson 	vlv_c0_read(dev_priv, &now);
122531685c25SDeepak S 
1226679cb6c1SMika Kuoppala 	if (prev->ktime) {
1227e0e8c7cbSChris Wilson 		u64 time, c0;
1228569884e3SChris Wilson 		u32 render, media;
1229e0e8c7cbSChris Wilson 
1230679cb6c1SMika Kuoppala 		time = ktime_us_delta(now.ktime, prev->ktime);
12318f68d591SChris Wilson 
1232e0e8c7cbSChris Wilson 		time *= dev_priv->czclk_freq;
1233e0e8c7cbSChris Wilson 
1234e0e8c7cbSChris Wilson 		/* Workload can be split between render + media,
1235e0e8c7cbSChris Wilson 		 * e.g. SwapBuffers being blitted in X after being rendered in
1236e0e8c7cbSChris Wilson 		 * mesa. To account for this we need to combine both engines
1237e0e8c7cbSChris Wilson 		 * into our activity counter.
1238e0e8c7cbSChris Wilson 		 */
1239569884e3SChris Wilson 		render = now.render_c0 - prev->render_c0;
1240569884e3SChris Wilson 		media = now.media_c0 - prev->media_c0;
1241569884e3SChris Wilson 		c0 = max(render, media);
12426b7f6aa7SMika Kuoppala 		c0 *= 1000 * 100 << 8; /* to usecs and scale to threshold% */
1243e0e8c7cbSChris Wilson 
1244562d9baeSSagar Arun Kamble 		if (c0 > time * rps->up_threshold)
1245e0e8c7cbSChris Wilson 			events = GEN6_PM_RP_UP_THRESHOLD;
1246562d9baeSSagar Arun Kamble 		else if (c0 < time * rps->down_threshold)
1247e0e8c7cbSChris Wilson 			events = GEN6_PM_RP_DOWN_THRESHOLD;
124831685c25SDeepak S 	}
124931685c25SDeepak S 
1250562d9baeSSagar Arun Kamble 	rps->ei = now;
125143cf3bf0SChris Wilson 	return events;
125231685c25SDeepak S }
125331685c25SDeepak S 
12544912d041SBen Widawsky static void gen6_pm_rps_work(struct work_struct *work)
12553b8d8d91SJesse Barnes {
12562d1013ddSJani Nikula 	struct drm_i915_private *dev_priv =
1257562d9baeSSagar Arun Kamble 		container_of(work, struct drm_i915_private, gt_pm.rps.work);
1258562d9baeSSagar Arun Kamble 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
12597c0a16adSChris Wilson 	bool client_boost = false;
12608d3afd7dSChris Wilson 	int new_delay, adj, min, max;
12617c0a16adSChris Wilson 	u32 pm_iir = 0;
12623b8d8d91SJesse Barnes 
126359cdb63dSDaniel Vetter 	spin_lock_irq(&dev_priv->irq_lock);
1264562d9baeSSagar Arun Kamble 	if (rps->interrupts_enabled) {
1265562d9baeSSagar Arun Kamble 		pm_iir = fetch_and_zero(&rps->pm_iir);
1266562d9baeSSagar Arun Kamble 		client_boost = atomic_read(&rps->num_waiters);
1267d4d70aa5SImre Deak 	}
126859cdb63dSDaniel Vetter 	spin_unlock_irq(&dev_priv->irq_lock);
12694912d041SBen Widawsky 
127060611c13SPaulo Zanoni 	/* Make sure we didn't queue anything we're not going to process. */
1271a6706b45SDeepak S 	WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
12728d3afd7dSChris Wilson 	if ((pm_iir & dev_priv->pm_rps_events) == 0 && !client_boost)
12737c0a16adSChris Wilson 		goto out;
12743b8d8d91SJesse Barnes 
12759f817501SSagar Arun Kamble 	mutex_lock(&dev_priv->pcu_lock);
12767b9e0ae6SChris Wilson 
127743cf3bf0SChris Wilson 	pm_iir |= vlv_wa_c0_ei(dev_priv, pm_iir);
127843cf3bf0SChris Wilson 
1279562d9baeSSagar Arun Kamble 	adj = rps->last_adj;
1280562d9baeSSagar Arun Kamble 	new_delay = rps->cur_freq;
1281562d9baeSSagar Arun Kamble 	min = rps->min_freq_softlimit;
1282562d9baeSSagar Arun Kamble 	max = rps->max_freq_softlimit;
12837b92c1bdSChris Wilson 	if (client_boost)
1284562d9baeSSagar Arun Kamble 		max = rps->max_freq;
1285562d9baeSSagar Arun Kamble 	if (client_boost && new_delay < rps->boost_freq) {
1286562d9baeSSagar Arun Kamble 		new_delay = rps->boost_freq;
12878d3afd7dSChris Wilson 		adj = 0;
12888d3afd7dSChris Wilson 	} else if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
1289dd75fdc8SChris Wilson 		if (adj > 0)
1290dd75fdc8SChris Wilson 			adj *= 2;
1291edcf284bSChris Wilson 		else /* CHV needs even encode values */
1292edcf284bSChris Wilson 			adj = IS_CHERRYVIEW(dev_priv) ? 2 : 1;
12937e79a683SSagar Arun Kamble 
1294562d9baeSSagar Arun Kamble 		if (new_delay >= rps->max_freq_softlimit)
12957e79a683SSagar Arun Kamble 			adj = 0;
12967b92c1bdSChris Wilson 	} else if (client_boost) {
1297f5a4c67dSChris Wilson 		adj = 0;
1298dd75fdc8SChris Wilson 	} else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) {
1299562d9baeSSagar Arun Kamble 		if (rps->cur_freq > rps->efficient_freq)
1300562d9baeSSagar Arun Kamble 			new_delay = rps->efficient_freq;
1301562d9baeSSagar Arun Kamble 		else if (rps->cur_freq > rps->min_freq_softlimit)
1302562d9baeSSagar Arun Kamble 			new_delay = rps->min_freq_softlimit;
1303dd75fdc8SChris Wilson 		adj = 0;
1304dd75fdc8SChris Wilson 	} else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
1305dd75fdc8SChris Wilson 		if (adj < 0)
1306dd75fdc8SChris Wilson 			adj *= 2;
1307edcf284bSChris Wilson 		else /* CHV needs even encode values */
1308edcf284bSChris Wilson 			adj = IS_CHERRYVIEW(dev_priv) ? -2 : -1;
13097e79a683SSagar Arun Kamble 
1310562d9baeSSagar Arun Kamble 		if (new_delay <= rps->min_freq_softlimit)
13117e79a683SSagar Arun Kamble 			adj = 0;
1312dd75fdc8SChris Wilson 	} else { /* unknown event */
1313edcf284bSChris Wilson 		adj = 0;
1314dd75fdc8SChris Wilson 	}
13153b8d8d91SJesse Barnes 
1316562d9baeSSagar Arun Kamble 	rps->last_adj = adj;
1317edcf284bSChris Wilson 
131879249636SBen Widawsky 	/* sysfs frequency interfaces may have snuck in while servicing the
131979249636SBen Widawsky 	 * interrupt
132079249636SBen Widawsky 	 */
1321edcf284bSChris Wilson 	new_delay += adj;
13228d3afd7dSChris Wilson 	new_delay = clamp_t(int, new_delay, min, max);
132327544369SDeepak S 
13249fcee2f7SChris Wilson 	if (intel_set_rps(dev_priv, new_delay)) {
13259fcee2f7SChris Wilson 		DRM_DEBUG_DRIVER("Failed to set new GPU frequency\n");
1326562d9baeSSagar Arun Kamble 		rps->last_adj = 0;
13279fcee2f7SChris Wilson 	}
13283b8d8d91SJesse Barnes 
13299f817501SSagar Arun Kamble 	mutex_unlock(&dev_priv->pcu_lock);
13307c0a16adSChris Wilson 
13317c0a16adSChris Wilson out:
13327c0a16adSChris Wilson 	/* Make sure not to corrupt PMIMR state used by ringbuffer on GEN6 */
13337c0a16adSChris Wilson 	spin_lock_irq(&dev_priv->irq_lock);
1334562d9baeSSagar Arun Kamble 	if (rps->interrupts_enabled)
13357c0a16adSChris Wilson 		gen6_unmask_pm_irq(dev_priv, dev_priv->pm_rps_events);
13367c0a16adSChris Wilson 	spin_unlock_irq(&dev_priv->irq_lock);
13373b8d8d91SJesse Barnes }
13383b8d8d91SJesse Barnes 
1339e3689190SBen Widawsky 
1340e3689190SBen Widawsky /**
1341e3689190SBen Widawsky  * ivybridge_parity_work - Workqueue called when a parity error interrupt
1342e3689190SBen Widawsky  * occurred.
1343e3689190SBen Widawsky  * @work: workqueue struct
1344e3689190SBen Widawsky  *
1345e3689190SBen Widawsky  * Doesn't actually do anything except notify userspace. As a consequence of
1346e3689190SBen Widawsky  * this event, userspace should try to remap the bad rows since statistically
1347e3689190SBen Widawsky  * it is likely the same row is more likely to go bad again.
1348e3689190SBen Widawsky  */
1349e3689190SBen Widawsky static void ivybridge_parity_work(struct work_struct *work)
1350e3689190SBen Widawsky {
13512d1013ddSJani Nikula 	struct drm_i915_private *dev_priv =
1352cefcff8fSJoonas Lahtinen 		container_of(work, typeof(*dev_priv), l3_parity.error_work);
1353e3689190SBen Widawsky 	u32 error_status, row, bank, subbank;
135435a85ac6SBen Widawsky 	char *parity_event[6];
1355e3689190SBen Widawsky 	uint32_t misccpctl;
135635a85ac6SBen Widawsky 	uint8_t slice = 0;
1357e3689190SBen Widawsky 
1358e3689190SBen Widawsky 	/* We must turn off DOP level clock gating to access the L3 registers.
1359e3689190SBen Widawsky 	 * In order to prevent a get/put style interface, acquire struct mutex
1360e3689190SBen Widawsky 	 * any time we access those registers.
1361e3689190SBen Widawsky 	 */
136291c8a326SChris Wilson 	mutex_lock(&dev_priv->drm.struct_mutex);
1363e3689190SBen Widawsky 
136435a85ac6SBen Widawsky 	/* If we've screwed up tracking, just let the interrupt fire again */
136535a85ac6SBen Widawsky 	if (WARN_ON(!dev_priv->l3_parity.which_slice))
136635a85ac6SBen Widawsky 		goto out;
136735a85ac6SBen Widawsky 
1368e3689190SBen Widawsky 	misccpctl = I915_READ(GEN7_MISCCPCTL);
1369e3689190SBen Widawsky 	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
1370e3689190SBen Widawsky 	POSTING_READ(GEN7_MISCCPCTL);
1371e3689190SBen Widawsky 
137235a85ac6SBen Widawsky 	while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
1373f0f59a00SVille Syrjälä 		i915_reg_t reg;
137435a85ac6SBen Widawsky 
137535a85ac6SBen Widawsky 		slice--;
13762d1fe073SJoonas Lahtinen 		if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv)))
137735a85ac6SBen Widawsky 			break;
137835a85ac6SBen Widawsky 
137935a85ac6SBen Widawsky 		dev_priv->l3_parity.which_slice &= ~(1<<slice);
138035a85ac6SBen Widawsky 
13816fa1c5f1SVille Syrjälä 		reg = GEN7_L3CDERRST1(slice);
138235a85ac6SBen Widawsky 
138335a85ac6SBen Widawsky 		error_status = I915_READ(reg);
1384e3689190SBen Widawsky 		row = GEN7_PARITY_ERROR_ROW(error_status);
1385e3689190SBen Widawsky 		bank = GEN7_PARITY_ERROR_BANK(error_status);
1386e3689190SBen Widawsky 		subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
1387e3689190SBen Widawsky 
138835a85ac6SBen Widawsky 		I915_WRITE(reg, GEN7_PARITY_ERROR_VALID | GEN7_L3CDERRST1_ENABLE);
138935a85ac6SBen Widawsky 		POSTING_READ(reg);
1390e3689190SBen Widawsky 
1391cce723edSBen Widawsky 		parity_event[0] = I915_L3_PARITY_UEVENT "=1";
1392e3689190SBen Widawsky 		parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
1393e3689190SBen Widawsky 		parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
1394e3689190SBen Widawsky 		parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
139535a85ac6SBen Widawsky 		parity_event[4] = kasprintf(GFP_KERNEL, "SLICE=%d", slice);
139635a85ac6SBen Widawsky 		parity_event[5] = NULL;
1397e3689190SBen Widawsky 
139891c8a326SChris Wilson 		kobject_uevent_env(&dev_priv->drm.primary->kdev->kobj,
1399e3689190SBen Widawsky 				   KOBJ_CHANGE, parity_event);
1400e3689190SBen Widawsky 
140135a85ac6SBen Widawsky 		DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n",
140235a85ac6SBen Widawsky 			  slice, row, bank, subbank);
1403e3689190SBen Widawsky 
140435a85ac6SBen Widawsky 		kfree(parity_event[4]);
1405e3689190SBen Widawsky 		kfree(parity_event[3]);
1406e3689190SBen Widawsky 		kfree(parity_event[2]);
1407e3689190SBen Widawsky 		kfree(parity_event[1]);
1408e3689190SBen Widawsky 	}
1409e3689190SBen Widawsky 
141035a85ac6SBen Widawsky 	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
141135a85ac6SBen Widawsky 
141235a85ac6SBen Widawsky out:
141335a85ac6SBen Widawsky 	WARN_ON(dev_priv->l3_parity.which_slice);
14144cb21832SDaniel Vetter 	spin_lock_irq(&dev_priv->irq_lock);
14152d1fe073SJoonas Lahtinen 	gen5_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv));
14164cb21832SDaniel Vetter 	spin_unlock_irq(&dev_priv->irq_lock);
141735a85ac6SBen Widawsky 
141891c8a326SChris Wilson 	mutex_unlock(&dev_priv->drm.struct_mutex);
141935a85ac6SBen Widawsky }
142035a85ac6SBen Widawsky 
1421261e40b8SVille Syrjälä static void ivybridge_parity_error_irq_handler(struct drm_i915_private *dev_priv,
1422261e40b8SVille Syrjälä 					       u32 iir)
1423e3689190SBen Widawsky {
1424261e40b8SVille Syrjälä 	if (!HAS_L3_DPF(dev_priv))
1425e3689190SBen Widawsky 		return;
1426e3689190SBen Widawsky 
1427d0ecd7e2SDaniel Vetter 	spin_lock(&dev_priv->irq_lock);
1428261e40b8SVille Syrjälä 	gen5_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv));
1429d0ecd7e2SDaniel Vetter 	spin_unlock(&dev_priv->irq_lock);
1430e3689190SBen Widawsky 
1431261e40b8SVille Syrjälä 	iir &= GT_PARITY_ERROR(dev_priv);
143235a85ac6SBen Widawsky 	if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1)
143335a85ac6SBen Widawsky 		dev_priv->l3_parity.which_slice |= 1 << 1;
143435a85ac6SBen Widawsky 
143535a85ac6SBen Widawsky 	if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
143635a85ac6SBen Widawsky 		dev_priv->l3_parity.which_slice |= 1 << 0;
143735a85ac6SBen Widawsky 
1438a4da4fa4SDaniel Vetter 	queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
1439e3689190SBen Widawsky }
1440e3689190SBen Widawsky 
1441261e40b8SVille Syrjälä static void ilk_gt_irq_handler(struct drm_i915_private *dev_priv,
1442f1af8fc1SPaulo Zanoni 			       u32 gt_iir)
1443f1af8fc1SPaulo Zanoni {
1444f8973c21SChris Wilson 	if (gt_iir & GT_RENDER_USER_INTERRUPT)
14453b3f1650SAkash Goel 		notify_ring(dev_priv->engine[RCS]);
1446f1af8fc1SPaulo Zanoni 	if (gt_iir & ILK_BSD_USER_INTERRUPT)
14473b3f1650SAkash Goel 		notify_ring(dev_priv->engine[VCS]);
1448f1af8fc1SPaulo Zanoni }
1449f1af8fc1SPaulo Zanoni 
1450261e40b8SVille Syrjälä static void snb_gt_irq_handler(struct drm_i915_private *dev_priv,
1451e7b4c6b1SDaniel Vetter 			       u32 gt_iir)
1452e7b4c6b1SDaniel Vetter {
1453f8973c21SChris Wilson 	if (gt_iir & GT_RENDER_USER_INTERRUPT)
14543b3f1650SAkash Goel 		notify_ring(dev_priv->engine[RCS]);
1455cc609d5dSBen Widawsky 	if (gt_iir & GT_BSD_USER_INTERRUPT)
14563b3f1650SAkash Goel 		notify_ring(dev_priv->engine[VCS]);
1457cc609d5dSBen Widawsky 	if (gt_iir & GT_BLT_USER_INTERRUPT)
14583b3f1650SAkash Goel 		notify_ring(dev_priv->engine[BCS]);
1459e7b4c6b1SDaniel Vetter 
1460cc609d5dSBen Widawsky 	if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
1461cc609d5dSBen Widawsky 		      GT_BSD_CS_ERROR_INTERRUPT |
1462aaecdf61SDaniel Vetter 		      GT_RENDER_CS_MASTER_ERROR_INTERRUPT))
1463aaecdf61SDaniel Vetter 		DRM_DEBUG("Command parser error, gt_iir 0x%08x\n", gt_iir);
1464e3689190SBen Widawsky 
1465261e40b8SVille Syrjälä 	if (gt_iir & GT_PARITY_ERROR(dev_priv))
1466261e40b8SVille Syrjälä 		ivybridge_parity_error_irq_handler(dev_priv, gt_iir);
1467e7b4c6b1SDaniel Vetter }
1468e7b4c6b1SDaniel Vetter 
14695d3d69d5SChris Wilson static void
147051f6b0f9SChris Wilson gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir)
1471fbcc1a0cSNick Hoath {
1472b620e870SMika Kuoppala 	struct intel_engine_execlists * const execlists = &engine->execlists;
147331de7350SChris Wilson 	bool tasklet = false;
1474f747026cSChris Wilson 
147551f6b0f9SChris Wilson 	if (iir & GT_CONTEXT_SWITCH_INTERRUPT) {
14761c645bf4SChris Wilson 		if (READ_ONCE(engine->execlists.active))
14771c645bf4SChris Wilson 			tasklet = !test_and_set_bit(ENGINE_IRQ_EXECLIST,
14781c645bf4SChris Wilson 						    &engine->irq_posted);
14794a118ecbSChris Wilson 	}
148031de7350SChris Wilson 
148151f6b0f9SChris Wilson 	if (iir & GT_RENDER_USER_INTERRUPT) {
148231de7350SChris Wilson 		notify_ring(engine);
148393ffbe8eSMichal Wajdeczko 		tasklet |= USES_GUC_SUBMISSION(engine->i915);
148431de7350SChris Wilson 	}
148531de7350SChris Wilson 
148631de7350SChris Wilson 	if (tasklet)
1487c6dce8f1SSagar Arun Kamble 		tasklet_hi_schedule(&execlists->tasklet);
1488fbcc1a0cSNick Hoath }
1489fbcc1a0cSNick Hoath 
14902e4a5b25SChris Wilson static void gen8_gt_irq_ack(struct drm_i915_private *i915,
149155ef72f2SChris Wilson 			    u32 master_ctl, u32 gt_iir[4])
1492abd58f01SBen Widawsky {
14932e4a5b25SChris Wilson 	void __iomem * const regs = i915->regs;
14942e4a5b25SChris Wilson 
1495f0fd96f5SChris Wilson #define GEN8_GT_IRQS (GEN8_GT_RCS_IRQ | \
1496f0fd96f5SChris Wilson 		      GEN8_GT_BCS_IRQ | \
1497f0fd96f5SChris Wilson 		      GEN8_GT_VCS1_IRQ | \
1498f0fd96f5SChris Wilson 		      GEN8_GT_VCS2_IRQ | \
1499f0fd96f5SChris Wilson 		      GEN8_GT_VECS_IRQ | \
1500f0fd96f5SChris Wilson 		      GEN8_GT_PM_IRQ | \
1501f0fd96f5SChris Wilson 		      GEN8_GT_GUC_IRQ)
1502f0fd96f5SChris Wilson 
1503abd58f01SBen Widawsky 	if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
15042e4a5b25SChris Wilson 		gt_iir[0] = raw_reg_read(regs, GEN8_GT_IIR(0));
15052e4a5b25SChris Wilson 		if (likely(gt_iir[0]))
15062e4a5b25SChris Wilson 			raw_reg_write(regs, GEN8_GT_IIR(0), gt_iir[0]);
1507abd58f01SBen Widawsky 	}
1508abd58f01SBen Widawsky 
150985f9b5f9SZhao Yakui 	if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
15102e4a5b25SChris Wilson 		gt_iir[1] = raw_reg_read(regs, GEN8_GT_IIR(1));
15112e4a5b25SChris Wilson 		if (likely(gt_iir[1]))
15122e4a5b25SChris Wilson 			raw_reg_write(regs, GEN8_GT_IIR(1), gt_iir[1]);
151374cdb337SChris Wilson 	}
151474cdb337SChris Wilson 
151526705e20SSagar Arun Kamble 	if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
15162e4a5b25SChris Wilson 		gt_iir[2] = raw_reg_read(regs, GEN8_GT_IIR(2));
15172e4a5b25SChris Wilson 		if (likely(gt_iir[2] & (i915->pm_rps_events |
15182e4a5b25SChris Wilson 					i915->pm_guc_events)))
15192e4a5b25SChris Wilson 			raw_reg_write(regs, GEN8_GT_IIR(2),
15202e4a5b25SChris Wilson 				      gt_iir[2] & (i915->pm_rps_events |
15212e4a5b25SChris Wilson 						   i915->pm_guc_events));
15220961021aSBen Widawsky 	}
15232e4a5b25SChris Wilson 
15242e4a5b25SChris Wilson 	if (master_ctl & GEN8_GT_VECS_IRQ) {
15252e4a5b25SChris Wilson 		gt_iir[3] = raw_reg_read(regs, GEN8_GT_IIR(3));
15262e4a5b25SChris Wilson 		if (likely(gt_iir[3]))
15272e4a5b25SChris Wilson 			raw_reg_write(regs, GEN8_GT_IIR(3), gt_iir[3]);
152855ef72f2SChris Wilson 	}
1529abd58f01SBen Widawsky }
1530abd58f01SBen Widawsky 
15312e4a5b25SChris Wilson static void gen8_gt_irq_handler(struct drm_i915_private *i915,
1532f0fd96f5SChris Wilson 				u32 master_ctl, u32 gt_iir[4])
1533e30e251aSVille Syrjälä {
1534f0fd96f5SChris Wilson 	if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
15352e4a5b25SChris Wilson 		gen8_cs_irq_handler(i915->engine[RCS],
153651f6b0f9SChris Wilson 				    gt_iir[0] >> GEN8_RCS_IRQ_SHIFT);
15372e4a5b25SChris Wilson 		gen8_cs_irq_handler(i915->engine[BCS],
153851f6b0f9SChris Wilson 				    gt_iir[0] >> GEN8_BCS_IRQ_SHIFT);
1539e30e251aSVille Syrjälä 	}
1540e30e251aSVille Syrjälä 
1541f0fd96f5SChris Wilson 	if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
15422e4a5b25SChris Wilson 		gen8_cs_irq_handler(i915->engine[VCS],
154351f6b0f9SChris Wilson 				    gt_iir[1] >> GEN8_VCS1_IRQ_SHIFT);
15442e4a5b25SChris Wilson 		gen8_cs_irq_handler(i915->engine[VCS2],
154551f6b0f9SChris Wilson 				    gt_iir[1] >> GEN8_VCS2_IRQ_SHIFT);
1546e30e251aSVille Syrjälä 	}
1547e30e251aSVille Syrjälä 
1548f0fd96f5SChris Wilson 	if (master_ctl & GEN8_GT_VECS_IRQ) {
15492e4a5b25SChris Wilson 		gen8_cs_irq_handler(i915->engine[VECS],
155051f6b0f9SChris Wilson 				    gt_iir[3] >> GEN8_VECS_IRQ_SHIFT);
1551f0fd96f5SChris Wilson 	}
1552e30e251aSVille Syrjälä 
1553f0fd96f5SChris Wilson 	if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
15542e4a5b25SChris Wilson 		gen6_rps_irq_handler(i915, gt_iir[2]);
15552e4a5b25SChris Wilson 		gen9_guc_irq_handler(i915, gt_iir[2]);
1556e30e251aSVille Syrjälä 	}
1557f0fd96f5SChris Wilson }
1558e30e251aSVille Syrjälä 
1559121e758eSDhinakaran Pandiyan static bool gen11_port_hotplug_long_detect(enum port port, u32 val)
1560121e758eSDhinakaran Pandiyan {
1561121e758eSDhinakaran Pandiyan 	switch (port) {
1562121e758eSDhinakaran Pandiyan 	case PORT_C:
1563121e758eSDhinakaran Pandiyan 		return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC1);
1564121e758eSDhinakaran Pandiyan 	case PORT_D:
1565121e758eSDhinakaran Pandiyan 		return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC2);
1566121e758eSDhinakaran Pandiyan 	case PORT_E:
1567121e758eSDhinakaran Pandiyan 		return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC3);
1568121e758eSDhinakaran Pandiyan 	case PORT_F:
1569121e758eSDhinakaran Pandiyan 		return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4);
1570121e758eSDhinakaran Pandiyan 	default:
1571121e758eSDhinakaran Pandiyan 		return false;
1572121e758eSDhinakaran Pandiyan 	}
1573121e758eSDhinakaran Pandiyan }
1574121e758eSDhinakaran Pandiyan 
157563c88d22SImre Deak static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
157663c88d22SImre Deak {
157763c88d22SImre Deak 	switch (port) {
157863c88d22SImre Deak 	case PORT_A:
1579195baa06SVille Syrjälä 		return val & PORTA_HOTPLUG_LONG_DETECT;
158063c88d22SImre Deak 	case PORT_B:
158163c88d22SImre Deak 		return val & PORTB_HOTPLUG_LONG_DETECT;
158263c88d22SImre Deak 	case PORT_C:
158363c88d22SImre Deak 		return val & PORTC_HOTPLUG_LONG_DETECT;
158463c88d22SImre Deak 	default:
158563c88d22SImre Deak 		return false;
158663c88d22SImre Deak 	}
158763c88d22SImre Deak }
158863c88d22SImre Deak 
15896dbf30ceSVille Syrjälä static bool spt_port_hotplug2_long_detect(enum port port, u32 val)
15906dbf30ceSVille Syrjälä {
15916dbf30ceSVille Syrjälä 	switch (port) {
15926dbf30ceSVille Syrjälä 	case PORT_E:
15936dbf30ceSVille Syrjälä 		return val & PORTE_HOTPLUG_LONG_DETECT;
15946dbf30ceSVille Syrjälä 	default:
15956dbf30ceSVille Syrjälä 		return false;
15966dbf30ceSVille Syrjälä 	}
15976dbf30ceSVille Syrjälä }
15986dbf30ceSVille Syrjälä 
159974c0b395SVille Syrjälä static bool spt_port_hotplug_long_detect(enum port port, u32 val)
160074c0b395SVille Syrjälä {
160174c0b395SVille Syrjälä 	switch (port) {
160274c0b395SVille Syrjälä 	case PORT_A:
160374c0b395SVille Syrjälä 		return val & PORTA_HOTPLUG_LONG_DETECT;
160474c0b395SVille Syrjälä 	case PORT_B:
160574c0b395SVille Syrjälä 		return val & PORTB_HOTPLUG_LONG_DETECT;
160674c0b395SVille Syrjälä 	case PORT_C:
160774c0b395SVille Syrjälä 		return val & PORTC_HOTPLUG_LONG_DETECT;
160874c0b395SVille Syrjälä 	case PORT_D:
160974c0b395SVille Syrjälä 		return val & PORTD_HOTPLUG_LONG_DETECT;
161074c0b395SVille Syrjälä 	default:
161174c0b395SVille Syrjälä 		return false;
161274c0b395SVille Syrjälä 	}
161374c0b395SVille Syrjälä }
161474c0b395SVille Syrjälä 
1615e4ce95aaSVille Syrjälä static bool ilk_port_hotplug_long_detect(enum port port, u32 val)
1616e4ce95aaSVille Syrjälä {
1617e4ce95aaSVille Syrjälä 	switch (port) {
1618e4ce95aaSVille Syrjälä 	case PORT_A:
1619e4ce95aaSVille Syrjälä 		return val & DIGITAL_PORTA_HOTPLUG_LONG_DETECT;
1620e4ce95aaSVille Syrjälä 	default:
1621e4ce95aaSVille Syrjälä 		return false;
1622e4ce95aaSVille Syrjälä 	}
1623e4ce95aaSVille Syrjälä }
1624e4ce95aaSVille Syrjälä 
1625676574dfSJani Nikula static bool pch_port_hotplug_long_detect(enum port port, u32 val)
162613cf5504SDave Airlie {
162713cf5504SDave Airlie 	switch (port) {
162813cf5504SDave Airlie 	case PORT_B:
1629676574dfSJani Nikula 		return val & PORTB_HOTPLUG_LONG_DETECT;
163013cf5504SDave Airlie 	case PORT_C:
1631676574dfSJani Nikula 		return val & PORTC_HOTPLUG_LONG_DETECT;
163213cf5504SDave Airlie 	case PORT_D:
1633676574dfSJani Nikula 		return val & PORTD_HOTPLUG_LONG_DETECT;
1634676574dfSJani Nikula 	default:
1635676574dfSJani Nikula 		return false;
163613cf5504SDave Airlie 	}
163713cf5504SDave Airlie }
163813cf5504SDave Airlie 
1639676574dfSJani Nikula static bool i9xx_port_hotplug_long_detect(enum port port, u32 val)
164013cf5504SDave Airlie {
164113cf5504SDave Airlie 	switch (port) {
164213cf5504SDave Airlie 	case PORT_B:
1643676574dfSJani Nikula 		return val & PORTB_HOTPLUG_INT_LONG_PULSE;
164413cf5504SDave Airlie 	case PORT_C:
1645676574dfSJani Nikula 		return val & PORTC_HOTPLUG_INT_LONG_PULSE;
164613cf5504SDave Airlie 	case PORT_D:
1647676574dfSJani Nikula 		return val & PORTD_HOTPLUG_INT_LONG_PULSE;
1648676574dfSJani Nikula 	default:
1649676574dfSJani Nikula 		return false;
165013cf5504SDave Airlie 	}
165113cf5504SDave Airlie }
165213cf5504SDave Airlie 
165342db67d6SVille Syrjälä /*
165442db67d6SVille Syrjälä  * Get a bit mask of pins that have triggered, and which ones may be long.
165542db67d6SVille Syrjälä  * This can be called multiple times with the same masks to accumulate
165642db67d6SVille Syrjälä  * hotplug detection results from several registers.
165742db67d6SVille Syrjälä  *
165842db67d6SVille Syrjälä  * Note that the caller is expected to zero out the masks initially.
165942db67d6SVille Syrjälä  */
1660cf53902fSRodrigo Vivi static void intel_get_hpd_pins(struct drm_i915_private *dev_priv,
1661cf53902fSRodrigo Vivi 			       u32 *pin_mask, u32 *long_mask,
16628c841e57SJani Nikula 			       u32 hotplug_trigger, u32 dig_hotplug_reg,
1663fd63e2a9SImre Deak 			       const u32 hpd[HPD_NUM_PINS],
1664fd63e2a9SImre Deak 			       bool long_pulse_detect(enum port port, u32 val))
1665676574dfSJani Nikula {
16668c841e57SJani Nikula 	enum port port;
1667676574dfSJani Nikula 	int i;
1668676574dfSJani Nikula 
1669676574dfSJani Nikula 	for_each_hpd_pin(i) {
16708c841e57SJani Nikula 		if ((hpd[i] & hotplug_trigger) == 0)
16718c841e57SJani Nikula 			continue;
16728c841e57SJani Nikula 
1673676574dfSJani Nikula 		*pin_mask |= BIT(i);
1674676574dfSJani Nikula 
1675cf53902fSRodrigo Vivi 		port = intel_hpd_pin_to_port(dev_priv, i);
1676256cfddeSRodrigo Vivi 		if (port == PORT_NONE)
1677cc24fcdcSImre Deak 			continue;
1678cc24fcdcSImre Deak 
1679fd63e2a9SImre Deak 		if (long_pulse_detect(port, dig_hotplug_reg))
1680676574dfSJani Nikula 			*long_mask |= BIT(i);
1681676574dfSJani Nikula 	}
1682676574dfSJani Nikula 
1683676574dfSJani Nikula 	DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x\n",
1684676574dfSJani Nikula 			 hotplug_trigger, dig_hotplug_reg, *pin_mask);
1685676574dfSJani Nikula 
1686676574dfSJani Nikula }
1687676574dfSJani Nikula 
168891d14251STvrtko Ursulin static void gmbus_irq_handler(struct drm_i915_private *dev_priv)
1689515ac2bbSDaniel Vetter {
169028c70f16SDaniel Vetter 	wake_up_all(&dev_priv->gmbus_wait_queue);
1691515ac2bbSDaniel Vetter }
1692515ac2bbSDaniel Vetter 
169391d14251STvrtko Ursulin static void dp_aux_irq_handler(struct drm_i915_private *dev_priv)
1694ce99c256SDaniel Vetter {
16959ee32feaSDaniel Vetter 	wake_up_all(&dev_priv->gmbus_wait_queue);
1696ce99c256SDaniel Vetter }
1697ce99c256SDaniel Vetter 
16988bf1e9f1SShuang He #if defined(CONFIG_DEBUG_FS)
169991d14251STvrtko Ursulin static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
170091d14251STvrtko Ursulin 					 enum pipe pipe,
1701eba94eb9SDaniel Vetter 					 uint32_t crc0, uint32_t crc1,
1702eba94eb9SDaniel Vetter 					 uint32_t crc2, uint32_t crc3,
17038bc5e955SDaniel Vetter 					 uint32_t crc4)
17048bf1e9f1SShuang He {
17058bf1e9f1SShuang He 	struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
17068bf1e9f1SShuang He 	struct intel_pipe_crc_entry *entry;
17078c6b709dSTomeu Vizoso 	struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
17088c6b709dSTomeu Vizoso 	struct drm_driver *driver = dev_priv->drm.driver;
17098c6b709dSTomeu Vizoso 	uint32_t crcs[5];
1710ac2300d4SDamien Lespiau 	int head, tail;
1711b2c88f5bSDamien Lespiau 
1712d538bbdfSDamien Lespiau 	spin_lock(&pipe_crc->lock);
1713033b7a23SMaarten Lankhorst 	if (pipe_crc->source && !crtc->base.crc.opened) {
17140c912c79SDamien Lespiau 		if (!pipe_crc->entries) {
1715d538bbdfSDamien Lespiau 			spin_unlock(&pipe_crc->lock);
171634273620SDaniel Vetter 			DRM_DEBUG_KMS("spurious interrupt\n");
17170c912c79SDamien Lespiau 			return;
17180c912c79SDamien Lespiau 		}
17190c912c79SDamien Lespiau 
1720d538bbdfSDamien Lespiau 		head = pipe_crc->head;
1721d538bbdfSDamien Lespiau 		tail = pipe_crc->tail;
1722b2c88f5bSDamien Lespiau 
1723b2c88f5bSDamien Lespiau 		if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) {
1724d538bbdfSDamien Lespiau 			spin_unlock(&pipe_crc->lock);
1725b2c88f5bSDamien Lespiau 			DRM_ERROR("CRC buffer overflowing\n");
1726b2c88f5bSDamien Lespiau 			return;
1727b2c88f5bSDamien Lespiau 		}
1728b2c88f5bSDamien Lespiau 
1729b2c88f5bSDamien Lespiau 		entry = &pipe_crc->entries[head];
17308bf1e9f1SShuang He 
17318c6b709dSTomeu Vizoso 		entry->frame = driver->get_vblank_counter(&dev_priv->drm, pipe);
1732eba94eb9SDaniel Vetter 		entry->crc[0] = crc0;
1733eba94eb9SDaniel Vetter 		entry->crc[1] = crc1;
1734eba94eb9SDaniel Vetter 		entry->crc[2] = crc2;
1735eba94eb9SDaniel Vetter 		entry->crc[3] = crc3;
1736eba94eb9SDaniel Vetter 		entry->crc[4] = crc4;
1737b2c88f5bSDamien Lespiau 
1738b2c88f5bSDamien Lespiau 		head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
1739d538bbdfSDamien Lespiau 		pipe_crc->head = head;
1740d538bbdfSDamien Lespiau 
1741d538bbdfSDamien Lespiau 		spin_unlock(&pipe_crc->lock);
174207144428SDamien Lespiau 
174307144428SDamien Lespiau 		wake_up_interruptible(&pipe_crc->wq);
17448c6b709dSTomeu Vizoso 	} else {
17458c6b709dSTomeu Vizoso 		/*
17468c6b709dSTomeu Vizoso 		 * For some not yet identified reason, the first CRC is
17478c6b709dSTomeu Vizoso 		 * bonkers. So let's just wait for the next vblank and read
17488c6b709dSTomeu Vizoso 		 * out the buggy result.
17498c6b709dSTomeu Vizoso 		 *
1750163e8aecSRodrigo Vivi 		 * On GEN8+ sometimes the second CRC is bonkers as well, so
17518c6b709dSTomeu Vizoso 		 * don't trust that one either.
17528c6b709dSTomeu Vizoso 		 */
1753033b7a23SMaarten Lankhorst 		if (pipe_crc->skipped <= 0 ||
1754163e8aecSRodrigo Vivi 		    (INTEL_GEN(dev_priv) >= 8 && pipe_crc->skipped == 1)) {
17558c6b709dSTomeu Vizoso 			pipe_crc->skipped++;
17568c6b709dSTomeu Vizoso 			spin_unlock(&pipe_crc->lock);
17578c6b709dSTomeu Vizoso 			return;
17588c6b709dSTomeu Vizoso 		}
17598c6b709dSTomeu Vizoso 		spin_unlock(&pipe_crc->lock);
17608c6b709dSTomeu Vizoso 		crcs[0] = crc0;
17618c6b709dSTomeu Vizoso 		crcs[1] = crc1;
17628c6b709dSTomeu Vizoso 		crcs[2] = crc2;
17638c6b709dSTomeu Vizoso 		crcs[3] = crc3;
17648c6b709dSTomeu Vizoso 		crcs[4] = crc4;
1765246ee524STomeu Vizoso 		drm_crtc_add_crc_entry(&crtc->base, true,
1766ca814b25SDaniel Vetter 				       drm_crtc_accurate_vblank_count(&crtc->base),
1767246ee524STomeu Vizoso 				       crcs);
17688c6b709dSTomeu Vizoso 	}
17698bf1e9f1SShuang He }
1770277de95eSDaniel Vetter #else
1771277de95eSDaniel Vetter static inline void
177291d14251STvrtko Ursulin display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
177391d14251STvrtko Ursulin 			     enum pipe pipe,
1774277de95eSDaniel Vetter 			     uint32_t crc0, uint32_t crc1,
1775277de95eSDaniel Vetter 			     uint32_t crc2, uint32_t crc3,
1776277de95eSDaniel Vetter 			     uint32_t crc4) {}
1777277de95eSDaniel Vetter #endif
1778eba94eb9SDaniel Vetter 
1779277de95eSDaniel Vetter 
178091d14251STvrtko Ursulin static void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
178191d14251STvrtko Ursulin 				     enum pipe pipe)
17825a69b89fSDaniel Vetter {
178391d14251STvrtko Ursulin 	display_pipe_crc_irq_handler(dev_priv, pipe,
17845a69b89fSDaniel Vetter 				     I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
17855a69b89fSDaniel Vetter 				     0, 0, 0, 0);
17865a69b89fSDaniel Vetter }
17875a69b89fSDaniel Vetter 
178891d14251STvrtko Ursulin static void ivb_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
178991d14251STvrtko Ursulin 				     enum pipe pipe)
1790eba94eb9SDaniel Vetter {
179191d14251STvrtko Ursulin 	display_pipe_crc_irq_handler(dev_priv, pipe,
1792eba94eb9SDaniel Vetter 				     I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
1793eba94eb9SDaniel Vetter 				     I915_READ(PIPE_CRC_RES_2_IVB(pipe)),
1794eba94eb9SDaniel Vetter 				     I915_READ(PIPE_CRC_RES_3_IVB(pipe)),
1795eba94eb9SDaniel Vetter 				     I915_READ(PIPE_CRC_RES_4_IVB(pipe)),
17968bc5e955SDaniel Vetter 				     I915_READ(PIPE_CRC_RES_5_IVB(pipe)));
1797eba94eb9SDaniel Vetter }
17985b3a856bSDaniel Vetter 
179991d14251STvrtko Ursulin static void i9xx_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
180091d14251STvrtko Ursulin 				      enum pipe pipe)
18015b3a856bSDaniel Vetter {
18020b5c5ed0SDaniel Vetter 	uint32_t res1, res2;
18030b5c5ed0SDaniel Vetter 
180491d14251STvrtko Ursulin 	if (INTEL_GEN(dev_priv) >= 3)
18050b5c5ed0SDaniel Vetter 		res1 = I915_READ(PIPE_CRC_RES_RES1_I915(pipe));
18060b5c5ed0SDaniel Vetter 	else
18070b5c5ed0SDaniel Vetter 		res1 = 0;
18080b5c5ed0SDaniel Vetter 
180991d14251STvrtko Ursulin 	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
18100b5c5ed0SDaniel Vetter 		res2 = I915_READ(PIPE_CRC_RES_RES2_G4X(pipe));
18110b5c5ed0SDaniel Vetter 	else
18120b5c5ed0SDaniel Vetter 		res2 = 0;
18135b3a856bSDaniel Vetter 
181491d14251STvrtko Ursulin 	display_pipe_crc_irq_handler(dev_priv, pipe,
18150b5c5ed0SDaniel Vetter 				     I915_READ(PIPE_CRC_RES_RED(pipe)),
18160b5c5ed0SDaniel Vetter 				     I915_READ(PIPE_CRC_RES_GREEN(pipe)),
18170b5c5ed0SDaniel Vetter 				     I915_READ(PIPE_CRC_RES_BLUE(pipe)),
18180b5c5ed0SDaniel Vetter 				     res1, res2);
18195b3a856bSDaniel Vetter }
18208bf1e9f1SShuang He 
18211403c0d4SPaulo Zanoni /* The RPS events need forcewake, so we add them to a work queue and mask their
18221403c0d4SPaulo Zanoni  * IMR bits until the work is done. Other interrupts can be processed without
18231403c0d4SPaulo Zanoni  * the work queue. */
18241403c0d4SPaulo Zanoni static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
1825baf02a1fSBen Widawsky {
1826562d9baeSSagar Arun Kamble 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
1827562d9baeSSagar Arun Kamble 
1828a6706b45SDeepak S 	if (pm_iir & dev_priv->pm_rps_events) {
182959cdb63dSDaniel Vetter 		spin_lock(&dev_priv->irq_lock);
1830f4e9af4fSAkash Goel 		gen6_mask_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
1831562d9baeSSagar Arun Kamble 		if (rps->interrupts_enabled) {
1832562d9baeSSagar Arun Kamble 			rps->pm_iir |= pm_iir & dev_priv->pm_rps_events;
1833562d9baeSSagar Arun Kamble 			schedule_work(&rps->work);
183441a05a3aSDaniel Vetter 		}
1835d4d70aa5SImre Deak 		spin_unlock(&dev_priv->irq_lock);
1836d4d70aa5SImre Deak 	}
1837baf02a1fSBen Widawsky 
1838bca2bf2aSPandiyan, Dhinakaran 	if (INTEL_GEN(dev_priv) >= 8)
1839c9a9a268SImre Deak 		return;
1840c9a9a268SImre Deak 
18412d1fe073SJoonas Lahtinen 	if (HAS_VEBOX(dev_priv)) {
184212638c57SBen Widawsky 		if (pm_iir & PM_VEBOX_USER_INTERRUPT)
18433b3f1650SAkash Goel 			notify_ring(dev_priv->engine[VECS]);
184412638c57SBen Widawsky 
1845aaecdf61SDaniel Vetter 		if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT)
1846aaecdf61SDaniel Vetter 			DRM_DEBUG("Command parser error, pm_iir 0x%08x\n", pm_iir);
184712638c57SBen Widawsky 	}
18481403c0d4SPaulo Zanoni }
1849baf02a1fSBen Widawsky 
185026705e20SSagar Arun Kamble static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
185126705e20SSagar Arun Kamble {
185293bf8096SMichal Wajdeczko 	if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT)
185393bf8096SMichal Wajdeczko 		intel_guc_to_host_event_handler(&dev_priv->guc);
185426705e20SSagar Arun Kamble }
185526705e20SSagar Arun Kamble 
185644d9241eSVille Syrjälä static void i9xx_pipestat_irq_reset(struct drm_i915_private *dev_priv)
185744d9241eSVille Syrjälä {
185844d9241eSVille Syrjälä 	enum pipe pipe;
185944d9241eSVille Syrjälä 
186044d9241eSVille Syrjälä 	for_each_pipe(dev_priv, pipe) {
186144d9241eSVille Syrjälä 		I915_WRITE(PIPESTAT(pipe),
186244d9241eSVille Syrjälä 			   PIPESTAT_INT_STATUS_MASK |
186344d9241eSVille Syrjälä 			   PIPE_FIFO_UNDERRUN_STATUS);
186444d9241eSVille Syrjälä 
186544d9241eSVille Syrjälä 		dev_priv->pipestat_irq_mask[pipe] = 0;
186644d9241eSVille Syrjälä 	}
186744d9241eSVille Syrjälä }
186844d9241eSVille Syrjälä 
1869eb64343cSVille Syrjälä static void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv,
187091d14251STvrtko Ursulin 				  u32 iir, u32 pipe_stats[I915_MAX_PIPES])
18717e231dbeSJesse Barnes {
18727e231dbeSJesse Barnes 	int pipe;
18737e231dbeSJesse Barnes 
187458ead0d7SImre Deak 	spin_lock(&dev_priv->irq_lock);
18751ca993d2SVille Syrjälä 
18761ca993d2SVille Syrjälä 	if (!dev_priv->display_irqs_enabled) {
18771ca993d2SVille Syrjälä 		spin_unlock(&dev_priv->irq_lock);
18781ca993d2SVille Syrjälä 		return;
18791ca993d2SVille Syrjälä 	}
18801ca993d2SVille Syrjälä 
1881055e393fSDamien Lespiau 	for_each_pipe(dev_priv, pipe) {
1882f0f59a00SVille Syrjälä 		i915_reg_t reg;
18836b12ca56SVille Syrjälä 		u32 status_mask, enable_mask, iir_bit = 0;
188491d181ddSImre Deak 
1885bbb5eebfSDaniel Vetter 		/*
1886bbb5eebfSDaniel Vetter 		 * PIPESTAT bits get signalled even when the interrupt is
1887bbb5eebfSDaniel Vetter 		 * disabled with the mask bits, and some of the status bits do
1888bbb5eebfSDaniel Vetter 		 * not generate interrupts at all (like the underrun bit). Hence
1889bbb5eebfSDaniel Vetter 		 * we need to be careful that we only handle what we want to
1890bbb5eebfSDaniel Vetter 		 * handle.
1891bbb5eebfSDaniel Vetter 		 */
18920f239f4cSDaniel Vetter 
18930f239f4cSDaniel Vetter 		/* fifo underruns are filterered in the underrun handler. */
18946b12ca56SVille Syrjälä 		status_mask = PIPE_FIFO_UNDERRUN_STATUS;
1895bbb5eebfSDaniel Vetter 
1896bbb5eebfSDaniel Vetter 		switch (pipe) {
1897bbb5eebfSDaniel Vetter 		case PIPE_A:
1898bbb5eebfSDaniel Vetter 			iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
1899bbb5eebfSDaniel Vetter 			break;
1900bbb5eebfSDaniel Vetter 		case PIPE_B:
1901bbb5eebfSDaniel Vetter 			iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
1902bbb5eebfSDaniel Vetter 			break;
19033278f67fSVille Syrjälä 		case PIPE_C:
19043278f67fSVille Syrjälä 			iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
19053278f67fSVille Syrjälä 			break;
1906bbb5eebfSDaniel Vetter 		}
1907bbb5eebfSDaniel Vetter 		if (iir & iir_bit)
19086b12ca56SVille Syrjälä 			status_mask |= dev_priv->pipestat_irq_mask[pipe];
1909bbb5eebfSDaniel Vetter 
19106b12ca56SVille Syrjälä 		if (!status_mask)
191191d181ddSImre Deak 			continue;
191291d181ddSImre Deak 
191391d181ddSImre Deak 		reg = PIPESTAT(pipe);
19146b12ca56SVille Syrjälä 		pipe_stats[pipe] = I915_READ(reg) & status_mask;
19156b12ca56SVille Syrjälä 		enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
19167e231dbeSJesse Barnes 
19177e231dbeSJesse Barnes 		/*
19187e231dbeSJesse Barnes 		 * Clear the PIPE*STAT regs before the IIR
1919132c27c9SVille Syrjälä 		 *
1920132c27c9SVille Syrjälä 		 * Toggle the enable bits to make sure we get an
1921132c27c9SVille Syrjälä 		 * edge in the ISR pipe event bit if we don't clear
1922132c27c9SVille Syrjälä 		 * all the enabled status bits. Otherwise the edge
1923132c27c9SVille Syrjälä 		 * triggered IIR on i965/g4x wouldn't notice that
1924132c27c9SVille Syrjälä 		 * an interrupt is still pending.
19257e231dbeSJesse Barnes 		 */
1926132c27c9SVille Syrjälä 		if (pipe_stats[pipe]) {
1927132c27c9SVille Syrjälä 			I915_WRITE(reg, pipe_stats[pipe]);
1928132c27c9SVille Syrjälä 			I915_WRITE(reg, enable_mask);
1929132c27c9SVille Syrjälä 		}
19307e231dbeSJesse Barnes 	}
193158ead0d7SImre Deak 	spin_unlock(&dev_priv->irq_lock);
19322ecb8ca4SVille Syrjälä }
19332ecb8ca4SVille Syrjälä 
1934eb64343cSVille Syrjälä static void i8xx_pipestat_irq_handler(struct drm_i915_private *dev_priv,
1935eb64343cSVille Syrjälä 				      u16 iir, u32 pipe_stats[I915_MAX_PIPES])
1936eb64343cSVille Syrjälä {
1937eb64343cSVille Syrjälä 	enum pipe pipe;
1938eb64343cSVille Syrjälä 
1939eb64343cSVille Syrjälä 	for_each_pipe(dev_priv, pipe) {
1940eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
1941eb64343cSVille Syrjälä 			drm_handle_vblank(&dev_priv->drm, pipe);
1942eb64343cSVille Syrjälä 
1943eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
1944eb64343cSVille Syrjälä 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
1945eb64343cSVille Syrjälä 
1946eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
1947eb64343cSVille Syrjälä 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
1948eb64343cSVille Syrjälä 	}
1949eb64343cSVille Syrjälä }
1950eb64343cSVille Syrjälä 
1951eb64343cSVille Syrjälä static void i915_pipestat_irq_handler(struct drm_i915_private *dev_priv,
1952eb64343cSVille Syrjälä 				      u32 iir, u32 pipe_stats[I915_MAX_PIPES])
1953eb64343cSVille Syrjälä {
1954eb64343cSVille Syrjälä 	bool blc_event = false;
1955eb64343cSVille Syrjälä 	enum pipe pipe;
1956eb64343cSVille Syrjälä 
1957eb64343cSVille Syrjälä 	for_each_pipe(dev_priv, pipe) {
1958eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
1959eb64343cSVille Syrjälä 			drm_handle_vblank(&dev_priv->drm, pipe);
1960eb64343cSVille Syrjälä 
1961eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
1962eb64343cSVille Syrjälä 			blc_event = true;
1963eb64343cSVille Syrjälä 
1964eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
1965eb64343cSVille Syrjälä 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
1966eb64343cSVille Syrjälä 
1967eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
1968eb64343cSVille Syrjälä 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
1969eb64343cSVille Syrjälä 	}
1970eb64343cSVille Syrjälä 
1971eb64343cSVille Syrjälä 	if (blc_event || (iir & I915_ASLE_INTERRUPT))
1972eb64343cSVille Syrjälä 		intel_opregion_asle_intr(dev_priv);
1973eb64343cSVille Syrjälä }
1974eb64343cSVille Syrjälä 
1975eb64343cSVille Syrjälä static void i965_pipestat_irq_handler(struct drm_i915_private *dev_priv,
1976eb64343cSVille Syrjälä 				      u32 iir, u32 pipe_stats[I915_MAX_PIPES])
1977eb64343cSVille Syrjälä {
1978eb64343cSVille Syrjälä 	bool blc_event = false;
1979eb64343cSVille Syrjälä 	enum pipe pipe;
1980eb64343cSVille Syrjälä 
1981eb64343cSVille Syrjälä 	for_each_pipe(dev_priv, pipe) {
1982eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
1983eb64343cSVille Syrjälä 			drm_handle_vblank(&dev_priv->drm, pipe);
1984eb64343cSVille Syrjälä 
1985eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
1986eb64343cSVille Syrjälä 			blc_event = true;
1987eb64343cSVille Syrjälä 
1988eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
1989eb64343cSVille Syrjälä 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
1990eb64343cSVille Syrjälä 
1991eb64343cSVille Syrjälä 		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
1992eb64343cSVille Syrjälä 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
1993eb64343cSVille Syrjälä 	}
1994eb64343cSVille Syrjälä 
1995eb64343cSVille Syrjälä 	if (blc_event || (iir & I915_ASLE_INTERRUPT))
1996eb64343cSVille Syrjälä 		intel_opregion_asle_intr(dev_priv);
1997eb64343cSVille Syrjälä 
1998eb64343cSVille Syrjälä 	if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
1999eb64343cSVille Syrjälä 		gmbus_irq_handler(dev_priv);
2000eb64343cSVille Syrjälä }
2001eb64343cSVille Syrjälä 
200291d14251STvrtko Ursulin static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
20032ecb8ca4SVille Syrjälä 					    u32 pipe_stats[I915_MAX_PIPES])
20042ecb8ca4SVille Syrjälä {
20052ecb8ca4SVille Syrjälä 	enum pipe pipe;
20067e231dbeSJesse Barnes 
2007055e393fSDamien Lespiau 	for_each_pipe(dev_priv, pipe) {
2008fd3a4024SDaniel Vetter 		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
2009fd3a4024SDaniel Vetter 			drm_handle_vblank(&dev_priv->drm, pipe);
20104356d586SDaniel Vetter 
20114356d586SDaniel Vetter 		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
201291d14251STvrtko Ursulin 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
20132d9d2b0bSVille Syrjälä 
20141f7247c0SDaniel Vetter 		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
20151f7247c0SDaniel Vetter 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
201631acc7f5SJesse Barnes 	}
201731acc7f5SJesse Barnes 
2018c1874ed7SImre Deak 	if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
201991d14251STvrtko Ursulin 		gmbus_irq_handler(dev_priv);
2020c1874ed7SImre Deak }
2021c1874ed7SImre Deak 
20221ae3c34cSVille Syrjälä static u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv)
202316c6c56bSVille Syrjälä {
202416c6c56bSVille Syrjälä 	u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
202516c6c56bSVille Syrjälä 
20261ae3c34cSVille Syrjälä 	if (hotplug_status)
20273ff60f89SOscar Mateo 		I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
20281ae3c34cSVille Syrjälä 
20291ae3c34cSVille Syrjälä 	return hotplug_status;
20301ae3c34cSVille Syrjälä }
20311ae3c34cSVille Syrjälä 
203291d14251STvrtko Ursulin static void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv,
20331ae3c34cSVille Syrjälä 				 u32 hotplug_status)
20341ae3c34cSVille Syrjälä {
20351ae3c34cSVille Syrjälä 	u32 pin_mask = 0, long_mask = 0;
20363ff60f89SOscar Mateo 
203791d14251STvrtko Ursulin 	if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) ||
203891d14251STvrtko Ursulin 	    IS_CHERRYVIEW(dev_priv)) {
203916c6c56bSVille Syrjälä 		u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
204016c6c56bSVille Syrjälä 
204158f2cf24SVille Syrjälä 		if (hotplug_trigger) {
2042cf53902fSRodrigo Vivi 			intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
2043cf53902fSRodrigo Vivi 					   hotplug_trigger, hotplug_trigger,
2044cf53902fSRodrigo Vivi 					   hpd_status_g4x,
2045fd63e2a9SImre Deak 					   i9xx_port_hotplug_long_detect);
204658f2cf24SVille Syrjälä 
204791d14251STvrtko Ursulin 			intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
204858f2cf24SVille Syrjälä 		}
2049369712e8SJani Nikula 
2050369712e8SJani Nikula 		if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
205191d14251STvrtko Ursulin 			dp_aux_irq_handler(dev_priv);
205216c6c56bSVille Syrjälä 	} else {
205316c6c56bSVille Syrjälä 		u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
205416c6c56bSVille Syrjälä 
205558f2cf24SVille Syrjälä 		if (hotplug_trigger) {
2056cf53902fSRodrigo Vivi 			intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
2057cf53902fSRodrigo Vivi 					   hotplug_trigger, hotplug_trigger,
2058cf53902fSRodrigo Vivi 					   hpd_status_i915,
2059fd63e2a9SImre Deak 					   i9xx_port_hotplug_long_detect);
206091d14251STvrtko Ursulin 			intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
206116c6c56bSVille Syrjälä 		}
20623ff60f89SOscar Mateo 	}
206358f2cf24SVille Syrjälä }
206416c6c56bSVille Syrjälä 
2065c1874ed7SImre Deak static irqreturn_t valleyview_irq_handler(int irq, void *arg)
2066c1874ed7SImre Deak {
206745a83f84SDaniel Vetter 	struct drm_device *dev = arg;
2068fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
2069c1874ed7SImre Deak 	irqreturn_t ret = IRQ_NONE;
2070c1874ed7SImre Deak 
20712dd2a883SImre Deak 	if (!intel_irqs_enabled(dev_priv))
20722dd2a883SImre Deak 		return IRQ_NONE;
20732dd2a883SImre Deak 
20741f814dacSImre Deak 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
20751f814dacSImre Deak 	disable_rpm_wakeref_asserts(dev_priv);
20761f814dacSImre Deak 
20771e1cace9SVille Syrjälä 	do {
20786e814800SVille Syrjälä 		u32 iir, gt_iir, pm_iir;
20792ecb8ca4SVille Syrjälä 		u32 pipe_stats[I915_MAX_PIPES] = {};
20801ae3c34cSVille Syrjälä 		u32 hotplug_status = 0;
2081a5e485a9SVille Syrjälä 		u32 ier = 0;
20823ff60f89SOscar Mateo 
2083c1874ed7SImre Deak 		gt_iir = I915_READ(GTIIR);
2084c1874ed7SImre Deak 		pm_iir = I915_READ(GEN6_PMIIR);
20853ff60f89SOscar Mateo 		iir = I915_READ(VLV_IIR);
2086c1874ed7SImre Deak 
2087c1874ed7SImre Deak 		if (gt_iir == 0 && pm_iir == 0 && iir == 0)
20881e1cace9SVille Syrjälä 			break;
2089c1874ed7SImre Deak 
2090c1874ed7SImre Deak 		ret = IRQ_HANDLED;
2091c1874ed7SImre Deak 
2092a5e485a9SVille Syrjälä 		/*
2093a5e485a9SVille Syrjälä 		 * Theory on interrupt generation, based on empirical evidence:
2094a5e485a9SVille Syrjälä 		 *
2095a5e485a9SVille Syrjälä 		 * x = ((VLV_IIR & VLV_IER) ||
2096a5e485a9SVille Syrjälä 		 *      (((GT_IIR & GT_IER) || (GEN6_PMIIR & GEN6_PMIER)) &&
2097a5e485a9SVille Syrjälä 		 *       (VLV_MASTER_IER & MASTER_INTERRUPT_ENABLE)));
2098a5e485a9SVille Syrjälä 		 *
2099a5e485a9SVille Syrjälä 		 * A CPU interrupt will only be raised when 'x' has a 0->1 edge.
2100a5e485a9SVille Syrjälä 		 * Hence we clear MASTER_INTERRUPT_ENABLE and VLV_IER to
2101a5e485a9SVille Syrjälä 		 * guarantee the CPU interrupt will be raised again even if we
2102a5e485a9SVille Syrjälä 		 * don't end up clearing all the VLV_IIR, GT_IIR, GEN6_PMIIR
2103a5e485a9SVille Syrjälä 		 * bits this time around.
2104a5e485a9SVille Syrjälä 		 */
21054a0a0202SVille Syrjälä 		I915_WRITE(VLV_MASTER_IER, 0);
2106a5e485a9SVille Syrjälä 		ier = I915_READ(VLV_IER);
2107a5e485a9SVille Syrjälä 		I915_WRITE(VLV_IER, 0);
21084a0a0202SVille Syrjälä 
21094a0a0202SVille Syrjälä 		if (gt_iir)
21104a0a0202SVille Syrjälä 			I915_WRITE(GTIIR, gt_iir);
21114a0a0202SVille Syrjälä 		if (pm_iir)
21124a0a0202SVille Syrjälä 			I915_WRITE(GEN6_PMIIR, pm_iir);
21134a0a0202SVille Syrjälä 
21147ce4d1f2SVille Syrjälä 		if (iir & I915_DISPLAY_PORT_INTERRUPT)
21151ae3c34cSVille Syrjälä 			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
21167ce4d1f2SVille Syrjälä 
21173ff60f89SOscar Mateo 		/* Call regardless, as some status bits might not be
21183ff60f89SOscar Mateo 		 * signalled in iir */
2119eb64343cSVille Syrjälä 		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
21207ce4d1f2SVille Syrjälä 
2121eef57324SJerome Anand 		if (iir & (I915_LPE_PIPE_A_INTERRUPT |
2122eef57324SJerome Anand 			   I915_LPE_PIPE_B_INTERRUPT))
2123eef57324SJerome Anand 			intel_lpe_audio_irq_handler(dev_priv);
2124eef57324SJerome Anand 
21257ce4d1f2SVille Syrjälä 		/*
21267ce4d1f2SVille Syrjälä 		 * VLV_IIR is single buffered, and reflects the level
21277ce4d1f2SVille Syrjälä 		 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
21287ce4d1f2SVille Syrjälä 		 */
21297ce4d1f2SVille Syrjälä 		if (iir)
21307ce4d1f2SVille Syrjälä 			I915_WRITE(VLV_IIR, iir);
21314a0a0202SVille Syrjälä 
2132a5e485a9SVille Syrjälä 		I915_WRITE(VLV_IER, ier);
21334a0a0202SVille Syrjälä 		I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
21344a0a0202SVille Syrjälä 		POSTING_READ(VLV_MASTER_IER);
21351ae3c34cSVille Syrjälä 
213652894874SVille Syrjälä 		if (gt_iir)
2137261e40b8SVille Syrjälä 			snb_gt_irq_handler(dev_priv, gt_iir);
213852894874SVille Syrjälä 		if (pm_iir)
213952894874SVille Syrjälä 			gen6_rps_irq_handler(dev_priv, pm_iir);
214052894874SVille Syrjälä 
21411ae3c34cSVille Syrjälä 		if (hotplug_status)
214291d14251STvrtko Ursulin 			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
21432ecb8ca4SVille Syrjälä 
214491d14251STvrtko Ursulin 		valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
21451e1cace9SVille Syrjälä 	} while (0);
21467e231dbeSJesse Barnes 
21471f814dacSImre Deak 	enable_rpm_wakeref_asserts(dev_priv);
21481f814dacSImre Deak 
21497e231dbeSJesse Barnes 	return ret;
21507e231dbeSJesse Barnes }
21517e231dbeSJesse Barnes 
215243f328d7SVille Syrjälä static irqreturn_t cherryview_irq_handler(int irq, void *arg)
215343f328d7SVille Syrjälä {
215445a83f84SDaniel Vetter 	struct drm_device *dev = arg;
2155fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
215643f328d7SVille Syrjälä 	irqreturn_t ret = IRQ_NONE;
215743f328d7SVille Syrjälä 
21582dd2a883SImre Deak 	if (!intel_irqs_enabled(dev_priv))
21592dd2a883SImre Deak 		return IRQ_NONE;
21602dd2a883SImre Deak 
21611f814dacSImre Deak 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
21621f814dacSImre Deak 	disable_rpm_wakeref_asserts(dev_priv);
21631f814dacSImre Deak 
2164579de73bSChris Wilson 	do {
21656e814800SVille Syrjälä 		u32 master_ctl, iir;
21662ecb8ca4SVille Syrjälä 		u32 pipe_stats[I915_MAX_PIPES] = {};
21671ae3c34cSVille Syrjälä 		u32 hotplug_status = 0;
2168f0fd96f5SChris Wilson 		u32 gt_iir[4];
2169a5e485a9SVille Syrjälä 		u32 ier = 0;
2170a5e485a9SVille Syrjälä 
21718e5fd599SVille Syrjälä 		master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
21723278f67fSVille Syrjälä 		iir = I915_READ(VLV_IIR);
21733278f67fSVille Syrjälä 
21743278f67fSVille Syrjälä 		if (master_ctl == 0 && iir == 0)
21758e5fd599SVille Syrjälä 			break;
217643f328d7SVille Syrjälä 
217727b6c122SOscar Mateo 		ret = IRQ_HANDLED;
217827b6c122SOscar Mateo 
2179a5e485a9SVille Syrjälä 		/*
2180a5e485a9SVille Syrjälä 		 * Theory on interrupt generation, based on empirical evidence:
2181a5e485a9SVille Syrjälä 		 *
2182a5e485a9SVille Syrjälä 		 * x = ((VLV_IIR & VLV_IER) ||
2183a5e485a9SVille Syrjälä 		 *      ((GEN8_MASTER_IRQ & ~GEN8_MASTER_IRQ_CONTROL) &&
2184a5e485a9SVille Syrjälä 		 *       (GEN8_MASTER_IRQ & GEN8_MASTER_IRQ_CONTROL)));
2185a5e485a9SVille Syrjälä 		 *
2186a5e485a9SVille Syrjälä 		 * A CPU interrupt will only be raised when 'x' has a 0->1 edge.
2187a5e485a9SVille Syrjälä 		 * Hence we clear GEN8_MASTER_IRQ_CONTROL and VLV_IER to
2188a5e485a9SVille Syrjälä 		 * guarantee the CPU interrupt will be raised again even if we
2189a5e485a9SVille Syrjälä 		 * don't end up clearing all the VLV_IIR and GEN8_MASTER_IRQ_CONTROL
2190a5e485a9SVille Syrjälä 		 * bits this time around.
2191a5e485a9SVille Syrjälä 		 */
219243f328d7SVille Syrjälä 		I915_WRITE(GEN8_MASTER_IRQ, 0);
2193a5e485a9SVille Syrjälä 		ier = I915_READ(VLV_IER);
2194a5e485a9SVille Syrjälä 		I915_WRITE(VLV_IER, 0);
219543f328d7SVille Syrjälä 
2196e30e251aSVille Syrjälä 		gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
219727b6c122SOscar Mateo 
219827b6c122SOscar Mateo 		if (iir & I915_DISPLAY_PORT_INTERRUPT)
21991ae3c34cSVille Syrjälä 			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
220043f328d7SVille Syrjälä 
220127b6c122SOscar Mateo 		/* Call regardless, as some status bits might not be
220227b6c122SOscar Mateo 		 * signalled in iir */
2203eb64343cSVille Syrjälä 		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
220443f328d7SVille Syrjälä 
2205eef57324SJerome Anand 		if (iir & (I915_LPE_PIPE_A_INTERRUPT |
2206eef57324SJerome Anand 			   I915_LPE_PIPE_B_INTERRUPT |
2207eef57324SJerome Anand 			   I915_LPE_PIPE_C_INTERRUPT))
2208eef57324SJerome Anand 			intel_lpe_audio_irq_handler(dev_priv);
2209eef57324SJerome Anand 
22107ce4d1f2SVille Syrjälä 		/*
22117ce4d1f2SVille Syrjälä 		 * VLV_IIR is single buffered, and reflects the level
22127ce4d1f2SVille Syrjälä 		 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
22137ce4d1f2SVille Syrjälä 		 */
22147ce4d1f2SVille Syrjälä 		if (iir)
22157ce4d1f2SVille Syrjälä 			I915_WRITE(VLV_IIR, iir);
22167ce4d1f2SVille Syrjälä 
2217a5e485a9SVille Syrjälä 		I915_WRITE(VLV_IER, ier);
2218e5328c43SVille Syrjälä 		I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
221943f328d7SVille Syrjälä 		POSTING_READ(GEN8_MASTER_IRQ);
22201ae3c34cSVille Syrjälä 
2221f0fd96f5SChris Wilson 		gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir);
2222e30e251aSVille Syrjälä 
22231ae3c34cSVille Syrjälä 		if (hotplug_status)
222491d14251STvrtko Ursulin 			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
22252ecb8ca4SVille Syrjälä 
222691d14251STvrtko Ursulin 		valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
2227579de73bSChris Wilson 	} while (0);
22283278f67fSVille Syrjälä 
22291f814dacSImre Deak 	enable_rpm_wakeref_asserts(dev_priv);
22301f814dacSImre Deak 
223143f328d7SVille Syrjälä 	return ret;
223243f328d7SVille Syrjälä }
223343f328d7SVille Syrjälä 
223491d14251STvrtko Ursulin static void ibx_hpd_irq_handler(struct drm_i915_private *dev_priv,
223591d14251STvrtko Ursulin 				u32 hotplug_trigger,
223640e56410SVille Syrjälä 				const u32 hpd[HPD_NUM_PINS])
2237776ad806SJesse Barnes {
223842db67d6SVille Syrjälä 	u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
2239776ad806SJesse Barnes 
22406a39d7c9SJani Nikula 	/*
22416a39d7c9SJani Nikula 	 * Somehow the PCH doesn't seem to really ack the interrupt to the CPU
22426a39d7c9SJani Nikula 	 * unless we touch the hotplug register, even if hotplug_trigger is
22436a39d7c9SJani Nikula 	 * zero. Not acking leads to "The master control interrupt lied (SDE)!"
22446a39d7c9SJani Nikula 	 * errors.
22456a39d7c9SJani Nikula 	 */
224613cf5504SDave Airlie 	dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
22476a39d7c9SJani Nikula 	if (!hotplug_trigger) {
22486a39d7c9SJani Nikula 		u32 mask = PORTA_HOTPLUG_STATUS_MASK |
22496a39d7c9SJani Nikula 			PORTD_HOTPLUG_STATUS_MASK |
22506a39d7c9SJani Nikula 			PORTC_HOTPLUG_STATUS_MASK |
22516a39d7c9SJani Nikula 			PORTB_HOTPLUG_STATUS_MASK;
22526a39d7c9SJani Nikula 		dig_hotplug_reg &= ~mask;
22536a39d7c9SJani Nikula 	}
22546a39d7c9SJani Nikula 
225513cf5504SDave Airlie 	I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
22566a39d7c9SJani Nikula 	if (!hotplug_trigger)
22576a39d7c9SJani Nikula 		return;
225813cf5504SDave Airlie 
2259cf53902fSRodrigo Vivi 	intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger,
226040e56410SVille Syrjälä 			   dig_hotplug_reg, hpd,
2261fd63e2a9SImre Deak 			   pch_port_hotplug_long_detect);
226240e56410SVille Syrjälä 
226391d14251STvrtko Ursulin 	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
2264aaf5ec2eSSonika Jindal }
226591d131d2SDaniel Vetter 
226691d14251STvrtko Ursulin static void ibx_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
226740e56410SVille Syrjälä {
226840e56410SVille Syrjälä 	int pipe;
226940e56410SVille Syrjälä 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
227040e56410SVille Syrjälä 
227191d14251STvrtko Ursulin 	ibx_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ibx);
227240e56410SVille Syrjälä 
2273cfc33bf7SVille Syrjälä 	if (pch_iir & SDE_AUDIO_POWER_MASK) {
2274cfc33bf7SVille Syrjälä 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
2275776ad806SJesse Barnes 			       SDE_AUDIO_POWER_SHIFT);
2276cfc33bf7SVille Syrjälä 		DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
2277cfc33bf7SVille Syrjälä 				 port_name(port));
2278cfc33bf7SVille Syrjälä 	}
2279776ad806SJesse Barnes 
2280ce99c256SDaniel Vetter 	if (pch_iir & SDE_AUX_MASK)
228191d14251STvrtko Ursulin 		dp_aux_irq_handler(dev_priv);
2282ce99c256SDaniel Vetter 
2283776ad806SJesse Barnes 	if (pch_iir & SDE_GMBUS)
228491d14251STvrtko Ursulin 		gmbus_irq_handler(dev_priv);
2285776ad806SJesse Barnes 
2286776ad806SJesse Barnes 	if (pch_iir & SDE_AUDIO_HDCP_MASK)
2287776ad806SJesse Barnes 		DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n");
2288776ad806SJesse Barnes 
2289776ad806SJesse Barnes 	if (pch_iir & SDE_AUDIO_TRANS_MASK)
2290776ad806SJesse Barnes 		DRM_DEBUG_DRIVER("PCH transcoder audio interrupt\n");
2291776ad806SJesse Barnes 
2292776ad806SJesse Barnes 	if (pch_iir & SDE_POISON)
2293776ad806SJesse Barnes 		DRM_ERROR("PCH poison interrupt\n");
2294776ad806SJesse Barnes 
22959db4a9c7SJesse Barnes 	if (pch_iir & SDE_FDI_MASK)
2296055e393fSDamien Lespiau 		for_each_pipe(dev_priv, pipe)
22979db4a9c7SJesse Barnes 			DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
22989db4a9c7SJesse Barnes 					 pipe_name(pipe),
22999db4a9c7SJesse Barnes 					 I915_READ(FDI_RX_IIR(pipe)));
2300776ad806SJesse Barnes 
2301776ad806SJesse Barnes 	if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE))
2302776ad806SJesse Barnes 		DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n");
2303776ad806SJesse Barnes 
2304776ad806SJesse Barnes 	if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR))
2305776ad806SJesse Barnes 		DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
2306776ad806SJesse Barnes 
2307776ad806SJesse Barnes 	if (pch_iir & SDE_TRANSA_FIFO_UNDER)
2308a2196033SMatthias Kaehlcke 		intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_A);
23098664281bSPaulo Zanoni 
23108664281bSPaulo Zanoni 	if (pch_iir & SDE_TRANSB_FIFO_UNDER)
2311a2196033SMatthias Kaehlcke 		intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_B);
23128664281bSPaulo Zanoni }
23138664281bSPaulo Zanoni 
231491d14251STvrtko Ursulin static void ivb_err_int_handler(struct drm_i915_private *dev_priv)
23158664281bSPaulo Zanoni {
23168664281bSPaulo Zanoni 	u32 err_int = I915_READ(GEN7_ERR_INT);
23175a69b89fSDaniel Vetter 	enum pipe pipe;
23188664281bSPaulo Zanoni 
2319de032bf4SPaulo Zanoni 	if (err_int & ERR_INT_POISON)
2320de032bf4SPaulo Zanoni 		DRM_ERROR("Poison interrupt\n");
2321de032bf4SPaulo Zanoni 
2322055e393fSDamien Lespiau 	for_each_pipe(dev_priv, pipe) {
23231f7247c0SDaniel Vetter 		if (err_int & ERR_INT_FIFO_UNDERRUN(pipe))
23241f7247c0SDaniel Vetter 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
23258664281bSPaulo Zanoni 
23265a69b89fSDaniel Vetter 		if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
232791d14251STvrtko Ursulin 			if (IS_IVYBRIDGE(dev_priv))
232891d14251STvrtko Ursulin 				ivb_pipe_crc_irq_handler(dev_priv, pipe);
23295a69b89fSDaniel Vetter 			else
233091d14251STvrtko Ursulin 				hsw_pipe_crc_irq_handler(dev_priv, pipe);
23315a69b89fSDaniel Vetter 		}
23325a69b89fSDaniel Vetter 	}
23338bf1e9f1SShuang He 
23348664281bSPaulo Zanoni 	I915_WRITE(GEN7_ERR_INT, err_int);
23358664281bSPaulo Zanoni }
23368664281bSPaulo Zanoni 
233791d14251STvrtko Ursulin static void cpt_serr_int_handler(struct drm_i915_private *dev_priv)
23388664281bSPaulo Zanoni {
23398664281bSPaulo Zanoni 	u32 serr_int = I915_READ(SERR_INT);
234045c1cd87SMika Kahola 	enum pipe pipe;
23418664281bSPaulo Zanoni 
2342de032bf4SPaulo Zanoni 	if (serr_int & SERR_INT_POISON)
2343de032bf4SPaulo Zanoni 		DRM_ERROR("PCH poison interrupt\n");
2344de032bf4SPaulo Zanoni 
234545c1cd87SMika Kahola 	for_each_pipe(dev_priv, pipe)
234645c1cd87SMika Kahola 		if (serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pipe))
234745c1cd87SMika Kahola 			intel_pch_fifo_underrun_irq_handler(dev_priv, pipe);
23488664281bSPaulo Zanoni 
23498664281bSPaulo Zanoni 	I915_WRITE(SERR_INT, serr_int);
2350776ad806SJesse Barnes }
2351776ad806SJesse Barnes 
235291d14251STvrtko Ursulin static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
235323e81d69SAdam Jackson {
235423e81d69SAdam Jackson 	int pipe;
23556dbf30ceSVille Syrjälä 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
2356aaf5ec2eSSonika Jindal 
235791d14251STvrtko Ursulin 	ibx_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_cpt);
235891d131d2SDaniel Vetter 
2359cfc33bf7SVille Syrjälä 	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
2360cfc33bf7SVille Syrjälä 		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
236123e81d69SAdam Jackson 			       SDE_AUDIO_POWER_SHIFT_CPT);
2362cfc33bf7SVille Syrjälä 		DRM_DEBUG_DRIVER("PCH audio power change on port %c\n",
2363cfc33bf7SVille Syrjälä 				 port_name(port));
2364cfc33bf7SVille Syrjälä 	}
236523e81d69SAdam Jackson 
236623e81d69SAdam Jackson 	if (pch_iir & SDE_AUX_MASK_CPT)
236791d14251STvrtko Ursulin 		dp_aux_irq_handler(dev_priv);
236823e81d69SAdam Jackson 
236923e81d69SAdam Jackson 	if (pch_iir & SDE_GMBUS_CPT)
237091d14251STvrtko Ursulin 		gmbus_irq_handler(dev_priv);
237123e81d69SAdam Jackson 
237223e81d69SAdam Jackson 	if (pch_iir & SDE_AUDIO_CP_REQ_CPT)
237323e81d69SAdam Jackson 		DRM_DEBUG_DRIVER("Audio CP request interrupt\n");
237423e81d69SAdam Jackson 
237523e81d69SAdam Jackson 	if (pch_iir & SDE_AUDIO_CP_CHG_CPT)
237623e81d69SAdam Jackson 		DRM_DEBUG_DRIVER("Audio CP change interrupt\n");
237723e81d69SAdam Jackson 
237823e81d69SAdam Jackson 	if (pch_iir & SDE_FDI_MASK_CPT)
2379055e393fSDamien Lespiau 		for_each_pipe(dev_priv, pipe)
238023e81d69SAdam Jackson 			DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
238123e81d69SAdam Jackson 					 pipe_name(pipe),
238223e81d69SAdam Jackson 					 I915_READ(FDI_RX_IIR(pipe)));
23838664281bSPaulo Zanoni 
23848664281bSPaulo Zanoni 	if (pch_iir & SDE_ERROR_CPT)
238591d14251STvrtko Ursulin 		cpt_serr_int_handler(dev_priv);
238623e81d69SAdam Jackson }
238723e81d69SAdam Jackson 
238891d14251STvrtko Ursulin static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
23896dbf30ceSVille Syrjälä {
23906dbf30ceSVille Syrjälä 	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT &
23916dbf30ceSVille Syrjälä 		~SDE_PORTE_HOTPLUG_SPT;
23926dbf30ceSVille Syrjälä 	u32 hotplug2_trigger = pch_iir & SDE_PORTE_HOTPLUG_SPT;
23936dbf30ceSVille Syrjälä 	u32 pin_mask = 0, long_mask = 0;
23946dbf30ceSVille Syrjälä 
23956dbf30ceSVille Syrjälä 	if (hotplug_trigger) {
23966dbf30ceSVille Syrjälä 		u32 dig_hotplug_reg;
23976dbf30ceSVille Syrjälä 
23986dbf30ceSVille Syrjälä 		dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
23996dbf30ceSVille Syrjälä 		I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
24006dbf30ceSVille Syrjälä 
2401cf53902fSRodrigo Vivi 		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
2402cf53902fSRodrigo Vivi 				   hotplug_trigger, dig_hotplug_reg, hpd_spt,
240374c0b395SVille Syrjälä 				   spt_port_hotplug_long_detect);
24046dbf30ceSVille Syrjälä 	}
24056dbf30ceSVille Syrjälä 
24066dbf30ceSVille Syrjälä 	if (hotplug2_trigger) {
24076dbf30ceSVille Syrjälä 		u32 dig_hotplug_reg;
24086dbf30ceSVille Syrjälä 
24096dbf30ceSVille Syrjälä 		dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2);
24106dbf30ceSVille Syrjälä 		I915_WRITE(PCH_PORT_HOTPLUG2, dig_hotplug_reg);
24116dbf30ceSVille Syrjälä 
2412cf53902fSRodrigo Vivi 		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
2413cf53902fSRodrigo Vivi 				   hotplug2_trigger, dig_hotplug_reg, hpd_spt,
24146dbf30ceSVille Syrjälä 				   spt_port_hotplug2_long_detect);
24156dbf30ceSVille Syrjälä 	}
24166dbf30ceSVille Syrjälä 
24176dbf30ceSVille Syrjälä 	if (pin_mask)
241891d14251STvrtko Ursulin 		intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
24196dbf30ceSVille Syrjälä 
24206dbf30ceSVille Syrjälä 	if (pch_iir & SDE_GMBUS_CPT)
242191d14251STvrtko Ursulin 		gmbus_irq_handler(dev_priv);
24226dbf30ceSVille Syrjälä }
24236dbf30ceSVille Syrjälä 
242491d14251STvrtko Ursulin static void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv,
242591d14251STvrtko Ursulin 				u32 hotplug_trigger,
242640e56410SVille Syrjälä 				const u32 hpd[HPD_NUM_PINS])
2427c008bc6eSPaulo Zanoni {
2428e4ce95aaSVille Syrjälä 	u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
2429e4ce95aaSVille Syrjälä 
2430e4ce95aaSVille Syrjälä 	dig_hotplug_reg = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
2431e4ce95aaSVille Syrjälä 	I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, dig_hotplug_reg);
2432e4ce95aaSVille Syrjälä 
2433cf53902fSRodrigo Vivi 	intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger,
243440e56410SVille Syrjälä 			   dig_hotplug_reg, hpd,
2435e4ce95aaSVille Syrjälä 			   ilk_port_hotplug_long_detect);
243640e56410SVille Syrjälä 
243791d14251STvrtko Ursulin 	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
2438e4ce95aaSVille Syrjälä }
2439c008bc6eSPaulo Zanoni 
244091d14251STvrtko Ursulin static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
244191d14251STvrtko Ursulin 				    u32 de_iir)
244240e56410SVille Syrjälä {
244340e56410SVille Syrjälä 	enum pipe pipe;
244440e56410SVille Syrjälä 	u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG;
244540e56410SVille Syrjälä 
244640e56410SVille Syrjälä 	if (hotplug_trigger)
244791d14251STvrtko Ursulin 		ilk_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ilk);
244840e56410SVille Syrjälä 
2449c008bc6eSPaulo Zanoni 	if (de_iir & DE_AUX_CHANNEL_A)
245091d14251STvrtko Ursulin 		dp_aux_irq_handler(dev_priv);
2451c008bc6eSPaulo Zanoni 
2452c008bc6eSPaulo Zanoni 	if (de_iir & DE_GSE)
245391d14251STvrtko Ursulin 		intel_opregion_asle_intr(dev_priv);
2454c008bc6eSPaulo Zanoni 
2455c008bc6eSPaulo Zanoni 	if (de_iir & DE_POISON)
2456c008bc6eSPaulo Zanoni 		DRM_ERROR("Poison interrupt\n");
2457c008bc6eSPaulo Zanoni 
2458055e393fSDamien Lespiau 	for_each_pipe(dev_priv, pipe) {
2459fd3a4024SDaniel Vetter 		if (de_iir & DE_PIPE_VBLANK(pipe))
2460fd3a4024SDaniel Vetter 			drm_handle_vblank(&dev_priv->drm, pipe);
2461c008bc6eSPaulo Zanoni 
246240da17c2SDaniel Vetter 		if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
24631f7247c0SDaniel Vetter 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
2464c008bc6eSPaulo Zanoni 
246540da17c2SDaniel Vetter 		if (de_iir & DE_PIPE_CRC_DONE(pipe))
246691d14251STvrtko Ursulin 			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
2467c008bc6eSPaulo Zanoni 	}
2468c008bc6eSPaulo Zanoni 
2469c008bc6eSPaulo Zanoni 	/* check event from PCH */
2470c008bc6eSPaulo Zanoni 	if (de_iir & DE_PCH_EVENT) {
2471c008bc6eSPaulo Zanoni 		u32 pch_iir = I915_READ(SDEIIR);
2472c008bc6eSPaulo Zanoni 
247391d14251STvrtko Ursulin 		if (HAS_PCH_CPT(dev_priv))
247491d14251STvrtko Ursulin 			cpt_irq_handler(dev_priv, pch_iir);
2475c008bc6eSPaulo Zanoni 		else
247691d14251STvrtko Ursulin 			ibx_irq_handler(dev_priv, pch_iir);
2477c008bc6eSPaulo Zanoni 
2478c008bc6eSPaulo Zanoni 		/* should clear PCH hotplug event before clear CPU irq */
2479c008bc6eSPaulo Zanoni 		I915_WRITE(SDEIIR, pch_iir);
2480c008bc6eSPaulo Zanoni 	}
2481c008bc6eSPaulo Zanoni 
248291d14251STvrtko Ursulin 	if (IS_GEN5(dev_priv) && de_iir & DE_PCU_EVENT)
248391d14251STvrtko Ursulin 		ironlake_rps_change_irq_handler(dev_priv);
2484c008bc6eSPaulo Zanoni }
2485c008bc6eSPaulo Zanoni 
248691d14251STvrtko Ursulin static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
248791d14251STvrtko Ursulin 				    u32 de_iir)
24889719fb98SPaulo Zanoni {
248907d27e20SDamien Lespiau 	enum pipe pipe;
249023bb4cb5SVille Syrjälä 	u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB;
249123bb4cb5SVille Syrjälä 
249240e56410SVille Syrjälä 	if (hotplug_trigger)
249391d14251STvrtko Ursulin 		ilk_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ivb);
24949719fb98SPaulo Zanoni 
24959719fb98SPaulo Zanoni 	if (de_iir & DE_ERR_INT_IVB)
249691d14251STvrtko Ursulin 		ivb_err_int_handler(dev_priv);
24979719fb98SPaulo Zanoni 
249854fd3149SDhinakaran Pandiyan 	if (de_iir & DE_EDP_PSR_INT_HSW) {
249954fd3149SDhinakaran Pandiyan 		u32 psr_iir = I915_READ(EDP_PSR_IIR);
250054fd3149SDhinakaran Pandiyan 
250154fd3149SDhinakaran Pandiyan 		intel_psr_irq_handler(dev_priv, psr_iir);
250254fd3149SDhinakaran Pandiyan 		I915_WRITE(EDP_PSR_IIR, psr_iir);
250354fd3149SDhinakaran Pandiyan 	}
2504fc340442SDaniel Vetter 
25059719fb98SPaulo Zanoni 	if (de_iir & DE_AUX_CHANNEL_A_IVB)
250691d14251STvrtko Ursulin 		dp_aux_irq_handler(dev_priv);
25079719fb98SPaulo Zanoni 
25089719fb98SPaulo Zanoni 	if (de_iir & DE_GSE_IVB)
250991d14251STvrtko Ursulin 		intel_opregion_asle_intr(dev_priv);
25109719fb98SPaulo Zanoni 
2511055e393fSDamien Lespiau 	for_each_pipe(dev_priv, pipe) {
2512fd3a4024SDaniel Vetter 		if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
2513fd3a4024SDaniel Vetter 			drm_handle_vblank(&dev_priv->drm, pipe);
25149719fb98SPaulo Zanoni 	}
25159719fb98SPaulo Zanoni 
25169719fb98SPaulo Zanoni 	/* check event from PCH */
251791d14251STvrtko Ursulin 	if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) {
25189719fb98SPaulo Zanoni 		u32 pch_iir = I915_READ(SDEIIR);
25199719fb98SPaulo Zanoni 
252091d14251STvrtko Ursulin 		cpt_irq_handler(dev_priv, pch_iir);
25219719fb98SPaulo Zanoni 
25229719fb98SPaulo Zanoni 		/* clear PCH hotplug event before clear CPU irq */
25239719fb98SPaulo Zanoni 		I915_WRITE(SDEIIR, pch_iir);
25249719fb98SPaulo Zanoni 	}
25259719fb98SPaulo Zanoni }
25269719fb98SPaulo Zanoni 
252772c90f62SOscar Mateo /*
252872c90f62SOscar Mateo  * To handle irqs with the minimum potential races with fresh interrupts, we:
252972c90f62SOscar Mateo  * 1 - Disable Master Interrupt Control.
253072c90f62SOscar Mateo  * 2 - Find the source(s) of the interrupt.
253172c90f62SOscar Mateo  * 3 - Clear the Interrupt Identity bits (IIR).
253272c90f62SOscar Mateo  * 4 - Process the interrupt(s) that had bits set in the IIRs.
253372c90f62SOscar Mateo  * 5 - Re-enable Master Interrupt Control.
253472c90f62SOscar Mateo  */
2535f1af8fc1SPaulo Zanoni static irqreturn_t ironlake_irq_handler(int irq, void *arg)
2536b1f14ad0SJesse Barnes {
253745a83f84SDaniel Vetter 	struct drm_device *dev = arg;
2538fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
2539f1af8fc1SPaulo Zanoni 	u32 de_iir, gt_iir, de_ier, sde_ier = 0;
25400e43406bSChris Wilson 	irqreturn_t ret = IRQ_NONE;
2541b1f14ad0SJesse Barnes 
25422dd2a883SImre Deak 	if (!intel_irqs_enabled(dev_priv))
25432dd2a883SImre Deak 		return IRQ_NONE;
25442dd2a883SImre Deak 
25451f814dacSImre Deak 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
25461f814dacSImre Deak 	disable_rpm_wakeref_asserts(dev_priv);
25471f814dacSImre Deak 
2548b1f14ad0SJesse Barnes 	/* disable master interrupt before clearing iir  */
2549b1f14ad0SJesse Barnes 	de_ier = I915_READ(DEIER);
2550b1f14ad0SJesse Barnes 	I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
255123a78516SPaulo Zanoni 	POSTING_READ(DEIER);
25520e43406bSChris Wilson 
255344498aeaSPaulo Zanoni 	/* Disable south interrupts. We'll only write to SDEIIR once, so further
255444498aeaSPaulo Zanoni 	 * interrupts will will be stored on its back queue, and then we'll be
255544498aeaSPaulo Zanoni 	 * able to process them after we restore SDEIER (as soon as we restore
255644498aeaSPaulo Zanoni 	 * it, we'll get an interrupt if SDEIIR still has something to process
255744498aeaSPaulo Zanoni 	 * due to its back queue). */
255891d14251STvrtko Ursulin 	if (!HAS_PCH_NOP(dev_priv)) {
255944498aeaSPaulo Zanoni 		sde_ier = I915_READ(SDEIER);
256044498aeaSPaulo Zanoni 		I915_WRITE(SDEIER, 0);
256144498aeaSPaulo Zanoni 		POSTING_READ(SDEIER);
2562ab5c608bSBen Widawsky 	}
256344498aeaSPaulo Zanoni 
256472c90f62SOscar Mateo 	/* Find, clear, then process each source of interrupt */
256572c90f62SOscar Mateo 
25660e43406bSChris Wilson 	gt_iir = I915_READ(GTIIR);
25670e43406bSChris Wilson 	if (gt_iir) {
256872c90f62SOscar Mateo 		I915_WRITE(GTIIR, gt_iir);
256972c90f62SOscar Mateo 		ret = IRQ_HANDLED;
257091d14251STvrtko Ursulin 		if (INTEL_GEN(dev_priv) >= 6)
2571261e40b8SVille Syrjälä 			snb_gt_irq_handler(dev_priv, gt_iir);
2572d8fc8a47SPaulo Zanoni 		else
2573261e40b8SVille Syrjälä 			ilk_gt_irq_handler(dev_priv, gt_iir);
25740e43406bSChris Wilson 	}
2575b1f14ad0SJesse Barnes 
2576b1f14ad0SJesse Barnes 	de_iir = I915_READ(DEIIR);
25770e43406bSChris Wilson 	if (de_iir) {
257872c90f62SOscar Mateo 		I915_WRITE(DEIIR, de_iir);
257972c90f62SOscar Mateo 		ret = IRQ_HANDLED;
258091d14251STvrtko Ursulin 		if (INTEL_GEN(dev_priv) >= 7)
258191d14251STvrtko Ursulin 			ivb_display_irq_handler(dev_priv, de_iir);
2582f1af8fc1SPaulo Zanoni 		else
258391d14251STvrtko Ursulin 			ilk_display_irq_handler(dev_priv, de_iir);
25840e43406bSChris Wilson 	}
25850e43406bSChris Wilson 
258691d14251STvrtko Ursulin 	if (INTEL_GEN(dev_priv) >= 6) {
2587f1af8fc1SPaulo Zanoni 		u32 pm_iir = I915_READ(GEN6_PMIIR);
25880e43406bSChris Wilson 		if (pm_iir) {
2589b1f14ad0SJesse Barnes 			I915_WRITE(GEN6_PMIIR, pm_iir);
25900e43406bSChris Wilson 			ret = IRQ_HANDLED;
259172c90f62SOscar Mateo 			gen6_rps_irq_handler(dev_priv, pm_iir);
25920e43406bSChris Wilson 		}
2593f1af8fc1SPaulo Zanoni 	}
2594b1f14ad0SJesse Barnes 
2595b1f14ad0SJesse Barnes 	I915_WRITE(DEIER, de_ier);
2596b1f14ad0SJesse Barnes 	POSTING_READ(DEIER);
259791d14251STvrtko Ursulin 	if (!HAS_PCH_NOP(dev_priv)) {
259844498aeaSPaulo Zanoni 		I915_WRITE(SDEIER, sde_ier);
259944498aeaSPaulo Zanoni 		POSTING_READ(SDEIER);
2600ab5c608bSBen Widawsky 	}
2601b1f14ad0SJesse Barnes 
26021f814dacSImre Deak 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
26031f814dacSImre Deak 	enable_rpm_wakeref_asserts(dev_priv);
26041f814dacSImre Deak 
2605b1f14ad0SJesse Barnes 	return ret;
2606b1f14ad0SJesse Barnes }
2607b1f14ad0SJesse Barnes 
260891d14251STvrtko Ursulin static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv,
260991d14251STvrtko Ursulin 				u32 hotplug_trigger,
261040e56410SVille Syrjälä 				const u32 hpd[HPD_NUM_PINS])
2611d04a492dSShashank Sharma {
2612cebd87a0SVille Syrjälä 	u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
2613d04a492dSShashank Sharma 
2614a52bb15bSVille Syrjälä 	dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
2615a52bb15bSVille Syrjälä 	I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
2616d04a492dSShashank Sharma 
2617cf53902fSRodrigo Vivi 	intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger,
261840e56410SVille Syrjälä 			   dig_hotplug_reg, hpd,
2619cebd87a0SVille Syrjälä 			   bxt_port_hotplug_long_detect);
262040e56410SVille Syrjälä 
262191d14251STvrtko Ursulin 	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
2622d04a492dSShashank Sharma }
2623d04a492dSShashank Sharma 
2624121e758eSDhinakaran Pandiyan static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
2625121e758eSDhinakaran Pandiyan {
2626121e758eSDhinakaran Pandiyan 	u32 pin_mask = 0, long_mask = 0;
2627*b796b971SDhinakaran Pandiyan 	u32 trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK;
2628*b796b971SDhinakaran Pandiyan 	u32 trigger_tbt = iir & GEN11_DE_TBT_HOTPLUG_MASK;
2629121e758eSDhinakaran Pandiyan 
2630121e758eSDhinakaran Pandiyan 	if (trigger_tc) {
2631*b796b971SDhinakaran Pandiyan 		u32 dig_hotplug_reg;
2632*b796b971SDhinakaran Pandiyan 
2633121e758eSDhinakaran Pandiyan 		dig_hotplug_reg = I915_READ(GEN11_TC_HOTPLUG_CTL);
2634121e758eSDhinakaran Pandiyan 		I915_WRITE(GEN11_TC_HOTPLUG_CTL, dig_hotplug_reg);
2635121e758eSDhinakaran Pandiyan 
2636121e758eSDhinakaran Pandiyan 		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, trigger_tc,
2637*b796b971SDhinakaran Pandiyan 				   dig_hotplug_reg, hpd_gen11,
2638121e758eSDhinakaran Pandiyan 				   gen11_port_hotplug_long_detect);
2639121e758eSDhinakaran Pandiyan 	}
2640*b796b971SDhinakaran Pandiyan 
2641*b796b971SDhinakaran Pandiyan 	if (trigger_tbt) {
2642*b796b971SDhinakaran Pandiyan 		u32 dig_hotplug_reg;
2643*b796b971SDhinakaran Pandiyan 
2644*b796b971SDhinakaran Pandiyan 		dig_hotplug_reg = I915_READ(GEN11_TBT_HOTPLUG_CTL);
2645*b796b971SDhinakaran Pandiyan 		I915_WRITE(GEN11_TBT_HOTPLUG_CTL, dig_hotplug_reg);
2646*b796b971SDhinakaran Pandiyan 
2647*b796b971SDhinakaran Pandiyan 		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, trigger_tbt,
2648*b796b971SDhinakaran Pandiyan 				   dig_hotplug_reg, hpd_gen11,
2649*b796b971SDhinakaran Pandiyan 				   gen11_port_hotplug_long_detect);
2650*b796b971SDhinakaran Pandiyan 	}
2651*b796b971SDhinakaran Pandiyan 
2652*b796b971SDhinakaran Pandiyan 	if (pin_mask)
2653*b796b971SDhinakaran Pandiyan 		intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
2654*b796b971SDhinakaran Pandiyan 	else
2655*b796b971SDhinakaran Pandiyan 		DRM_ERROR("Unexpected DE HPD interrupt 0x%08x\n", iir);
2656121e758eSDhinakaran Pandiyan }
2657121e758eSDhinakaran Pandiyan 
2658f11a0f46STvrtko Ursulin static irqreturn_t
2659f11a0f46STvrtko Ursulin gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
2660abd58f01SBen Widawsky {
2661abd58f01SBen Widawsky 	irqreturn_t ret = IRQ_NONE;
2662f11a0f46STvrtko Ursulin 	u32 iir;
2663c42664ccSDaniel Vetter 	enum pipe pipe;
266488e04703SJesse Barnes 
2665abd58f01SBen Widawsky 	if (master_ctl & GEN8_DE_MISC_IRQ) {
2666e32192e1STvrtko Ursulin 		iir = I915_READ(GEN8_DE_MISC_IIR);
2667e32192e1STvrtko Ursulin 		if (iir) {
2668e04f7eceSVille Syrjälä 			bool found = false;
2669e04f7eceSVille Syrjälä 
2670e32192e1STvrtko Ursulin 			I915_WRITE(GEN8_DE_MISC_IIR, iir);
2671abd58f01SBen Widawsky 			ret = IRQ_HANDLED;
2672e04f7eceSVille Syrjälä 
2673e04f7eceSVille Syrjälä 			if (iir & GEN8_DE_MISC_GSE) {
267491d14251STvrtko Ursulin 				intel_opregion_asle_intr(dev_priv);
2675e04f7eceSVille Syrjälä 				found = true;
2676e04f7eceSVille Syrjälä 			}
2677e04f7eceSVille Syrjälä 
2678e04f7eceSVille Syrjälä 			if (iir & GEN8_DE_EDP_PSR) {
267954fd3149SDhinakaran Pandiyan 				u32 psr_iir = I915_READ(EDP_PSR_IIR);
268054fd3149SDhinakaran Pandiyan 
268154fd3149SDhinakaran Pandiyan 				intel_psr_irq_handler(dev_priv, psr_iir);
268254fd3149SDhinakaran Pandiyan 				I915_WRITE(EDP_PSR_IIR, psr_iir);
2683e04f7eceSVille Syrjälä 				found = true;
2684e04f7eceSVille Syrjälä 			}
2685e04f7eceSVille Syrjälä 
2686e04f7eceSVille Syrjälä 			if (!found)
268738cc46d7SOscar Mateo 				DRM_ERROR("Unexpected DE Misc interrupt\n");
2688abd58f01SBen Widawsky 		}
268938cc46d7SOscar Mateo 		else
269038cc46d7SOscar Mateo 			DRM_ERROR("The master control interrupt lied (DE MISC)!\n");
2691abd58f01SBen Widawsky 	}
2692abd58f01SBen Widawsky 
2693121e758eSDhinakaran Pandiyan 	if (INTEL_GEN(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) {
2694121e758eSDhinakaran Pandiyan 		iir = I915_READ(GEN11_DE_HPD_IIR);
2695121e758eSDhinakaran Pandiyan 		if (iir) {
2696121e758eSDhinakaran Pandiyan 			I915_WRITE(GEN11_DE_HPD_IIR, iir);
2697121e758eSDhinakaran Pandiyan 			ret = IRQ_HANDLED;
2698121e758eSDhinakaran Pandiyan 			gen11_hpd_irq_handler(dev_priv, iir);
2699121e758eSDhinakaran Pandiyan 		} else {
2700121e758eSDhinakaran Pandiyan 			DRM_ERROR("The master control interrupt lied, (DE HPD)!\n");
2701121e758eSDhinakaran Pandiyan 		}
2702121e758eSDhinakaran Pandiyan 	}
2703121e758eSDhinakaran Pandiyan 
27046d766f02SDaniel Vetter 	if (master_ctl & GEN8_DE_PORT_IRQ) {
2705e32192e1STvrtko Ursulin 		iir = I915_READ(GEN8_DE_PORT_IIR);
2706e32192e1STvrtko Ursulin 		if (iir) {
2707e32192e1STvrtko Ursulin 			u32 tmp_mask;
2708d04a492dSShashank Sharma 			bool found = false;
2709cebd87a0SVille Syrjälä 
2710e32192e1STvrtko Ursulin 			I915_WRITE(GEN8_DE_PORT_IIR, iir);
27116d766f02SDaniel Vetter 			ret = IRQ_HANDLED;
271288e04703SJesse Barnes 
2713e32192e1STvrtko Ursulin 			tmp_mask = GEN8_AUX_CHANNEL_A;
2714bca2bf2aSPandiyan, Dhinakaran 			if (INTEL_GEN(dev_priv) >= 9)
2715e32192e1STvrtko Ursulin 				tmp_mask |= GEN9_AUX_CHANNEL_B |
2716e32192e1STvrtko Ursulin 					    GEN9_AUX_CHANNEL_C |
2717e32192e1STvrtko Ursulin 					    GEN9_AUX_CHANNEL_D;
2718e32192e1STvrtko Ursulin 
2719bb187e93SJames Ausmus 			if (INTEL_GEN(dev_priv) >= 11)
2720bb187e93SJames Ausmus 				tmp_mask |= ICL_AUX_CHANNEL_E;
2721bb187e93SJames Ausmus 
27229bb635d9SDhinakaran Pandiyan 			if (IS_CNL_WITH_PORT_F(dev_priv) ||
27239bb635d9SDhinakaran Pandiyan 			    INTEL_GEN(dev_priv) >= 11)
2724a324fcacSRodrigo Vivi 				tmp_mask |= CNL_AUX_CHANNEL_F;
2725a324fcacSRodrigo Vivi 
2726e32192e1STvrtko Ursulin 			if (iir & tmp_mask) {
272791d14251STvrtko Ursulin 				dp_aux_irq_handler(dev_priv);
2728d04a492dSShashank Sharma 				found = true;
2729d04a492dSShashank Sharma 			}
2730d04a492dSShashank Sharma 
2731cc3f90f0SAnder Conselvan de Oliveira 			if (IS_GEN9_LP(dev_priv)) {
2732e32192e1STvrtko Ursulin 				tmp_mask = iir & BXT_DE_PORT_HOTPLUG_MASK;
2733e32192e1STvrtko Ursulin 				if (tmp_mask) {
273491d14251STvrtko Ursulin 					bxt_hpd_irq_handler(dev_priv, tmp_mask,
273591d14251STvrtko Ursulin 							    hpd_bxt);
2736d04a492dSShashank Sharma 					found = true;
2737d04a492dSShashank Sharma 				}
2738e32192e1STvrtko Ursulin 			} else if (IS_BROADWELL(dev_priv)) {
2739e32192e1STvrtko Ursulin 				tmp_mask = iir & GEN8_PORT_DP_A_HOTPLUG;
2740e32192e1STvrtko Ursulin 				if (tmp_mask) {
274191d14251STvrtko Ursulin 					ilk_hpd_irq_handler(dev_priv,
274291d14251STvrtko Ursulin 							    tmp_mask, hpd_bdw);
2743e32192e1STvrtko Ursulin 					found = true;
2744e32192e1STvrtko Ursulin 				}
2745e32192e1STvrtko Ursulin 			}
2746d04a492dSShashank Sharma 
2747cc3f90f0SAnder Conselvan de Oliveira 			if (IS_GEN9_LP(dev_priv) && (iir & BXT_DE_PORT_GMBUS)) {
274891d14251STvrtko Ursulin 				gmbus_irq_handler(dev_priv);
27499e63743eSShashank Sharma 				found = true;
27509e63743eSShashank Sharma 			}
27519e63743eSShashank Sharma 
2752d04a492dSShashank Sharma 			if (!found)
275338cc46d7SOscar Mateo 				DRM_ERROR("Unexpected DE Port interrupt\n");
27546d766f02SDaniel Vetter 		}
275538cc46d7SOscar Mateo 		else
275638cc46d7SOscar Mateo 			DRM_ERROR("The master control interrupt lied (DE PORT)!\n");
27576d766f02SDaniel Vetter 	}
27586d766f02SDaniel Vetter 
2759055e393fSDamien Lespiau 	for_each_pipe(dev_priv, pipe) {
2760fd3a4024SDaniel Vetter 		u32 fault_errors;
2761abd58f01SBen Widawsky 
2762c42664ccSDaniel Vetter 		if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
2763c42664ccSDaniel Vetter 			continue;
2764c42664ccSDaniel Vetter 
2765e32192e1STvrtko Ursulin 		iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
2766e32192e1STvrtko Ursulin 		if (!iir) {
2767e32192e1STvrtko Ursulin 			DRM_ERROR("The master control interrupt lied (DE PIPE)!\n");
2768e32192e1STvrtko Ursulin 			continue;
2769e32192e1STvrtko Ursulin 		}
2770770de83dSDamien Lespiau 
2771e32192e1STvrtko Ursulin 		ret = IRQ_HANDLED;
2772e32192e1STvrtko Ursulin 		I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir);
2773e32192e1STvrtko Ursulin 
2774fd3a4024SDaniel Vetter 		if (iir & GEN8_PIPE_VBLANK)
2775fd3a4024SDaniel Vetter 			drm_handle_vblank(&dev_priv->drm, pipe);
2776abd58f01SBen Widawsky 
2777e32192e1STvrtko Ursulin 		if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
277891d14251STvrtko Ursulin 			hsw_pipe_crc_irq_handler(dev_priv, pipe);
27790fbe7870SDaniel Vetter 
2780e32192e1STvrtko Ursulin 		if (iir & GEN8_PIPE_FIFO_UNDERRUN)
2781e32192e1STvrtko Ursulin 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
278238d83c96SDaniel Vetter 
2783e32192e1STvrtko Ursulin 		fault_errors = iir;
2784bca2bf2aSPandiyan, Dhinakaran 		if (INTEL_GEN(dev_priv) >= 9)
2785e32192e1STvrtko Ursulin 			fault_errors &= GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
2786770de83dSDamien Lespiau 		else
2787e32192e1STvrtko Ursulin 			fault_errors &= GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
2788770de83dSDamien Lespiau 
2789770de83dSDamien Lespiau 		if (fault_errors)
27901353ec38STvrtko Ursulin 			DRM_ERROR("Fault errors on pipe %c: 0x%08x\n",
279130100f2bSDaniel Vetter 				  pipe_name(pipe),
2792e32192e1STvrtko Ursulin 				  fault_errors);
2793abd58f01SBen Widawsky 	}
2794abd58f01SBen Widawsky 
279591d14251STvrtko Ursulin 	if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) &&
2796266ea3d9SShashank Sharma 	    master_ctl & GEN8_DE_PCH_IRQ) {
279792d03a80SDaniel Vetter 		/*
279892d03a80SDaniel Vetter 		 * FIXME(BDW): Assume for now that the new interrupt handling
279992d03a80SDaniel Vetter 		 * scheme also closed the SDE interrupt handling race we've seen
280092d03a80SDaniel Vetter 		 * on older pch-split platforms. But this needs testing.
280192d03a80SDaniel Vetter 		 */
2802e32192e1STvrtko Ursulin 		iir = I915_READ(SDEIIR);
2803e32192e1STvrtko Ursulin 		if (iir) {
2804e32192e1STvrtko Ursulin 			I915_WRITE(SDEIIR, iir);
280592d03a80SDaniel Vetter 			ret = IRQ_HANDLED;
28066dbf30ceSVille Syrjälä 
28077b22b8c4SRodrigo Vivi 			if (HAS_PCH_SPT(dev_priv) || HAS_PCH_KBP(dev_priv) ||
28087b22b8c4SRodrigo Vivi 			    HAS_PCH_CNP(dev_priv))
280991d14251STvrtko Ursulin 				spt_irq_handler(dev_priv, iir);
28106dbf30ceSVille Syrjälä 			else
281191d14251STvrtko Ursulin 				cpt_irq_handler(dev_priv, iir);
28122dfb0b81SJani Nikula 		} else {
28132dfb0b81SJani Nikula 			/*
28142dfb0b81SJani Nikula 			 * Like on previous PCH there seems to be something
28152dfb0b81SJani Nikula 			 * fishy going on with forwarding PCH interrupts.
28162dfb0b81SJani Nikula 			 */
28172dfb0b81SJani Nikula 			DRM_DEBUG_DRIVER("The master control interrupt lied (SDE)!\n");
28182dfb0b81SJani Nikula 		}
281992d03a80SDaniel Vetter 	}
282092d03a80SDaniel Vetter 
2821f11a0f46STvrtko Ursulin 	return ret;
2822f11a0f46STvrtko Ursulin }
2823f11a0f46STvrtko Ursulin 
2824f11a0f46STvrtko Ursulin static irqreturn_t gen8_irq_handler(int irq, void *arg)
2825f11a0f46STvrtko Ursulin {
2826f0fd96f5SChris Wilson 	struct drm_i915_private *dev_priv = to_i915(arg);
2827f11a0f46STvrtko Ursulin 	u32 master_ctl;
2828f0fd96f5SChris Wilson 	u32 gt_iir[4];
2829f11a0f46STvrtko Ursulin 
2830f11a0f46STvrtko Ursulin 	if (!intel_irqs_enabled(dev_priv))
2831f11a0f46STvrtko Ursulin 		return IRQ_NONE;
2832f11a0f46STvrtko Ursulin 
2833f11a0f46STvrtko Ursulin 	master_ctl = I915_READ_FW(GEN8_MASTER_IRQ);
2834f11a0f46STvrtko Ursulin 	master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
2835f11a0f46STvrtko Ursulin 	if (!master_ctl)
2836f11a0f46STvrtko Ursulin 		return IRQ_NONE;
2837f11a0f46STvrtko Ursulin 
2838f11a0f46STvrtko Ursulin 	I915_WRITE_FW(GEN8_MASTER_IRQ, 0);
2839f11a0f46STvrtko Ursulin 
2840f11a0f46STvrtko Ursulin 	/* Find, clear, then process each source of interrupt */
284155ef72f2SChris Wilson 	gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
2842f0fd96f5SChris Wilson 
2843f0fd96f5SChris Wilson 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
2844f0fd96f5SChris Wilson 	if (master_ctl & ~GEN8_GT_IRQS) {
2845f0fd96f5SChris Wilson 		disable_rpm_wakeref_asserts(dev_priv);
284655ef72f2SChris Wilson 		gen8_de_irq_handler(dev_priv, master_ctl);
2847f0fd96f5SChris Wilson 		enable_rpm_wakeref_asserts(dev_priv);
2848f0fd96f5SChris Wilson 	}
2849f11a0f46STvrtko Ursulin 
2850cb0d205eSChris Wilson 	I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
2851abd58f01SBen Widawsky 
2852f0fd96f5SChris Wilson 	gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir);
28531f814dacSImre Deak 
285455ef72f2SChris Wilson 	return IRQ_HANDLED;
2855abd58f01SBen Widawsky }
2856abd58f01SBen Widawsky 
285736703e79SChris Wilson struct wedge_me {
285836703e79SChris Wilson 	struct delayed_work work;
285936703e79SChris Wilson 	struct drm_i915_private *i915;
286036703e79SChris Wilson 	const char *name;
286136703e79SChris Wilson };
286236703e79SChris Wilson 
286336703e79SChris Wilson static void wedge_me(struct work_struct *work)
286436703e79SChris Wilson {
286536703e79SChris Wilson 	struct wedge_me *w = container_of(work, typeof(*w), work.work);
286636703e79SChris Wilson 
286736703e79SChris Wilson 	dev_err(w->i915->drm.dev,
286836703e79SChris Wilson 		"%s timed out, cancelling all in-flight rendering.\n",
286936703e79SChris Wilson 		w->name);
287036703e79SChris Wilson 	i915_gem_set_wedged(w->i915);
287136703e79SChris Wilson }
287236703e79SChris Wilson 
287336703e79SChris Wilson static void __init_wedge(struct wedge_me *w,
287436703e79SChris Wilson 			 struct drm_i915_private *i915,
287536703e79SChris Wilson 			 long timeout,
287636703e79SChris Wilson 			 const char *name)
287736703e79SChris Wilson {
287836703e79SChris Wilson 	w->i915 = i915;
287936703e79SChris Wilson 	w->name = name;
288036703e79SChris Wilson 
288136703e79SChris Wilson 	INIT_DELAYED_WORK_ONSTACK(&w->work, wedge_me);
288236703e79SChris Wilson 	schedule_delayed_work(&w->work, timeout);
288336703e79SChris Wilson }
288436703e79SChris Wilson 
288536703e79SChris Wilson static void __fini_wedge(struct wedge_me *w)
288636703e79SChris Wilson {
288736703e79SChris Wilson 	cancel_delayed_work_sync(&w->work);
288836703e79SChris Wilson 	destroy_delayed_work_on_stack(&w->work);
288936703e79SChris Wilson 	w->i915 = NULL;
289036703e79SChris Wilson }
289136703e79SChris Wilson 
289236703e79SChris Wilson #define i915_wedge_on_timeout(W, DEV, TIMEOUT)				\
289336703e79SChris Wilson 	for (__init_wedge((W), (DEV), (TIMEOUT), __func__);		\
289436703e79SChris Wilson 	     (W)->i915;							\
289536703e79SChris Wilson 	     __fini_wedge((W)))
289636703e79SChris Wilson 
289751951ae7SMika Kuoppala static u32
2898f744dbc2SMika Kuoppala gen11_gt_engine_identity(struct drm_i915_private * const i915,
289951951ae7SMika Kuoppala 			 const unsigned int bank, const unsigned int bit)
290051951ae7SMika Kuoppala {
290151951ae7SMika Kuoppala 	void __iomem * const regs = i915->regs;
290251951ae7SMika Kuoppala 	u32 timeout_ts;
290351951ae7SMika Kuoppala 	u32 ident;
290451951ae7SMika Kuoppala 
290596606f3bSOscar Mateo 	lockdep_assert_held(&i915->irq_lock);
290696606f3bSOscar Mateo 
290751951ae7SMika Kuoppala 	raw_reg_write(regs, GEN11_IIR_REG_SELECTOR(bank), BIT(bit));
290851951ae7SMika Kuoppala 
290951951ae7SMika Kuoppala 	/*
291051951ae7SMika Kuoppala 	 * NB: Specs do not specify how long to spin wait,
291151951ae7SMika Kuoppala 	 * so we do ~100us as an educated guess.
291251951ae7SMika Kuoppala 	 */
291351951ae7SMika Kuoppala 	timeout_ts = (local_clock() >> 10) + 100;
291451951ae7SMika Kuoppala 	do {
291551951ae7SMika Kuoppala 		ident = raw_reg_read(regs, GEN11_INTR_IDENTITY_REG(bank));
291651951ae7SMika Kuoppala 	} while (!(ident & GEN11_INTR_DATA_VALID) &&
291751951ae7SMika Kuoppala 		 !time_after32(local_clock() >> 10, timeout_ts));
291851951ae7SMika Kuoppala 
291951951ae7SMika Kuoppala 	if (unlikely(!(ident & GEN11_INTR_DATA_VALID))) {
292051951ae7SMika Kuoppala 		DRM_ERROR("INTR_IDENTITY_REG%u:%u 0x%08x not valid!\n",
292151951ae7SMika Kuoppala 			  bank, bit, ident);
292251951ae7SMika Kuoppala 		return 0;
292351951ae7SMika Kuoppala 	}
292451951ae7SMika Kuoppala 
292551951ae7SMika Kuoppala 	raw_reg_write(regs, GEN11_INTR_IDENTITY_REG(bank),
292651951ae7SMika Kuoppala 		      GEN11_INTR_DATA_VALID);
292751951ae7SMika Kuoppala 
2928f744dbc2SMika Kuoppala 	return ident;
2929f744dbc2SMika Kuoppala }
2930f744dbc2SMika Kuoppala 
2931f744dbc2SMika Kuoppala static void
2932f744dbc2SMika Kuoppala gen11_other_irq_handler(struct drm_i915_private * const i915,
2933f744dbc2SMika Kuoppala 			const u8 instance, const u16 iir)
2934f744dbc2SMika Kuoppala {
2935d02b98b8SOscar Mateo 	if (instance == OTHER_GTPM_INSTANCE)
2936d02b98b8SOscar Mateo 		return gen6_rps_irq_handler(i915, iir);
2937d02b98b8SOscar Mateo 
2938f744dbc2SMika Kuoppala 	WARN_ONCE(1, "unhandled other interrupt instance=0x%x, iir=0x%x\n",
2939f744dbc2SMika Kuoppala 		  instance, iir);
2940f744dbc2SMika Kuoppala }
2941f744dbc2SMika Kuoppala 
2942f744dbc2SMika Kuoppala static void
2943f744dbc2SMika Kuoppala gen11_engine_irq_handler(struct drm_i915_private * const i915,
2944f744dbc2SMika Kuoppala 			 const u8 class, const u8 instance, const u16 iir)
2945f744dbc2SMika Kuoppala {
2946f744dbc2SMika Kuoppala 	struct intel_engine_cs *engine;
2947f744dbc2SMika Kuoppala 
2948f744dbc2SMika Kuoppala 	if (instance <= MAX_ENGINE_INSTANCE)
2949f744dbc2SMika Kuoppala 		engine = i915->engine_class[class][instance];
2950f744dbc2SMika Kuoppala 	else
2951f744dbc2SMika Kuoppala 		engine = NULL;
2952f744dbc2SMika Kuoppala 
2953f744dbc2SMika Kuoppala 	if (likely(engine))
2954f744dbc2SMika Kuoppala 		return gen8_cs_irq_handler(engine, iir);
2955f744dbc2SMika Kuoppala 
2956f744dbc2SMika Kuoppala 	WARN_ONCE(1, "unhandled engine interrupt class=0x%x, instance=0x%x\n",
2957f744dbc2SMika Kuoppala 		  class, instance);
2958f744dbc2SMika Kuoppala }
2959f744dbc2SMika Kuoppala 
2960f744dbc2SMika Kuoppala static void
2961f744dbc2SMika Kuoppala gen11_gt_identity_handler(struct drm_i915_private * const i915,
2962f744dbc2SMika Kuoppala 			  const u32 identity)
2963f744dbc2SMika Kuoppala {
2964f744dbc2SMika Kuoppala 	const u8 class = GEN11_INTR_ENGINE_CLASS(identity);
2965f744dbc2SMika Kuoppala 	const u8 instance = GEN11_INTR_ENGINE_INSTANCE(identity);
2966f744dbc2SMika Kuoppala 	const u16 intr = GEN11_INTR_ENGINE_INTR(identity);
2967f744dbc2SMika Kuoppala 
2968f744dbc2SMika Kuoppala 	if (unlikely(!intr))
2969f744dbc2SMika Kuoppala 		return;
2970f744dbc2SMika Kuoppala 
2971f744dbc2SMika Kuoppala 	if (class <= COPY_ENGINE_CLASS)
2972f744dbc2SMika Kuoppala 		return gen11_engine_irq_handler(i915, class, instance, intr);
2973f744dbc2SMika Kuoppala 
2974f744dbc2SMika Kuoppala 	if (class == OTHER_CLASS)
2975f744dbc2SMika Kuoppala 		return gen11_other_irq_handler(i915, instance, intr);
2976f744dbc2SMika Kuoppala 
2977f744dbc2SMika Kuoppala 	WARN_ONCE(1, "unknown interrupt class=0x%x, instance=0x%x, intr=0x%x\n",
2978f744dbc2SMika Kuoppala 		  class, instance, intr);
297951951ae7SMika Kuoppala }
298051951ae7SMika Kuoppala 
298151951ae7SMika Kuoppala static void
298296606f3bSOscar Mateo gen11_gt_bank_handler(struct drm_i915_private * const i915,
298396606f3bSOscar Mateo 		      const unsigned int bank)
298451951ae7SMika Kuoppala {
298551951ae7SMika Kuoppala 	void __iomem * const regs = i915->regs;
298651951ae7SMika Kuoppala 	unsigned long intr_dw;
298751951ae7SMika Kuoppala 	unsigned int bit;
298851951ae7SMika Kuoppala 
298996606f3bSOscar Mateo 	lockdep_assert_held(&i915->irq_lock);
299051951ae7SMika Kuoppala 
299151951ae7SMika Kuoppala 	intr_dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank));
299251951ae7SMika Kuoppala 
299351951ae7SMika Kuoppala 	if (unlikely(!intr_dw)) {
299451951ae7SMika Kuoppala 		DRM_ERROR("GT_INTR_DW%u blank!\n", bank);
299596606f3bSOscar Mateo 		return;
299651951ae7SMika Kuoppala 	}
299751951ae7SMika Kuoppala 
299851951ae7SMika Kuoppala 	for_each_set_bit(bit, &intr_dw, 32) {
2999f744dbc2SMika Kuoppala 		const u32 ident = gen11_gt_engine_identity(i915,
3000f744dbc2SMika Kuoppala 							   bank, bit);
300151951ae7SMika Kuoppala 
3002f744dbc2SMika Kuoppala 		gen11_gt_identity_handler(i915, ident);
300351951ae7SMika Kuoppala 	}
300451951ae7SMika Kuoppala 
300551951ae7SMika Kuoppala 	/* Clear must be after shared has been served for engine */
300651951ae7SMika Kuoppala 	raw_reg_write(regs, GEN11_GT_INTR_DW(bank), intr_dw);
300751951ae7SMika Kuoppala }
300896606f3bSOscar Mateo 
300996606f3bSOscar Mateo static void
301096606f3bSOscar Mateo gen11_gt_irq_handler(struct drm_i915_private * const i915,
301196606f3bSOscar Mateo 		     const u32 master_ctl)
301296606f3bSOscar Mateo {
301396606f3bSOscar Mateo 	unsigned int bank;
301496606f3bSOscar Mateo 
301596606f3bSOscar Mateo 	spin_lock(&i915->irq_lock);
301696606f3bSOscar Mateo 
301796606f3bSOscar Mateo 	for (bank = 0; bank < 2; bank++) {
301896606f3bSOscar Mateo 		if (master_ctl & GEN11_GT_DW_IRQ(bank))
301996606f3bSOscar Mateo 			gen11_gt_bank_handler(i915, bank);
302096606f3bSOscar Mateo 	}
302196606f3bSOscar Mateo 
302296606f3bSOscar Mateo 	spin_unlock(&i915->irq_lock);
302351951ae7SMika Kuoppala }
302451951ae7SMika Kuoppala 
3025df0d28c1SDhinakaran Pandiyan static void
3026df0d28c1SDhinakaran Pandiyan gen11_gu_misc_irq_ack(struct drm_i915_private *dev_priv, const u32 master_ctl,
3027df0d28c1SDhinakaran Pandiyan 		      u32 *iir)
3028df0d28c1SDhinakaran Pandiyan {
3029df0d28c1SDhinakaran Pandiyan 	void __iomem * const regs = dev_priv->regs;
3030df0d28c1SDhinakaran Pandiyan 
3031df0d28c1SDhinakaran Pandiyan 	if (!(master_ctl & GEN11_GU_MISC_IRQ))
3032df0d28c1SDhinakaran Pandiyan 		return;
3033df0d28c1SDhinakaran Pandiyan 
3034df0d28c1SDhinakaran Pandiyan 	*iir = raw_reg_read(regs, GEN11_GU_MISC_IIR);
3035df0d28c1SDhinakaran Pandiyan 	if (likely(*iir))
3036df0d28c1SDhinakaran Pandiyan 		raw_reg_write(regs, GEN11_GU_MISC_IIR, *iir);
3037df0d28c1SDhinakaran Pandiyan }
3038df0d28c1SDhinakaran Pandiyan 
3039df0d28c1SDhinakaran Pandiyan static void
3040df0d28c1SDhinakaran Pandiyan gen11_gu_misc_irq_handler(struct drm_i915_private *dev_priv,
3041df0d28c1SDhinakaran Pandiyan 			  const u32 master_ctl, const u32 iir)
3042df0d28c1SDhinakaran Pandiyan {
3043df0d28c1SDhinakaran Pandiyan 	if (!(master_ctl & GEN11_GU_MISC_IRQ))
3044df0d28c1SDhinakaran Pandiyan 		return;
3045df0d28c1SDhinakaran Pandiyan 
3046df0d28c1SDhinakaran Pandiyan 	if (unlikely(!iir)) {
3047df0d28c1SDhinakaran Pandiyan 		DRM_ERROR("GU_MISC iir blank!\n");
3048df0d28c1SDhinakaran Pandiyan 		return;
3049df0d28c1SDhinakaran Pandiyan 	}
3050df0d28c1SDhinakaran Pandiyan 
3051df0d28c1SDhinakaran Pandiyan 	if (iir & GEN11_GU_MISC_GSE)
3052df0d28c1SDhinakaran Pandiyan 		intel_opregion_asle_intr(dev_priv);
3053df0d28c1SDhinakaran Pandiyan 	else
3054df0d28c1SDhinakaran Pandiyan 		DRM_ERROR("Unexpected GU_MISC interrupt 0x%x\n", iir);
3055df0d28c1SDhinakaran Pandiyan }
3056df0d28c1SDhinakaran Pandiyan 
305751951ae7SMika Kuoppala static irqreturn_t gen11_irq_handler(int irq, void *arg)
305851951ae7SMika Kuoppala {
305951951ae7SMika Kuoppala 	struct drm_i915_private * const i915 = to_i915(arg);
306051951ae7SMika Kuoppala 	void __iomem * const regs = i915->regs;
306151951ae7SMika Kuoppala 	u32 master_ctl;
3062df0d28c1SDhinakaran Pandiyan 	u32 gu_misc_iir;
306351951ae7SMika Kuoppala 
306451951ae7SMika Kuoppala 	if (!intel_irqs_enabled(i915))
306551951ae7SMika Kuoppala 		return IRQ_NONE;
306651951ae7SMika Kuoppala 
306751951ae7SMika Kuoppala 	master_ctl = raw_reg_read(regs, GEN11_GFX_MSTR_IRQ);
306851951ae7SMika Kuoppala 	master_ctl &= ~GEN11_MASTER_IRQ;
306951951ae7SMika Kuoppala 	if (!master_ctl)
307051951ae7SMika Kuoppala 		return IRQ_NONE;
307151951ae7SMika Kuoppala 
307251951ae7SMika Kuoppala 	/* Disable interrupts. */
307351951ae7SMika Kuoppala 	raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, 0);
307451951ae7SMika Kuoppala 
307551951ae7SMika Kuoppala 	/* Find, clear, then process each source of interrupt. */
307651951ae7SMika Kuoppala 	gen11_gt_irq_handler(i915, master_ctl);
307751951ae7SMika Kuoppala 
307851951ae7SMika Kuoppala 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
307951951ae7SMika Kuoppala 	if (master_ctl & GEN11_DISPLAY_IRQ) {
308051951ae7SMika Kuoppala 		const u32 disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL);
308151951ae7SMika Kuoppala 
308251951ae7SMika Kuoppala 		disable_rpm_wakeref_asserts(i915);
308351951ae7SMika Kuoppala 		/*
308451951ae7SMika Kuoppala 		 * GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ
308551951ae7SMika Kuoppala 		 * for the display related bits.
308651951ae7SMika Kuoppala 		 */
308751951ae7SMika Kuoppala 		gen8_de_irq_handler(i915, disp_ctl);
308851951ae7SMika Kuoppala 		enable_rpm_wakeref_asserts(i915);
308951951ae7SMika Kuoppala 	}
309051951ae7SMika Kuoppala 
3091df0d28c1SDhinakaran Pandiyan 	gen11_gu_misc_irq_ack(i915, master_ctl, &gu_misc_iir);
3092df0d28c1SDhinakaran Pandiyan 
309351951ae7SMika Kuoppala 	/* Acknowledge and enable interrupts. */
309451951ae7SMika Kuoppala 	raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ | master_ctl);
309551951ae7SMika Kuoppala 
3096df0d28c1SDhinakaran Pandiyan 	gen11_gu_misc_irq_handler(i915, master_ctl, gu_misc_iir);
3097df0d28c1SDhinakaran Pandiyan 
309851951ae7SMika Kuoppala 	return IRQ_HANDLED;
309951951ae7SMika Kuoppala }
310051951ae7SMika Kuoppala 
3101ce800754SChris Wilson static void i915_reset_device(struct drm_i915_private *dev_priv,
3102d0667e9cSChris Wilson 			      u32 engine_mask,
3103d0667e9cSChris Wilson 			      const char *reason)
31048a905236SJesse Barnes {
3105ce800754SChris Wilson 	struct i915_gpu_error *error = &dev_priv->gpu_error;
310691c8a326SChris Wilson 	struct kobject *kobj = &dev_priv->drm.primary->kdev->kobj;
3107cce723edSBen Widawsky 	char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
3108cce723edSBen Widawsky 	char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
3109cce723edSBen Widawsky 	char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
311036703e79SChris Wilson 	struct wedge_me w;
31118a905236SJesse Barnes 
3112c033666aSChris Wilson 	kobject_uevent_env(kobj, KOBJ_CHANGE, error_event);
31138a905236SJesse Barnes 
311444d98a61SZhao Yakui 	DRM_DEBUG_DRIVER("resetting chip\n");
3115c033666aSChris Wilson 	kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event);
31161f83fee0SDaniel Vetter 
311736703e79SChris Wilson 	/* Use a watchdog to ensure that our reset completes */
311836703e79SChris Wilson 	i915_wedge_on_timeout(&w, dev_priv, 5*HZ) {
3119c033666aSChris Wilson 		intel_prepare_reset(dev_priv);
31207514747dSVille Syrjälä 
3121d0667e9cSChris Wilson 		error->reason = reason;
3122d0667e9cSChris Wilson 		error->stalled_mask = engine_mask;
3123ce800754SChris Wilson 
312436703e79SChris Wilson 		/* Signal that locked waiters should reset the GPU */
3125d0667e9cSChris Wilson 		smp_mb__before_atomic();
3126ce800754SChris Wilson 		set_bit(I915_RESET_HANDOFF, &error->flags);
3127ce800754SChris Wilson 		wake_up_all(&error->wait_queue);
31288c185ecaSChris Wilson 
312936703e79SChris Wilson 		/* Wait for anyone holding the lock to wakeup, without
313036703e79SChris Wilson 		 * blocking indefinitely on struct_mutex.
313117e1df07SDaniel Vetter 		 */
313236703e79SChris Wilson 		do {
3133780f262aSChris Wilson 			if (mutex_trylock(&dev_priv->drm.struct_mutex)) {
3134d0667e9cSChris Wilson 				i915_reset(dev_priv, engine_mask, reason);
3135221fe799SChris Wilson 				mutex_unlock(&dev_priv->drm.struct_mutex);
3136780f262aSChris Wilson 			}
3137ce800754SChris Wilson 		} while (wait_on_bit_timeout(&error->flags,
31388c185ecaSChris Wilson 					     I915_RESET_HANDOFF,
3139780f262aSChris Wilson 					     TASK_UNINTERRUPTIBLE,
314036703e79SChris Wilson 					     1));
3141f69061beSDaniel Vetter 
3142d0667e9cSChris Wilson 		error->stalled_mask = 0;
3143ce800754SChris Wilson 		error->reason = NULL;
3144ce800754SChris Wilson 
3145c033666aSChris Wilson 		intel_finish_reset(dev_priv);
314636703e79SChris Wilson 	}
3147f454c694SImre Deak 
3148ce800754SChris Wilson 	if (!test_bit(I915_WEDGED, &error->flags))
3149ce800754SChris Wilson 		kobject_uevent_env(kobj, KOBJ_CHANGE, reset_done_event);
3150f316a42cSBen Gamari }
31518a905236SJesse Barnes 
3152eaa14c24SChris Wilson static void i915_clear_error_registers(struct drm_i915_private *dev_priv)
3153c0e09200SDave Airlie {
3154eaa14c24SChris Wilson 	u32 eir;
315563eeaf38SJesse Barnes 
3156eaa14c24SChris Wilson 	if (!IS_GEN2(dev_priv))
3157eaa14c24SChris Wilson 		I915_WRITE(PGTBL_ER, I915_READ(PGTBL_ER));
315863eeaf38SJesse Barnes 
3159eaa14c24SChris Wilson 	if (INTEL_GEN(dev_priv) < 4)
3160eaa14c24SChris Wilson 		I915_WRITE(IPEIR, I915_READ(IPEIR));
3161eaa14c24SChris Wilson 	else
3162eaa14c24SChris Wilson 		I915_WRITE(IPEIR_I965, I915_READ(IPEIR_I965));
31638a905236SJesse Barnes 
3164eaa14c24SChris Wilson 	I915_WRITE(EIR, I915_READ(EIR));
316563eeaf38SJesse Barnes 	eir = I915_READ(EIR);
316663eeaf38SJesse Barnes 	if (eir) {
316763eeaf38SJesse Barnes 		/*
316863eeaf38SJesse Barnes 		 * some errors might have become stuck,
316963eeaf38SJesse Barnes 		 * mask them.
317063eeaf38SJesse Barnes 		 */
3171eaa14c24SChris Wilson 		DRM_DEBUG_DRIVER("EIR stuck: 0x%08x, masking\n", eir);
317263eeaf38SJesse Barnes 		I915_WRITE(EMR, I915_READ(EMR) | eir);
317363eeaf38SJesse Barnes 		I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
317463eeaf38SJesse Barnes 	}
317535aed2e6SChris Wilson }
317635aed2e6SChris Wilson 
317735aed2e6SChris Wilson /**
3178b8d24a06SMika Kuoppala  * i915_handle_error - handle a gpu error
317914bb2c11STvrtko Ursulin  * @dev_priv: i915 device private
318014b730fcSarun.siluvery@linux.intel.com  * @engine_mask: mask representing engines that are hung
3181ce800754SChris Wilson  * @flags: control flags
318287c390b6SMichel Thierry  * @fmt: Error message format string
318387c390b6SMichel Thierry  *
3184aafd8581SJavier Martinez Canillas  * Do some basic checking of register state at error time and
318535aed2e6SChris Wilson  * dump it to the syslog.  Also call i915_capture_error_state() to make
318635aed2e6SChris Wilson  * sure we get a record and make it available in debugfs.  Fire a uevent
318735aed2e6SChris Wilson  * so userspace knows something bad happened (should trigger collection
318835aed2e6SChris Wilson  * of a ring dump etc.).
318935aed2e6SChris Wilson  */
3190c033666aSChris Wilson void i915_handle_error(struct drm_i915_private *dev_priv,
3191c033666aSChris Wilson 		       u32 engine_mask,
3192ce800754SChris Wilson 		       unsigned long flags,
319358174462SMika Kuoppala 		       const char *fmt, ...)
319435aed2e6SChris Wilson {
3195142bc7d9SMichel Thierry 	struct intel_engine_cs *engine;
3196142bc7d9SMichel Thierry 	unsigned int tmp;
319758174462SMika Kuoppala 	char error_msg[80];
3198ce800754SChris Wilson 	char *msg = NULL;
3199ce800754SChris Wilson 
3200ce800754SChris Wilson 	if (fmt) {
3201ce800754SChris Wilson 		va_list args;
320235aed2e6SChris Wilson 
320358174462SMika Kuoppala 		va_start(args, fmt);
320458174462SMika Kuoppala 		vscnprintf(error_msg, sizeof(error_msg), fmt, args);
320558174462SMika Kuoppala 		va_end(args);
320658174462SMika Kuoppala 
3207ce800754SChris Wilson 		msg = error_msg;
3208ce800754SChris Wilson 	}
3209ce800754SChris Wilson 
32101604a86dSChris Wilson 	/*
32111604a86dSChris Wilson 	 * In most cases it's guaranteed that we get here with an RPM
32121604a86dSChris Wilson 	 * reference held, for example because there is a pending GPU
32131604a86dSChris Wilson 	 * request that won't finish until the reset is done. This
32141604a86dSChris Wilson 	 * isn't the case at least when we get here by doing a
32151604a86dSChris Wilson 	 * simulated reset via debugfs, so get an RPM reference.
32161604a86dSChris Wilson 	 */
32171604a86dSChris Wilson 	intel_runtime_pm_get(dev_priv);
32181604a86dSChris Wilson 
3219873d66fbSChris Wilson 	engine_mask &= INTEL_INFO(dev_priv)->ring_mask;
3220ce800754SChris Wilson 
3221ce800754SChris Wilson 	if (flags & I915_ERROR_CAPTURE) {
3222ce800754SChris Wilson 		i915_capture_error_state(dev_priv, engine_mask, msg);
3223eaa14c24SChris Wilson 		i915_clear_error_registers(dev_priv);
3224ce800754SChris Wilson 	}
32258a905236SJesse Barnes 
3226142bc7d9SMichel Thierry 	/*
3227142bc7d9SMichel Thierry 	 * Try engine reset when available. We fall back to full reset if
3228142bc7d9SMichel Thierry 	 * single reset fails.
3229142bc7d9SMichel Thierry 	 */
3230142bc7d9SMichel Thierry 	if (intel_has_reset_engine(dev_priv)) {
3231142bc7d9SMichel Thierry 		for_each_engine_masked(engine, dev_priv, engine_mask, tmp) {
32329db529aaSDaniel Vetter 			BUILD_BUG_ON(I915_RESET_MODESET >= I915_RESET_ENGINE);
3233142bc7d9SMichel Thierry 			if (test_and_set_bit(I915_RESET_ENGINE + engine->id,
3234142bc7d9SMichel Thierry 					     &dev_priv->gpu_error.flags))
3235142bc7d9SMichel Thierry 				continue;
3236142bc7d9SMichel Thierry 
3237ce800754SChris Wilson 			if (i915_reset_engine(engine, msg) == 0)
3238142bc7d9SMichel Thierry 				engine_mask &= ~intel_engine_flag(engine);
3239142bc7d9SMichel Thierry 
3240142bc7d9SMichel Thierry 			clear_bit(I915_RESET_ENGINE + engine->id,
3241142bc7d9SMichel Thierry 				  &dev_priv->gpu_error.flags);
3242142bc7d9SMichel Thierry 			wake_up_bit(&dev_priv->gpu_error.flags,
3243142bc7d9SMichel Thierry 				    I915_RESET_ENGINE + engine->id);
3244142bc7d9SMichel Thierry 		}
3245142bc7d9SMichel Thierry 	}
3246142bc7d9SMichel Thierry 
32478af29b0cSChris Wilson 	if (!engine_mask)
32481604a86dSChris Wilson 		goto out;
32498af29b0cSChris Wilson 
3250142bc7d9SMichel Thierry 	/* Full reset needs the mutex, stop any other user trying to do so. */
3251d5367307SChris Wilson 	if (test_and_set_bit(I915_RESET_BACKOFF, &dev_priv->gpu_error.flags)) {
3252d5367307SChris Wilson 		wait_event(dev_priv->gpu_error.reset_queue,
3253d5367307SChris Wilson 			   !test_bit(I915_RESET_BACKOFF,
3254d5367307SChris Wilson 				     &dev_priv->gpu_error.flags));
32551604a86dSChris Wilson 		goto out;
3256d5367307SChris Wilson 	}
3257ba1234d1SBen Gamari 
3258142bc7d9SMichel Thierry 	/* Prevent any other reset-engine attempt. */
3259142bc7d9SMichel Thierry 	for_each_engine(engine, dev_priv, tmp) {
3260142bc7d9SMichel Thierry 		while (test_and_set_bit(I915_RESET_ENGINE + engine->id,
3261142bc7d9SMichel Thierry 					&dev_priv->gpu_error.flags))
3262142bc7d9SMichel Thierry 			wait_on_bit(&dev_priv->gpu_error.flags,
3263142bc7d9SMichel Thierry 				    I915_RESET_ENGINE + engine->id,
3264142bc7d9SMichel Thierry 				    TASK_UNINTERRUPTIBLE);
3265142bc7d9SMichel Thierry 	}
3266142bc7d9SMichel Thierry 
3267d0667e9cSChris Wilson 	i915_reset_device(dev_priv, engine_mask, msg);
3268d5367307SChris Wilson 
3269142bc7d9SMichel Thierry 	for_each_engine(engine, dev_priv, tmp) {
3270142bc7d9SMichel Thierry 		clear_bit(I915_RESET_ENGINE + engine->id,
3271142bc7d9SMichel Thierry 			  &dev_priv->gpu_error.flags);
3272142bc7d9SMichel Thierry 	}
3273142bc7d9SMichel Thierry 
3274d5367307SChris Wilson 	clear_bit(I915_RESET_BACKOFF, &dev_priv->gpu_error.flags);
3275d5367307SChris Wilson 	wake_up_all(&dev_priv->gpu_error.reset_queue);
32761604a86dSChris Wilson 
32771604a86dSChris Wilson out:
32781604a86dSChris Wilson 	intel_runtime_pm_put(dev_priv);
32798a905236SJesse Barnes }
32808a905236SJesse Barnes 
328142f52ef8SKeith Packard /* Called from drm generic code, passed 'crtc' which
328242f52ef8SKeith Packard  * we use as a pipe index
328342f52ef8SKeith Packard  */
328486e83e35SChris Wilson static int i8xx_enable_vblank(struct drm_device *dev, unsigned int pipe)
32850a3e67a4SJesse Barnes {
3286fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
3287e9d21d7fSKeith Packard 	unsigned long irqflags;
328871e0ffa5SJesse Barnes 
32891ec14ad3SChris Wilson 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
329086e83e35SChris Wilson 	i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS);
329186e83e35SChris Wilson 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
329286e83e35SChris Wilson 
329386e83e35SChris Wilson 	return 0;
329486e83e35SChris Wilson }
329586e83e35SChris Wilson 
329686e83e35SChris Wilson static int i965_enable_vblank(struct drm_device *dev, unsigned int pipe)
329786e83e35SChris Wilson {
329886e83e35SChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
329986e83e35SChris Wilson 	unsigned long irqflags;
330086e83e35SChris Wilson 
330186e83e35SChris Wilson 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
33027c463586SKeith Packard 	i915_enable_pipestat(dev_priv, pipe,
3303755e9019SImre Deak 			     PIPE_START_VBLANK_INTERRUPT_STATUS);
33041ec14ad3SChris Wilson 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
33058692d00eSChris Wilson 
33060a3e67a4SJesse Barnes 	return 0;
33070a3e67a4SJesse Barnes }
33080a3e67a4SJesse Barnes 
330988e72717SThierry Reding static int ironlake_enable_vblank(struct drm_device *dev, unsigned int pipe)
3310f796cf8fSJesse Barnes {
3311fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
3312f796cf8fSJesse Barnes 	unsigned long irqflags;
331355b8f2a7STvrtko Ursulin 	uint32_t bit = INTEL_GEN(dev_priv) >= 7 ?
331486e83e35SChris Wilson 		DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe);
3315f796cf8fSJesse Barnes 
3316f796cf8fSJesse Barnes 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
3317fbdedaeaSVille Syrjälä 	ilk_enable_display_irq(dev_priv, bit);
3318b1f14ad0SJesse Barnes 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
3319b1f14ad0SJesse Barnes 
33202e8bf223SDhinakaran Pandiyan 	/* Even though there is no DMC, frame counter can get stuck when
33212e8bf223SDhinakaran Pandiyan 	 * PSR is active as no frames are generated.
33222e8bf223SDhinakaran Pandiyan 	 */
33232e8bf223SDhinakaran Pandiyan 	if (HAS_PSR(dev_priv))
33242e8bf223SDhinakaran Pandiyan 		drm_vblank_restore(dev, pipe);
33252e8bf223SDhinakaran Pandiyan 
3326b1f14ad0SJesse Barnes 	return 0;
3327b1f14ad0SJesse Barnes }
3328b1f14ad0SJesse Barnes 
332988e72717SThierry Reding static int gen8_enable_vblank(struct drm_device *dev, unsigned int pipe)
3330abd58f01SBen Widawsky {
3331fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
3332abd58f01SBen Widawsky 	unsigned long irqflags;
3333abd58f01SBen Widawsky 
3334abd58f01SBen Widawsky 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
3335013d3752SVille Syrjälä 	bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
3336abd58f01SBen Widawsky 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
3337013d3752SVille Syrjälä 
33382e8bf223SDhinakaran Pandiyan 	/* Even if there is no DMC, frame counter can get stuck when
33392e8bf223SDhinakaran Pandiyan 	 * PSR is active as no frames are generated, so check only for PSR.
33402e8bf223SDhinakaran Pandiyan 	 */
33412e8bf223SDhinakaran Pandiyan 	if (HAS_PSR(dev_priv))
33422e8bf223SDhinakaran Pandiyan 		drm_vblank_restore(dev, pipe);
33432e8bf223SDhinakaran Pandiyan 
3344abd58f01SBen Widawsky 	return 0;
3345abd58f01SBen Widawsky }
3346abd58f01SBen Widawsky 
334742f52ef8SKeith Packard /* Called from drm generic code, passed 'crtc' which
334842f52ef8SKeith Packard  * we use as a pipe index
334942f52ef8SKeith Packard  */
335086e83e35SChris Wilson static void i8xx_disable_vblank(struct drm_device *dev, unsigned int pipe)
335186e83e35SChris Wilson {
335286e83e35SChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
335386e83e35SChris Wilson 	unsigned long irqflags;
335486e83e35SChris Wilson 
335586e83e35SChris Wilson 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
335686e83e35SChris Wilson 	i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS);
335786e83e35SChris Wilson 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
335886e83e35SChris Wilson }
335986e83e35SChris Wilson 
336086e83e35SChris Wilson static void i965_disable_vblank(struct drm_device *dev, unsigned int pipe)
33610a3e67a4SJesse Barnes {
3362fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
3363e9d21d7fSKeith Packard 	unsigned long irqflags;
33640a3e67a4SJesse Barnes 
33651ec14ad3SChris Wilson 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
33667c463586SKeith Packard 	i915_disable_pipestat(dev_priv, pipe,
3367755e9019SImre Deak 			      PIPE_START_VBLANK_INTERRUPT_STATUS);
33681ec14ad3SChris Wilson 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
33690a3e67a4SJesse Barnes }
33700a3e67a4SJesse Barnes 
337188e72717SThierry Reding static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe)
3372f796cf8fSJesse Barnes {
3373fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
3374f796cf8fSJesse Barnes 	unsigned long irqflags;
337555b8f2a7STvrtko Ursulin 	uint32_t bit = INTEL_GEN(dev_priv) >= 7 ?
337686e83e35SChris Wilson 		DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe);
3377f796cf8fSJesse Barnes 
3378f796cf8fSJesse Barnes 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
3379fbdedaeaSVille Syrjälä 	ilk_disable_display_irq(dev_priv, bit);
3380b1f14ad0SJesse Barnes 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
3381b1f14ad0SJesse Barnes }
3382b1f14ad0SJesse Barnes 
338388e72717SThierry Reding static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
3384abd58f01SBen Widawsky {
3385fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
3386abd58f01SBen Widawsky 	unsigned long irqflags;
3387abd58f01SBen Widawsky 
3388abd58f01SBen Widawsky 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
3389013d3752SVille Syrjälä 	bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
3390abd58f01SBen Widawsky 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
3391abd58f01SBen Widawsky }
3392abd58f01SBen Widawsky 
3393b243f530STvrtko Ursulin static void ibx_irq_reset(struct drm_i915_private *dev_priv)
339491738a95SPaulo Zanoni {
33956e266956STvrtko Ursulin 	if (HAS_PCH_NOP(dev_priv))
339691738a95SPaulo Zanoni 		return;
339791738a95SPaulo Zanoni 
33983488d4ebSVille Syrjälä 	GEN3_IRQ_RESET(SDE);
3399105b122eSPaulo Zanoni 
34006e266956STvrtko Ursulin 	if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv))
3401105b122eSPaulo Zanoni 		I915_WRITE(SERR_INT, 0xffffffff);
3402622364b6SPaulo Zanoni }
3403105b122eSPaulo Zanoni 
340491738a95SPaulo Zanoni /*
3405622364b6SPaulo Zanoni  * SDEIER is also touched by the interrupt handler to work around missed PCH
3406622364b6SPaulo Zanoni  * interrupts. Hence we can't update it after the interrupt handler is enabled -
3407622364b6SPaulo Zanoni  * instead we unconditionally enable all PCH interrupt sources here, but then
3408622364b6SPaulo Zanoni  * only unmask them as needed with SDEIMR.
3409622364b6SPaulo Zanoni  *
3410622364b6SPaulo Zanoni  * This function needs to be called before interrupts are enabled.
341191738a95SPaulo Zanoni  */
3412622364b6SPaulo Zanoni static void ibx_irq_pre_postinstall(struct drm_device *dev)
3413622364b6SPaulo Zanoni {
3414fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
3415622364b6SPaulo Zanoni 
34166e266956STvrtko Ursulin 	if (HAS_PCH_NOP(dev_priv))
3417622364b6SPaulo Zanoni 		return;
3418622364b6SPaulo Zanoni 
3419622364b6SPaulo Zanoni 	WARN_ON(I915_READ(SDEIER) != 0);
342091738a95SPaulo Zanoni 	I915_WRITE(SDEIER, 0xffffffff);
342191738a95SPaulo Zanoni 	POSTING_READ(SDEIER);
342291738a95SPaulo Zanoni }
342391738a95SPaulo Zanoni 
3424b243f530STvrtko Ursulin static void gen5_gt_irq_reset(struct drm_i915_private *dev_priv)
3425d18ea1b5SDaniel Vetter {
34263488d4ebSVille Syrjälä 	GEN3_IRQ_RESET(GT);
3427b243f530STvrtko Ursulin 	if (INTEL_GEN(dev_priv) >= 6)
34283488d4ebSVille Syrjälä 		GEN3_IRQ_RESET(GEN6_PM);
3429d18ea1b5SDaniel Vetter }
3430d18ea1b5SDaniel Vetter 
343170591a41SVille Syrjälä static void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
343270591a41SVille Syrjälä {
343371b8b41dSVille Syrjälä 	if (IS_CHERRYVIEW(dev_priv))
343471b8b41dSVille Syrjälä 		I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV);
343571b8b41dSVille Syrjälä 	else
343671b8b41dSVille Syrjälä 		I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK);
343771b8b41dSVille Syrjälä 
3438ad22d106SVille Syrjälä 	i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0);
343970591a41SVille Syrjälä 	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
344070591a41SVille Syrjälä 
344144d9241eSVille Syrjälä 	i9xx_pipestat_irq_reset(dev_priv);
344270591a41SVille Syrjälä 
34433488d4ebSVille Syrjälä 	GEN3_IRQ_RESET(VLV_);
34448bd099a7SChris Wilson 	dev_priv->irq_mask = ~0u;
344570591a41SVille Syrjälä }
344670591a41SVille Syrjälä 
34478bb61306SVille Syrjälä static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
34488bb61306SVille Syrjälä {
34498bb61306SVille Syrjälä 	u32 pipestat_mask;
34509ab981f2SVille Syrjälä 	u32 enable_mask;
34518bb61306SVille Syrjälä 	enum pipe pipe;
34528bb61306SVille Syrjälä 
3453842ebf7aSVille Syrjälä 	pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS;
34548bb61306SVille Syrjälä 
34558bb61306SVille Syrjälä 	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
34568bb61306SVille Syrjälä 	for_each_pipe(dev_priv, pipe)
34578bb61306SVille Syrjälä 		i915_enable_pipestat(dev_priv, pipe, pipestat_mask);
34588bb61306SVille Syrjälä 
34599ab981f2SVille Syrjälä 	enable_mask = I915_DISPLAY_PORT_INTERRUPT |
34608bb61306SVille Syrjälä 		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
3461ebf5f921SVille Syrjälä 		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
3462ebf5f921SVille Syrjälä 		I915_LPE_PIPE_A_INTERRUPT |
3463ebf5f921SVille Syrjälä 		I915_LPE_PIPE_B_INTERRUPT;
3464ebf5f921SVille Syrjälä 
34658bb61306SVille Syrjälä 	if (IS_CHERRYVIEW(dev_priv))
3466ebf5f921SVille Syrjälä 		enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT |
3467ebf5f921SVille Syrjälä 			I915_LPE_PIPE_C_INTERRUPT;
34686b7eafc1SVille Syrjälä 
34698bd099a7SChris Wilson 	WARN_ON(dev_priv->irq_mask != ~0u);
34706b7eafc1SVille Syrjälä 
34719ab981f2SVille Syrjälä 	dev_priv->irq_mask = ~enable_mask;
34728bb61306SVille Syrjälä 
34733488d4ebSVille Syrjälä 	GEN3_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask);
34748bb61306SVille Syrjälä }
34758bb61306SVille Syrjälä 
34768bb61306SVille Syrjälä /* drm_dma.h hooks
34778bb61306SVille Syrjälä */
34788bb61306SVille Syrjälä static void ironlake_irq_reset(struct drm_device *dev)
34798bb61306SVille Syrjälä {
3480fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
34818bb61306SVille Syrjälä 
3482d420a50cSVille Syrjälä 	if (IS_GEN5(dev_priv))
34838bb61306SVille Syrjälä 		I915_WRITE(HWSTAM, 0xffffffff);
34848bb61306SVille Syrjälä 
34853488d4ebSVille Syrjälä 	GEN3_IRQ_RESET(DE);
34865db94019STvrtko Ursulin 	if (IS_GEN7(dev_priv))
34878bb61306SVille Syrjälä 		I915_WRITE(GEN7_ERR_INT, 0xffffffff);
34888bb61306SVille Syrjälä 
3489fc340442SDaniel Vetter 	if (IS_HASWELL(dev_priv)) {
3490fc340442SDaniel Vetter 		I915_WRITE(EDP_PSR_IMR, 0xffffffff);
3491fc340442SDaniel Vetter 		I915_WRITE(EDP_PSR_IIR, 0xffffffff);
3492fc340442SDaniel Vetter 	}
3493fc340442SDaniel Vetter 
3494b243f530STvrtko Ursulin 	gen5_gt_irq_reset(dev_priv);
34958bb61306SVille Syrjälä 
3496b243f530STvrtko Ursulin 	ibx_irq_reset(dev_priv);
34978bb61306SVille Syrjälä }
34988bb61306SVille Syrjälä 
34996bcdb1c8SVille Syrjälä static void valleyview_irq_reset(struct drm_device *dev)
35007e231dbeSJesse Barnes {
3501fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
35027e231dbeSJesse Barnes 
350334c7b8a7SVille Syrjälä 	I915_WRITE(VLV_MASTER_IER, 0);
350434c7b8a7SVille Syrjälä 	POSTING_READ(VLV_MASTER_IER);
350534c7b8a7SVille Syrjälä 
3506b243f530STvrtko Ursulin 	gen5_gt_irq_reset(dev_priv);
35077e231dbeSJesse Barnes 
3508ad22d106SVille Syrjälä 	spin_lock_irq(&dev_priv->irq_lock);
35099918271eSVille Syrjälä 	if (dev_priv->display_irqs_enabled)
351070591a41SVille Syrjälä 		vlv_display_irq_reset(dev_priv);
3511ad22d106SVille Syrjälä 	spin_unlock_irq(&dev_priv->irq_lock);
35127e231dbeSJesse Barnes }
35137e231dbeSJesse Barnes 
3514d6e3cca3SDaniel Vetter static void gen8_gt_irq_reset(struct drm_i915_private *dev_priv)
3515d6e3cca3SDaniel Vetter {
3516d6e3cca3SDaniel Vetter 	GEN8_IRQ_RESET_NDX(GT, 0);
3517d6e3cca3SDaniel Vetter 	GEN8_IRQ_RESET_NDX(GT, 1);
3518d6e3cca3SDaniel Vetter 	GEN8_IRQ_RESET_NDX(GT, 2);
3519d6e3cca3SDaniel Vetter 	GEN8_IRQ_RESET_NDX(GT, 3);
3520d6e3cca3SDaniel Vetter }
3521d6e3cca3SDaniel Vetter 
3522823f6b38SPaulo Zanoni static void gen8_irq_reset(struct drm_device *dev)
3523abd58f01SBen Widawsky {
3524fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
3525abd58f01SBen Widawsky 	int pipe;
3526abd58f01SBen Widawsky 
3527abd58f01SBen Widawsky 	I915_WRITE(GEN8_MASTER_IRQ, 0);
3528abd58f01SBen Widawsky 	POSTING_READ(GEN8_MASTER_IRQ);
3529abd58f01SBen Widawsky 
3530d6e3cca3SDaniel Vetter 	gen8_gt_irq_reset(dev_priv);
3531abd58f01SBen Widawsky 
3532e04f7eceSVille Syrjälä 	I915_WRITE(EDP_PSR_IMR, 0xffffffff);
3533e04f7eceSVille Syrjälä 	I915_WRITE(EDP_PSR_IIR, 0xffffffff);
3534e04f7eceSVille Syrjälä 
3535055e393fSDamien Lespiau 	for_each_pipe(dev_priv, pipe)
3536f458ebbcSDaniel Vetter 		if (intel_display_power_is_enabled(dev_priv,
3537813bde43SPaulo Zanoni 						   POWER_DOMAIN_PIPE(pipe)))
3538f86f3fb0SPaulo Zanoni 			GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
3539abd58f01SBen Widawsky 
35403488d4ebSVille Syrjälä 	GEN3_IRQ_RESET(GEN8_DE_PORT_);
35413488d4ebSVille Syrjälä 	GEN3_IRQ_RESET(GEN8_DE_MISC_);
35423488d4ebSVille Syrjälä 	GEN3_IRQ_RESET(GEN8_PCU_);
3543abd58f01SBen Widawsky 
35446e266956STvrtko Ursulin 	if (HAS_PCH_SPLIT(dev_priv))
3545b243f530STvrtko Ursulin 		ibx_irq_reset(dev_priv);
3546abd58f01SBen Widawsky }
3547abd58f01SBen Widawsky 
354851951ae7SMika Kuoppala static void gen11_gt_irq_reset(struct drm_i915_private *dev_priv)
354951951ae7SMika Kuoppala {
355051951ae7SMika Kuoppala 	/* Disable RCS, BCS, VCS and VECS class engines. */
355151951ae7SMika Kuoppala 	I915_WRITE(GEN11_RENDER_COPY_INTR_ENABLE, 0);
355251951ae7SMika Kuoppala 	I915_WRITE(GEN11_VCS_VECS_INTR_ENABLE,	  0);
355351951ae7SMika Kuoppala 
355451951ae7SMika Kuoppala 	/* Restore masks irqs on RCS, BCS, VCS and VECS engines. */
355551951ae7SMika Kuoppala 	I915_WRITE(GEN11_RCS0_RSVD_INTR_MASK,	~0);
355651951ae7SMika Kuoppala 	I915_WRITE(GEN11_BCS_RSVD_INTR_MASK,	~0);
355751951ae7SMika Kuoppala 	I915_WRITE(GEN11_VCS0_VCS1_INTR_MASK,	~0);
355851951ae7SMika Kuoppala 	I915_WRITE(GEN11_VCS2_VCS3_INTR_MASK,	~0);
355951951ae7SMika Kuoppala 	I915_WRITE(GEN11_VECS0_VECS1_INTR_MASK,	~0);
3560d02b98b8SOscar Mateo 
3561d02b98b8SOscar Mateo 	I915_WRITE(GEN11_GPM_WGBOXPERF_INTR_ENABLE, 0);
3562d02b98b8SOscar Mateo 	I915_WRITE(GEN11_GPM_WGBOXPERF_INTR_MASK,  ~0);
356351951ae7SMika Kuoppala }
356451951ae7SMika Kuoppala 
356551951ae7SMika Kuoppala static void gen11_irq_reset(struct drm_device *dev)
356651951ae7SMika Kuoppala {
356751951ae7SMika Kuoppala 	struct drm_i915_private *dev_priv = dev->dev_private;
356851951ae7SMika Kuoppala 	int pipe;
356951951ae7SMika Kuoppala 
357051951ae7SMika Kuoppala 	I915_WRITE(GEN11_GFX_MSTR_IRQ, 0);
357151951ae7SMika Kuoppala 	POSTING_READ(GEN11_GFX_MSTR_IRQ);
357251951ae7SMika Kuoppala 
357351951ae7SMika Kuoppala 	gen11_gt_irq_reset(dev_priv);
357451951ae7SMika Kuoppala 
357551951ae7SMika Kuoppala 	I915_WRITE(GEN11_DISPLAY_INT_CTL, 0);
357651951ae7SMika Kuoppala 
357751951ae7SMika Kuoppala 	for_each_pipe(dev_priv, pipe)
357851951ae7SMika Kuoppala 		if (intel_display_power_is_enabled(dev_priv,
357951951ae7SMika Kuoppala 						   POWER_DOMAIN_PIPE(pipe)))
358051951ae7SMika Kuoppala 			GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
358151951ae7SMika Kuoppala 
358251951ae7SMika Kuoppala 	GEN3_IRQ_RESET(GEN8_DE_PORT_);
358351951ae7SMika Kuoppala 	GEN3_IRQ_RESET(GEN8_DE_MISC_);
3584121e758eSDhinakaran Pandiyan 	GEN3_IRQ_RESET(GEN11_DE_HPD_);
3585df0d28c1SDhinakaran Pandiyan 	GEN3_IRQ_RESET(GEN11_GU_MISC_);
358651951ae7SMika Kuoppala 	GEN3_IRQ_RESET(GEN8_PCU_);
358751951ae7SMika Kuoppala }
358851951ae7SMika Kuoppala 
35894c6c03beSDamien Lespiau void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
3590001bd2cbSImre Deak 				     u8 pipe_mask)
3591d49bdb0eSPaulo Zanoni {
35921180e206SPaulo Zanoni 	uint32_t extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN;
35936831f3e3SVille Syrjälä 	enum pipe pipe;
3594d49bdb0eSPaulo Zanoni 
359513321786SDaniel Vetter 	spin_lock_irq(&dev_priv->irq_lock);
35969dfe2e3aSImre Deak 
35979dfe2e3aSImre Deak 	if (!intel_irqs_enabled(dev_priv)) {
35989dfe2e3aSImre Deak 		spin_unlock_irq(&dev_priv->irq_lock);
35999dfe2e3aSImre Deak 		return;
36009dfe2e3aSImre Deak 	}
36019dfe2e3aSImre Deak 
36026831f3e3SVille Syrjälä 	for_each_pipe_masked(dev_priv, pipe, pipe_mask)
36036831f3e3SVille Syrjälä 		GEN8_IRQ_INIT_NDX(DE_PIPE, pipe,
36046831f3e3SVille Syrjälä 				  dev_priv->de_irq_mask[pipe],
36056831f3e3SVille Syrjälä 				  ~dev_priv->de_irq_mask[pipe] | extra_ier);
36069dfe2e3aSImre Deak 
360713321786SDaniel Vetter 	spin_unlock_irq(&dev_priv->irq_lock);
3608d49bdb0eSPaulo Zanoni }
3609d49bdb0eSPaulo Zanoni 
3610aae8ba84SVille Syrjälä void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
3611001bd2cbSImre Deak 				     u8 pipe_mask)
3612aae8ba84SVille Syrjälä {
36136831f3e3SVille Syrjälä 	enum pipe pipe;
36146831f3e3SVille Syrjälä 
3615aae8ba84SVille Syrjälä 	spin_lock_irq(&dev_priv->irq_lock);
36169dfe2e3aSImre Deak 
36179dfe2e3aSImre Deak 	if (!intel_irqs_enabled(dev_priv)) {
36189dfe2e3aSImre Deak 		spin_unlock_irq(&dev_priv->irq_lock);
36199dfe2e3aSImre Deak 		return;
36209dfe2e3aSImre Deak 	}
36219dfe2e3aSImre Deak 
36226831f3e3SVille Syrjälä 	for_each_pipe_masked(dev_priv, pipe, pipe_mask)
36236831f3e3SVille Syrjälä 		GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
36249dfe2e3aSImre Deak 
3625aae8ba84SVille Syrjälä 	spin_unlock_irq(&dev_priv->irq_lock);
3626aae8ba84SVille Syrjälä 
3627aae8ba84SVille Syrjälä 	/* make sure we're done processing display irqs */
362891c8a326SChris Wilson 	synchronize_irq(dev_priv->drm.irq);
3629aae8ba84SVille Syrjälä }
3630aae8ba84SVille Syrjälä 
36316bcdb1c8SVille Syrjälä static void cherryview_irq_reset(struct drm_device *dev)
363243f328d7SVille Syrjälä {
3633fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
363443f328d7SVille Syrjälä 
363543f328d7SVille Syrjälä 	I915_WRITE(GEN8_MASTER_IRQ, 0);
363643f328d7SVille Syrjälä 	POSTING_READ(GEN8_MASTER_IRQ);
363743f328d7SVille Syrjälä 
3638d6e3cca3SDaniel Vetter 	gen8_gt_irq_reset(dev_priv);
363943f328d7SVille Syrjälä 
36403488d4ebSVille Syrjälä 	GEN3_IRQ_RESET(GEN8_PCU_);
364143f328d7SVille Syrjälä 
3642ad22d106SVille Syrjälä 	spin_lock_irq(&dev_priv->irq_lock);
36439918271eSVille Syrjälä 	if (dev_priv->display_irqs_enabled)
364470591a41SVille Syrjälä 		vlv_display_irq_reset(dev_priv);
3645ad22d106SVille Syrjälä 	spin_unlock_irq(&dev_priv->irq_lock);
364643f328d7SVille Syrjälä }
364743f328d7SVille Syrjälä 
364891d14251STvrtko Ursulin static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
364987a02106SVille Syrjälä 				  const u32 hpd[HPD_NUM_PINS])
365087a02106SVille Syrjälä {
365187a02106SVille Syrjälä 	struct intel_encoder *encoder;
365287a02106SVille Syrjälä 	u32 enabled_irqs = 0;
365387a02106SVille Syrjälä 
365491c8a326SChris Wilson 	for_each_intel_encoder(&dev_priv->drm, encoder)
365587a02106SVille Syrjälä 		if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED)
365687a02106SVille Syrjälä 			enabled_irqs |= hpd[encoder->hpd_pin];
365787a02106SVille Syrjälä 
365887a02106SVille Syrjälä 	return enabled_irqs;
365987a02106SVille Syrjälä }
366087a02106SVille Syrjälä 
36611a56b1a2SImre Deak static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv)
36621a56b1a2SImre Deak {
36631a56b1a2SImre Deak 	u32 hotplug;
36641a56b1a2SImre Deak 
36651a56b1a2SImre Deak 	/*
36661a56b1a2SImre Deak 	 * Enable digital hotplug on the PCH, and configure the DP short pulse
36671a56b1a2SImre Deak 	 * duration to 2ms (which is the minimum in the Display Port spec).
36681a56b1a2SImre Deak 	 * The pulse duration bits are reserved on LPT+.
36691a56b1a2SImre Deak 	 */
36701a56b1a2SImre Deak 	hotplug = I915_READ(PCH_PORT_HOTPLUG);
36711a56b1a2SImre Deak 	hotplug &= ~(PORTB_PULSE_DURATION_MASK |
36721a56b1a2SImre Deak 		     PORTC_PULSE_DURATION_MASK |
36731a56b1a2SImre Deak 		     PORTD_PULSE_DURATION_MASK);
36741a56b1a2SImre Deak 	hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms;
36751a56b1a2SImre Deak 	hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms;
36761a56b1a2SImre Deak 	hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
36771a56b1a2SImre Deak 	/*
36781a56b1a2SImre Deak 	 * When CPU and PCH are on the same package, port A
36791a56b1a2SImre Deak 	 * HPD must be enabled in both north and south.
36801a56b1a2SImre Deak 	 */
36811a56b1a2SImre Deak 	if (HAS_PCH_LPT_LP(dev_priv))
36821a56b1a2SImre Deak 		hotplug |= PORTA_HOTPLUG_ENABLE;
36831a56b1a2SImre Deak 	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
36841a56b1a2SImre Deak }
36851a56b1a2SImre Deak 
368691d14251STvrtko Ursulin static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
368782a28bcfSDaniel Vetter {
36881a56b1a2SImre Deak 	u32 hotplug_irqs, enabled_irqs;
368982a28bcfSDaniel Vetter 
369091d14251STvrtko Ursulin 	if (HAS_PCH_IBX(dev_priv)) {
3691fee884edSDaniel Vetter 		hotplug_irqs = SDE_HOTPLUG_MASK;
369291d14251STvrtko Ursulin 		enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ibx);
369382a28bcfSDaniel Vetter 	} else {
3694fee884edSDaniel Vetter 		hotplug_irqs = SDE_HOTPLUG_MASK_CPT;
369591d14251STvrtko Ursulin 		enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_cpt);
369682a28bcfSDaniel Vetter 	}
369782a28bcfSDaniel Vetter 
3698fee884edSDaniel Vetter 	ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
369982a28bcfSDaniel Vetter 
37001a56b1a2SImre Deak 	ibx_hpd_detection_setup(dev_priv);
37016dbf30ceSVille Syrjälä }
370226951cafSXiong Zhang 
3703121e758eSDhinakaran Pandiyan static void gen11_hpd_detection_setup(struct drm_i915_private *dev_priv)
3704121e758eSDhinakaran Pandiyan {
3705121e758eSDhinakaran Pandiyan 	u32 hotplug;
3706121e758eSDhinakaran Pandiyan 
3707121e758eSDhinakaran Pandiyan 	hotplug = I915_READ(GEN11_TC_HOTPLUG_CTL);
3708121e758eSDhinakaran Pandiyan 	hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
3709121e758eSDhinakaran Pandiyan 		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
3710121e758eSDhinakaran Pandiyan 		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) |
3711121e758eSDhinakaran Pandiyan 		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4);
3712121e758eSDhinakaran Pandiyan 	I915_WRITE(GEN11_TC_HOTPLUG_CTL, hotplug);
3713*b796b971SDhinakaran Pandiyan 
3714*b796b971SDhinakaran Pandiyan 	hotplug = I915_READ(GEN11_TBT_HOTPLUG_CTL);
3715*b796b971SDhinakaran Pandiyan 	hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
3716*b796b971SDhinakaran Pandiyan 		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
3717*b796b971SDhinakaran Pandiyan 		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) |
3718*b796b971SDhinakaran Pandiyan 		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4);
3719*b796b971SDhinakaran Pandiyan 	I915_WRITE(GEN11_TBT_HOTPLUG_CTL, hotplug);
3720121e758eSDhinakaran Pandiyan }
3721121e758eSDhinakaran Pandiyan 
3722121e758eSDhinakaran Pandiyan static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv)
3723121e758eSDhinakaran Pandiyan {
3724121e758eSDhinakaran Pandiyan 	u32 hotplug_irqs, enabled_irqs;
3725121e758eSDhinakaran Pandiyan 	u32 val;
3726121e758eSDhinakaran Pandiyan 
3727*b796b971SDhinakaran Pandiyan 	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_gen11);
3728*b796b971SDhinakaran Pandiyan 	hotplug_irqs = GEN11_DE_TC_HOTPLUG_MASK | GEN11_DE_TBT_HOTPLUG_MASK;
3729121e758eSDhinakaran Pandiyan 
3730121e758eSDhinakaran Pandiyan 	val = I915_READ(GEN11_DE_HPD_IMR);
3731121e758eSDhinakaran Pandiyan 	val &= ~hotplug_irqs;
3732121e758eSDhinakaran Pandiyan 	I915_WRITE(GEN11_DE_HPD_IMR, val);
3733121e758eSDhinakaran Pandiyan 	POSTING_READ(GEN11_DE_HPD_IMR);
3734121e758eSDhinakaran Pandiyan 
3735121e758eSDhinakaran Pandiyan 	gen11_hpd_detection_setup(dev_priv);
3736121e758eSDhinakaran Pandiyan }
3737121e758eSDhinakaran Pandiyan 
37382a57d9ccSImre Deak static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv)
37392a57d9ccSImre Deak {
37403b92e263SRodrigo Vivi 	u32 val, hotplug;
37413b92e263SRodrigo Vivi 
37423b92e263SRodrigo Vivi 	/* Display WA #1179 WaHardHangonHotPlug: cnp */
37433b92e263SRodrigo Vivi 	if (HAS_PCH_CNP(dev_priv)) {
37443b92e263SRodrigo Vivi 		val = I915_READ(SOUTH_CHICKEN1);
37453b92e263SRodrigo Vivi 		val &= ~CHASSIS_CLK_REQ_DURATION_MASK;
37463b92e263SRodrigo Vivi 		val |= CHASSIS_CLK_REQ_DURATION(0xf);
37473b92e263SRodrigo Vivi 		I915_WRITE(SOUTH_CHICKEN1, val);
37483b92e263SRodrigo Vivi 	}
37492a57d9ccSImre Deak 
37502a57d9ccSImre Deak 	/* Enable digital hotplug on the PCH */
37512a57d9ccSImre Deak 	hotplug = I915_READ(PCH_PORT_HOTPLUG);
37522a57d9ccSImre Deak 	hotplug |= PORTA_HOTPLUG_ENABLE |
37532a57d9ccSImre Deak 		   PORTB_HOTPLUG_ENABLE |
37542a57d9ccSImre Deak 		   PORTC_HOTPLUG_ENABLE |
37552a57d9ccSImre Deak 		   PORTD_HOTPLUG_ENABLE;
37562a57d9ccSImre Deak 	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
37572a57d9ccSImre Deak 
37582a57d9ccSImre Deak 	hotplug = I915_READ(PCH_PORT_HOTPLUG2);
37592a57d9ccSImre Deak 	hotplug |= PORTE_HOTPLUG_ENABLE;
37602a57d9ccSImre Deak 	I915_WRITE(PCH_PORT_HOTPLUG2, hotplug);
37612a57d9ccSImre Deak }
37622a57d9ccSImre Deak 
376391d14251STvrtko Ursulin static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv)
37646dbf30ceSVille Syrjälä {
37652a57d9ccSImre Deak 	u32 hotplug_irqs, enabled_irqs;
37666dbf30ceSVille Syrjälä 
37676dbf30ceSVille Syrjälä 	hotplug_irqs = SDE_HOTPLUG_MASK_SPT;
376891d14251STvrtko Ursulin 	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_spt);
37696dbf30ceSVille Syrjälä 
37706dbf30ceSVille Syrjälä 	ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
37716dbf30ceSVille Syrjälä 
37722a57d9ccSImre Deak 	spt_hpd_detection_setup(dev_priv);
377326951cafSXiong Zhang }
37747fe0b973SKeith Packard 
37751a56b1a2SImre Deak static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv)
37761a56b1a2SImre Deak {
37771a56b1a2SImre Deak 	u32 hotplug;
37781a56b1a2SImre Deak 
37791a56b1a2SImre Deak 	/*
37801a56b1a2SImre Deak 	 * Enable digital hotplug on the CPU, and configure the DP short pulse
37811a56b1a2SImre Deak 	 * duration to 2ms (which is the minimum in the Display Port spec)
37821a56b1a2SImre Deak 	 * The pulse duration bits are reserved on HSW+.
37831a56b1a2SImre Deak 	 */
37841a56b1a2SImre Deak 	hotplug = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
37851a56b1a2SImre Deak 	hotplug &= ~DIGITAL_PORTA_PULSE_DURATION_MASK;
37861a56b1a2SImre Deak 	hotplug |= DIGITAL_PORTA_HOTPLUG_ENABLE |
37871a56b1a2SImre Deak 		   DIGITAL_PORTA_PULSE_DURATION_2ms;
37881a56b1a2SImre Deak 	I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, hotplug);
37891a56b1a2SImre Deak }
37901a56b1a2SImre Deak 
379191d14251STvrtko Ursulin static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv)
3792e4ce95aaSVille Syrjälä {
37931a56b1a2SImre Deak 	u32 hotplug_irqs, enabled_irqs;
3794e4ce95aaSVille Syrjälä 
379591d14251STvrtko Ursulin 	if (INTEL_GEN(dev_priv) >= 8) {
37963a3b3c7dSVille Syrjälä 		hotplug_irqs = GEN8_PORT_DP_A_HOTPLUG;
379791d14251STvrtko Ursulin 		enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_bdw);
37983a3b3c7dSVille Syrjälä 
37993a3b3c7dSVille Syrjälä 		bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
380091d14251STvrtko Ursulin 	} else if (INTEL_GEN(dev_priv) >= 7) {
380123bb4cb5SVille Syrjälä 		hotplug_irqs = DE_DP_A_HOTPLUG_IVB;
380291d14251STvrtko Ursulin 		enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ivb);
38033a3b3c7dSVille Syrjälä 
38043a3b3c7dSVille Syrjälä 		ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
380523bb4cb5SVille Syrjälä 	} else {
3806e4ce95aaSVille Syrjälä 		hotplug_irqs = DE_DP_A_HOTPLUG;
380791d14251STvrtko Ursulin 		enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ilk);
3808e4ce95aaSVille Syrjälä 
3809e4ce95aaSVille Syrjälä 		ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
38103a3b3c7dSVille Syrjälä 	}
3811e4ce95aaSVille Syrjälä 
38121a56b1a2SImre Deak 	ilk_hpd_detection_setup(dev_priv);
3813e4ce95aaSVille Syrjälä 
381491d14251STvrtko Ursulin 	ibx_hpd_irq_setup(dev_priv);
3815e4ce95aaSVille Syrjälä }
3816e4ce95aaSVille Syrjälä 
38172a57d9ccSImre Deak static void __bxt_hpd_detection_setup(struct drm_i915_private *dev_priv,
38182a57d9ccSImre Deak 				      u32 enabled_irqs)
3819e0a20ad7SShashank Sharma {
38202a57d9ccSImre Deak 	u32 hotplug;
3821e0a20ad7SShashank Sharma 
3822a52bb15bSVille Syrjälä 	hotplug = I915_READ(PCH_PORT_HOTPLUG);
38232a57d9ccSImre Deak 	hotplug |= PORTA_HOTPLUG_ENABLE |
38242a57d9ccSImre Deak 		   PORTB_HOTPLUG_ENABLE |
38252a57d9ccSImre Deak 		   PORTC_HOTPLUG_ENABLE;
3826d252bf68SShubhangi Shrivastava 
3827d252bf68SShubhangi Shrivastava 	DRM_DEBUG_KMS("Invert bit setting: hp_ctl:%x hp_port:%x\n",
3828d252bf68SShubhangi Shrivastava 		      hotplug, enabled_irqs);
3829d252bf68SShubhangi Shrivastava 	hotplug &= ~BXT_DDI_HPD_INVERT_MASK;
3830d252bf68SShubhangi Shrivastava 
3831d252bf68SShubhangi Shrivastava 	/*
3832d252bf68SShubhangi Shrivastava 	 * For BXT invert bit has to be set based on AOB design
3833d252bf68SShubhangi Shrivastava 	 * for HPD detection logic, update it based on VBT fields.
3834d252bf68SShubhangi Shrivastava 	 */
3835d252bf68SShubhangi Shrivastava 	if ((enabled_irqs & BXT_DE_PORT_HP_DDIA) &&
3836d252bf68SShubhangi Shrivastava 	    intel_bios_is_port_hpd_inverted(dev_priv, PORT_A))
3837d252bf68SShubhangi Shrivastava 		hotplug |= BXT_DDIA_HPD_INVERT;
3838d252bf68SShubhangi Shrivastava 	if ((enabled_irqs & BXT_DE_PORT_HP_DDIB) &&
3839d252bf68SShubhangi Shrivastava 	    intel_bios_is_port_hpd_inverted(dev_priv, PORT_B))
3840d252bf68SShubhangi Shrivastava 		hotplug |= BXT_DDIB_HPD_INVERT;
3841d252bf68SShubhangi Shrivastava 	if ((enabled_irqs & BXT_DE_PORT_HP_DDIC) &&
3842d252bf68SShubhangi Shrivastava 	    intel_bios_is_port_hpd_inverted(dev_priv, PORT_C))
3843d252bf68SShubhangi Shrivastava 		hotplug |= BXT_DDIC_HPD_INVERT;
3844d252bf68SShubhangi Shrivastava 
3845a52bb15bSVille Syrjälä 	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
3846e0a20ad7SShashank Sharma }
3847e0a20ad7SShashank Sharma 
38482a57d9ccSImre Deak static void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv)
38492a57d9ccSImre Deak {
38502a57d9ccSImre Deak 	__bxt_hpd_detection_setup(dev_priv, BXT_DE_PORT_HOTPLUG_MASK);
38512a57d9ccSImre Deak }
38522a57d9ccSImre Deak 
38532a57d9ccSImre Deak static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv)
38542a57d9ccSImre Deak {
38552a57d9ccSImre Deak 	u32 hotplug_irqs, enabled_irqs;
38562a57d9ccSImre Deak 
38572a57d9ccSImre Deak 	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_bxt);
38582a57d9ccSImre Deak 	hotplug_irqs = BXT_DE_PORT_HOTPLUG_MASK;
38592a57d9ccSImre Deak 
38602a57d9ccSImre Deak 	bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
38612a57d9ccSImre Deak 
38622a57d9ccSImre Deak 	__bxt_hpd_detection_setup(dev_priv, enabled_irqs);
38632a57d9ccSImre Deak }
38642a57d9ccSImre Deak 
3865d46da437SPaulo Zanoni static void ibx_irq_postinstall(struct drm_device *dev)
3866d46da437SPaulo Zanoni {
3867fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
386882a28bcfSDaniel Vetter 	u32 mask;
3869d46da437SPaulo Zanoni 
38706e266956STvrtko Ursulin 	if (HAS_PCH_NOP(dev_priv))
3871692a04cfSDaniel Vetter 		return;
3872692a04cfSDaniel Vetter 
38736e266956STvrtko Ursulin 	if (HAS_PCH_IBX(dev_priv))
38745c673b60SDaniel Vetter 		mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
38754ebc6509SDhinakaran Pandiyan 	else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv))
38765c673b60SDaniel Vetter 		mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
38774ebc6509SDhinakaran Pandiyan 	else
38784ebc6509SDhinakaran Pandiyan 		mask = SDE_GMBUS_CPT;
38798664281bSPaulo Zanoni 
38803488d4ebSVille Syrjälä 	gen3_assert_iir_is_zero(dev_priv, SDEIIR);
3881d46da437SPaulo Zanoni 	I915_WRITE(SDEIMR, ~mask);
38822a57d9ccSImre Deak 
38832a57d9ccSImre Deak 	if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) ||
38842a57d9ccSImre Deak 	    HAS_PCH_LPT(dev_priv))
38851a56b1a2SImre Deak 		ibx_hpd_detection_setup(dev_priv);
38862a57d9ccSImre Deak 	else
38872a57d9ccSImre Deak 		spt_hpd_detection_setup(dev_priv);
3888d46da437SPaulo Zanoni }
3889d46da437SPaulo Zanoni 
38900a9a8c91SDaniel Vetter static void gen5_gt_irq_postinstall(struct drm_device *dev)
38910a9a8c91SDaniel Vetter {
3892fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
38930a9a8c91SDaniel Vetter 	u32 pm_irqs, gt_irqs;
38940a9a8c91SDaniel Vetter 
38950a9a8c91SDaniel Vetter 	pm_irqs = gt_irqs = 0;
38960a9a8c91SDaniel Vetter 
38970a9a8c91SDaniel Vetter 	dev_priv->gt_irq_mask = ~0;
38983c9192bcSTvrtko Ursulin 	if (HAS_L3_DPF(dev_priv)) {
38990a9a8c91SDaniel Vetter 		/* L3 parity interrupt is always unmasked. */
3900772c2a51STvrtko Ursulin 		dev_priv->gt_irq_mask = ~GT_PARITY_ERROR(dev_priv);
3901772c2a51STvrtko Ursulin 		gt_irqs |= GT_PARITY_ERROR(dev_priv);
39020a9a8c91SDaniel Vetter 	}
39030a9a8c91SDaniel Vetter 
39040a9a8c91SDaniel Vetter 	gt_irqs |= GT_RENDER_USER_INTERRUPT;
39055db94019STvrtko Ursulin 	if (IS_GEN5(dev_priv)) {
3906f8973c21SChris Wilson 		gt_irqs |= ILK_BSD_USER_INTERRUPT;
39070a9a8c91SDaniel Vetter 	} else {
39080a9a8c91SDaniel Vetter 		gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
39090a9a8c91SDaniel Vetter 	}
39100a9a8c91SDaniel Vetter 
39113488d4ebSVille Syrjälä 	GEN3_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs);
39120a9a8c91SDaniel Vetter 
3913b243f530STvrtko Ursulin 	if (INTEL_GEN(dev_priv) >= 6) {
391478e68d36SImre Deak 		/*
391578e68d36SImre Deak 		 * RPS interrupts will get enabled/disabled on demand when RPS
391678e68d36SImre Deak 		 * itself is enabled/disabled.
391778e68d36SImre Deak 		 */
3918f4e9af4fSAkash Goel 		if (HAS_VEBOX(dev_priv)) {
39190a9a8c91SDaniel Vetter 			pm_irqs |= PM_VEBOX_USER_INTERRUPT;
3920f4e9af4fSAkash Goel 			dev_priv->pm_ier |= PM_VEBOX_USER_INTERRUPT;
3921f4e9af4fSAkash Goel 		}
39220a9a8c91SDaniel Vetter 
3923f4e9af4fSAkash Goel 		dev_priv->pm_imr = 0xffffffff;
39243488d4ebSVille Syrjälä 		GEN3_IRQ_INIT(GEN6_PM, dev_priv->pm_imr, pm_irqs);
39250a9a8c91SDaniel Vetter 	}
39260a9a8c91SDaniel Vetter }
39270a9a8c91SDaniel Vetter 
3928f71d4af4SJesse Barnes static int ironlake_irq_postinstall(struct drm_device *dev)
3929036a4a7dSZhenyu Wang {
3930fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
39318e76f8dcSPaulo Zanoni 	u32 display_mask, extra_mask;
39328e76f8dcSPaulo Zanoni 
3933b243f530STvrtko Ursulin 	if (INTEL_GEN(dev_priv) >= 7) {
39348e76f8dcSPaulo Zanoni 		display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
3935842ebf7aSVille Syrjälä 				DE_PCH_EVENT_IVB | DE_AUX_CHANNEL_A_IVB);
39368e76f8dcSPaulo Zanoni 		extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
393723bb4cb5SVille Syrjälä 			      DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB |
393823bb4cb5SVille Syrjälä 			      DE_DP_A_HOTPLUG_IVB);
39398e76f8dcSPaulo Zanoni 	} else {
39408e76f8dcSPaulo Zanoni 		display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
3941842ebf7aSVille Syrjälä 				DE_AUX_CHANNEL_A | DE_PIPEB_CRC_DONE |
3942842ebf7aSVille Syrjälä 				DE_PIPEA_CRC_DONE | DE_POISON);
3943e4ce95aaSVille Syrjälä 		extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
3944e4ce95aaSVille Syrjälä 			      DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
3945e4ce95aaSVille Syrjälä 			      DE_DP_A_HOTPLUG);
39468e76f8dcSPaulo Zanoni 	}
3947036a4a7dSZhenyu Wang 
3948fc340442SDaniel Vetter 	if (IS_HASWELL(dev_priv)) {
3949fc340442SDaniel Vetter 		gen3_assert_iir_is_zero(dev_priv, EDP_PSR_IIR);
395054fd3149SDhinakaran Pandiyan 		intel_psr_irq_control(dev_priv, dev_priv->psr.debug);
3951fc340442SDaniel Vetter 		display_mask |= DE_EDP_PSR_INT_HSW;
3952fc340442SDaniel Vetter 	}
3953fc340442SDaniel Vetter 
39541ec14ad3SChris Wilson 	dev_priv->irq_mask = ~display_mask;
3955036a4a7dSZhenyu Wang 
3956622364b6SPaulo Zanoni 	ibx_irq_pre_postinstall(dev);
3957622364b6SPaulo Zanoni 
39583488d4ebSVille Syrjälä 	GEN3_IRQ_INIT(DE, dev_priv->irq_mask, display_mask | extra_mask);
3959036a4a7dSZhenyu Wang 
39600a9a8c91SDaniel Vetter 	gen5_gt_irq_postinstall(dev);
3961036a4a7dSZhenyu Wang 
39621a56b1a2SImre Deak 	ilk_hpd_detection_setup(dev_priv);
39631a56b1a2SImre Deak 
3964d46da437SPaulo Zanoni 	ibx_irq_postinstall(dev);
39657fe0b973SKeith Packard 
396650a0bc90STvrtko Ursulin 	if (IS_IRONLAKE_M(dev_priv)) {
39676005ce42SDaniel Vetter 		/* Enable PCU event interrupts
39686005ce42SDaniel Vetter 		 *
39696005ce42SDaniel Vetter 		 * spinlocking not required here for correctness since interrupt
39704bc9d430SDaniel Vetter 		 * setup is guaranteed to run in single-threaded context. But we
39714bc9d430SDaniel Vetter 		 * need it to make the assert_spin_locked happy. */
3972d6207435SDaniel Vetter 		spin_lock_irq(&dev_priv->irq_lock);
3973fbdedaeaSVille Syrjälä 		ilk_enable_display_irq(dev_priv, DE_PCU_EVENT);
3974d6207435SDaniel Vetter 		spin_unlock_irq(&dev_priv->irq_lock);
3975f97108d1SJesse Barnes 	}
3976f97108d1SJesse Barnes 
3977036a4a7dSZhenyu Wang 	return 0;
3978036a4a7dSZhenyu Wang }
3979036a4a7dSZhenyu Wang 
3980f8b79e58SImre Deak void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv)
3981f8b79e58SImre Deak {
398267520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
3983f8b79e58SImre Deak 
3984f8b79e58SImre Deak 	if (dev_priv->display_irqs_enabled)
3985f8b79e58SImre Deak 		return;
3986f8b79e58SImre Deak 
3987f8b79e58SImre Deak 	dev_priv->display_irqs_enabled = true;
3988f8b79e58SImre Deak 
3989d6c69803SVille Syrjälä 	if (intel_irqs_enabled(dev_priv)) {
3990d6c69803SVille Syrjälä 		vlv_display_irq_reset(dev_priv);
3991ad22d106SVille Syrjälä 		vlv_display_irq_postinstall(dev_priv);
3992f8b79e58SImre Deak 	}
3993d6c69803SVille Syrjälä }
3994f8b79e58SImre Deak 
3995f8b79e58SImre Deak void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv)
3996f8b79e58SImre Deak {
399767520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
3998f8b79e58SImre Deak 
3999f8b79e58SImre Deak 	if (!dev_priv->display_irqs_enabled)
4000f8b79e58SImre Deak 		return;
4001f8b79e58SImre Deak 
4002f8b79e58SImre Deak 	dev_priv->display_irqs_enabled = false;
4003f8b79e58SImre Deak 
4004950eabafSImre Deak 	if (intel_irqs_enabled(dev_priv))
4005ad22d106SVille Syrjälä 		vlv_display_irq_reset(dev_priv);
4006f8b79e58SImre Deak }
4007f8b79e58SImre Deak 
40080e6c9a9eSVille Syrjälä 
40090e6c9a9eSVille Syrjälä static int valleyview_irq_postinstall(struct drm_device *dev)
40100e6c9a9eSVille Syrjälä {
4011fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
40120e6c9a9eSVille Syrjälä 
40130a9a8c91SDaniel Vetter 	gen5_gt_irq_postinstall(dev);
40147e231dbeSJesse Barnes 
4015ad22d106SVille Syrjälä 	spin_lock_irq(&dev_priv->irq_lock);
40169918271eSVille Syrjälä 	if (dev_priv->display_irqs_enabled)
4017ad22d106SVille Syrjälä 		vlv_display_irq_postinstall(dev_priv);
4018ad22d106SVille Syrjälä 	spin_unlock_irq(&dev_priv->irq_lock);
4019ad22d106SVille Syrjälä 
40207e231dbeSJesse Barnes 	I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
402134c7b8a7SVille Syrjälä 	POSTING_READ(VLV_MASTER_IER);
402220afbda2SDaniel Vetter 
402320afbda2SDaniel Vetter 	return 0;
402420afbda2SDaniel Vetter }
402520afbda2SDaniel Vetter 
4026abd58f01SBen Widawsky static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
4027abd58f01SBen Widawsky {
4028abd58f01SBen Widawsky 	/* These are interrupts we'll toggle with the ring mask register */
4029abd58f01SBen Widawsky 	uint32_t gt_interrupts[] = {
4030abd58f01SBen Widawsky 		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
403173d477f6SOscar Mateo 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
403273d477f6SOscar Mateo 			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
403373d477f6SOscar Mateo 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
4034abd58f01SBen Widawsky 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
403573d477f6SOscar Mateo 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
403673d477f6SOscar Mateo 			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT |
403773d477f6SOscar Mateo 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
4038abd58f01SBen Widawsky 		0,
403973d477f6SOscar Mateo 		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT |
404073d477f6SOscar Mateo 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT
4041abd58f01SBen Widawsky 		};
4042abd58f01SBen Widawsky 
404398735739STvrtko Ursulin 	if (HAS_L3_DPF(dev_priv))
404498735739STvrtko Ursulin 		gt_interrupts[0] |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
404598735739STvrtko Ursulin 
4046f4e9af4fSAkash Goel 	dev_priv->pm_ier = 0x0;
4047f4e9af4fSAkash Goel 	dev_priv->pm_imr = ~dev_priv->pm_ier;
40489a2d2d87SDeepak S 	GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
40499a2d2d87SDeepak S 	GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
405078e68d36SImre Deak 	/*
405178e68d36SImre Deak 	 * RPS interrupts will get enabled/disabled on demand when RPS itself
405226705e20SSagar Arun Kamble 	 * is enabled/disabled. Same wil be the case for GuC interrupts.
405378e68d36SImre Deak 	 */
4054f4e9af4fSAkash Goel 	GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier);
40559a2d2d87SDeepak S 	GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
4056abd58f01SBen Widawsky }
4057abd58f01SBen Widawsky 
4058abd58f01SBen Widawsky static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
4059abd58f01SBen Widawsky {
4060770de83dSDamien Lespiau 	uint32_t de_pipe_masked = GEN8_PIPE_CDCLK_CRC_DONE;
4061770de83dSDamien Lespiau 	uint32_t de_pipe_enables;
40623a3b3c7dSVille Syrjälä 	u32 de_port_masked = GEN8_AUX_CHANNEL_A;
40633a3b3c7dSVille Syrjälä 	u32 de_port_enables;
4064df0d28c1SDhinakaran Pandiyan 	u32 de_misc_masked = GEN8_DE_EDP_PSR;
40653a3b3c7dSVille Syrjälä 	enum pipe pipe;
4066770de83dSDamien Lespiau 
4067df0d28c1SDhinakaran Pandiyan 	if (INTEL_GEN(dev_priv) <= 10)
4068df0d28c1SDhinakaran Pandiyan 		de_misc_masked |= GEN8_DE_MISC_GSE;
4069df0d28c1SDhinakaran Pandiyan 
4070bca2bf2aSPandiyan, Dhinakaran 	if (INTEL_GEN(dev_priv) >= 9) {
4071842ebf7aSVille Syrjälä 		de_pipe_masked |= GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
40723a3b3c7dSVille Syrjälä 		de_port_masked |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
407388e04703SJesse Barnes 				  GEN9_AUX_CHANNEL_D;
4074cc3f90f0SAnder Conselvan de Oliveira 		if (IS_GEN9_LP(dev_priv))
40753a3b3c7dSVille Syrjälä 			de_port_masked |= BXT_DE_PORT_GMBUS;
40763a3b3c7dSVille Syrjälä 	} else {
4077842ebf7aSVille Syrjälä 		de_pipe_masked |= GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
40783a3b3c7dSVille Syrjälä 	}
4079770de83dSDamien Lespiau 
4080bb187e93SJames Ausmus 	if (INTEL_GEN(dev_priv) >= 11)
4081bb187e93SJames Ausmus 		de_port_masked |= ICL_AUX_CHANNEL_E;
4082bb187e93SJames Ausmus 
40839bb635d9SDhinakaran Pandiyan 	if (IS_CNL_WITH_PORT_F(dev_priv) || INTEL_GEN(dev_priv) >= 11)
4084a324fcacSRodrigo Vivi 		de_port_masked |= CNL_AUX_CHANNEL_F;
4085a324fcacSRodrigo Vivi 
4086770de83dSDamien Lespiau 	de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
4087770de83dSDamien Lespiau 					   GEN8_PIPE_FIFO_UNDERRUN;
4088770de83dSDamien Lespiau 
40893a3b3c7dSVille Syrjälä 	de_port_enables = de_port_masked;
4090cc3f90f0SAnder Conselvan de Oliveira 	if (IS_GEN9_LP(dev_priv))
4091a52bb15bSVille Syrjälä 		de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK;
4092a52bb15bSVille Syrjälä 	else if (IS_BROADWELL(dev_priv))
40933a3b3c7dSVille Syrjälä 		de_port_enables |= GEN8_PORT_DP_A_HOTPLUG;
40943a3b3c7dSVille Syrjälä 
4095e04f7eceSVille Syrjälä 	gen3_assert_iir_is_zero(dev_priv, EDP_PSR_IIR);
409654fd3149SDhinakaran Pandiyan 	intel_psr_irq_control(dev_priv, dev_priv->psr.debug);
4097e04f7eceSVille Syrjälä 
40980a195c02SMika Kahola 	for_each_pipe(dev_priv, pipe) {
40990a195c02SMika Kahola 		dev_priv->de_irq_mask[pipe] = ~de_pipe_masked;
4100abd58f01SBen Widawsky 
4101f458ebbcSDaniel Vetter 		if (intel_display_power_is_enabled(dev_priv,
4102813bde43SPaulo Zanoni 				POWER_DOMAIN_PIPE(pipe)))
4103813bde43SPaulo Zanoni 			GEN8_IRQ_INIT_NDX(DE_PIPE, pipe,
4104813bde43SPaulo Zanoni 					  dev_priv->de_irq_mask[pipe],
410535079899SPaulo Zanoni 					  de_pipe_enables);
41060a195c02SMika Kahola 	}
4107abd58f01SBen Widawsky 
41083488d4ebSVille Syrjälä 	GEN3_IRQ_INIT(GEN8_DE_PORT_, ~de_port_masked, de_port_enables);
41093488d4ebSVille Syrjälä 	GEN3_IRQ_INIT(GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked);
41102a57d9ccSImre Deak 
4111121e758eSDhinakaran Pandiyan 	if (INTEL_GEN(dev_priv) >= 11) {
4112121e758eSDhinakaran Pandiyan 		u32 de_hpd_masked = 0;
4113*b796b971SDhinakaran Pandiyan 		u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK |
4114*b796b971SDhinakaran Pandiyan 				     GEN11_DE_TBT_HOTPLUG_MASK;
4115121e758eSDhinakaran Pandiyan 
4116121e758eSDhinakaran Pandiyan 		GEN3_IRQ_INIT(GEN11_DE_HPD_, ~de_hpd_masked, de_hpd_enables);
4117121e758eSDhinakaran Pandiyan 		gen11_hpd_detection_setup(dev_priv);
4118121e758eSDhinakaran Pandiyan 	} else if (IS_GEN9_LP(dev_priv)) {
41192a57d9ccSImre Deak 		bxt_hpd_detection_setup(dev_priv);
4120121e758eSDhinakaran Pandiyan 	} else if (IS_BROADWELL(dev_priv)) {
41211a56b1a2SImre Deak 		ilk_hpd_detection_setup(dev_priv);
4122abd58f01SBen Widawsky 	}
4123121e758eSDhinakaran Pandiyan }
4124abd58f01SBen Widawsky 
4125abd58f01SBen Widawsky static int gen8_irq_postinstall(struct drm_device *dev)
4126abd58f01SBen Widawsky {
4127fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
4128abd58f01SBen Widawsky 
41296e266956STvrtko Ursulin 	if (HAS_PCH_SPLIT(dev_priv))
4130622364b6SPaulo Zanoni 		ibx_irq_pre_postinstall(dev);
4131622364b6SPaulo Zanoni 
4132abd58f01SBen Widawsky 	gen8_gt_irq_postinstall(dev_priv);
4133abd58f01SBen Widawsky 	gen8_de_irq_postinstall(dev_priv);
4134abd58f01SBen Widawsky 
41356e266956STvrtko Ursulin 	if (HAS_PCH_SPLIT(dev_priv))
4136abd58f01SBen Widawsky 		ibx_irq_postinstall(dev);
4137abd58f01SBen Widawsky 
4138e5328c43SVille Syrjälä 	I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
4139abd58f01SBen Widawsky 	POSTING_READ(GEN8_MASTER_IRQ);
4140abd58f01SBen Widawsky 
4141abd58f01SBen Widawsky 	return 0;
4142abd58f01SBen Widawsky }
4143abd58f01SBen Widawsky 
414451951ae7SMika Kuoppala static void gen11_gt_irq_postinstall(struct drm_i915_private *dev_priv)
414551951ae7SMika Kuoppala {
414651951ae7SMika Kuoppala 	const u32 irqs = GT_RENDER_USER_INTERRUPT | GT_CONTEXT_SWITCH_INTERRUPT;
414751951ae7SMika Kuoppala 
414851951ae7SMika Kuoppala 	BUILD_BUG_ON(irqs & 0xffff0000);
414951951ae7SMika Kuoppala 
415051951ae7SMika Kuoppala 	/* Enable RCS, BCS, VCS and VECS class interrupts. */
415151951ae7SMika Kuoppala 	I915_WRITE(GEN11_RENDER_COPY_INTR_ENABLE, irqs << 16 | irqs);
415251951ae7SMika Kuoppala 	I915_WRITE(GEN11_VCS_VECS_INTR_ENABLE,	  irqs << 16 | irqs);
415351951ae7SMika Kuoppala 
415451951ae7SMika Kuoppala 	/* Unmask irqs on RCS, BCS, VCS and VECS engines. */
415551951ae7SMika Kuoppala 	I915_WRITE(GEN11_RCS0_RSVD_INTR_MASK,	~(irqs << 16));
415651951ae7SMika Kuoppala 	I915_WRITE(GEN11_BCS_RSVD_INTR_MASK,	~(irqs << 16));
415751951ae7SMika Kuoppala 	I915_WRITE(GEN11_VCS0_VCS1_INTR_MASK,	~(irqs | irqs << 16));
415851951ae7SMika Kuoppala 	I915_WRITE(GEN11_VCS2_VCS3_INTR_MASK,	~(irqs | irqs << 16));
415951951ae7SMika Kuoppala 	I915_WRITE(GEN11_VECS0_VECS1_INTR_MASK,	~(irqs | irqs << 16));
416051951ae7SMika Kuoppala 
4161d02b98b8SOscar Mateo 	/*
4162d02b98b8SOscar Mateo 	 * RPS interrupts will get enabled/disabled on demand when RPS itself
4163d02b98b8SOscar Mateo 	 * is enabled/disabled.
4164d02b98b8SOscar Mateo 	 */
4165d02b98b8SOscar Mateo 	dev_priv->pm_ier = 0x0;
4166d02b98b8SOscar Mateo 	dev_priv->pm_imr = ~dev_priv->pm_ier;
4167d02b98b8SOscar Mateo 	I915_WRITE(GEN11_GPM_WGBOXPERF_INTR_ENABLE, 0);
4168d02b98b8SOscar Mateo 	I915_WRITE(GEN11_GPM_WGBOXPERF_INTR_MASK,  ~0);
416951951ae7SMika Kuoppala }
417051951ae7SMika Kuoppala 
417151951ae7SMika Kuoppala static int gen11_irq_postinstall(struct drm_device *dev)
417251951ae7SMika Kuoppala {
417351951ae7SMika Kuoppala 	struct drm_i915_private *dev_priv = dev->dev_private;
4174df0d28c1SDhinakaran Pandiyan 	u32 gu_misc_masked = GEN11_GU_MISC_GSE;
417551951ae7SMika Kuoppala 
417651951ae7SMika Kuoppala 	gen11_gt_irq_postinstall(dev_priv);
417751951ae7SMika Kuoppala 	gen8_de_irq_postinstall(dev_priv);
417851951ae7SMika Kuoppala 
4179df0d28c1SDhinakaran Pandiyan 	GEN3_IRQ_INIT(GEN11_GU_MISC_, ~gu_misc_masked, gu_misc_masked);
4180df0d28c1SDhinakaran Pandiyan 
418151951ae7SMika Kuoppala 	I915_WRITE(GEN11_DISPLAY_INT_CTL, GEN11_DISPLAY_IRQ_ENABLE);
418251951ae7SMika Kuoppala 
418351951ae7SMika Kuoppala 	I915_WRITE(GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ);
418451951ae7SMika Kuoppala 	POSTING_READ(GEN11_GFX_MSTR_IRQ);
418551951ae7SMika Kuoppala 
418651951ae7SMika Kuoppala 	return 0;
418751951ae7SMika Kuoppala }
418851951ae7SMika Kuoppala 
418943f328d7SVille Syrjälä static int cherryview_irq_postinstall(struct drm_device *dev)
419043f328d7SVille Syrjälä {
4191fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
419243f328d7SVille Syrjälä 
419343f328d7SVille Syrjälä 	gen8_gt_irq_postinstall(dev_priv);
419443f328d7SVille Syrjälä 
4195ad22d106SVille Syrjälä 	spin_lock_irq(&dev_priv->irq_lock);
41969918271eSVille Syrjälä 	if (dev_priv->display_irqs_enabled)
4197ad22d106SVille Syrjälä 		vlv_display_irq_postinstall(dev_priv);
4198ad22d106SVille Syrjälä 	spin_unlock_irq(&dev_priv->irq_lock);
4199ad22d106SVille Syrjälä 
4200e5328c43SVille Syrjälä 	I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
420143f328d7SVille Syrjälä 	POSTING_READ(GEN8_MASTER_IRQ);
420243f328d7SVille Syrjälä 
420343f328d7SVille Syrjälä 	return 0;
420443f328d7SVille Syrjälä }
420543f328d7SVille Syrjälä 
42066bcdb1c8SVille Syrjälä static void i8xx_irq_reset(struct drm_device *dev)
4207c2798b19SChris Wilson {
4208fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
4209c2798b19SChris Wilson 
421044d9241eSVille Syrjälä 	i9xx_pipestat_irq_reset(dev_priv);
421144d9241eSVille Syrjälä 
4212d420a50cSVille Syrjälä 	I915_WRITE16(HWSTAM, 0xffff);
4213d420a50cSVille Syrjälä 
4214e9e9848aSVille Syrjälä 	GEN2_IRQ_RESET();
4215c2798b19SChris Wilson }
4216c2798b19SChris Wilson 
4217c2798b19SChris Wilson static int i8xx_irq_postinstall(struct drm_device *dev)
4218c2798b19SChris Wilson {
4219fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
4220e9e9848aSVille Syrjälä 	u16 enable_mask;
4221c2798b19SChris Wilson 
4222045cebd2SVille Syrjälä 	I915_WRITE16(EMR, ~(I915_ERROR_PAGE_TABLE |
4223045cebd2SVille Syrjälä 			    I915_ERROR_MEMORY_REFRESH));
4224c2798b19SChris Wilson 
4225c2798b19SChris Wilson 	/* Unmask the interrupts that we always want on. */
4226c2798b19SChris Wilson 	dev_priv->irq_mask =
4227c2798b19SChris Wilson 		~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
4228842ebf7aSVille Syrjälä 		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
4229c2798b19SChris Wilson 
4230e9e9848aSVille Syrjälä 	enable_mask =
4231c2798b19SChris Wilson 		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
4232c2798b19SChris Wilson 		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
4233e9e9848aSVille Syrjälä 		I915_USER_INTERRUPT;
4234e9e9848aSVille Syrjälä 
4235e9e9848aSVille Syrjälä 	GEN2_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
4236c2798b19SChris Wilson 
4237379ef82dSDaniel Vetter 	/* Interrupt setup is already guaranteed to be single-threaded, this is
4238379ef82dSDaniel Vetter 	 * just to make the assert_spin_locked check happy. */
4239d6207435SDaniel Vetter 	spin_lock_irq(&dev_priv->irq_lock);
4240755e9019SImre Deak 	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
4241755e9019SImre Deak 	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
4242d6207435SDaniel Vetter 	spin_unlock_irq(&dev_priv->irq_lock);
4243379ef82dSDaniel Vetter 
4244c2798b19SChris Wilson 	return 0;
4245c2798b19SChris Wilson }
4246c2798b19SChris Wilson 
4247ff1f525eSDaniel Vetter static irqreturn_t i8xx_irq_handler(int irq, void *arg)
4248c2798b19SChris Wilson {
424945a83f84SDaniel Vetter 	struct drm_device *dev = arg;
4250fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
4251af722d28SVille Syrjälä 	irqreturn_t ret = IRQ_NONE;
4252c2798b19SChris Wilson 
42532dd2a883SImre Deak 	if (!intel_irqs_enabled(dev_priv))
42542dd2a883SImre Deak 		return IRQ_NONE;
42552dd2a883SImre Deak 
42561f814dacSImre Deak 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
42571f814dacSImre Deak 	disable_rpm_wakeref_asserts(dev_priv);
42581f814dacSImre Deak 
4259af722d28SVille Syrjälä 	do {
4260af722d28SVille Syrjälä 		u32 pipe_stats[I915_MAX_PIPES] = {};
4261af722d28SVille Syrjälä 		u16 iir;
4262af722d28SVille Syrjälä 
4263c2798b19SChris Wilson 		iir = I915_READ16(IIR);
4264c2798b19SChris Wilson 		if (iir == 0)
4265af722d28SVille Syrjälä 			break;
4266c2798b19SChris Wilson 
4267af722d28SVille Syrjälä 		ret = IRQ_HANDLED;
4268c2798b19SChris Wilson 
4269eb64343cSVille Syrjälä 		/* Call regardless, as some status bits might not be
4270eb64343cSVille Syrjälä 		 * signalled in iir */
4271eb64343cSVille Syrjälä 		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
4272c2798b19SChris Wilson 
4273fd3a4024SDaniel Vetter 		I915_WRITE16(IIR, iir);
4274c2798b19SChris Wilson 
4275c2798b19SChris Wilson 		if (iir & I915_USER_INTERRUPT)
42763b3f1650SAkash Goel 			notify_ring(dev_priv->engine[RCS]);
4277c2798b19SChris Wilson 
4278af722d28SVille Syrjälä 		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
4279af722d28SVille Syrjälä 			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
4280af722d28SVille Syrjälä 
4281eb64343cSVille Syrjälä 		i8xx_pipestat_irq_handler(dev_priv, iir, pipe_stats);
4282af722d28SVille Syrjälä 	} while (0);
4283c2798b19SChris Wilson 
42841f814dacSImre Deak 	enable_rpm_wakeref_asserts(dev_priv);
42851f814dacSImre Deak 
42861f814dacSImre Deak 	return ret;
4287c2798b19SChris Wilson }
4288c2798b19SChris Wilson 
42896bcdb1c8SVille Syrjälä static void i915_irq_reset(struct drm_device *dev)
4290a266c7d5SChris Wilson {
4291fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
4292a266c7d5SChris Wilson 
429356b857a5STvrtko Ursulin 	if (I915_HAS_HOTPLUG(dev_priv)) {
42940706f17cSEgbert Eich 		i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
4295a266c7d5SChris Wilson 		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
4296a266c7d5SChris Wilson 	}
4297a266c7d5SChris Wilson 
429844d9241eSVille Syrjälä 	i9xx_pipestat_irq_reset(dev_priv);
429944d9241eSVille Syrjälä 
4300d420a50cSVille Syrjälä 	I915_WRITE(HWSTAM, 0xffffffff);
430144d9241eSVille Syrjälä 
4302ba7eb789SVille Syrjälä 	GEN3_IRQ_RESET();
4303a266c7d5SChris Wilson }
4304a266c7d5SChris Wilson 
4305a266c7d5SChris Wilson static int i915_irq_postinstall(struct drm_device *dev)
4306a266c7d5SChris Wilson {
4307fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
430838bde180SChris Wilson 	u32 enable_mask;
4309a266c7d5SChris Wilson 
4310045cebd2SVille Syrjälä 	I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE |
4311045cebd2SVille Syrjälä 			  I915_ERROR_MEMORY_REFRESH));
431238bde180SChris Wilson 
431338bde180SChris Wilson 	/* Unmask the interrupts that we always want on. */
431438bde180SChris Wilson 	dev_priv->irq_mask =
431538bde180SChris Wilson 		~(I915_ASLE_INTERRUPT |
431638bde180SChris Wilson 		  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
4317842ebf7aSVille Syrjälä 		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
431838bde180SChris Wilson 
431938bde180SChris Wilson 	enable_mask =
432038bde180SChris Wilson 		I915_ASLE_INTERRUPT |
432138bde180SChris Wilson 		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
432238bde180SChris Wilson 		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
432338bde180SChris Wilson 		I915_USER_INTERRUPT;
432438bde180SChris Wilson 
432556b857a5STvrtko Ursulin 	if (I915_HAS_HOTPLUG(dev_priv)) {
4326a266c7d5SChris Wilson 		/* Enable in IER... */
4327a266c7d5SChris Wilson 		enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
4328a266c7d5SChris Wilson 		/* and unmask in IMR */
4329a266c7d5SChris Wilson 		dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT;
4330a266c7d5SChris Wilson 	}
4331a266c7d5SChris Wilson 
4332ba7eb789SVille Syrjälä 	GEN3_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
4333a266c7d5SChris Wilson 
4334379ef82dSDaniel Vetter 	/* Interrupt setup is already guaranteed to be single-threaded, this is
4335379ef82dSDaniel Vetter 	 * just to make the assert_spin_locked check happy. */
4336d6207435SDaniel Vetter 	spin_lock_irq(&dev_priv->irq_lock);
4337755e9019SImre Deak 	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
4338755e9019SImre Deak 	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
4339d6207435SDaniel Vetter 	spin_unlock_irq(&dev_priv->irq_lock);
4340379ef82dSDaniel Vetter 
4341c30bb1fdSVille Syrjälä 	i915_enable_asle_pipestat(dev_priv);
4342c30bb1fdSVille Syrjälä 
434320afbda2SDaniel Vetter 	return 0;
434420afbda2SDaniel Vetter }
434520afbda2SDaniel Vetter 
4346ff1f525eSDaniel Vetter static irqreturn_t i915_irq_handler(int irq, void *arg)
4347a266c7d5SChris Wilson {
434845a83f84SDaniel Vetter 	struct drm_device *dev = arg;
4349fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
4350af722d28SVille Syrjälä 	irqreturn_t ret = IRQ_NONE;
4351a266c7d5SChris Wilson 
43522dd2a883SImre Deak 	if (!intel_irqs_enabled(dev_priv))
43532dd2a883SImre Deak 		return IRQ_NONE;
43542dd2a883SImre Deak 
43551f814dacSImre Deak 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
43561f814dacSImre Deak 	disable_rpm_wakeref_asserts(dev_priv);
43571f814dacSImre Deak 
435838bde180SChris Wilson 	do {
4359eb64343cSVille Syrjälä 		u32 pipe_stats[I915_MAX_PIPES] = {};
4360af722d28SVille Syrjälä 		u32 hotplug_status = 0;
4361af722d28SVille Syrjälä 		u32 iir;
4362a266c7d5SChris Wilson 
4363af722d28SVille Syrjälä 		iir = I915_READ(IIR);
4364af722d28SVille Syrjälä 		if (iir == 0)
4365af722d28SVille Syrjälä 			break;
4366af722d28SVille Syrjälä 
4367af722d28SVille Syrjälä 		ret = IRQ_HANDLED;
4368af722d28SVille Syrjälä 
4369af722d28SVille Syrjälä 		if (I915_HAS_HOTPLUG(dev_priv) &&
4370af722d28SVille Syrjälä 		    iir & I915_DISPLAY_PORT_INTERRUPT)
4371af722d28SVille Syrjälä 			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
4372a266c7d5SChris Wilson 
4373eb64343cSVille Syrjälä 		/* Call regardless, as some status bits might not be
4374eb64343cSVille Syrjälä 		 * signalled in iir */
4375eb64343cSVille Syrjälä 		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
4376a266c7d5SChris Wilson 
4377fd3a4024SDaniel Vetter 		I915_WRITE(IIR, iir);
4378a266c7d5SChris Wilson 
4379a266c7d5SChris Wilson 		if (iir & I915_USER_INTERRUPT)
43803b3f1650SAkash Goel 			notify_ring(dev_priv->engine[RCS]);
4381a266c7d5SChris Wilson 
4382af722d28SVille Syrjälä 		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
4383af722d28SVille Syrjälä 			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
4384a266c7d5SChris Wilson 
4385af722d28SVille Syrjälä 		if (hotplug_status)
4386af722d28SVille Syrjälä 			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
4387af722d28SVille Syrjälä 
4388af722d28SVille Syrjälä 		i915_pipestat_irq_handler(dev_priv, iir, pipe_stats);
4389af722d28SVille Syrjälä 	} while (0);
4390a266c7d5SChris Wilson 
43911f814dacSImre Deak 	enable_rpm_wakeref_asserts(dev_priv);
43921f814dacSImre Deak 
4393a266c7d5SChris Wilson 	return ret;
4394a266c7d5SChris Wilson }
4395a266c7d5SChris Wilson 
43966bcdb1c8SVille Syrjälä static void i965_irq_reset(struct drm_device *dev)
4397a266c7d5SChris Wilson {
4398fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
4399a266c7d5SChris Wilson 
44000706f17cSEgbert Eich 	i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
4401a266c7d5SChris Wilson 	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
4402a266c7d5SChris Wilson 
440344d9241eSVille Syrjälä 	i9xx_pipestat_irq_reset(dev_priv);
440444d9241eSVille Syrjälä 
4405d420a50cSVille Syrjälä 	I915_WRITE(HWSTAM, 0xffffffff);
440644d9241eSVille Syrjälä 
4407ba7eb789SVille Syrjälä 	GEN3_IRQ_RESET();
4408a266c7d5SChris Wilson }
4409a266c7d5SChris Wilson 
4410a266c7d5SChris Wilson static int i965_irq_postinstall(struct drm_device *dev)
4411a266c7d5SChris Wilson {
4412fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
4413bbba0a97SChris Wilson 	u32 enable_mask;
4414a266c7d5SChris Wilson 	u32 error_mask;
4415a266c7d5SChris Wilson 
4416045cebd2SVille Syrjälä 	/*
4417045cebd2SVille Syrjälä 	 * Enable some error detection, note the instruction error mask
4418045cebd2SVille Syrjälä 	 * bit is reserved, so we leave it masked.
4419045cebd2SVille Syrjälä 	 */
4420045cebd2SVille Syrjälä 	if (IS_G4X(dev_priv)) {
4421045cebd2SVille Syrjälä 		error_mask = ~(GM45_ERROR_PAGE_TABLE |
4422045cebd2SVille Syrjälä 			       GM45_ERROR_MEM_PRIV |
4423045cebd2SVille Syrjälä 			       GM45_ERROR_CP_PRIV |
4424045cebd2SVille Syrjälä 			       I915_ERROR_MEMORY_REFRESH);
4425045cebd2SVille Syrjälä 	} else {
4426045cebd2SVille Syrjälä 		error_mask = ~(I915_ERROR_PAGE_TABLE |
4427045cebd2SVille Syrjälä 			       I915_ERROR_MEMORY_REFRESH);
4428045cebd2SVille Syrjälä 	}
4429045cebd2SVille Syrjälä 	I915_WRITE(EMR, error_mask);
4430045cebd2SVille Syrjälä 
4431a266c7d5SChris Wilson 	/* Unmask the interrupts that we always want on. */
4432c30bb1fdSVille Syrjälä 	dev_priv->irq_mask =
4433c30bb1fdSVille Syrjälä 		~(I915_ASLE_INTERRUPT |
4434adca4730SChris Wilson 		  I915_DISPLAY_PORT_INTERRUPT |
4435bbba0a97SChris Wilson 		  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
4436bbba0a97SChris Wilson 		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
4437bbba0a97SChris Wilson 		  I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
4438bbba0a97SChris Wilson 
4439c30bb1fdSVille Syrjälä 	enable_mask =
4440c30bb1fdSVille Syrjälä 		I915_ASLE_INTERRUPT |
4441c30bb1fdSVille Syrjälä 		I915_DISPLAY_PORT_INTERRUPT |
4442c30bb1fdSVille Syrjälä 		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
4443c30bb1fdSVille Syrjälä 		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
4444c30bb1fdSVille Syrjälä 		I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
4445c30bb1fdSVille Syrjälä 		I915_USER_INTERRUPT;
4446bbba0a97SChris Wilson 
444791d14251STvrtko Ursulin 	if (IS_G4X(dev_priv))
4448bbba0a97SChris Wilson 		enable_mask |= I915_BSD_USER_INTERRUPT;
4449a266c7d5SChris Wilson 
4450c30bb1fdSVille Syrjälä 	GEN3_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
4451c30bb1fdSVille Syrjälä 
4452b79480baSDaniel Vetter 	/* Interrupt setup is already guaranteed to be single-threaded, this is
4453b79480baSDaniel Vetter 	 * just to make the assert_spin_locked check happy. */
4454d6207435SDaniel Vetter 	spin_lock_irq(&dev_priv->irq_lock);
4455755e9019SImre Deak 	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
4456755e9019SImre Deak 	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
4457755e9019SImre Deak 	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
4458d6207435SDaniel Vetter 	spin_unlock_irq(&dev_priv->irq_lock);
4459a266c7d5SChris Wilson 
446091d14251STvrtko Ursulin 	i915_enable_asle_pipestat(dev_priv);
446120afbda2SDaniel Vetter 
446220afbda2SDaniel Vetter 	return 0;
446320afbda2SDaniel Vetter }
446420afbda2SDaniel Vetter 
446591d14251STvrtko Ursulin static void i915_hpd_irq_setup(struct drm_i915_private *dev_priv)
446620afbda2SDaniel Vetter {
446720afbda2SDaniel Vetter 	u32 hotplug_en;
446820afbda2SDaniel Vetter 
446967520415SChris Wilson 	lockdep_assert_held(&dev_priv->irq_lock);
4470b5ea2d56SDaniel Vetter 
4471adca4730SChris Wilson 	/* Note HDMI and DP share hotplug bits */
4472e5868a31SEgbert Eich 	/* enable bits are the same for all generations */
447391d14251STvrtko Ursulin 	hotplug_en = intel_hpd_enabled_irqs(dev_priv, hpd_mask_i915);
4474a266c7d5SChris Wilson 	/* Programming the CRT detection parameters tends
4475a266c7d5SChris Wilson 	   to generate a spurious hotplug event about three
4476a266c7d5SChris Wilson 	   seconds later.  So just do it once.
4477a266c7d5SChris Wilson 	*/
447891d14251STvrtko Ursulin 	if (IS_G4X(dev_priv))
4479a266c7d5SChris Wilson 		hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
4480a266c7d5SChris Wilson 	hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
4481a266c7d5SChris Wilson 
4482a266c7d5SChris Wilson 	/* Ignore TV since it's buggy */
44830706f17cSEgbert Eich 	i915_hotplug_interrupt_update_locked(dev_priv,
4484f9e3dc78SJani Nikula 					     HOTPLUG_INT_EN_MASK |
4485f9e3dc78SJani Nikula 					     CRT_HOTPLUG_VOLTAGE_COMPARE_MASK |
4486f9e3dc78SJani Nikula 					     CRT_HOTPLUG_ACTIVATION_PERIOD_64,
44870706f17cSEgbert Eich 					     hotplug_en);
4488a266c7d5SChris Wilson }
4489a266c7d5SChris Wilson 
4490ff1f525eSDaniel Vetter static irqreturn_t i965_irq_handler(int irq, void *arg)
4491a266c7d5SChris Wilson {
449245a83f84SDaniel Vetter 	struct drm_device *dev = arg;
4493fac5e23eSChris Wilson 	struct drm_i915_private *dev_priv = to_i915(dev);
4494af722d28SVille Syrjälä 	irqreturn_t ret = IRQ_NONE;
4495a266c7d5SChris Wilson 
44962dd2a883SImre Deak 	if (!intel_irqs_enabled(dev_priv))
44972dd2a883SImre Deak 		return IRQ_NONE;
44982dd2a883SImre Deak 
44991f814dacSImre Deak 	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
45001f814dacSImre Deak 	disable_rpm_wakeref_asserts(dev_priv);
45011f814dacSImre Deak 
4502af722d28SVille Syrjälä 	do {
4503eb64343cSVille Syrjälä 		u32 pipe_stats[I915_MAX_PIPES] = {};
4504af722d28SVille Syrjälä 		u32 hotplug_status = 0;
4505af722d28SVille Syrjälä 		u32 iir;
45062c8ba29fSChris Wilson 
4507af722d28SVille Syrjälä 		iir = I915_READ(IIR);
4508af722d28SVille Syrjälä 		if (iir == 0)
4509af722d28SVille Syrjälä 			break;
4510af722d28SVille Syrjälä 
4511af722d28SVille Syrjälä 		ret = IRQ_HANDLED;
4512af722d28SVille Syrjälä 
4513af722d28SVille Syrjälä 		if (iir & I915_DISPLAY_PORT_INTERRUPT)
4514af722d28SVille Syrjälä 			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
4515a266c7d5SChris Wilson 
4516eb64343cSVille Syrjälä 		/* Call regardless, as some status bits might not be
4517eb64343cSVille Syrjälä 		 * signalled in iir */
4518eb64343cSVille Syrjälä 		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
4519a266c7d5SChris Wilson 
4520fd3a4024SDaniel Vetter 		I915_WRITE(IIR, iir);
4521a266c7d5SChris Wilson 
4522a266c7d5SChris Wilson 		if (iir & I915_USER_INTERRUPT)
45233b3f1650SAkash Goel 			notify_ring(dev_priv->engine[RCS]);
4524af722d28SVille Syrjälä 
4525a266c7d5SChris Wilson 		if (iir & I915_BSD_USER_INTERRUPT)
45263b3f1650SAkash Goel 			notify_ring(dev_priv->engine[VCS]);
4527a266c7d5SChris Wilson 
4528af722d28SVille Syrjälä 		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
4529af722d28SVille Syrjälä 			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
4530515ac2bbSDaniel Vetter 
4531af722d28SVille Syrjälä 		if (hotplug_status)
4532af722d28SVille Syrjälä 			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
4533af722d28SVille Syrjälä 
4534af722d28SVille Syrjälä 		i965_pipestat_irq_handler(dev_priv, iir, pipe_stats);
4535af722d28SVille Syrjälä 	} while (0);
4536a266c7d5SChris Wilson 
45371f814dacSImre Deak 	enable_rpm_wakeref_asserts(dev_priv);
45381f814dacSImre Deak 
4539a266c7d5SChris Wilson 	return ret;
4540a266c7d5SChris Wilson }
4541a266c7d5SChris Wilson 
4542fca52a55SDaniel Vetter /**
4543fca52a55SDaniel Vetter  * intel_irq_init - initializes irq support
4544fca52a55SDaniel Vetter  * @dev_priv: i915 device instance
4545fca52a55SDaniel Vetter  *
4546fca52a55SDaniel Vetter  * This function initializes all the irq support including work items, timers
4547fca52a55SDaniel Vetter  * and all the vtables. It does not setup the interrupt itself though.
4548fca52a55SDaniel Vetter  */
4549b963291cSDaniel Vetter void intel_irq_init(struct drm_i915_private *dev_priv)
4550f71d4af4SJesse Barnes {
455191c8a326SChris Wilson 	struct drm_device *dev = &dev_priv->drm;
4552562d9baeSSagar Arun Kamble 	struct intel_rps *rps = &dev_priv->gt_pm.rps;
4553cefcff8fSJoonas Lahtinen 	int i;
45548b2e326dSChris Wilson 
455577913b39SJani Nikula 	intel_hpd_init_work(dev_priv);
455677913b39SJani Nikula 
4557562d9baeSSagar Arun Kamble 	INIT_WORK(&rps->work, gen6_pm_rps_work);
4558cefcff8fSJoonas Lahtinen 
4559a4da4fa4SDaniel Vetter 	INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
4560cefcff8fSJoonas Lahtinen 	for (i = 0; i < MAX_L3_SLICES; ++i)
4561cefcff8fSJoonas Lahtinen 		dev_priv->l3_parity.remap_info[i] = NULL;
45628b2e326dSChris Wilson 
45634805fe82STvrtko Ursulin 	if (HAS_GUC_SCHED(dev_priv))
456426705e20SSagar Arun Kamble 		dev_priv->pm_guc_events = GEN9_GUC_TO_HOST_INT_EVENT;
456526705e20SSagar Arun Kamble 
4566a6706b45SDeepak S 	/* Let's track the enabled rps events */
4567666a4537SWayne Boyer 	if (IS_VALLEYVIEW(dev_priv))
45686c65a587SVille Syrjälä 		/* WaGsvRC0ResidencyMethod:vlv */
4569e0e8c7cbSChris Wilson 		dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
457031685c25SDeepak S 	else
4571a6706b45SDeepak S 		dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
4572a6706b45SDeepak S 
4573562d9baeSSagar Arun Kamble 	rps->pm_intrmsk_mbz = 0;
45741800ad25SSagar Arun Kamble 
45751800ad25SSagar Arun Kamble 	/*
4576acf2dc22SMika Kuoppala 	 * SNB,IVB,HSW can while VLV,CHV may hard hang on looping batchbuffer
45771800ad25SSagar Arun Kamble 	 * if GEN6_PM_UP_EI_EXPIRED is masked.
45781800ad25SSagar Arun Kamble 	 *
45791800ad25SSagar Arun Kamble 	 * TODO: verify if this can be reproduced on VLV,CHV.
45801800ad25SSagar Arun Kamble 	 */
4581bca2bf2aSPandiyan, Dhinakaran 	if (INTEL_GEN(dev_priv) <= 7)
4582562d9baeSSagar Arun Kamble 		rps->pm_intrmsk_mbz |= GEN6_PM_RP_UP_EI_EXPIRED;
45831800ad25SSagar Arun Kamble 
4584bca2bf2aSPandiyan, Dhinakaran 	if (INTEL_GEN(dev_priv) >= 8)
4585562d9baeSSagar Arun Kamble 		rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
45861800ad25SSagar Arun Kamble 
4587b963291cSDaniel Vetter 	if (IS_GEN2(dev_priv)) {
45884194c088SRodrigo Vivi 		/* Gen2 doesn't have a hardware frame counter */
45894cdb83ecSVille Syrjälä 		dev->max_vblank_count = 0;
4590bca2bf2aSPandiyan, Dhinakaran 	} else if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
4591f71d4af4SJesse Barnes 		dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
4592fd8f507cSVille Syrjälä 		dev->driver->get_vblank_counter = g4x_get_vblank_counter;
4593391f75e2SVille Syrjälä 	} else {
4594391f75e2SVille Syrjälä 		dev->driver->get_vblank_counter = i915_get_vblank_counter;
4595391f75e2SVille Syrjälä 		dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
4596f71d4af4SJesse Barnes 	}
4597f71d4af4SJesse Barnes 
459821da2700SVille Syrjälä 	/*
459921da2700SVille Syrjälä 	 * Opt out of the vblank disable timer on everything except gen2.
460021da2700SVille Syrjälä 	 * Gen2 doesn't have a hardware frame counter and so depends on
460121da2700SVille Syrjälä 	 * vblank interrupts to produce sane vblank seuquence numbers.
460221da2700SVille Syrjälä 	 */
4603b963291cSDaniel Vetter 	if (!IS_GEN2(dev_priv))
460421da2700SVille Syrjälä 		dev->vblank_disable_immediate = true;
460521da2700SVille Syrjälä 
4606262fd485SChris Wilson 	/* Most platforms treat the display irq block as an always-on
4607262fd485SChris Wilson 	 * power domain. vlv/chv can disable it at runtime and need
4608262fd485SChris Wilson 	 * special care to avoid writing any of the display block registers
4609262fd485SChris Wilson 	 * outside of the power domain. We defer setting up the display irqs
4610262fd485SChris Wilson 	 * in this case to the runtime pm.
4611262fd485SChris Wilson 	 */
4612262fd485SChris Wilson 	dev_priv->display_irqs_enabled = true;
4613262fd485SChris Wilson 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
4614262fd485SChris Wilson 		dev_priv->display_irqs_enabled = false;
4615262fd485SChris Wilson 
4616317eaa95SLyude 	dev_priv->hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD;
4617317eaa95SLyude 
46181bf6ad62SDaniel Vetter 	dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos;
4619f71d4af4SJesse Barnes 	dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
4620f71d4af4SJesse Barnes 
4621b963291cSDaniel Vetter 	if (IS_CHERRYVIEW(dev_priv)) {
462243f328d7SVille Syrjälä 		dev->driver->irq_handler = cherryview_irq_handler;
46236bcdb1c8SVille Syrjälä 		dev->driver->irq_preinstall = cherryview_irq_reset;
462443f328d7SVille Syrjälä 		dev->driver->irq_postinstall = cherryview_irq_postinstall;
46256bcdb1c8SVille Syrjälä 		dev->driver->irq_uninstall = cherryview_irq_reset;
462686e83e35SChris Wilson 		dev->driver->enable_vblank = i965_enable_vblank;
462786e83e35SChris Wilson 		dev->driver->disable_vblank = i965_disable_vblank;
462843f328d7SVille Syrjälä 		dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
4629b963291cSDaniel Vetter 	} else if (IS_VALLEYVIEW(dev_priv)) {
46307e231dbeSJesse Barnes 		dev->driver->irq_handler = valleyview_irq_handler;
46316bcdb1c8SVille Syrjälä 		dev->driver->irq_preinstall = valleyview_irq_reset;
46327e231dbeSJesse Barnes 		dev->driver->irq_postinstall = valleyview_irq_postinstall;
46336bcdb1c8SVille Syrjälä 		dev->driver->irq_uninstall = valleyview_irq_reset;
463486e83e35SChris Wilson 		dev->driver->enable_vblank = i965_enable_vblank;
463586e83e35SChris Wilson 		dev->driver->disable_vblank = i965_disable_vblank;
4636fa00abe0SEgbert Eich 		dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
463751951ae7SMika Kuoppala 	} else if (INTEL_GEN(dev_priv) >= 11) {
463851951ae7SMika Kuoppala 		dev->driver->irq_handler = gen11_irq_handler;
463951951ae7SMika Kuoppala 		dev->driver->irq_preinstall = gen11_irq_reset;
464051951ae7SMika Kuoppala 		dev->driver->irq_postinstall = gen11_irq_postinstall;
464151951ae7SMika Kuoppala 		dev->driver->irq_uninstall = gen11_irq_reset;
464251951ae7SMika Kuoppala 		dev->driver->enable_vblank = gen8_enable_vblank;
464351951ae7SMika Kuoppala 		dev->driver->disable_vblank = gen8_disable_vblank;
4644121e758eSDhinakaran Pandiyan 		dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup;
4645bca2bf2aSPandiyan, Dhinakaran 	} else if (INTEL_GEN(dev_priv) >= 8) {
4646abd58f01SBen Widawsky 		dev->driver->irq_handler = gen8_irq_handler;
4647723761b8SDaniel Vetter 		dev->driver->irq_preinstall = gen8_irq_reset;
4648abd58f01SBen Widawsky 		dev->driver->irq_postinstall = gen8_irq_postinstall;
46496bcdb1c8SVille Syrjälä 		dev->driver->irq_uninstall = gen8_irq_reset;
4650abd58f01SBen Widawsky 		dev->driver->enable_vblank = gen8_enable_vblank;
4651abd58f01SBen Widawsky 		dev->driver->disable_vblank = gen8_disable_vblank;
4652cc3f90f0SAnder Conselvan de Oliveira 		if (IS_GEN9_LP(dev_priv))
4653e0a20ad7SShashank Sharma 			dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup;
46547b22b8c4SRodrigo Vivi 		else if (HAS_PCH_SPT(dev_priv) || HAS_PCH_KBP(dev_priv) ||
46557b22b8c4SRodrigo Vivi 			 HAS_PCH_CNP(dev_priv))
46566dbf30ceSVille Syrjälä 			dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup;
46576dbf30ceSVille Syrjälä 		else
46583a3b3c7dSVille Syrjälä 			dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
46596e266956STvrtko Ursulin 	} else if (HAS_PCH_SPLIT(dev_priv)) {
4660f71d4af4SJesse Barnes 		dev->driver->irq_handler = ironlake_irq_handler;
4661723761b8SDaniel Vetter 		dev->driver->irq_preinstall = ironlake_irq_reset;
4662f71d4af4SJesse Barnes 		dev->driver->irq_postinstall = ironlake_irq_postinstall;
46636bcdb1c8SVille Syrjälä 		dev->driver->irq_uninstall = ironlake_irq_reset;
4664f71d4af4SJesse Barnes 		dev->driver->enable_vblank = ironlake_enable_vblank;
4665f71d4af4SJesse Barnes 		dev->driver->disable_vblank = ironlake_disable_vblank;
4666e4ce95aaSVille Syrjälä 		dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
4667f71d4af4SJesse Barnes 	} else {
46687e22dbbbSTvrtko Ursulin 		if (IS_GEN2(dev_priv)) {
46696bcdb1c8SVille Syrjälä 			dev->driver->irq_preinstall = i8xx_irq_reset;
4670c2798b19SChris Wilson 			dev->driver->irq_postinstall = i8xx_irq_postinstall;
4671c2798b19SChris Wilson 			dev->driver->irq_handler = i8xx_irq_handler;
46726bcdb1c8SVille Syrjälä 			dev->driver->irq_uninstall = i8xx_irq_reset;
467386e83e35SChris Wilson 			dev->driver->enable_vblank = i8xx_enable_vblank;
467486e83e35SChris Wilson 			dev->driver->disable_vblank = i8xx_disable_vblank;
46757e22dbbbSTvrtko Ursulin 		} else if (IS_GEN3(dev_priv)) {
46766bcdb1c8SVille Syrjälä 			dev->driver->irq_preinstall = i915_irq_reset;
4677a266c7d5SChris Wilson 			dev->driver->irq_postinstall = i915_irq_postinstall;
46786bcdb1c8SVille Syrjälä 			dev->driver->irq_uninstall = i915_irq_reset;
4679a266c7d5SChris Wilson 			dev->driver->irq_handler = i915_irq_handler;
468086e83e35SChris Wilson 			dev->driver->enable_vblank = i8xx_enable_vblank;
468186e83e35SChris Wilson 			dev->driver->disable_vblank = i8xx_disable_vblank;
4682c2798b19SChris Wilson 		} else {
46836bcdb1c8SVille Syrjälä 			dev->driver->irq_preinstall = i965_irq_reset;
4684a266c7d5SChris Wilson 			dev->driver->irq_postinstall = i965_irq_postinstall;
46856bcdb1c8SVille Syrjälä 			dev->driver->irq_uninstall = i965_irq_reset;
4686a266c7d5SChris Wilson 			dev->driver->irq_handler = i965_irq_handler;
468786e83e35SChris Wilson 			dev->driver->enable_vblank = i965_enable_vblank;
468886e83e35SChris Wilson 			dev->driver->disable_vblank = i965_disable_vblank;
4689c2798b19SChris Wilson 		}
4690778eb334SVille Syrjälä 		if (I915_HAS_HOTPLUG(dev_priv))
4691778eb334SVille Syrjälä 			dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
4692f71d4af4SJesse Barnes 	}
4693f71d4af4SJesse Barnes }
469420afbda2SDaniel Vetter 
4695fca52a55SDaniel Vetter /**
4696cefcff8fSJoonas Lahtinen  * intel_irq_fini - deinitializes IRQ support
4697cefcff8fSJoonas Lahtinen  * @i915: i915 device instance
4698cefcff8fSJoonas Lahtinen  *
4699cefcff8fSJoonas Lahtinen  * This function deinitializes all the IRQ support.
4700cefcff8fSJoonas Lahtinen  */
4701cefcff8fSJoonas Lahtinen void intel_irq_fini(struct drm_i915_private *i915)
4702cefcff8fSJoonas Lahtinen {
4703cefcff8fSJoonas Lahtinen 	int i;
4704cefcff8fSJoonas Lahtinen 
4705cefcff8fSJoonas Lahtinen 	for (i = 0; i < MAX_L3_SLICES; ++i)
4706cefcff8fSJoonas Lahtinen 		kfree(i915->l3_parity.remap_info[i]);
4707cefcff8fSJoonas Lahtinen }
4708cefcff8fSJoonas Lahtinen 
4709cefcff8fSJoonas Lahtinen /**
4710fca52a55SDaniel Vetter  * intel_irq_install - enables the hardware interrupt
4711fca52a55SDaniel Vetter  * @dev_priv: i915 device instance
4712fca52a55SDaniel Vetter  *
4713fca52a55SDaniel Vetter  * This function enables the hardware interrupt handling, but leaves the hotplug
4714fca52a55SDaniel Vetter  * handling still disabled. It is called after intel_irq_init().
4715fca52a55SDaniel Vetter  *
4716fca52a55SDaniel Vetter  * In the driver load and resume code we need working interrupts in a few places
4717fca52a55SDaniel Vetter  * but don't want to deal with the hassle of concurrent probe and hotplug
4718fca52a55SDaniel Vetter  * workers. Hence the split into this two-stage approach.
4719fca52a55SDaniel Vetter  */
47202aeb7d3aSDaniel Vetter int intel_irq_install(struct drm_i915_private *dev_priv)
47212aeb7d3aSDaniel Vetter {
47222aeb7d3aSDaniel Vetter 	/*
47232aeb7d3aSDaniel Vetter 	 * We enable some interrupt sources in our postinstall hooks, so mark
47242aeb7d3aSDaniel Vetter 	 * interrupts as enabled _before_ actually enabling them to avoid
47252aeb7d3aSDaniel Vetter 	 * special cases in our ordering checks.
47262aeb7d3aSDaniel Vetter 	 */
4727ad1443f0SSagar Arun Kamble 	dev_priv->runtime_pm.irqs_enabled = true;
47282aeb7d3aSDaniel Vetter 
472991c8a326SChris Wilson 	return drm_irq_install(&dev_priv->drm, dev_priv->drm.pdev->irq);
47302aeb7d3aSDaniel Vetter }
47312aeb7d3aSDaniel Vetter 
4732fca52a55SDaniel Vetter /**
4733fca52a55SDaniel Vetter  * intel_irq_uninstall - finilizes all irq handling
4734fca52a55SDaniel Vetter  * @dev_priv: i915 device instance
4735fca52a55SDaniel Vetter  *
4736fca52a55SDaniel Vetter  * This stops interrupt and hotplug handling and unregisters and frees all
4737fca52a55SDaniel Vetter  * resources acquired in the init functions.
4738fca52a55SDaniel Vetter  */
47392aeb7d3aSDaniel Vetter void intel_irq_uninstall(struct drm_i915_private *dev_priv)
47402aeb7d3aSDaniel Vetter {
474191c8a326SChris Wilson 	drm_irq_uninstall(&dev_priv->drm);
47422aeb7d3aSDaniel Vetter 	intel_hpd_cancel_work(dev_priv);
4743ad1443f0SSagar Arun Kamble 	dev_priv->runtime_pm.irqs_enabled = false;
47442aeb7d3aSDaniel Vetter }
47452aeb7d3aSDaniel Vetter 
4746fca52a55SDaniel Vetter /**
4747fca52a55SDaniel Vetter  * intel_runtime_pm_disable_interrupts - runtime interrupt disabling
4748fca52a55SDaniel Vetter  * @dev_priv: i915 device instance
4749fca52a55SDaniel Vetter  *
4750fca52a55SDaniel Vetter  * This function is used to disable interrupts at runtime, both in the runtime
4751fca52a55SDaniel Vetter  * pm and the system suspend/resume code.
4752fca52a55SDaniel Vetter  */
4753b963291cSDaniel Vetter void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
4754c67a470bSPaulo Zanoni {
475591c8a326SChris Wilson 	dev_priv->drm.driver->irq_uninstall(&dev_priv->drm);
4756ad1443f0SSagar Arun Kamble 	dev_priv->runtime_pm.irqs_enabled = false;
475791c8a326SChris Wilson 	synchronize_irq(dev_priv->drm.irq);
4758c67a470bSPaulo Zanoni }
4759c67a470bSPaulo Zanoni 
4760fca52a55SDaniel Vetter /**
4761fca52a55SDaniel Vetter  * intel_runtime_pm_enable_interrupts - runtime interrupt enabling
4762fca52a55SDaniel Vetter  * @dev_priv: i915 device instance
4763fca52a55SDaniel Vetter  *
4764fca52a55SDaniel Vetter  * This function is used to enable interrupts at runtime, both in the runtime
4765fca52a55SDaniel Vetter  * pm and the system suspend/resume code.
4766fca52a55SDaniel Vetter  */
4767b963291cSDaniel Vetter void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv)
4768c67a470bSPaulo Zanoni {
4769ad1443f0SSagar Arun Kamble 	dev_priv->runtime_pm.irqs_enabled = true;
477091c8a326SChris Wilson 	dev_priv->drm.driver->irq_preinstall(&dev_priv->drm);
477191c8a326SChris Wilson 	dev_priv->drm.driver->irq_postinstall(&dev_priv->drm);
4772c67a470bSPaulo Zanoni }
4773