1c4a9e910SFrançois Tigeot /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*- 2c4a9e910SFrançois Tigeot */ 300640ec9SFrançois Tigeot /* 4c4a9e910SFrançois Tigeot * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 5c4a9e910SFrançois Tigeot * All Rights Reserved. 6c4a9e910SFrançois Tigeot * 7c4a9e910SFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 8c4a9e910SFrançois Tigeot * copy of this software and associated documentation files (the 9c4a9e910SFrançois Tigeot * "Software"), to deal in the Software without restriction, including 10c4a9e910SFrançois Tigeot * without limitation the rights to use, copy, modify, merge, publish, 11c4a9e910SFrançois Tigeot * distribute, sub license, and/or sell copies of the Software, and to 12c4a9e910SFrançois Tigeot * permit persons to whom the Software is furnished to do so, subject to 13c4a9e910SFrançois Tigeot * the following conditions: 14c4a9e910SFrançois Tigeot * 15c4a9e910SFrançois Tigeot * The above copyright notice and this permission notice (including the 16c4a9e910SFrançois Tigeot * next paragraph) shall be included in all copies or substantial portions 17c4a9e910SFrançois Tigeot * of the Software. 18c4a9e910SFrançois Tigeot * 19c4a9e910SFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20c4a9e910SFrançois Tigeot * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21c4a9e910SFrançois Tigeot * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22c4a9e910SFrançois Tigeot * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 23c4a9e910SFrançois Tigeot * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24c4a9e910SFrançois Tigeot * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25c4a9e910SFrançois Tigeot * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26c4a9e910SFrançois Tigeot * 27c4a9e910SFrançois Tigeot */ 28c4a9e910SFrançois Tigeot 2918e26a6dSFrançois Tigeot #include <drm/drmP.h> 305c6c6f23SFrançois Tigeot #include <drm/i915_drm.h> 31c4a9e910SFrançois Tigeot #include "i915_drv.h" 32*9edbd4a0SFrançois Tigeot #include "i915_trace.h" 33e3adcf8fSFrançois Tigeot #include "intel_drv.h" 34c4a9e910SFrançois Tigeot 358e26cdf6SFrançois Tigeot static const u32 hpd_ibx[] = { 368e26cdf6SFrançois Tigeot [HPD_CRT] = SDE_CRT_HOTPLUG, 378e26cdf6SFrançois Tigeot [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG, 388e26cdf6SFrançois Tigeot [HPD_PORT_B] = SDE_PORTB_HOTPLUG, 398e26cdf6SFrançois Tigeot [HPD_PORT_C] = SDE_PORTC_HOTPLUG, 408e26cdf6SFrançois Tigeot [HPD_PORT_D] = SDE_PORTD_HOTPLUG 418e26cdf6SFrançois Tigeot }; 428e26cdf6SFrançois Tigeot 438e26cdf6SFrançois Tigeot static const u32 hpd_cpt[] = { 448e26cdf6SFrançois Tigeot [HPD_CRT] = SDE_CRT_HOTPLUG_CPT, 458e26cdf6SFrançois Tigeot [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT, 468e26cdf6SFrançois Tigeot [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT, 478e26cdf6SFrançois Tigeot [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT, 488e26cdf6SFrançois Tigeot [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT 498e26cdf6SFrançois Tigeot }; 508e26cdf6SFrançois Tigeot 518e26cdf6SFrançois Tigeot static const u32 hpd_mask_i915[] = { 528e26cdf6SFrançois Tigeot [HPD_CRT] = CRT_HOTPLUG_INT_EN, 538e26cdf6SFrançois Tigeot [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN, 548e26cdf6SFrançois Tigeot [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN, 558e26cdf6SFrançois Tigeot [HPD_PORT_B] = PORTB_HOTPLUG_INT_EN, 568e26cdf6SFrançois Tigeot [HPD_PORT_C] = PORTC_HOTPLUG_INT_EN, 578e26cdf6SFrançois Tigeot [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN 588e26cdf6SFrançois Tigeot }; 598e26cdf6SFrançois Tigeot 60*9edbd4a0SFrançois Tigeot static const u32 hpd_status_g4x[] = { 618e26cdf6SFrançois Tigeot [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, 628e26cdf6SFrançois Tigeot [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X, 638e26cdf6SFrançois Tigeot [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X, 648e26cdf6SFrançois Tigeot [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, 658e26cdf6SFrançois Tigeot [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, 668e26cdf6SFrançois Tigeot [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS 678e26cdf6SFrançois Tigeot }; 688e26cdf6SFrançois Tigeot 698e26cdf6SFrançois Tigeot static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ 708e26cdf6SFrançois Tigeot [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, 718e26cdf6SFrançois Tigeot [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915, 728e26cdf6SFrançois Tigeot [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915, 738e26cdf6SFrançois Tigeot [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, 748e26cdf6SFrançois Tigeot [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, 758e26cdf6SFrançois Tigeot [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS 768e26cdf6SFrançois Tigeot }; 778e26cdf6SFrançois Tigeot 78e3adcf8fSFrançois Tigeot /* For display hotplug interrupt */ 79e3adcf8fSFrançois Tigeot static void 80e3adcf8fSFrançois Tigeot ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) 81c4a9e910SFrançois Tigeot { 82*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 83*9edbd4a0SFrançois Tigeot 84*9edbd4a0SFrançois Tigeot if (dev_priv->pc8.irqs_disabled) { 85*9edbd4a0SFrançois Tigeot WARN(1, "IRQs disabled\n"); 86*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.deimr &= ~mask; 87*9edbd4a0SFrançois Tigeot return; 88*9edbd4a0SFrançois Tigeot } 89*9edbd4a0SFrançois Tigeot 90e3adcf8fSFrançois Tigeot if ((dev_priv->irq_mask & mask) != 0) { 91e3adcf8fSFrançois Tigeot dev_priv->irq_mask &= ~mask; 92e3adcf8fSFrançois Tigeot I915_WRITE(DEIMR, dev_priv->irq_mask); 93e3adcf8fSFrançois Tigeot POSTING_READ(DEIMR); 94c4a9e910SFrançois Tigeot } 95c4a9e910SFrançois Tigeot } 96c4a9e910SFrançois Tigeot 978e26cdf6SFrançois Tigeot static void 98e3adcf8fSFrançois Tigeot ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) 99c4a9e910SFrançois Tigeot { 100*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 101*9edbd4a0SFrançois Tigeot 102*9edbd4a0SFrançois Tigeot if (dev_priv->pc8.irqs_disabled) { 103*9edbd4a0SFrançois Tigeot WARN(1, "IRQs disabled\n"); 104*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.deimr |= mask; 105*9edbd4a0SFrançois Tigeot return; 106*9edbd4a0SFrançois Tigeot } 107*9edbd4a0SFrançois Tigeot 108e3adcf8fSFrançois Tigeot if ((dev_priv->irq_mask & mask) != mask) { 109e3adcf8fSFrançois Tigeot dev_priv->irq_mask |= mask; 110e3adcf8fSFrançois Tigeot I915_WRITE(DEIMR, dev_priv->irq_mask); 111e3adcf8fSFrançois Tigeot POSTING_READ(DEIMR); 112c4a9e910SFrançois Tigeot } 113c4a9e910SFrançois Tigeot } 114c4a9e910SFrançois Tigeot 115*9edbd4a0SFrançois Tigeot /** 116*9edbd4a0SFrançois Tigeot * ilk_update_gt_irq - update GTIMR 117*9edbd4a0SFrançois Tigeot * @dev_priv: driver private 118*9edbd4a0SFrançois Tigeot * @interrupt_mask: mask of interrupt bits to update 119*9edbd4a0SFrançois Tigeot * @enabled_irq_mask: mask of interrupt bits to enable 120*9edbd4a0SFrançois Tigeot */ 121*9edbd4a0SFrançois Tigeot static void ilk_update_gt_irq(struct drm_i915_private *dev_priv, 122*9edbd4a0SFrançois Tigeot uint32_t interrupt_mask, 123*9edbd4a0SFrançois Tigeot uint32_t enabled_irq_mask) 124*9edbd4a0SFrançois Tigeot { 125*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 126*9edbd4a0SFrançois Tigeot 127*9edbd4a0SFrançois Tigeot if (dev_priv->pc8.irqs_disabled) { 128*9edbd4a0SFrançois Tigeot WARN(1, "IRQs disabled\n"); 129*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.gtimr &= ~interrupt_mask; 130*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.gtimr |= (~enabled_irq_mask & 131*9edbd4a0SFrançois Tigeot interrupt_mask); 132*9edbd4a0SFrançois Tigeot return; 133*9edbd4a0SFrançois Tigeot } 134*9edbd4a0SFrançois Tigeot 135*9edbd4a0SFrançois Tigeot dev_priv->gt_irq_mask &= ~interrupt_mask; 136*9edbd4a0SFrançois Tigeot dev_priv->gt_irq_mask |= (~enabled_irq_mask & interrupt_mask); 137*9edbd4a0SFrançois Tigeot I915_WRITE(GTIMR, dev_priv->gt_irq_mask); 138*9edbd4a0SFrançois Tigeot POSTING_READ(GTIMR); 139*9edbd4a0SFrançois Tigeot } 140*9edbd4a0SFrançois Tigeot 141*9edbd4a0SFrançois Tigeot void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) 142*9edbd4a0SFrançois Tigeot { 143*9edbd4a0SFrançois Tigeot ilk_update_gt_irq(dev_priv, mask, mask); 144*9edbd4a0SFrançois Tigeot } 145*9edbd4a0SFrançois Tigeot 146*9edbd4a0SFrançois Tigeot void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) 147*9edbd4a0SFrançois Tigeot { 148*9edbd4a0SFrançois Tigeot ilk_update_gt_irq(dev_priv, mask, 0); 149*9edbd4a0SFrançois Tigeot } 150*9edbd4a0SFrançois Tigeot 151*9edbd4a0SFrançois Tigeot /** 152*9edbd4a0SFrançois Tigeot * snb_update_pm_irq - update GEN6_PMIMR 153*9edbd4a0SFrançois Tigeot * @dev_priv: driver private 154*9edbd4a0SFrançois Tigeot * @interrupt_mask: mask of interrupt bits to update 155*9edbd4a0SFrançois Tigeot * @enabled_irq_mask: mask of interrupt bits to enable 156*9edbd4a0SFrançois Tigeot */ 157*9edbd4a0SFrançois Tigeot static void snb_update_pm_irq(struct drm_i915_private *dev_priv, 158*9edbd4a0SFrançois Tigeot uint32_t interrupt_mask, 159*9edbd4a0SFrançois Tigeot uint32_t enabled_irq_mask) 160*9edbd4a0SFrançois Tigeot { 161*9edbd4a0SFrançois Tigeot uint32_t new_val; 162*9edbd4a0SFrançois Tigeot 163*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 164*9edbd4a0SFrançois Tigeot 165*9edbd4a0SFrançois Tigeot if (dev_priv->pc8.irqs_disabled) { 166*9edbd4a0SFrançois Tigeot WARN(1, "IRQs disabled\n"); 167*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.gen6_pmimr &= ~interrupt_mask; 168*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.gen6_pmimr |= (~enabled_irq_mask & 169*9edbd4a0SFrançois Tigeot interrupt_mask); 170*9edbd4a0SFrançois Tigeot return; 171*9edbd4a0SFrançois Tigeot } 172*9edbd4a0SFrançois Tigeot 173*9edbd4a0SFrançois Tigeot new_val = dev_priv->pm_irq_mask; 174*9edbd4a0SFrançois Tigeot new_val &= ~interrupt_mask; 175*9edbd4a0SFrançois Tigeot new_val |= (~enabled_irq_mask & interrupt_mask); 176*9edbd4a0SFrançois Tigeot 177*9edbd4a0SFrançois Tigeot if (new_val != dev_priv->pm_irq_mask) { 178*9edbd4a0SFrançois Tigeot dev_priv->pm_irq_mask = new_val; 179*9edbd4a0SFrançois Tigeot I915_WRITE(GEN6_PMIMR, dev_priv->pm_irq_mask); 180*9edbd4a0SFrançois Tigeot POSTING_READ(GEN6_PMIMR); 181*9edbd4a0SFrançois Tigeot } 182*9edbd4a0SFrançois Tigeot } 183*9edbd4a0SFrançois Tigeot 184*9edbd4a0SFrançois Tigeot void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) 185*9edbd4a0SFrançois Tigeot { 186*9edbd4a0SFrançois Tigeot snb_update_pm_irq(dev_priv, mask, mask); 187*9edbd4a0SFrançois Tigeot } 188*9edbd4a0SFrançois Tigeot 189*9edbd4a0SFrançois Tigeot void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) 190*9edbd4a0SFrançois Tigeot { 191*9edbd4a0SFrançois Tigeot snb_update_pm_irq(dev_priv, mask, 0); 192*9edbd4a0SFrançois Tigeot } 193*9edbd4a0SFrançois Tigeot 1945d0b1887SFrançois Tigeot static bool ivb_can_enable_err_int(struct drm_device *dev) 1955d0b1887SFrançois Tigeot { 1965d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1975d0b1887SFrançois Tigeot struct intel_crtc *crtc; 1985d0b1887SFrançois Tigeot enum i915_pipe pipe; 1995d0b1887SFrançois Tigeot 200*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 201*9edbd4a0SFrançois Tigeot 2025d0b1887SFrançois Tigeot for_each_pipe(pipe) { 2035d0b1887SFrançois Tigeot crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); 2045d0b1887SFrançois Tigeot 2055d0b1887SFrançois Tigeot if (crtc->cpu_fifo_underrun_disabled) 2065d0b1887SFrançois Tigeot return false; 2075d0b1887SFrançois Tigeot } 2085d0b1887SFrançois Tigeot 2095d0b1887SFrançois Tigeot return true; 2105d0b1887SFrançois Tigeot } 2115d0b1887SFrançois Tigeot 2125d0b1887SFrançois Tigeot static bool cpt_can_enable_serr_int(struct drm_device *dev) 2135d0b1887SFrançois Tigeot { 2145d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2155d0b1887SFrançois Tigeot enum i915_pipe pipe; 2165d0b1887SFrançois Tigeot struct intel_crtc *crtc; 2175d0b1887SFrançois Tigeot 218*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 219*9edbd4a0SFrançois Tigeot 2205d0b1887SFrançois Tigeot for_each_pipe(pipe) { 2215d0b1887SFrançois Tigeot crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); 2225d0b1887SFrançois Tigeot 2235d0b1887SFrançois Tigeot if (crtc->pch_fifo_underrun_disabled) 2245d0b1887SFrançois Tigeot return false; 2255d0b1887SFrançois Tigeot } 2265d0b1887SFrançois Tigeot 2275d0b1887SFrançois Tigeot return true; 2285d0b1887SFrançois Tigeot } 2295d0b1887SFrançois Tigeot 2305d0b1887SFrançois Tigeot static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, 2315d0b1887SFrançois Tigeot enum i915_pipe pipe, bool enable) 2325d0b1887SFrançois Tigeot { 2335d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2345d0b1887SFrançois Tigeot uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN : 2355d0b1887SFrançois Tigeot DE_PIPEB_FIFO_UNDERRUN; 2365d0b1887SFrançois Tigeot 2375d0b1887SFrançois Tigeot if (enable) 2385d0b1887SFrançois Tigeot ironlake_enable_display_irq(dev_priv, bit); 2395d0b1887SFrançois Tigeot else 2405d0b1887SFrançois Tigeot ironlake_disable_display_irq(dev_priv, bit); 2415d0b1887SFrançois Tigeot } 2425d0b1887SFrançois Tigeot 2435d0b1887SFrançois Tigeot static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, 244*9edbd4a0SFrançois Tigeot enum i915_pipe pipe, bool enable) 2455d0b1887SFrançois Tigeot { 2465d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2475d0b1887SFrançois Tigeot if (enable) { 248*9edbd4a0SFrançois Tigeot I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe)); 249*9edbd4a0SFrançois Tigeot 2505d0b1887SFrançois Tigeot if (!ivb_can_enable_err_int(dev)) 2515d0b1887SFrançois Tigeot return; 2525d0b1887SFrançois Tigeot 2535d0b1887SFrançois Tigeot ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); 2545d0b1887SFrançois Tigeot } else { 255*9edbd4a0SFrançois Tigeot bool was_enabled = !(I915_READ(DEIMR) & DE_ERR_INT_IVB); 256*9edbd4a0SFrançois Tigeot 257*9edbd4a0SFrançois Tigeot /* Change the state _after_ we've read out the current one. */ 2585d0b1887SFrançois Tigeot ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); 259*9edbd4a0SFrançois Tigeot 260*9edbd4a0SFrançois Tigeot if (!was_enabled && 261*9edbd4a0SFrançois Tigeot (I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe))) { 262*9edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("uncleared fifo underrun on pipe %c\n", 263*9edbd4a0SFrançois Tigeot pipe_name(pipe)); 264*9edbd4a0SFrançois Tigeot } 2655d0b1887SFrançois Tigeot } 2665d0b1887SFrançois Tigeot } 2675d0b1887SFrançois Tigeot 268*9edbd4a0SFrançois Tigeot static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev, 269*9edbd4a0SFrançois Tigeot enum i915_pipe pipe, bool enable) 2705d0b1887SFrançois Tigeot { 2715d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 272*9edbd4a0SFrançois Tigeot 273*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 2745d0b1887SFrançois Tigeot 2755d0b1887SFrançois Tigeot if (enable) 276*9edbd4a0SFrançois Tigeot dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN; 2775d0b1887SFrançois Tigeot else 278*9edbd4a0SFrançois Tigeot dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN; 279*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); 280*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); 281*9edbd4a0SFrançois Tigeot } 2825d0b1887SFrançois Tigeot 283*9edbd4a0SFrançois Tigeot /** 284*9edbd4a0SFrançois Tigeot * ibx_display_interrupt_update - update SDEIMR 285*9edbd4a0SFrançois Tigeot * @dev_priv: driver private 286*9edbd4a0SFrançois Tigeot * @interrupt_mask: mask of interrupt bits to update 287*9edbd4a0SFrançois Tigeot * @enabled_irq_mask: mask of interrupt bits to enable 288*9edbd4a0SFrançois Tigeot */ 289*9edbd4a0SFrançois Tigeot static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv, 290*9edbd4a0SFrançois Tigeot uint32_t interrupt_mask, 291*9edbd4a0SFrançois Tigeot uint32_t enabled_irq_mask) 292*9edbd4a0SFrançois Tigeot { 293*9edbd4a0SFrançois Tigeot uint32_t sdeimr = I915_READ(SDEIMR); 294*9edbd4a0SFrançois Tigeot sdeimr &= ~interrupt_mask; 295*9edbd4a0SFrançois Tigeot sdeimr |= (~enabled_irq_mask & interrupt_mask); 296*9edbd4a0SFrançois Tigeot 297*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 298*9edbd4a0SFrançois Tigeot 299*9edbd4a0SFrançois Tigeot if (dev_priv->pc8.irqs_disabled && 300*9edbd4a0SFrançois Tigeot (interrupt_mask & SDE_HOTPLUG_MASK_CPT)) { 301*9edbd4a0SFrançois Tigeot WARN(1, "IRQs disabled\n"); 302*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.sdeimr &= ~interrupt_mask; 303*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.sdeimr |= (~enabled_irq_mask & 304*9edbd4a0SFrançois Tigeot interrupt_mask); 305*9edbd4a0SFrançois Tigeot return; 306*9edbd4a0SFrançois Tigeot } 307*9edbd4a0SFrançois Tigeot 308*9edbd4a0SFrançois Tigeot I915_WRITE(SDEIMR, sdeimr); 3095d0b1887SFrançois Tigeot POSTING_READ(SDEIMR); 3105d0b1887SFrançois Tigeot } 311*9edbd4a0SFrançois Tigeot #define ibx_enable_display_interrupt(dev_priv, bits) \ 312*9edbd4a0SFrançois Tigeot ibx_display_interrupt_update((dev_priv), (bits), (bits)) 313*9edbd4a0SFrançois Tigeot #define ibx_disable_display_interrupt(dev_priv, bits) \ 314*9edbd4a0SFrançois Tigeot ibx_display_interrupt_update((dev_priv), (bits), 0) 315*9edbd4a0SFrançois Tigeot 316*9edbd4a0SFrançois Tigeot static void ibx_set_fifo_underrun_reporting(struct drm_device *dev, 317*9edbd4a0SFrançois Tigeot enum transcoder pch_transcoder, 318*9edbd4a0SFrançois Tigeot bool enable) 319*9edbd4a0SFrançois Tigeot { 320*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 321*9edbd4a0SFrançois Tigeot uint32_t bit = (pch_transcoder == TRANSCODER_A) ? 322*9edbd4a0SFrançois Tigeot SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER; 323*9edbd4a0SFrançois Tigeot 324*9edbd4a0SFrançois Tigeot if (enable) 325*9edbd4a0SFrançois Tigeot ibx_enable_display_interrupt(dev_priv, bit); 326*9edbd4a0SFrançois Tigeot else 327*9edbd4a0SFrançois Tigeot ibx_disable_display_interrupt(dev_priv, bit); 328*9edbd4a0SFrançois Tigeot } 3295d0b1887SFrançois Tigeot 3305d0b1887SFrançois Tigeot static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, 3315d0b1887SFrançois Tigeot enum transcoder pch_transcoder, 3325d0b1887SFrançois Tigeot bool enable) 3335d0b1887SFrançois Tigeot { 3345d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 3355d0b1887SFrançois Tigeot 3365d0b1887SFrançois Tigeot if (enable) { 337*9edbd4a0SFrançois Tigeot I915_WRITE(SERR_INT, 338*9edbd4a0SFrançois Tigeot SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)); 339*9edbd4a0SFrançois Tigeot 3405d0b1887SFrançois Tigeot if (!cpt_can_enable_serr_int(dev)) 3415d0b1887SFrançois Tigeot return; 3425d0b1887SFrançois Tigeot 343*9edbd4a0SFrançois Tigeot ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT); 3445d0b1887SFrançois Tigeot } else { 345*9edbd4a0SFrançois Tigeot uint32_t tmp = I915_READ(SERR_INT); 346*9edbd4a0SFrançois Tigeot bool was_enabled = !(I915_READ(SDEIMR) & SDE_ERROR_CPT); 3475d0b1887SFrançois Tigeot 348*9edbd4a0SFrançois Tigeot /* Change the state _after_ we've read out the current one. */ 349*9edbd4a0SFrançois Tigeot ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT); 350*9edbd4a0SFrançois Tigeot 351*9edbd4a0SFrançois Tigeot if (!was_enabled && 352*9edbd4a0SFrançois Tigeot (tmp & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder))) { 353*9edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("uncleared pch fifo underrun on pch transcoder %c\n", 354*9edbd4a0SFrançois Tigeot transcoder_name(pch_transcoder)); 355*9edbd4a0SFrançois Tigeot } 356*9edbd4a0SFrançois Tigeot } 3575d0b1887SFrançois Tigeot } 3585d0b1887SFrançois Tigeot 3595d0b1887SFrançois Tigeot /** 3605d0b1887SFrançois Tigeot * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages 3615d0b1887SFrançois Tigeot * @dev: drm device 3625d0b1887SFrançois Tigeot * @pipe: pipe 3635d0b1887SFrançois Tigeot * @enable: true if we want to report FIFO underrun errors, false otherwise 3645d0b1887SFrançois Tigeot * 3655d0b1887SFrançois Tigeot * This function makes us disable or enable CPU fifo underruns for a specific 3665d0b1887SFrançois Tigeot * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun 3675d0b1887SFrançois Tigeot * reporting for one pipe may also disable all the other CPU error interruts for 3685d0b1887SFrançois Tigeot * the other pipes, due to the fact that there's just one interrupt mask/enable 3695d0b1887SFrançois Tigeot * bit for all the pipes. 3705d0b1887SFrançois Tigeot * 3715d0b1887SFrançois Tigeot * Returns the previous state of underrun reporting. 3725d0b1887SFrançois Tigeot */ 3735d0b1887SFrançois Tigeot bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, 3745d0b1887SFrançois Tigeot enum i915_pipe pipe, bool enable) 3755d0b1887SFrançois Tigeot { 3765d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 3775d0b1887SFrançois Tigeot struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; 3785d0b1887SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 3795d0b1887SFrançois Tigeot bool ret; 3805d0b1887SFrançois Tigeot 3815d0b1887SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3825d0b1887SFrançois Tigeot 3835d0b1887SFrançois Tigeot ret = !intel_crtc->cpu_fifo_underrun_disabled; 3845d0b1887SFrançois Tigeot 3855d0b1887SFrançois Tigeot if (enable == ret) 3865d0b1887SFrançois Tigeot goto done; 3875d0b1887SFrançois Tigeot 3885d0b1887SFrançois Tigeot intel_crtc->cpu_fifo_underrun_disabled = !enable; 3895d0b1887SFrançois Tigeot 3905d0b1887SFrançois Tigeot if (IS_GEN5(dev) || IS_GEN6(dev)) 3915d0b1887SFrançois Tigeot ironlake_set_fifo_underrun_reporting(dev, pipe, enable); 3925d0b1887SFrançois Tigeot else if (IS_GEN7(dev)) 393*9edbd4a0SFrançois Tigeot ivybridge_set_fifo_underrun_reporting(dev, pipe, enable); 394*9edbd4a0SFrançois Tigeot else if (IS_GEN8(dev)) 395*9edbd4a0SFrançois Tigeot broadwell_set_fifo_underrun_reporting(dev, pipe, enable); 3965d0b1887SFrançois Tigeot 3975d0b1887SFrançois Tigeot done: 3985d0b1887SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3995d0b1887SFrançois Tigeot return ret; 4005d0b1887SFrançois Tigeot } 4015d0b1887SFrançois Tigeot 4025d0b1887SFrançois Tigeot /** 4035d0b1887SFrançois Tigeot * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages 4045d0b1887SFrançois Tigeot * @dev: drm device 4055d0b1887SFrançois Tigeot * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older) 4065d0b1887SFrançois Tigeot * @enable: true if we want to report FIFO underrun errors, false otherwise 4075d0b1887SFrançois Tigeot * 4085d0b1887SFrançois Tigeot * This function makes us disable or enable PCH fifo underruns for a specific 4095d0b1887SFrançois Tigeot * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO 4105d0b1887SFrançois Tigeot * underrun reporting for one transcoder may also disable all the other PCH 4115d0b1887SFrançois Tigeot * error interruts for the other transcoders, due to the fact that there's just 4125d0b1887SFrançois Tigeot * one interrupt mask/enable bit for all the transcoders. 4135d0b1887SFrançois Tigeot * 4145d0b1887SFrançois Tigeot * Returns the previous state of underrun reporting. 4155d0b1887SFrançois Tigeot */ 4165d0b1887SFrançois Tigeot bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, 4175d0b1887SFrançois Tigeot enum transcoder pch_transcoder, 4185d0b1887SFrançois Tigeot bool enable) 4195d0b1887SFrançois Tigeot { 4205d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 421*9edbd4a0SFrançois Tigeot struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder]; 422*9edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 4235d0b1887SFrançois Tigeot bool ret; 4245d0b1887SFrançois Tigeot 425*9edbd4a0SFrançois Tigeot /* 426*9edbd4a0SFrançois Tigeot * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT 427*9edbd4a0SFrançois Tigeot * has only one pch transcoder A that all pipes can use. To avoid racy 428*9edbd4a0SFrançois Tigeot * pch transcoder -> pipe lookups from interrupt code simply store the 429*9edbd4a0SFrançois Tigeot * underrun statistics in crtc A. Since we never expose this anywhere 430*9edbd4a0SFrançois Tigeot * nor use it outside of the fifo underrun code here using the "wrong" 431*9edbd4a0SFrançois Tigeot * crtc on LPT won't cause issues. 432*9edbd4a0SFrançois Tigeot */ 4335d0b1887SFrançois Tigeot 4345d0b1887SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 4355d0b1887SFrançois Tigeot 4365d0b1887SFrançois Tigeot ret = !intel_crtc->pch_fifo_underrun_disabled; 4375d0b1887SFrançois Tigeot 4385d0b1887SFrançois Tigeot if (enable == ret) 4395d0b1887SFrançois Tigeot goto done; 4405d0b1887SFrançois Tigeot 4415d0b1887SFrançois Tigeot intel_crtc->pch_fifo_underrun_disabled = !enable; 4425d0b1887SFrançois Tigeot 4435d0b1887SFrançois Tigeot if (HAS_PCH_IBX(dev)) 444*9edbd4a0SFrançois Tigeot ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable); 4455d0b1887SFrançois Tigeot else 4465d0b1887SFrançois Tigeot cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable); 4475d0b1887SFrançois Tigeot 4485d0b1887SFrançois Tigeot done: 4495d0b1887SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 4505d0b1887SFrançois Tigeot return ret; 4515d0b1887SFrançois Tigeot } 4525d0b1887SFrançois Tigeot 4535d0b1887SFrançois Tigeot 454c4a9e910SFrançois Tigeot void 455*9edbd4a0SFrançois Tigeot i915_enable_pipestat(drm_i915_private_t *dev_priv, enum i915_pipe pipe, u32 mask) 456c4a9e910SFrançois Tigeot { 457e3adcf8fSFrançois Tigeot u32 reg = PIPESTAT(pipe); 4588e26cdf6SFrançois Tigeot u32 pipestat = I915_READ(reg) & 0x7fff0000; 459c4a9e910SFrançois Tigeot 460*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 461*9edbd4a0SFrançois Tigeot 4628e26cdf6SFrançois Tigeot if ((pipestat & mask) == mask) 4638e26cdf6SFrançois Tigeot return; 4648e26cdf6SFrançois Tigeot 465c4a9e910SFrançois Tigeot /* Enable the interrupt, clear any pending status */ 4668e26cdf6SFrançois Tigeot pipestat |= mask | (mask >> 16); 4678e26cdf6SFrançois Tigeot I915_WRITE(reg, pipestat); 468e3adcf8fSFrançois Tigeot POSTING_READ(reg); 469c4a9e910SFrançois Tigeot } 470c4a9e910SFrançois Tigeot 471c4a9e910SFrançois Tigeot void 472*9edbd4a0SFrançois Tigeot i915_disable_pipestat(drm_i915_private_t *dev_priv, enum i915_pipe pipe, u32 mask) 473c4a9e910SFrançois Tigeot { 474e3adcf8fSFrançois Tigeot u32 reg = PIPESTAT(pipe); 4758e26cdf6SFrançois Tigeot u32 pipestat = I915_READ(reg) & 0x7fff0000; 476c4a9e910SFrançois Tigeot 477*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 478*9edbd4a0SFrançois Tigeot 4798e26cdf6SFrançois Tigeot if ((pipestat & mask) == 0) 4808e26cdf6SFrançois Tigeot return; 4818e26cdf6SFrançois Tigeot 4828e26cdf6SFrançois Tigeot pipestat &= ~mask; 4838e26cdf6SFrançois Tigeot I915_WRITE(reg, pipestat); 484e3adcf8fSFrançois Tigeot POSTING_READ(reg); 485c4a9e910SFrançois Tigeot } 486c4a9e910SFrançois Tigeot 487c4a9e910SFrançois Tigeot /** 4885d0b1887SFrançois Tigeot * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion 489e3adcf8fSFrançois Tigeot */ 4905d0b1887SFrançois Tigeot static void i915_enable_asle_pipestat(struct drm_device *dev) 491e3adcf8fSFrançois Tigeot { 492e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 493e3adcf8fSFrançois Tigeot 4945d0b1887SFrançois Tigeot if (!dev_priv->opregion.asle || !IS_MOBILE(dev)) 49500640ec9SFrançois Tigeot return; 49600640ec9SFrançois Tigeot 497e3adcf8fSFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 498e3adcf8fSFrançois Tigeot 499*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_ENABLE); 500e3adcf8fSFrançois Tigeot if (INTEL_INFO(dev)->gen >= 4) 501*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, 502*9edbd4a0SFrançois Tigeot PIPE_LEGACY_BLC_EVENT_ENABLE); 503e3adcf8fSFrançois Tigeot 504e3adcf8fSFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 505e3adcf8fSFrançois Tigeot } 506e3adcf8fSFrançois Tigeot 507e3adcf8fSFrançois Tigeot /** 508c4a9e910SFrançois Tigeot * i915_pipe_enabled - check if a pipe is enabled 509c4a9e910SFrançois Tigeot * @dev: DRM device 510c4a9e910SFrançois Tigeot * @pipe: pipe to check 511c4a9e910SFrançois Tigeot * 512c4a9e910SFrançois Tigeot * Reading certain registers when the pipe is disabled can hang the chip. 513c4a9e910SFrançois Tigeot * Use this routine to make sure the PLL is running and the pipe is active 514c4a9e910SFrançois Tigeot * before reading such registers if unsure. 515c4a9e910SFrançois Tigeot */ 516c4a9e910SFrançois Tigeot static int 517c4a9e910SFrançois Tigeot i915_pipe_enabled(struct drm_device *dev, int pipe) 518c4a9e910SFrançois Tigeot { 519c4a9e910SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 52000640ec9SFrançois Tigeot 5215d0b1887SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_MODESET)) { 5225d0b1887SFrançois Tigeot /* Locking is horribly broken here, but whatever. */ 5235d0b1887SFrançois Tigeot struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; 5245d0b1887SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 5255d0b1887SFrançois Tigeot 5265d0b1887SFrançois Tigeot return intel_crtc->active; 5275d0b1887SFrançois Tigeot } else { 5285d0b1887SFrançois Tigeot return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE; 5295d0b1887SFrançois Tigeot } 530c4a9e910SFrançois Tigeot } 531c4a9e910SFrançois Tigeot 532*9edbd4a0SFrançois Tigeot static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe) 533*9edbd4a0SFrançois Tigeot { 534*9edbd4a0SFrançois Tigeot /* Gen2 doesn't have a hardware frame counter */ 535*9edbd4a0SFrançois Tigeot return 0; 536*9edbd4a0SFrançois Tigeot } 537*9edbd4a0SFrançois Tigeot 538c4a9e910SFrançois Tigeot /* Called from drm generic code, passed a 'crtc', which 539c4a9e910SFrançois Tigeot * we use as a pipe index 540c4a9e910SFrançois Tigeot */ 54100640ec9SFrançois Tigeot static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) 542c4a9e910SFrançois Tigeot { 543c4a9e910SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 544c4a9e910SFrançois Tigeot unsigned long high_frame; 545c4a9e910SFrançois Tigeot unsigned long low_frame; 546*9edbd4a0SFrançois Tigeot u32 high1, high2, low, pixel, vbl_start; 547c4a9e910SFrançois Tigeot 548c4a9e910SFrançois Tigeot if (!i915_pipe_enabled(dev, pipe)) { 54900640ec9SFrançois Tigeot DRM_DEBUG_DRIVER("trying to get vblank count for disabled " 550e3adcf8fSFrançois Tigeot "pipe %c\n", pipe_name(pipe)); 551c4a9e910SFrançois Tigeot return 0; 552c4a9e910SFrançois Tigeot } 553c4a9e910SFrançois Tigeot 554*9edbd4a0SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_MODESET)) { 555*9edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc = 556*9edbd4a0SFrançois Tigeot to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); 557*9edbd4a0SFrançois Tigeot const struct drm_display_mode *mode = 558*9edbd4a0SFrançois Tigeot &intel_crtc->config.adjusted_mode; 559*9edbd4a0SFrançois Tigeot 560*9edbd4a0SFrançois Tigeot vbl_start = mode->crtc_vblank_start * mode->crtc_htotal; 561*9edbd4a0SFrançois Tigeot } else { 562*9edbd4a0SFrançois Tigeot enum transcoder cpu_transcoder = (enum transcoder) pipe; 563*9edbd4a0SFrançois Tigeot u32 htotal; 564*9edbd4a0SFrançois Tigeot 565*9edbd4a0SFrançois Tigeot htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1; 566*9edbd4a0SFrançois Tigeot vbl_start = (I915_READ(VBLANK(cpu_transcoder)) & 0x1fff) + 1; 567*9edbd4a0SFrançois Tigeot 568*9edbd4a0SFrançois Tigeot vbl_start *= htotal; 569*9edbd4a0SFrançois Tigeot } 570*9edbd4a0SFrançois Tigeot 571e3adcf8fSFrançois Tigeot high_frame = PIPEFRAME(pipe); 572e3adcf8fSFrançois Tigeot low_frame = PIPEFRAMEPIXEL(pipe); 573e3adcf8fSFrançois Tigeot 574c4a9e910SFrançois Tigeot /* 575c4a9e910SFrançois Tigeot * High & low register fields aren't synchronized, so make sure 576c4a9e910SFrançois Tigeot * we get a low value that's stable across two reads of the high 577c4a9e910SFrançois Tigeot * register. 578c4a9e910SFrançois Tigeot */ 579c4a9e910SFrançois Tigeot do { 580e3adcf8fSFrançois Tigeot high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; 581*9edbd4a0SFrançois Tigeot low = I915_READ(low_frame); 582e3adcf8fSFrançois Tigeot high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; 583c4a9e910SFrançois Tigeot } while (high1 != high2); 584c4a9e910SFrançois Tigeot 585e3adcf8fSFrançois Tigeot high1 >>= PIPE_FRAME_HIGH_SHIFT; 586*9edbd4a0SFrançois Tigeot pixel = low & PIPE_PIXEL_MASK; 587e3adcf8fSFrançois Tigeot low >>= PIPE_FRAME_LOW_SHIFT; 588*9edbd4a0SFrançois Tigeot 589*9edbd4a0SFrançois Tigeot /* 590*9edbd4a0SFrançois Tigeot * The frame counter increments at beginning of active. 591*9edbd4a0SFrançois Tigeot * Cook up a vblank counter by also checking the pixel 592*9edbd4a0SFrançois Tigeot * counter against vblank start. 593*9edbd4a0SFrançois Tigeot */ 594*9edbd4a0SFrançois Tigeot return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff; 595c4a9e910SFrançois Tigeot } 596c4a9e910SFrançois Tigeot 59700640ec9SFrançois Tigeot static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) 598c4a9e910SFrançois Tigeot { 599c4a9e910SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 600e3adcf8fSFrançois Tigeot int reg = PIPE_FRMCOUNT_GM45(pipe); 601c4a9e910SFrançois Tigeot 602c4a9e910SFrançois Tigeot if (!i915_pipe_enabled(dev, pipe)) { 60300640ec9SFrançois Tigeot DRM_DEBUG_DRIVER("trying to get vblank count for disabled " 604e3adcf8fSFrançois Tigeot "pipe %c\n", pipe_name(pipe)); 605c4a9e910SFrançois Tigeot return 0; 606c4a9e910SFrançois Tigeot } 607c4a9e910SFrançois Tigeot 608c4a9e910SFrançois Tigeot return I915_READ(reg); 609c4a9e910SFrançois Tigeot } 610c4a9e910SFrançois Tigeot 611*9edbd4a0SFrançois Tigeot /* raw reads, only for fast reads of display block, no need for forcewake etc. */ 612*9edbd4a0SFrançois Tigeot #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__)) 613*9edbd4a0SFrançois Tigeot 614*9edbd4a0SFrançois Tigeot static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum i915_pipe pipe) 615*9edbd4a0SFrançois Tigeot { 616*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 617*9edbd4a0SFrançois Tigeot uint32_t status; 618*9edbd4a0SFrançois Tigeot int reg; 619*9edbd4a0SFrançois Tigeot 620*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 8) { 621*9edbd4a0SFrançois Tigeot status = GEN8_PIPE_VBLANK; 622*9edbd4a0SFrançois Tigeot reg = GEN8_DE_PIPE_ISR(pipe); 623*9edbd4a0SFrançois Tigeot } else if (INTEL_INFO(dev)->gen >= 7) { 624*9edbd4a0SFrançois Tigeot status = DE_PIPE_VBLANK_IVB(pipe); 625*9edbd4a0SFrançois Tigeot reg = DEISR; 626*9edbd4a0SFrançois Tigeot } else { 627*9edbd4a0SFrançois Tigeot status = DE_PIPE_VBLANK(pipe); 628*9edbd4a0SFrançois Tigeot reg = DEISR; 629*9edbd4a0SFrançois Tigeot } 630*9edbd4a0SFrançois Tigeot 631*9edbd4a0SFrançois Tigeot return __raw_i915_read32(dev_priv, reg) & status; 632*9edbd4a0SFrançois Tigeot } 633*9edbd4a0SFrançois Tigeot 63400640ec9SFrançois Tigeot static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, 635e3adcf8fSFrançois Tigeot int *vpos, int *hpos) 636e3adcf8fSFrançois Tigeot { 637*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 638*9edbd4a0SFrançois Tigeot struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; 639*9edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 640*9edbd4a0SFrançois Tigeot const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode; 641*9edbd4a0SFrançois Tigeot int position; 642e3adcf8fSFrançois Tigeot int vbl_start, vbl_end, htotal, vtotal; 643e3adcf8fSFrançois Tigeot bool in_vbl = true; 644e3adcf8fSFrançois Tigeot int ret = 0; 645e3adcf8fSFrançois Tigeot 646*9edbd4a0SFrançois Tigeot if (!intel_crtc->active) { 64700640ec9SFrançois Tigeot DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " 648e3adcf8fSFrançois Tigeot "pipe %c\n", pipe_name(pipe)); 649e3adcf8fSFrançois Tigeot return 0; 650e3adcf8fSFrançois Tigeot } 651e3adcf8fSFrançois Tigeot 652*9edbd4a0SFrançois Tigeot htotal = mode->crtc_htotal; 653*9edbd4a0SFrançois Tigeot vtotal = mode->crtc_vtotal; 654*9edbd4a0SFrançois Tigeot vbl_start = mode->crtc_vblank_start; 655*9edbd4a0SFrançois Tigeot vbl_end = mode->crtc_vblank_end; 656e3adcf8fSFrançois Tigeot 657*9edbd4a0SFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_INTERLACE) { 658*9edbd4a0SFrançois Tigeot vbl_start = DIV_ROUND_UP(vbl_start, 2); 659*9edbd4a0SFrançois Tigeot vbl_end /= 2; 660*9edbd4a0SFrançois Tigeot vtotal /= 2; 661*9edbd4a0SFrançois Tigeot } 662*9edbd4a0SFrançois Tigeot 663*9edbd4a0SFrançois Tigeot ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; 664*9edbd4a0SFrançois Tigeot 665*9edbd4a0SFrançois Tigeot /* 666*9edbd4a0SFrançois Tigeot * Lock uncore.lock, as we will do multiple timing critical raw 667*9edbd4a0SFrançois Tigeot * register reads, potentially with preemption disabled, so the 668*9edbd4a0SFrançois Tigeot * following code must not block on uncore.lock. 669*9edbd4a0SFrançois Tigeot */ 670*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->uncore.lock, LK_EXCLUSIVE); 671*9edbd4a0SFrançois Tigeot 672*9edbd4a0SFrançois Tigeot /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ 673*9edbd4a0SFrançois Tigeot 674*9edbd4a0SFrançois Tigeot /* Get optional system timestamp before query. */ 675*9edbd4a0SFrançois Tigeot #if 0 676*9edbd4a0SFrançois Tigeot if (stime) 677*9edbd4a0SFrançois Tigeot *stime = ktime_get(); 678*9edbd4a0SFrançois Tigeot #endif 679*9edbd4a0SFrançois Tigeot 680*9edbd4a0SFrançois Tigeot if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { 681e3adcf8fSFrançois Tigeot /* No obvious pixelcount register. Only query vertical 682e3adcf8fSFrançois Tigeot * scanout position from Display scan line register. 683e3adcf8fSFrançois Tigeot */ 684*9edbd4a0SFrançois Tigeot if (IS_GEN2(dev)) 685*9edbd4a0SFrançois Tigeot position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2; 686*9edbd4a0SFrançois Tigeot else 687*9edbd4a0SFrançois Tigeot position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; 688e3adcf8fSFrançois Tigeot 689*9edbd4a0SFrançois Tigeot if (HAS_DDI(dev)) { 690*9edbd4a0SFrançois Tigeot /* 691*9edbd4a0SFrançois Tigeot * On HSW HDMI outputs there seems to be a 2 line 692*9edbd4a0SFrançois Tigeot * difference, whereas eDP has the normal 1 line 693*9edbd4a0SFrançois Tigeot * difference that earlier platforms have. External 694*9edbd4a0SFrançois Tigeot * DP is unknown. For now just check for the 2 line 695*9edbd4a0SFrançois Tigeot * difference case on all output types on HSW+. 696*9edbd4a0SFrançois Tigeot * 697*9edbd4a0SFrançois Tigeot * This might misinterpret the scanline counter being 698*9edbd4a0SFrançois Tigeot * one line too far along on eDP, but that's less 699*9edbd4a0SFrançois Tigeot * dangerous than the alternative since that would lead 700*9edbd4a0SFrançois Tigeot * the vblank timestamp code astray when it sees a 701*9edbd4a0SFrançois Tigeot * scanline count before vblank_start during a vblank 702*9edbd4a0SFrançois Tigeot * interrupt. 703e3adcf8fSFrançois Tigeot */ 704*9edbd4a0SFrançois Tigeot in_vbl = ilk_pipe_in_vblank_locked(dev, pipe); 705*9edbd4a0SFrançois Tigeot if ((in_vbl && (position == vbl_start - 2 || 706*9edbd4a0SFrançois Tigeot position == vbl_start - 1)) || 707*9edbd4a0SFrançois Tigeot (!in_vbl && (position == vbl_end - 2 || 708*9edbd4a0SFrançois Tigeot position == vbl_end - 1))) 709*9edbd4a0SFrançois Tigeot position = (position + 2) % vtotal; 710*9edbd4a0SFrançois Tigeot } else if (HAS_PCH_SPLIT(dev)) { 711*9edbd4a0SFrançois Tigeot /* 712*9edbd4a0SFrançois Tigeot * The scanline counter increments at the leading edge 713*9edbd4a0SFrançois Tigeot * of hsync, ie. it completely misses the active portion 714*9edbd4a0SFrançois Tigeot * of the line. Fix up the counter at both edges of vblank 715*9edbd4a0SFrançois Tigeot * to get a more accurate picture whether we're in vblank 716*9edbd4a0SFrançois Tigeot * or not. 717*9edbd4a0SFrançois Tigeot */ 718*9edbd4a0SFrançois Tigeot in_vbl = ilk_pipe_in_vblank_locked(dev, pipe); 719*9edbd4a0SFrançois Tigeot if ((in_vbl && position == vbl_start - 1) || 720*9edbd4a0SFrançois Tigeot (!in_vbl && position == vbl_end - 1)) 721*9edbd4a0SFrançois Tigeot position = (position + 1) % vtotal; 722*9edbd4a0SFrançois Tigeot } else { 723*9edbd4a0SFrançois Tigeot /* 724*9edbd4a0SFrançois Tigeot * ISR vblank status bits don't work the way we'd want 725*9edbd4a0SFrançois Tigeot * them to work on non-PCH platforms (for 726*9edbd4a0SFrançois Tigeot * ilk_pipe_in_vblank_locked()), and there doesn't 727*9edbd4a0SFrançois Tigeot * appear any other way to determine if we're currently 728*9edbd4a0SFrançois Tigeot * in vblank. 729*9edbd4a0SFrançois Tigeot * 730*9edbd4a0SFrançois Tigeot * Instead let's assume that we're already in vblank if 731*9edbd4a0SFrançois Tigeot * we got called from the vblank interrupt and the 732*9edbd4a0SFrançois Tigeot * scanline counter value indicates that we're on the 733*9edbd4a0SFrançois Tigeot * line just prior to vblank start. This should result 734*9edbd4a0SFrançois Tigeot * in the correct answer, unless the vblank interrupt 735*9edbd4a0SFrançois Tigeot * delivery really got delayed for almost exactly one 736*9edbd4a0SFrançois Tigeot * full frame/field. 737*9edbd4a0SFrançois Tigeot */ 738*9edbd4a0SFrançois Tigeot #if 0 739*9edbd4a0SFrançois Tigeot if (flags & DRM_CALLED_FROM_VBLIRQ && 740*9edbd4a0SFrançois Tigeot position == vbl_start - 1) { 741*9edbd4a0SFrançois Tigeot position = (position + 1) % vtotal; 742*9edbd4a0SFrançois Tigeot 743*9edbd4a0SFrançois Tigeot /* Signal this correction as "applied". */ 744*9edbd4a0SFrançois Tigeot ret |= 0x8; 745*9edbd4a0SFrançois Tigeot } 746*9edbd4a0SFrançois Tigeot #endif 747*9edbd4a0SFrançois Tigeot } 748e3adcf8fSFrançois Tigeot } else { 749e3adcf8fSFrançois Tigeot /* Have access to pixelcount since start of frame. 750e3adcf8fSFrançois Tigeot * We can split this into vertical and horizontal 751e3adcf8fSFrançois Tigeot * scanout position. 752e3adcf8fSFrançois Tigeot */ 753*9edbd4a0SFrançois Tigeot position = (__raw_i915_read32(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; 754e3adcf8fSFrançois Tigeot 755*9edbd4a0SFrançois Tigeot /* convert to pixel counts */ 756*9edbd4a0SFrançois Tigeot vbl_start *= htotal; 757*9edbd4a0SFrançois Tigeot vbl_end *= htotal; 758*9edbd4a0SFrançois Tigeot vtotal *= htotal; 759*9edbd4a0SFrançois Tigeot } 760*9edbd4a0SFrançois Tigeot 761*9edbd4a0SFrançois Tigeot /* Get optional system timestamp after query. */ 762*9edbd4a0SFrançois Tigeot #if 0 763*9edbd4a0SFrançois Tigeot if (etime) 764*9edbd4a0SFrançois Tigeot *etime = ktime_get(); 765*9edbd4a0SFrançois Tigeot #endif 766*9edbd4a0SFrançois Tigeot 767*9edbd4a0SFrançois Tigeot /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ 768*9edbd4a0SFrançois Tigeot 769*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->uncore.lock, LK_RELEASE); 770*9edbd4a0SFrançois Tigeot 771*9edbd4a0SFrançois Tigeot in_vbl = position >= vbl_start && position < vbl_end; 772*9edbd4a0SFrançois Tigeot 773*9edbd4a0SFrançois Tigeot /* 774*9edbd4a0SFrançois Tigeot * While in vblank, position will be negative 775*9edbd4a0SFrançois Tigeot * counting up towards 0 at vbl_end. And outside 776*9edbd4a0SFrançois Tigeot * vblank, position will be positive counting 777*9edbd4a0SFrançois Tigeot * up since vbl_end. 778*9edbd4a0SFrançois Tigeot */ 779*9edbd4a0SFrançois Tigeot if (position >= vbl_start) 780*9edbd4a0SFrançois Tigeot position -= vbl_end; 781*9edbd4a0SFrançois Tigeot else 782*9edbd4a0SFrançois Tigeot position += vtotal - vbl_end; 783*9edbd4a0SFrançois Tigeot 784*9edbd4a0SFrançois Tigeot if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { 785*9edbd4a0SFrançois Tigeot *vpos = position; 786*9edbd4a0SFrançois Tigeot *hpos = 0; 787*9edbd4a0SFrançois Tigeot } else { 788e3adcf8fSFrançois Tigeot *vpos = position / htotal; 789e3adcf8fSFrançois Tigeot *hpos = position - (*vpos * htotal); 790e3adcf8fSFrançois Tigeot } 791e3adcf8fSFrançois Tigeot 792e3adcf8fSFrançois Tigeot /* In vblank? */ 793e3adcf8fSFrançois Tigeot if (in_vbl) 794e3adcf8fSFrançois Tigeot ret |= DRM_SCANOUTPOS_INVBL; 795e3adcf8fSFrançois Tigeot 796e3adcf8fSFrançois Tigeot return ret; 797e3adcf8fSFrançois Tigeot } 798e3adcf8fSFrançois Tigeot 79900640ec9SFrançois Tigeot static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, 80000640ec9SFrançois Tigeot int *max_error, 80100640ec9SFrançois Tigeot struct timeval *vblank_time, 80200640ec9SFrançois Tigeot unsigned flags) 803e3adcf8fSFrançois Tigeot { 804e3adcf8fSFrançois Tigeot struct drm_crtc *crtc; 805e3adcf8fSFrançois Tigeot 8068e26cdf6SFrançois Tigeot if (pipe < 0 || pipe >= INTEL_INFO(dev)->num_pipes) { 807e3adcf8fSFrançois Tigeot DRM_ERROR("Invalid crtc %d\n", pipe); 808e3adcf8fSFrançois Tigeot return -EINVAL; 809e3adcf8fSFrançois Tigeot } 810e3adcf8fSFrançois Tigeot 811e3adcf8fSFrançois Tigeot /* Get drm_crtc to timestamp: */ 812e3adcf8fSFrançois Tigeot crtc = intel_get_crtc_for_pipe(dev, pipe); 813e3adcf8fSFrançois Tigeot if (crtc == NULL) { 814e3adcf8fSFrançois Tigeot DRM_ERROR("Invalid crtc %d\n", pipe); 815e3adcf8fSFrançois Tigeot return -EINVAL; 816e3adcf8fSFrançois Tigeot } 817e3adcf8fSFrançois Tigeot 818e3adcf8fSFrançois Tigeot if (!crtc->enabled) { 81900640ec9SFrançois Tigeot DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); 820e3adcf8fSFrançois Tigeot return -EBUSY; 821e3adcf8fSFrançois Tigeot } 822e3adcf8fSFrançois Tigeot 823e3adcf8fSFrançois Tigeot /* Helper routine in DRM core does all the work: */ 824e3adcf8fSFrançois Tigeot return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, 825e3adcf8fSFrançois Tigeot vblank_time, flags, 826e3adcf8fSFrançois Tigeot crtc); 827e3adcf8fSFrançois Tigeot } 828e3adcf8fSFrançois Tigeot 829*9edbd4a0SFrançois Tigeot static bool intel_hpd_irq_event(struct drm_device *dev, 830*9edbd4a0SFrançois Tigeot struct drm_connector *connector) 8315d0b1887SFrançois Tigeot { 8325d0b1887SFrançois Tigeot enum drm_connector_status old_status; 8335d0b1887SFrançois Tigeot 8345d0b1887SFrançois Tigeot WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 8355d0b1887SFrançois Tigeot old_status = connector->status; 8365d0b1887SFrançois Tigeot 8375d0b1887SFrançois Tigeot connector->status = connector->funcs->detect(connector, false); 838*9edbd4a0SFrançois Tigeot if (old_status == connector->status) 839*9edbd4a0SFrançois Tigeot return false; 840*9edbd4a0SFrançois Tigeot 841*9edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", 8425d0b1887SFrançois Tigeot connector->base.id, 8435d0b1887SFrançois Tigeot drm_get_connector_name(connector), 844*9edbd4a0SFrançois Tigeot drm_get_connector_status_name(old_status), 845*9edbd4a0SFrançois Tigeot drm_get_connector_status_name(connector->status)); 846*9edbd4a0SFrançois Tigeot 847*9edbd4a0SFrançois Tigeot return true; 8485d0b1887SFrançois Tigeot } 8495d0b1887SFrançois Tigeot 850e3adcf8fSFrançois Tigeot /* 851e3adcf8fSFrançois Tigeot * Handle hotplug events outside the interrupt handler proper. 852e3adcf8fSFrançois Tigeot */ 8538e26cdf6SFrançois Tigeot #define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) 8548e26cdf6SFrançois Tigeot 855abf1f4f4SFrançois Tigeot static void i915_hotplug_work_func(struct work_struct *work) 856e3adcf8fSFrançois Tigeot { 857abf1f4f4SFrançois Tigeot drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, 858abf1f4f4SFrançois Tigeot hotplug_work); 859e3adcf8fSFrançois Tigeot struct drm_device *dev = dev_priv->dev; 860abf1f4f4SFrançois Tigeot struct drm_mode_config *mode_config = &dev->mode_config; 8618e26cdf6SFrançois Tigeot struct intel_connector *intel_connector; 8628e26cdf6SFrançois Tigeot struct intel_encoder *intel_encoder; 8638e26cdf6SFrançois Tigeot struct drm_connector *connector; 8648e26cdf6SFrançois Tigeot bool hpd_disabled = false; 8655d0b1887SFrançois Tigeot bool changed = false; 8665d0b1887SFrançois Tigeot u32 hpd_event_bits; 867e3adcf8fSFrançois Tigeot 868a2fdbec6SFrançois Tigeot /* HPD irq before everything is fully set up. */ 869a2fdbec6SFrançois Tigeot if (!dev_priv->enable_hotplug_processing) 870a2fdbec6SFrançois Tigeot return; 871a2fdbec6SFrançois Tigeot 872a2fdbec6SFrançois Tigeot mutex_lock(&mode_config->mutex); 873e3adcf8fSFrançois Tigeot DRM_DEBUG_KMS("running encoder hotplug functions\n"); 874e3adcf8fSFrançois Tigeot 8758e26cdf6SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 8765d0b1887SFrançois Tigeot 8775d0b1887SFrançois Tigeot hpd_event_bits = dev_priv->hpd_event_bits; 8785d0b1887SFrançois Tigeot dev_priv->hpd_event_bits = 0; 8798e26cdf6SFrançois Tigeot list_for_each_entry(connector, &mode_config->connector_list, head) { 8808e26cdf6SFrançois Tigeot intel_connector = to_intel_connector(connector); 8818e26cdf6SFrançois Tigeot intel_encoder = intel_connector->encoder; 8828e26cdf6SFrançois Tigeot if (intel_encoder->hpd_pin > HPD_NONE && 8838e26cdf6SFrançois Tigeot dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_MARK_DISABLED && 8848e26cdf6SFrançois Tigeot connector->polled == DRM_CONNECTOR_POLL_HPD) { 8858e26cdf6SFrançois Tigeot DRM_INFO("HPD interrupt storm detected on connector %s: " 8868e26cdf6SFrançois Tigeot "switching from hotplug detection to polling\n", 8878e26cdf6SFrançois Tigeot drm_get_connector_name(connector)); 8888e26cdf6SFrançois Tigeot dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark = HPD_DISABLED; 8898e26cdf6SFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_CONNECT 8908e26cdf6SFrançois Tigeot | DRM_CONNECTOR_POLL_DISCONNECT; 8918e26cdf6SFrançois Tigeot hpd_disabled = true; 8928e26cdf6SFrançois Tigeot } 8935d0b1887SFrançois Tigeot if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { 8945d0b1887SFrançois Tigeot DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", 8955d0b1887SFrançois Tigeot drm_get_connector_name(connector), intel_encoder->hpd_pin); 8965d0b1887SFrançois Tigeot } 8978e26cdf6SFrançois Tigeot } 8988e26cdf6SFrançois Tigeot /* if there were no outputs to poll, poll was disabled, 8998e26cdf6SFrançois Tigeot * therefore make sure it's enabled when disabling HPD on 9008e26cdf6SFrançois Tigeot * some connectors */ 9018e26cdf6SFrançois Tigeot if (hpd_disabled) { 9028e26cdf6SFrançois Tigeot drm_kms_helper_poll_enable(dev); 9038e26cdf6SFrançois Tigeot mod_timer(&dev_priv->hotplug_reenable_timer, 9048e26cdf6SFrançois Tigeot jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); 9058e26cdf6SFrançois Tigeot } 9068e26cdf6SFrançois Tigeot 9078e26cdf6SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 9088e26cdf6SFrançois Tigeot 9095d0b1887SFrançois Tigeot list_for_each_entry(connector, &mode_config->connector_list, head) { 9105d0b1887SFrançois Tigeot intel_connector = to_intel_connector(connector); 9115d0b1887SFrançois Tigeot intel_encoder = intel_connector->encoder; 9125d0b1887SFrançois Tigeot if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { 9138e26cdf6SFrançois Tigeot if (intel_encoder->hot_plug) 9148e26cdf6SFrançois Tigeot intel_encoder->hot_plug(intel_encoder); 9155d0b1887SFrançois Tigeot if (intel_hpd_irq_event(dev, connector)) 9165d0b1887SFrançois Tigeot changed = true; 9175d0b1887SFrançois Tigeot } 9185d0b1887SFrançois Tigeot } 919a2fdbec6SFrançois Tigeot mutex_unlock(&mode_config->mutex); 920e3adcf8fSFrançois Tigeot 9215d0b1887SFrançois Tigeot if (changed) 9225d0b1887SFrançois Tigeot drm_kms_helper_hotplug_event(dev); 923e3adcf8fSFrançois Tigeot } 924e3adcf8fSFrançois Tigeot 925*9edbd4a0SFrançois Tigeot static void ironlake_rps_change_irq_handler(struct drm_device *dev) 926e3adcf8fSFrançois Tigeot { 927e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 928e3adcf8fSFrançois Tigeot u32 busy_up, busy_down, max_avg, min_avg; 929a2296444SFrançois Tigeot u8 new_delay; 930a2296444SFrançois Tigeot 931a2296444SFrançois Tigeot lockmgr(&mchdev_lock, LK_EXCLUSIVE); 932a2296444SFrançois Tigeot 933a2296444SFrançois Tigeot I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); 934a2296444SFrançois Tigeot 93500640ec9SFrançois Tigeot new_delay = dev_priv->ips.cur_delay; 936e3adcf8fSFrançois Tigeot 937e3adcf8fSFrançois Tigeot I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG); 938e3adcf8fSFrançois Tigeot busy_up = I915_READ(RCPREVBSYTUPAVG); 939e3adcf8fSFrançois Tigeot busy_down = I915_READ(RCPREVBSYTDNAVG); 940e3adcf8fSFrançois Tigeot max_avg = I915_READ(RCBMAXAVG); 941e3adcf8fSFrançois Tigeot min_avg = I915_READ(RCBMINAVG); 942e3adcf8fSFrançois Tigeot 943e3adcf8fSFrançois Tigeot /* Handle RCS change request from hw */ 944e3adcf8fSFrançois Tigeot if (busy_up > max_avg) { 94500640ec9SFrançois Tigeot if (dev_priv->ips.cur_delay != dev_priv->ips.max_delay) 94600640ec9SFrançois Tigeot new_delay = dev_priv->ips.cur_delay - 1; 94700640ec9SFrançois Tigeot if (new_delay < dev_priv->ips.max_delay) 94800640ec9SFrançois Tigeot new_delay = dev_priv->ips.max_delay; 949e3adcf8fSFrançois Tigeot } else if (busy_down < min_avg) { 95000640ec9SFrançois Tigeot if (dev_priv->ips.cur_delay != dev_priv->ips.min_delay) 95100640ec9SFrançois Tigeot new_delay = dev_priv->ips.cur_delay + 1; 95200640ec9SFrançois Tigeot if (new_delay > dev_priv->ips.min_delay) 95300640ec9SFrançois Tigeot new_delay = dev_priv->ips.min_delay; 954e3adcf8fSFrançois Tigeot } 955e3adcf8fSFrançois Tigeot 956e3adcf8fSFrançois Tigeot if (ironlake_set_drps(dev, new_delay)) 95700640ec9SFrançois Tigeot dev_priv->ips.cur_delay = new_delay; 958e3adcf8fSFrançois Tigeot 959a2296444SFrançois Tigeot lockmgr(&mchdev_lock, LK_RELEASE); 960a2296444SFrançois Tigeot 961e3adcf8fSFrançois Tigeot return; 962e3adcf8fSFrançois Tigeot } 963e3adcf8fSFrançois Tigeot 964e3adcf8fSFrançois Tigeot static void notify_ring(struct drm_device *dev, 965e3adcf8fSFrançois Tigeot struct intel_ring_buffer *ring) 966e3adcf8fSFrançois Tigeot { 967e3adcf8fSFrançois Tigeot if (ring->obj == NULL) 968e3adcf8fSFrançois Tigeot return; 969e3adcf8fSFrançois Tigeot 970*9edbd4a0SFrançois Tigeot trace_i915_gem_request_complete(ring); 971*9edbd4a0SFrançois Tigeot 97219b28dc8SFrançois Tigeot wake_up_all(&ring->irq_queue); 973*9edbd4a0SFrançois Tigeot i915_queue_hangcheck(dev); 974e3adcf8fSFrançois Tigeot } 975e3adcf8fSFrançois Tigeot 976abf1f4f4SFrançois Tigeot static void gen6_pm_rps_work(struct work_struct *work) 977e3adcf8fSFrançois Tigeot { 978abf1f4f4SFrançois Tigeot drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, 979abf1f4f4SFrançois Tigeot rps.work); 980*9edbd4a0SFrançois Tigeot u32 pm_iir; 981*9edbd4a0SFrançois Tigeot int new_delay, adj; 982e3adcf8fSFrançois Tigeot 983*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 984abf1f4f4SFrançois Tigeot pm_iir = dev_priv->rps.pm_iir; 985abf1f4f4SFrançois Tigeot dev_priv->rps.pm_iir = 0; 9865d0b1887SFrançois Tigeot /* Make sure not to corrupt PMIMR state used by ringbuffer code */ 987*9edbd4a0SFrançois Tigeot snb_enable_pm_irq(dev_priv, GEN6_PM_RPS_EVENTS); 988*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 989*9edbd4a0SFrançois Tigeot 990*9edbd4a0SFrançois Tigeot /* Make sure we didn't queue anything we're not going to process. */ 991*9edbd4a0SFrançois Tigeot WARN_ON(pm_iir & ~GEN6_PM_RPS_EVENTS); 992e3adcf8fSFrançois Tigeot 9935d0b1887SFrançois Tigeot if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0) 994e3adcf8fSFrançois Tigeot return; 995e3adcf8fSFrançois Tigeot 996a2fdbec6SFrançois Tigeot mutex_lock(&dev_priv->rps.hw_lock); 997e3adcf8fSFrançois Tigeot 998*9edbd4a0SFrançois Tigeot adj = dev_priv->rps.last_adj; 9995d0b1887SFrançois Tigeot if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { 1000*9edbd4a0SFrançois Tigeot if (adj > 0) 1001*9edbd4a0SFrançois Tigeot adj *= 2; 1002*9edbd4a0SFrançois Tigeot else 1003*9edbd4a0SFrançois Tigeot adj = 1; 1004*9edbd4a0SFrançois Tigeot new_delay = dev_priv->rps.cur_delay + adj; 10055d0b1887SFrançois Tigeot 10065d0b1887SFrançois Tigeot /* 10075d0b1887SFrançois Tigeot * For better performance, jump directly 10085d0b1887SFrançois Tigeot * to RPe if we're below it. 10095d0b1887SFrançois Tigeot */ 1010*9edbd4a0SFrançois Tigeot if (new_delay < dev_priv->rps.rpe_delay) 10115d0b1887SFrançois Tigeot new_delay = dev_priv->rps.rpe_delay; 1012*9edbd4a0SFrançois Tigeot } else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) { 1013*9edbd4a0SFrançois Tigeot if (dev_priv->rps.cur_delay > dev_priv->rps.rpe_delay) 1014*9edbd4a0SFrançois Tigeot new_delay = dev_priv->rps.rpe_delay; 1015*9edbd4a0SFrançois Tigeot else 1016*9edbd4a0SFrançois Tigeot new_delay = dev_priv->rps.min_delay; 1017*9edbd4a0SFrançois Tigeot adj = 0; 1018*9edbd4a0SFrançois Tigeot } else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) { 1019*9edbd4a0SFrançois Tigeot if (adj < 0) 1020*9edbd4a0SFrançois Tigeot adj *= 2; 1021*9edbd4a0SFrançois Tigeot else 1022*9edbd4a0SFrançois Tigeot adj = -1; 1023*9edbd4a0SFrançois Tigeot new_delay = dev_priv->rps.cur_delay + adj; 1024*9edbd4a0SFrançois Tigeot } else { /* unknown event */ 1025*9edbd4a0SFrançois Tigeot new_delay = dev_priv->rps.cur_delay; 1026*9edbd4a0SFrançois Tigeot } 1027e3adcf8fSFrançois Tigeot 1028abf1f4f4SFrançois Tigeot /* sysfs frequency interfaces may have snuck in while servicing the 1029abf1f4f4SFrançois Tigeot * interrupt 1030e3adcf8fSFrançois Tigeot */ 1031*9edbd4a0SFrançois Tigeot new_delay = clamp_t(int, new_delay, 1032*9edbd4a0SFrançois Tigeot dev_priv->rps.min_delay, dev_priv->rps.max_delay); 1033*9edbd4a0SFrançois Tigeot dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay; 1034*9edbd4a0SFrançois Tigeot 10355d0b1887SFrançois Tigeot if (IS_VALLEYVIEW(dev_priv->dev)) 10365d0b1887SFrançois Tigeot valleyview_set_rps(dev_priv->dev, new_delay); 10375d0b1887SFrançois Tigeot else 1038abf1f4f4SFrançois Tigeot gen6_set_rps(dev_priv->dev, new_delay); 10395d0b1887SFrançois Tigeot 1040a2fdbec6SFrançois Tigeot mutex_unlock(&dev_priv->rps.hw_lock); 1041e3adcf8fSFrançois Tigeot } 1042e3adcf8fSFrançois Tigeot 104300640ec9SFrançois Tigeot 104400640ec9SFrançois Tigeot /** 104500640ec9SFrançois Tigeot * ivybridge_parity_work - Workqueue called when a parity error interrupt 104600640ec9SFrançois Tigeot * occurred. 104700640ec9SFrançois Tigeot * @work: workqueue struct 104800640ec9SFrançois Tigeot * 104900640ec9SFrançois Tigeot * Doesn't actually do anything except notify userspace. As a consequence of 105000640ec9SFrançois Tigeot * this event, userspace should try to remap the bad rows since statistically 105100640ec9SFrançois Tigeot * it is likely the same row is more likely to go bad again. 105200640ec9SFrançois Tigeot */ 105300640ec9SFrançois Tigeot static void ivybridge_parity_work(struct work_struct *work) 105400640ec9SFrançois Tigeot { 105500640ec9SFrançois Tigeot drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, 105600640ec9SFrançois Tigeot l3_parity.error_work); 105700640ec9SFrançois Tigeot u32 error_status, row, bank, subbank; 1058*9edbd4a0SFrançois Tigeot char *parity_event[6]; 105900640ec9SFrançois Tigeot uint32_t misccpctl; 1060*9edbd4a0SFrançois Tigeot uint8_t slice = 0; 106100640ec9SFrançois Tigeot 106200640ec9SFrançois Tigeot /* We must turn off DOP level clock gating to access the L3 registers. 106300640ec9SFrançois Tigeot * In order to prevent a get/put style interface, acquire struct mutex 106400640ec9SFrançois Tigeot * any time we access those registers. 106500640ec9SFrançois Tigeot */ 1066a2fdbec6SFrançois Tigeot mutex_lock(&dev_priv->dev->struct_mutex); 106700640ec9SFrançois Tigeot 1068*9edbd4a0SFrançois Tigeot /* If we've screwed up tracking, just let the interrupt fire again */ 1069*9edbd4a0SFrançois Tigeot if (WARN_ON(!dev_priv->l3_parity.which_slice)) 1070*9edbd4a0SFrançois Tigeot goto out; 1071*9edbd4a0SFrançois Tigeot 107200640ec9SFrançois Tigeot misccpctl = I915_READ(GEN7_MISCCPCTL); 107300640ec9SFrançois Tigeot I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE); 107400640ec9SFrançois Tigeot POSTING_READ(GEN7_MISCCPCTL); 107500640ec9SFrançois Tigeot 1076*9edbd4a0SFrançois Tigeot while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) { 1077*9edbd4a0SFrançois Tigeot u32 reg; 1078*9edbd4a0SFrançois Tigeot 1079*9edbd4a0SFrançois Tigeot slice--; 1080*9edbd4a0SFrançois Tigeot if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev))) 1081*9edbd4a0SFrançois Tigeot break; 1082*9edbd4a0SFrançois Tigeot 1083*9edbd4a0SFrançois Tigeot dev_priv->l3_parity.which_slice &= ~(1<<slice); 1084*9edbd4a0SFrançois Tigeot 1085*9edbd4a0SFrançois Tigeot reg = GEN7_L3CDERRST1 + (slice * 0x200); 1086*9edbd4a0SFrançois Tigeot 1087*9edbd4a0SFrançois Tigeot error_status = I915_READ(reg); 108800640ec9SFrançois Tigeot row = GEN7_PARITY_ERROR_ROW(error_status); 108900640ec9SFrançois Tigeot bank = GEN7_PARITY_ERROR_BANK(error_status); 109000640ec9SFrançois Tigeot subbank = GEN7_PARITY_ERROR_SUBBANK(error_status); 109100640ec9SFrançois Tigeot 1092*9edbd4a0SFrançois Tigeot I915_WRITE(reg, GEN7_PARITY_ERROR_VALID | GEN7_L3CDERRST1_ENABLE); 1093*9edbd4a0SFrançois Tigeot POSTING_READ(reg); 1094*9edbd4a0SFrançois Tigeot 1095*9edbd4a0SFrançois Tigeot parity_event[0] = I915_L3_PARITY_UEVENT "=1"; 1096*9edbd4a0SFrançois Tigeot parity_event[5] = NULL; 1097*9edbd4a0SFrançois Tigeot 1098*9edbd4a0SFrançois Tigeot #if 0 1099*9edbd4a0SFrançois Tigeot kobject_uevent_env(&dev_priv->dev->primary->kdev->kobj, 1100*9edbd4a0SFrançois Tigeot KOBJ_CHANGE, parity_event); 1101*9edbd4a0SFrançois Tigeot #endif 1102*9edbd4a0SFrançois Tigeot 1103*9edbd4a0SFrançois Tigeot DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n", 1104*9edbd4a0SFrançois Tigeot slice, row, bank, subbank); 1105*9edbd4a0SFrançois Tigeot 1106*9edbd4a0SFrançois Tigeot #if 0 1107*9edbd4a0SFrançois Tigeot kfree(parity_event[4]); 1108*9edbd4a0SFrançois Tigeot kfree(parity_event[3]); 1109*9edbd4a0SFrançois Tigeot kfree(parity_event[2]); 1110*9edbd4a0SFrançois Tigeot kfree(parity_event[1]); 1111*9edbd4a0SFrançois Tigeot #endif 1112*9edbd4a0SFrançois Tigeot } 111300640ec9SFrançois Tigeot 111400640ec9SFrançois Tigeot I915_WRITE(GEN7_MISCCPCTL, misccpctl); 111500640ec9SFrançois Tigeot 1116*9edbd4a0SFrançois Tigeot out: 1117*9edbd4a0SFrançois Tigeot WARN_ON(dev_priv->l3_parity.which_slice); 111800640ec9SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 1119*9edbd4a0SFrançois Tigeot ilk_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv->dev)); 112000640ec9SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 112100640ec9SFrançois Tigeot 1122a2fdbec6SFrançois Tigeot mutex_unlock(&dev_priv->dev->struct_mutex); 112300640ec9SFrançois Tigeot } 112400640ec9SFrançois Tigeot 1125*9edbd4a0SFrançois Tigeot static void ivybridge_parity_error_irq_handler(struct drm_device *dev, u32 iir) 112600640ec9SFrançois Tigeot { 112700640ec9SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 112800640ec9SFrançois Tigeot 1129*9edbd4a0SFrançois Tigeot if (!HAS_L3_DPF(dev)) 113000640ec9SFrançois Tigeot return; 113100640ec9SFrançois Tigeot 113200640ec9SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 1133*9edbd4a0SFrançois Tigeot ilk_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev)); 113400640ec9SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 113500640ec9SFrançois Tigeot 1136*9edbd4a0SFrançois Tigeot iir &= GT_PARITY_ERROR(dev); 1137*9edbd4a0SFrançois Tigeot if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1) 1138*9edbd4a0SFrançois Tigeot dev_priv->l3_parity.which_slice |= 1 << 1; 1139*9edbd4a0SFrançois Tigeot 1140*9edbd4a0SFrançois Tigeot if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT) 1141*9edbd4a0SFrançois Tigeot dev_priv->l3_parity.which_slice |= 1 << 0; 1142*9edbd4a0SFrançois Tigeot 114300640ec9SFrançois Tigeot queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work); 114400640ec9SFrançois Tigeot } 114500640ec9SFrançois Tigeot 1146*9edbd4a0SFrançois Tigeot static void ilk_gt_irq_handler(struct drm_device *dev, 1147*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv, 1148*9edbd4a0SFrançois Tigeot u32 gt_iir) 1149*9edbd4a0SFrançois Tigeot { 1150*9edbd4a0SFrançois Tigeot if (gt_iir & 1151*9edbd4a0SFrançois Tigeot (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT)) 1152*9edbd4a0SFrançois Tigeot notify_ring(dev, &dev_priv->ring[RCS]); 1153*9edbd4a0SFrançois Tigeot if (gt_iir & ILK_BSD_USER_INTERRUPT) 1154*9edbd4a0SFrançois Tigeot notify_ring(dev, &dev_priv->ring[VCS]); 1155*9edbd4a0SFrançois Tigeot } 1156*9edbd4a0SFrançois Tigeot 1157a2296444SFrançois Tigeot static void snb_gt_irq_handler(struct drm_device *dev, 1158a2296444SFrançois Tigeot struct drm_i915_private *dev_priv, 1159a2296444SFrançois Tigeot u32 gt_iir) 1160a2296444SFrançois Tigeot { 1161a2296444SFrançois Tigeot 11625d0b1887SFrançois Tigeot if (gt_iir & 11635d0b1887SFrançois Tigeot (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT)) 1164a2296444SFrançois Tigeot notify_ring(dev, &dev_priv->ring[RCS]); 11655d0b1887SFrançois Tigeot if (gt_iir & GT_BSD_USER_INTERRUPT) 1166a2296444SFrançois Tigeot notify_ring(dev, &dev_priv->ring[VCS]); 11675d0b1887SFrançois Tigeot if (gt_iir & GT_BLT_USER_INTERRUPT) 1168a2296444SFrançois Tigeot notify_ring(dev, &dev_priv->ring[BCS]); 1169a2296444SFrançois Tigeot 11705d0b1887SFrançois Tigeot if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT | 11715d0b1887SFrançois Tigeot GT_BSD_CS_ERROR_INTERRUPT | 11725d0b1887SFrançois Tigeot GT_RENDER_CS_MASTER_ERROR_INTERRUPT)) { 1173a2296444SFrançois Tigeot DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir); 1174a2296444SFrançois Tigeot i915_handle_error(dev, false); 1175a2296444SFrançois Tigeot } 1176a2296444SFrançois Tigeot 1177*9edbd4a0SFrançois Tigeot if (gt_iir & GT_PARITY_ERROR(dev)) 1178*9edbd4a0SFrançois Tigeot ivybridge_parity_error_irq_handler(dev, gt_iir); 1179a2296444SFrançois Tigeot } 1180a2296444SFrançois Tigeot 1181*9edbd4a0SFrançois Tigeot static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, 1182*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv, 1183*9edbd4a0SFrançois Tigeot u32 master_ctl) 1184a2296444SFrançois Tigeot { 1185*9edbd4a0SFrançois Tigeot u32 rcs, bcs, vcs; 1186*9edbd4a0SFrançois Tigeot uint32_t tmp = 0; 1187a2296444SFrançois Tigeot 1188*9edbd4a0SFrançois Tigeot if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) { 1189*9edbd4a0SFrançois Tigeot tmp = I915_READ(GEN8_GT_IIR(0)); 1190*9edbd4a0SFrançois Tigeot if (tmp) { 1191*9edbd4a0SFrançois Tigeot rcs = tmp >> GEN8_RCS_IRQ_SHIFT; 1192*9edbd4a0SFrançois Tigeot bcs = tmp >> GEN8_BCS_IRQ_SHIFT; 1193*9edbd4a0SFrançois Tigeot if (rcs & GT_RENDER_USER_INTERRUPT) 1194*9edbd4a0SFrançois Tigeot notify_ring(dev, &dev_priv->ring[RCS]); 1195*9edbd4a0SFrançois Tigeot if (bcs & GT_RENDER_USER_INTERRUPT) 1196*9edbd4a0SFrançois Tigeot notify_ring(dev, &dev_priv->ring[BCS]); 1197*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_GT_IIR(0), tmp); 1198*9edbd4a0SFrançois Tigeot } else 1199*9edbd4a0SFrançois Tigeot DRM_ERROR("The master control interrupt lied (GT0)!\n"); 1200*9edbd4a0SFrançois Tigeot } 1201a2296444SFrançois Tigeot 1202*9edbd4a0SFrançois Tigeot if (master_ctl & GEN8_GT_VCS1_IRQ) { 1203*9edbd4a0SFrançois Tigeot tmp = I915_READ(GEN8_GT_IIR(1)); 1204*9edbd4a0SFrançois Tigeot if (tmp) { 1205*9edbd4a0SFrançois Tigeot vcs = tmp >> GEN8_VCS1_IRQ_SHIFT; 1206*9edbd4a0SFrançois Tigeot if (vcs & GT_RENDER_USER_INTERRUPT) 1207*9edbd4a0SFrançois Tigeot notify_ring(dev, &dev_priv->ring[VCS]); 1208*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_GT_IIR(1), tmp); 1209*9edbd4a0SFrançois Tigeot } else 1210*9edbd4a0SFrançois Tigeot DRM_ERROR("The master control interrupt lied (GT1)!\n"); 1211*9edbd4a0SFrançois Tigeot } 1212a2296444SFrançois Tigeot 1213*9edbd4a0SFrançois Tigeot if (master_ctl & GEN8_GT_VECS_IRQ) { 1214*9edbd4a0SFrançois Tigeot tmp = I915_READ(GEN8_GT_IIR(3)); 1215*9edbd4a0SFrançois Tigeot if (tmp) { 1216*9edbd4a0SFrançois Tigeot vcs = tmp >> GEN8_VECS_IRQ_SHIFT; 1217*9edbd4a0SFrançois Tigeot if (vcs & GT_RENDER_USER_INTERRUPT) 1218*9edbd4a0SFrançois Tigeot notify_ring(dev, &dev_priv->ring[VECS]); 1219*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_GT_IIR(3), tmp); 1220*9edbd4a0SFrançois Tigeot } else 1221*9edbd4a0SFrançois Tigeot DRM_ERROR("The master control interrupt lied (GT3)!\n"); 1222*9edbd4a0SFrançois Tigeot } 1223*9edbd4a0SFrançois Tigeot 1224a2296444SFrançois Tigeot } 1225a2296444SFrançois Tigeot 12268e26cdf6SFrançois Tigeot #define HPD_STORM_DETECT_PERIOD 1000 12278e26cdf6SFrançois Tigeot #define HPD_STORM_THRESHOLD 5 12288e26cdf6SFrançois Tigeot 12295d0b1887SFrançois Tigeot static inline void intel_hpd_irq_handler(struct drm_device *dev, 12308e26cdf6SFrançois Tigeot u32 hotplug_trigger, 12318e26cdf6SFrançois Tigeot const u32 *hpd) 12328e26cdf6SFrançois Tigeot { 12338e26cdf6SFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 12348e26cdf6SFrançois Tigeot int i; 12355d0b1887SFrançois Tigeot bool storm_detected = false; 12365d0b1887SFrançois Tigeot 12375d0b1887SFrançois Tigeot if (!hotplug_trigger) 12385d0b1887SFrançois Tigeot return; 12398e26cdf6SFrançois Tigeot 12408e26cdf6SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 12418e26cdf6SFrançois Tigeot for (i = 1; i < HPD_NUM_PINS; i++) { 12428e26cdf6SFrançois Tigeot 1243*9edbd4a0SFrançois Tigeot WARN_ONCE(hpd[i] & hotplug_trigger && 1244*9edbd4a0SFrançois Tigeot dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED, 1245*9edbd4a0SFrançois Tigeot "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n", 1246*9edbd4a0SFrançois Tigeot hotplug_trigger, i, hpd[i]); 1247*9edbd4a0SFrançois Tigeot 12488e26cdf6SFrançois Tigeot if (!(hpd[i] & hotplug_trigger) || 12498e26cdf6SFrançois Tigeot dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) 12508e26cdf6SFrançois Tigeot continue; 12518e26cdf6SFrançois Tigeot 12525d0b1887SFrançois Tigeot dev_priv->hpd_event_bits |= (1 << i); 12538e26cdf6SFrançois Tigeot if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies, 12548e26cdf6SFrançois Tigeot dev_priv->hpd_stats[i].hpd_last_jiffies 12558e26cdf6SFrançois Tigeot + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) { 12568e26cdf6SFrançois Tigeot dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies; 12578e26cdf6SFrançois Tigeot dev_priv->hpd_stats[i].hpd_cnt = 0; 1258*9edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", i); 12598e26cdf6SFrançois Tigeot } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) { 12608e26cdf6SFrançois Tigeot dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; 12615d0b1887SFrançois Tigeot dev_priv->hpd_event_bits &= ~(1 << i); 12628e26cdf6SFrançois Tigeot DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); 12635d0b1887SFrançois Tigeot storm_detected = true; 12648e26cdf6SFrançois Tigeot } else { 12658e26cdf6SFrançois Tigeot dev_priv->hpd_stats[i].hpd_cnt++; 1266*9edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", i, 1267*9edbd4a0SFrançois Tigeot dev_priv->hpd_stats[i].hpd_cnt); 12688e26cdf6SFrançois Tigeot } 12698e26cdf6SFrançois Tigeot } 12708e26cdf6SFrançois Tigeot 12715d0b1887SFrançois Tigeot if (storm_detected) 12725d0b1887SFrançois Tigeot dev_priv->display.hpd_irq_setup(dev); 1273*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 12745d0b1887SFrançois Tigeot 1275*9edbd4a0SFrançois Tigeot /* 1276*9edbd4a0SFrançois Tigeot * Our hotplug handler can grab modeset locks (by calling down into the 1277*9edbd4a0SFrançois Tigeot * fb helpers). Hence it must not be run on our own dev-priv->wq work 1278*9edbd4a0SFrançois Tigeot * queue for otherwise the flush_work in the pageflip code will 1279*9edbd4a0SFrançois Tigeot * deadlock. 1280*9edbd4a0SFrançois Tigeot */ 1281*9edbd4a0SFrançois Tigeot schedule_work(&dev_priv->hotplug_work); 12828e26cdf6SFrançois Tigeot } 12838e26cdf6SFrançois Tigeot 1284a2fdbec6SFrançois Tigeot static void gmbus_irq_handler(struct drm_device *dev) 1285a2fdbec6SFrançois Tigeot { 1286a2fdbec6SFrançois Tigeot struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; 1287a2fdbec6SFrançois Tigeot 1288a2fdbec6SFrançois Tigeot wake_up_all(&dev_priv->gmbus_wait_queue); 1289a2fdbec6SFrançois Tigeot } 1290a2fdbec6SFrançois Tigeot 1291a2fdbec6SFrançois Tigeot static void dp_aux_irq_handler(struct drm_device *dev) 1292a2fdbec6SFrançois Tigeot { 1293a2fdbec6SFrançois Tigeot struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; 1294a2fdbec6SFrançois Tigeot 1295a2fdbec6SFrançois Tigeot wake_up_all(&dev_priv->gmbus_wait_queue); 1296a2fdbec6SFrançois Tigeot } 1297a2fdbec6SFrançois Tigeot 1298*9edbd4a0SFrançois Tigeot #if defined(CONFIG_DEBUG_FS) 1299*9edbd4a0SFrançois Tigeot static void display_pipe_crc_irq_handler(struct drm_device *dev, enum i915_pipe pipe, 1300*9edbd4a0SFrançois Tigeot uint32_t crc0, uint32_t crc1, 1301*9edbd4a0SFrançois Tigeot uint32_t crc2, uint32_t crc3, 1302*9edbd4a0SFrançois Tigeot uint32_t crc4) 13035d0b1887SFrançois Tigeot { 1304*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1305*9edbd4a0SFrançois Tigeot struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; 1306*9edbd4a0SFrançois Tigeot struct intel_pipe_crc_entry *entry; 1307*9edbd4a0SFrançois Tigeot int head, tail; 1308*9edbd4a0SFrançois Tigeot 1309*9edbd4a0SFrançois Tigeot spin_lock(&pipe_crc->lock); 1310*9edbd4a0SFrançois Tigeot 1311*9edbd4a0SFrançois Tigeot if (!pipe_crc->entries) { 1312*9edbd4a0SFrançois Tigeot spin_unlock(&pipe_crc->lock); 1313*9edbd4a0SFrançois Tigeot DRM_ERROR("spurious interrupt\n"); 1314*9edbd4a0SFrançois Tigeot return; 1315*9edbd4a0SFrançois Tigeot } 1316*9edbd4a0SFrançois Tigeot 1317*9edbd4a0SFrançois Tigeot head = pipe_crc->head; 1318*9edbd4a0SFrançois Tigeot tail = pipe_crc->tail; 1319*9edbd4a0SFrançois Tigeot 1320*9edbd4a0SFrançois Tigeot if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) { 1321*9edbd4a0SFrançois Tigeot spin_unlock(&pipe_crc->lock); 1322*9edbd4a0SFrançois Tigeot DRM_ERROR("CRC buffer overflowing\n"); 1323*9edbd4a0SFrançois Tigeot return; 1324*9edbd4a0SFrançois Tigeot } 1325*9edbd4a0SFrançois Tigeot 1326*9edbd4a0SFrançois Tigeot entry = &pipe_crc->entries[head]; 1327*9edbd4a0SFrançois Tigeot 1328*9edbd4a0SFrançois Tigeot entry->frame = dev->driver->get_vblank_counter(dev, pipe); 1329*9edbd4a0SFrançois Tigeot entry->crc[0] = crc0; 1330*9edbd4a0SFrançois Tigeot entry->crc[1] = crc1; 1331*9edbd4a0SFrançois Tigeot entry->crc[2] = crc2; 1332*9edbd4a0SFrançois Tigeot entry->crc[3] = crc3; 1333*9edbd4a0SFrançois Tigeot entry->crc[4] = crc4; 1334*9edbd4a0SFrançois Tigeot 1335*9edbd4a0SFrançois Tigeot head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); 1336*9edbd4a0SFrançois Tigeot pipe_crc->head = head; 1337*9edbd4a0SFrançois Tigeot 1338*9edbd4a0SFrançois Tigeot spin_unlock(&pipe_crc->lock); 1339*9edbd4a0SFrançois Tigeot 1340*9edbd4a0SFrançois Tigeot wake_up_interruptible(&pipe_crc->wq); 1341*9edbd4a0SFrançois Tigeot } 1342*9edbd4a0SFrançois Tigeot #else 1343*9edbd4a0SFrançois Tigeot static inline void 1344*9edbd4a0SFrançois Tigeot display_pipe_crc_irq_handler(struct drm_device *dev, enum i915_pipe pipe, 1345*9edbd4a0SFrançois Tigeot uint32_t crc0, uint32_t crc1, 1346*9edbd4a0SFrançois Tigeot uint32_t crc2, uint32_t crc3, 1347*9edbd4a0SFrançois Tigeot uint32_t crc4) {} 1348*9edbd4a0SFrançois Tigeot #endif 1349*9edbd4a0SFrançois Tigeot 1350*9edbd4a0SFrançois Tigeot 1351*9edbd4a0SFrançois Tigeot static void hsw_pipe_crc_irq_handler(struct drm_device *dev, enum i915_pipe pipe) 1352*9edbd4a0SFrançois Tigeot { 1353*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1354*9edbd4a0SFrançois Tigeot 1355*9edbd4a0SFrançois Tigeot display_pipe_crc_irq_handler(dev, pipe, 1356*9edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_1_IVB(pipe)), 1357*9edbd4a0SFrançois Tigeot 0, 0, 0, 0); 1358*9edbd4a0SFrançois Tigeot } 1359*9edbd4a0SFrançois Tigeot 1360*9edbd4a0SFrançois Tigeot static void ivb_pipe_crc_irq_handler(struct drm_device *dev, enum i915_pipe pipe) 1361*9edbd4a0SFrançois Tigeot { 1362*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1363*9edbd4a0SFrançois Tigeot 1364*9edbd4a0SFrançois Tigeot display_pipe_crc_irq_handler(dev, pipe, 1365*9edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_1_IVB(pipe)), 1366*9edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_2_IVB(pipe)), 1367*9edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_3_IVB(pipe)), 1368*9edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_4_IVB(pipe)), 1369*9edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_5_IVB(pipe))); 1370*9edbd4a0SFrançois Tigeot } 1371*9edbd4a0SFrançois Tigeot 1372*9edbd4a0SFrançois Tigeot static void i9xx_pipe_crc_irq_handler(struct drm_device *dev, enum i915_pipe pipe) 1373*9edbd4a0SFrançois Tigeot { 1374*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1375*9edbd4a0SFrançois Tigeot uint32_t res1, res2; 1376*9edbd4a0SFrançois Tigeot 1377*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 3) 1378*9edbd4a0SFrançois Tigeot res1 = I915_READ(PIPE_CRC_RES_RES1_I915(pipe)); 1379*9edbd4a0SFrançois Tigeot else 1380*9edbd4a0SFrançois Tigeot res1 = 0; 1381*9edbd4a0SFrançois Tigeot 1382*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev)) 1383*9edbd4a0SFrançois Tigeot res2 = I915_READ(PIPE_CRC_RES_RES2_G4X(pipe)); 1384*9edbd4a0SFrançois Tigeot else 1385*9edbd4a0SFrançois Tigeot res2 = 0; 1386*9edbd4a0SFrançois Tigeot 1387*9edbd4a0SFrançois Tigeot display_pipe_crc_irq_handler(dev, pipe, 1388*9edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_RED(pipe)), 1389*9edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_GREEN(pipe)), 1390*9edbd4a0SFrançois Tigeot I915_READ(PIPE_CRC_RES_BLUE(pipe)), 1391*9edbd4a0SFrançois Tigeot res1, res2); 1392*9edbd4a0SFrançois Tigeot } 1393*9edbd4a0SFrançois Tigeot 1394*9edbd4a0SFrançois Tigeot /* The RPS events need forcewake, so we add them to a work queue and mask their 1395*9edbd4a0SFrançois Tigeot * IMR bits until the work is done. Other interrupts can be processed without 1396*9edbd4a0SFrançois Tigeot * the work queue. */ 1397*9edbd4a0SFrançois Tigeot static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) 1398*9edbd4a0SFrançois Tigeot { 1399*9edbd4a0SFrançois Tigeot if (pm_iir & GEN6_PM_RPS_EVENTS) { 1400*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 14015d0b1887SFrançois Tigeot dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS; 1402*9edbd4a0SFrançois Tigeot snb_disable_pm_irq(dev_priv, pm_iir & GEN6_PM_RPS_EVENTS); 1403*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 1404*9edbd4a0SFrançois Tigeot 14055d0b1887SFrançois Tigeot queue_work(dev_priv->wq, &dev_priv->rps.work); 14065d0b1887SFrançois Tigeot } 14075d0b1887SFrançois Tigeot 1408*9edbd4a0SFrançois Tigeot if (HAS_VEBOX(dev_priv->dev)) { 14095d0b1887SFrançois Tigeot if (pm_iir & PM_VEBOX_USER_INTERRUPT) 14105d0b1887SFrançois Tigeot notify_ring(dev_priv->dev, &dev_priv->ring[VECS]); 14115d0b1887SFrançois Tigeot 14125d0b1887SFrançois Tigeot if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) { 14135d0b1887SFrançois Tigeot DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir); 14145d0b1887SFrançois Tigeot i915_handle_error(dev_priv->dev, false); 14155d0b1887SFrançois Tigeot } 14165d0b1887SFrançois Tigeot } 14175d0b1887SFrançois Tigeot } 14185d0b1887SFrançois Tigeot 1419e9243325SFrançois Tigeot static irqreturn_t valleyview_irq_handler(void *arg) 1420e9243325SFrançois Tigeot { 1421e9243325SFrançois Tigeot struct drm_device *dev = (struct drm_device *) arg; 1422e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1423e9243325SFrançois Tigeot u32 iir, gt_iir, pm_iir; 1424e9243325SFrançois Tigeot int pipe; 1425e9243325SFrançois Tigeot u32 pipe_stats[I915_MAX_PIPES]; 1426e9243325SFrançois Tigeot 1427e9243325SFrançois Tigeot atomic_inc(&dev_priv->irq_received); 1428e9243325SFrançois Tigeot 1429e9243325SFrançois Tigeot while (true) { 1430e9243325SFrançois Tigeot iir = I915_READ(VLV_IIR); 1431e9243325SFrançois Tigeot gt_iir = I915_READ(GTIIR); 1432e9243325SFrançois Tigeot pm_iir = I915_READ(GEN6_PMIIR); 1433e9243325SFrançois Tigeot 1434e9243325SFrançois Tigeot if (gt_iir == 0 && pm_iir == 0 && iir == 0) 1435e9243325SFrançois Tigeot goto out; 1436e9243325SFrançois Tigeot 1437*9edbd4a0SFrançois Tigeot 1438e9243325SFrançois Tigeot snb_gt_irq_handler(dev, dev_priv, gt_iir); 1439e9243325SFrançois Tigeot 1440e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 1441e9243325SFrançois Tigeot for_each_pipe(pipe) { 1442e9243325SFrançois Tigeot int reg = PIPESTAT(pipe); 1443e9243325SFrançois Tigeot pipe_stats[pipe] = I915_READ(reg); 1444e9243325SFrançois Tigeot 1445e9243325SFrançois Tigeot /* 1446e9243325SFrançois Tigeot * Clear the PIPE*STAT regs before the IIR 1447e9243325SFrançois Tigeot */ 1448e9243325SFrançois Tigeot if (pipe_stats[pipe] & 0x8000ffff) { 1449e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 1450e9243325SFrançois Tigeot DRM_DEBUG_DRIVER("pipe %c underrun\n", 1451e9243325SFrançois Tigeot pipe_name(pipe)); 1452e9243325SFrançois Tigeot I915_WRITE(reg, pipe_stats[pipe]); 1453e9243325SFrançois Tigeot } 1454e9243325SFrançois Tigeot } 1455e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 1456e9243325SFrançois Tigeot 1457e9243325SFrançois Tigeot for_each_pipe(pipe) { 1458*9edbd4a0SFrançois Tigeot if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) 1459e9243325SFrançois Tigeot drm_handle_vblank(dev, pipe); 1460e9243325SFrançois Tigeot 1461e9243325SFrançois Tigeot if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) { 1462e9243325SFrançois Tigeot intel_prepare_page_flip(dev, pipe); 1463e9243325SFrançois Tigeot intel_finish_page_flip(dev, pipe); 1464e9243325SFrançois Tigeot } 1465*9edbd4a0SFrançois Tigeot 1466*9edbd4a0SFrançois Tigeot if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) 1467*9edbd4a0SFrançois Tigeot i9xx_pipe_crc_irq_handler(dev, pipe); 1468e9243325SFrançois Tigeot } 1469e9243325SFrançois Tigeot 1470e9243325SFrançois Tigeot /* Consume port. Then clear IIR or we'll miss events */ 1471e9243325SFrançois Tigeot if (iir & I915_DISPLAY_PORT_INTERRUPT) { 1472e9243325SFrançois Tigeot u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); 14738e26cdf6SFrançois Tigeot u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; 1474e9243325SFrançois Tigeot 1475e9243325SFrançois Tigeot DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", 1476e9243325SFrançois Tigeot hotplug_status); 14775d0b1887SFrançois Tigeot 14785d0b1887SFrançois Tigeot intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); 14795d0b1887SFrançois Tigeot 1480*9edbd4a0SFrançois Tigeot if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) 1481*9edbd4a0SFrançois Tigeot dp_aux_irq_handler(dev); 1482*9edbd4a0SFrançois Tigeot 1483e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); 1484e9243325SFrançois Tigeot I915_READ(PORT_HOTPLUG_STAT); 1485e9243325SFrançois Tigeot } 1486e9243325SFrançois Tigeot 1487a2fdbec6SFrançois Tigeot if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) 1488a2fdbec6SFrançois Tigeot gmbus_irq_handler(dev); 1489e9243325SFrançois Tigeot 1490*9edbd4a0SFrançois Tigeot if (pm_iir) 1491*9edbd4a0SFrançois Tigeot gen6_rps_irq_handler(dev_priv, pm_iir); 1492e9243325SFrançois Tigeot 1493e9243325SFrançois Tigeot I915_WRITE(GTIIR, gt_iir); 1494e9243325SFrançois Tigeot I915_WRITE(GEN6_PMIIR, pm_iir); 1495e9243325SFrançois Tigeot I915_WRITE(VLV_IIR, iir); 1496e9243325SFrançois Tigeot } 1497e9243325SFrançois Tigeot 1498e9243325SFrançois Tigeot out: 1499e9243325SFrançois Tigeot return; 1500e9243325SFrançois Tigeot } 1501e9243325SFrançois Tigeot 1502a2296444SFrançois Tigeot static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) 1503e3adcf8fSFrançois Tigeot { 1504e3adcf8fSFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1505e3adcf8fSFrançois Tigeot int pipe; 15068e26cdf6SFrançois Tigeot u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; 1507e3adcf8fSFrançois Tigeot 15085d0b1887SFrançois Tigeot intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx); 15095d0b1887SFrançois Tigeot 15105d0b1887SFrançois Tigeot if (pch_iir & SDE_AUDIO_POWER_MASK) { 15115d0b1887SFrançois Tigeot int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> 1512e3adcf8fSFrançois Tigeot SDE_AUDIO_POWER_SHIFT); 15135d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", 15145d0b1887SFrançois Tigeot port_name(port)); 15155d0b1887SFrançois Tigeot } 1516e3adcf8fSFrançois Tigeot 1517a2fdbec6SFrançois Tigeot if (pch_iir & SDE_AUX_MASK) 1518a2fdbec6SFrançois Tigeot dp_aux_irq_handler(dev); 1519a2fdbec6SFrançois Tigeot 1520e3adcf8fSFrançois Tigeot if (pch_iir & SDE_GMBUS) 1521a2fdbec6SFrançois Tigeot gmbus_irq_handler(dev); 1522e3adcf8fSFrançois Tigeot 1523e3adcf8fSFrançois Tigeot if (pch_iir & SDE_AUDIO_HDCP_MASK) 1524a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n"); 1525e3adcf8fSFrançois Tigeot 1526e3adcf8fSFrançois Tigeot if (pch_iir & SDE_AUDIO_TRANS_MASK) 1527a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder audio interrupt\n"); 1528e3adcf8fSFrançois Tigeot 1529e3adcf8fSFrançois Tigeot if (pch_iir & SDE_POISON) 1530a2296444SFrançois Tigeot DRM_ERROR("PCH poison interrupt\n"); 1531e3adcf8fSFrançois Tigeot 1532e3adcf8fSFrançois Tigeot if (pch_iir & SDE_FDI_MASK) 1533e3adcf8fSFrançois Tigeot for_each_pipe(pipe) 1534a2296444SFrançois Tigeot DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n", 1535e3adcf8fSFrançois Tigeot pipe_name(pipe), 1536e3adcf8fSFrançois Tigeot I915_READ(FDI_RX_IIR(pipe))); 1537e3adcf8fSFrançois Tigeot 1538e3adcf8fSFrançois Tigeot if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) 1539a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n"); 1540e3adcf8fSFrançois Tigeot 1541e3adcf8fSFrançois Tigeot if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) 1542a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n"); 1543e3adcf8fSFrançois Tigeot 1544e3adcf8fSFrançois Tigeot if (pch_iir & SDE_TRANSA_FIFO_UNDER) 15455d0b1887SFrançois Tigeot if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, 15465d0b1887SFrançois Tigeot false)) 15475d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n"); 15485d0b1887SFrançois Tigeot 15495d0b1887SFrançois Tigeot if (pch_iir & SDE_TRANSB_FIFO_UNDER) 15505d0b1887SFrançois Tigeot if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B, 15515d0b1887SFrançois Tigeot false)) 15525d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n"); 15535d0b1887SFrançois Tigeot } 15545d0b1887SFrançois Tigeot 15555d0b1887SFrançois Tigeot static void ivb_err_int_handler(struct drm_device *dev) 15565d0b1887SFrançois Tigeot { 15575d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 15585d0b1887SFrançois Tigeot u32 err_int = I915_READ(GEN7_ERR_INT); 1559*9edbd4a0SFrançois Tigeot enum i915_pipe pipe; 15605d0b1887SFrançois Tigeot 15615d0b1887SFrançois Tigeot if (err_int & ERR_INT_POISON) 15625d0b1887SFrançois Tigeot DRM_ERROR("Poison interrupt\n"); 15635d0b1887SFrançois Tigeot 1564*9edbd4a0SFrançois Tigeot for_each_pipe(pipe) { 1565*9edbd4a0SFrançois Tigeot if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) { 1566*9edbd4a0SFrançois Tigeot if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, 1567*9edbd4a0SFrançois Tigeot false)) 1568*9edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n", 1569*9edbd4a0SFrançois Tigeot pipe_name(pipe)); 1570*9edbd4a0SFrançois Tigeot } 15715d0b1887SFrançois Tigeot 1572*9edbd4a0SFrançois Tigeot if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { 1573*9edbd4a0SFrançois Tigeot if (IS_IVYBRIDGE(dev)) 1574*9edbd4a0SFrançois Tigeot ivb_pipe_crc_irq_handler(dev, pipe); 1575*9edbd4a0SFrançois Tigeot else 1576*9edbd4a0SFrançois Tigeot hsw_pipe_crc_irq_handler(dev, pipe); 1577*9edbd4a0SFrançois Tigeot } 1578*9edbd4a0SFrançois Tigeot } 15795d0b1887SFrançois Tigeot 15805d0b1887SFrançois Tigeot I915_WRITE(GEN7_ERR_INT, err_int); 15815d0b1887SFrançois Tigeot } 15825d0b1887SFrançois Tigeot 15835d0b1887SFrançois Tigeot static void cpt_serr_int_handler(struct drm_device *dev) 15845d0b1887SFrançois Tigeot { 15855d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 15865d0b1887SFrançois Tigeot u32 serr_int = I915_READ(SERR_INT); 15875d0b1887SFrançois Tigeot 15885d0b1887SFrançois Tigeot if (serr_int & SERR_INT_POISON) 15895d0b1887SFrançois Tigeot DRM_ERROR("PCH poison interrupt\n"); 15905d0b1887SFrançois Tigeot 15915d0b1887SFrançois Tigeot if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN) 15925d0b1887SFrançois Tigeot if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, 15935d0b1887SFrançois Tigeot false)) 15945d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n"); 15955d0b1887SFrançois Tigeot 15965d0b1887SFrançois Tigeot if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN) 15975d0b1887SFrançois Tigeot if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B, 15985d0b1887SFrançois Tigeot false)) 15995d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n"); 16005d0b1887SFrançois Tigeot 16015d0b1887SFrançois Tigeot if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN) 16025d0b1887SFrançois Tigeot if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C, 16035d0b1887SFrançois Tigeot false)) 16045d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n"); 16055d0b1887SFrançois Tigeot 16065d0b1887SFrançois Tigeot I915_WRITE(SERR_INT, serr_int); 1607a2296444SFrançois Tigeot } 1608a2296444SFrançois Tigeot 1609a2296444SFrançois Tigeot static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) 1610a2296444SFrançois Tigeot { 1611a2296444SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1612a2296444SFrançois Tigeot int pipe; 16138e26cdf6SFrançois Tigeot u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; 1614a2296444SFrançois Tigeot 16155d0b1887SFrançois Tigeot intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt); 16165d0b1887SFrançois Tigeot 16175d0b1887SFrançois Tigeot if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { 16185d0b1887SFrançois Tigeot int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> 1619a2296444SFrançois Tigeot SDE_AUDIO_POWER_SHIFT_CPT); 16205d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("PCH audio power change on port %c\n", 16215d0b1887SFrançois Tigeot port_name(port)); 16225d0b1887SFrançois Tigeot } 1623a2296444SFrançois Tigeot 1624a2296444SFrançois Tigeot if (pch_iir & SDE_AUX_MASK_CPT) 1625a2fdbec6SFrançois Tigeot dp_aux_irq_handler(dev); 1626a2296444SFrançois Tigeot 1627a2296444SFrançois Tigeot if (pch_iir & SDE_GMBUS_CPT) 1628a2fdbec6SFrançois Tigeot gmbus_irq_handler(dev); 1629a2296444SFrançois Tigeot 1630a2296444SFrançois Tigeot if (pch_iir & SDE_AUDIO_CP_REQ_CPT) 1631a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("Audio CP request interrupt\n"); 1632a2296444SFrançois Tigeot 1633a2296444SFrançois Tigeot if (pch_iir & SDE_AUDIO_CP_CHG_CPT) 1634a2296444SFrançois Tigeot DRM_DEBUG_DRIVER("Audio CP change interrupt\n"); 1635a2296444SFrançois Tigeot 1636a2296444SFrançois Tigeot if (pch_iir & SDE_FDI_MASK_CPT) 1637a2296444SFrançois Tigeot for_each_pipe(pipe) 1638a2296444SFrançois Tigeot DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n", 1639a2296444SFrançois Tigeot pipe_name(pipe), 1640a2296444SFrançois Tigeot I915_READ(FDI_RX_IIR(pipe))); 16415d0b1887SFrançois Tigeot 16425d0b1887SFrançois Tigeot if (pch_iir & SDE_ERROR_CPT) 16435d0b1887SFrançois Tigeot cpt_serr_int_handler(dev); 1644e3adcf8fSFrançois Tigeot } 1645e3adcf8fSFrançois Tigeot 1646*9edbd4a0SFrançois Tigeot static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir) 1647c4a9e910SFrançois Tigeot { 1648*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1649*9edbd4a0SFrançois Tigeot enum i915_pipe pipe; 1650e3adcf8fSFrançois Tigeot 1651a2fdbec6SFrançois Tigeot if (de_iir & DE_AUX_CHANNEL_A) 1652a2fdbec6SFrançois Tigeot dp_aux_irq_handler(dev); 1653a2fdbec6SFrançois Tigeot 165400640ec9SFrançois Tigeot if (de_iir & DE_GSE) 16555d0b1887SFrançois Tigeot intel_opregion_asle_intr(dev); 1656e3adcf8fSFrançois Tigeot 16575d0b1887SFrançois Tigeot if (de_iir & DE_POISON) 16585d0b1887SFrançois Tigeot DRM_ERROR("Poison interrupt\n"); 16595d0b1887SFrançois Tigeot 1660*9edbd4a0SFrançois Tigeot for_each_pipe(pipe) { 1661*9edbd4a0SFrançois Tigeot if (de_iir & DE_PIPE_VBLANK(pipe)) 1662*9edbd4a0SFrançois Tigeot drm_handle_vblank(dev, pipe); 16635d0b1887SFrançois Tigeot 1664*9edbd4a0SFrançois Tigeot if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) 1665*9edbd4a0SFrançois Tigeot if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) 1666*9edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n", 1667*9edbd4a0SFrançois Tigeot pipe_name(pipe)); 16685d0b1887SFrançois Tigeot 1669*9edbd4a0SFrançois Tigeot if (de_iir & DE_PIPE_CRC_DONE(pipe)) 1670*9edbd4a0SFrançois Tigeot i9xx_pipe_crc_irq_handler(dev, pipe); 1671*9edbd4a0SFrançois Tigeot 1672*9edbd4a0SFrançois Tigeot /* plane/pipes map 1:1 on ilk+ */ 1673*9edbd4a0SFrançois Tigeot if (de_iir & DE_PLANE_FLIP_DONE(pipe)) { 1674*9edbd4a0SFrançois Tigeot intel_prepare_page_flip(dev, pipe); 1675*9edbd4a0SFrançois Tigeot intel_finish_page_flip_plane(dev, pipe); 1676e3adcf8fSFrançois Tigeot } 1677e3adcf8fSFrançois Tigeot } 1678e3adcf8fSFrançois Tigeot 1679e3adcf8fSFrançois Tigeot /* check event from PCH */ 1680e3adcf8fSFrançois Tigeot if (de_iir & DE_PCH_EVENT) { 1681a2fdbec6SFrançois Tigeot u32 pch_iir = I915_READ(SDEIIR); 1682a2fdbec6SFrançois Tigeot 1683a2296444SFrançois Tigeot if (HAS_PCH_CPT(dev)) 1684a2296444SFrançois Tigeot cpt_irq_handler(dev, pch_iir); 1685a2296444SFrançois Tigeot else 1686a2296444SFrançois Tigeot ibx_irq_handler(dev, pch_iir); 1687a2fdbec6SFrançois Tigeot 1688a2fdbec6SFrançois Tigeot /* should clear PCH hotplug event before clear CPU irq */ 1689a2fdbec6SFrançois Tigeot I915_WRITE(SDEIIR, pch_iir); 1690e3adcf8fSFrançois Tigeot } 1691e3adcf8fSFrançois Tigeot 1692a2296444SFrançois Tigeot if (IS_GEN5(dev) && de_iir & DE_PCU_EVENT) 1693*9edbd4a0SFrançois Tigeot ironlake_rps_change_irq_handler(dev); 1694*9edbd4a0SFrançois Tigeot } 1695e3adcf8fSFrançois Tigeot 1696*9edbd4a0SFrançois Tigeot static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir) 1697*9edbd4a0SFrançois Tigeot { 1698*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1699*9edbd4a0SFrançois Tigeot enum i915_pipe i; 1700e3adcf8fSFrançois Tigeot 1701*9edbd4a0SFrançois Tigeot if (de_iir & DE_ERR_INT_IVB) 1702*9edbd4a0SFrançois Tigeot ivb_err_int_handler(dev); 1703*9edbd4a0SFrançois Tigeot 1704*9edbd4a0SFrançois Tigeot if (de_iir & DE_AUX_CHANNEL_A_IVB) 1705*9edbd4a0SFrançois Tigeot dp_aux_irq_handler(dev); 1706*9edbd4a0SFrançois Tigeot 1707*9edbd4a0SFrançois Tigeot if (de_iir & DE_GSE_IVB) 1708*9edbd4a0SFrançois Tigeot intel_opregion_asle_intr(dev); 1709*9edbd4a0SFrançois Tigeot 1710*9edbd4a0SFrançois Tigeot for_each_pipe(i) { 1711*9edbd4a0SFrançois Tigeot if (de_iir & (DE_PIPE_VBLANK_IVB(i))) 1712*9edbd4a0SFrançois Tigeot drm_handle_vblank(dev, i); 1713*9edbd4a0SFrançois Tigeot 1714*9edbd4a0SFrançois Tigeot /* plane/pipes map 1:1 on ilk+ */ 1715*9edbd4a0SFrançois Tigeot if (de_iir & DE_PLANE_FLIP_DONE_IVB(i)) { 1716*9edbd4a0SFrançois Tigeot intel_prepare_page_flip(dev, i); 1717*9edbd4a0SFrançois Tigeot intel_finish_page_flip_plane(dev, i); 1718*9edbd4a0SFrançois Tigeot } 1719*9edbd4a0SFrançois Tigeot } 1720*9edbd4a0SFrançois Tigeot 1721*9edbd4a0SFrançois Tigeot /* check event from PCH */ 1722*9edbd4a0SFrançois Tigeot if (!HAS_PCH_NOP(dev) && (de_iir & DE_PCH_EVENT_IVB)) { 1723*9edbd4a0SFrançois Tigeot u32 pch_iir = I915_READ(SDEIIR); 1724*9edbd4a0SFrançois Tigeot 1725*9edbd4a0SFrançois Tigeot cpt_irq_handler(dev, pch_iir); 1726*9edbd4a0SFrançois Tigeot 1727*9edbd4a0SFrançois Tigeot /* clear PCH hotplug event before clear CPU irq */ 1728*9edbd4a0SFrançois Tigeot I915_WRITE(SDEIIR, pch_iir); 1729*9edbd4a0SFrançois Tigeot } 1730*9edbd4a0SFrançois Tigeot } 1731*9edbd4a0SFrançois Tigeot 1732*9edbd4a0SFrançois Tigeot static irqreturn_t ironlake_irq_handler(void *arg) 1733*9edbd4a0SFrançois Tigeot { 1734*9edbd4a0SFrançois Tigeot struct drm_device *dev = (struct drm_device *) arg; 1735*9edbd4a0SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1736*9edbd4a0SFrançois Tigeot u32 de_iir, gt_iir, de_ier, sde_ier = 0; 1737*9edbd4a0SFrançois Tigeot 1738*9edbd4a0SFrançois Tigeot atomic_inc(&dev_priv->irq_received); 1739*9edbd4a0SFrançois Tigeot 1740*9edbd4a0SFrançois Tigeot /* We get interrupts on unclaimed registers, so check for this before we 1741*9edbd4a0SFrançois Tigeot * do any I915_{READ,WRITE}. */ 1742*9edbd4a0SFrançois Tigeot intel_uncore_check_errors(dev); 1743*9edbd4a0SFrançois Tigeot 1744*9edbd4a0SFrançois Tigeot /* disable master interrupt before clearing iir */ 1745*9edbd4a0SFrançois Tigeot de_ier = I915_READ(DEIER); 1746*9edbd4a0SFrançois Tigeot I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); 1747*9edbd4a0SFrançois Tigeot POSTING_READ(DEIER); 1748*9edbd4a0SFrançois Tigeot 1749*9edbd4a0SFrançois Tigeot /* Disable south interrupts. We'll only write to SDEIIR once, so further 1750*9edbd4a0SFrançois Tigeot * interrupts will will be stored on its back queue, and then we'll be 1751*9edbd4a0SFrançois Tigeot * able to process them after we restore SDEIER (as soon as we restore 1752*9edbd4a0SFrançois Tigeot * it, we'll get an interrupt if SDEIIR still has something to process 1753*9edbd4a0SFrançois Tigeot * due to its back queue). */ 1754*9edbd4a0SFrançois Tigeot if (!HAS_PCH_NOP(dev)) { 1755*9edbd4a0SFrançois Tigeot sde_ier = I915_READ(SDEIER); 1756*9edbd4a0SFrançois Tigeot I915_WRITE(SDEIER, 0); 1757*9edbd4a0SFrançois Tigeot POSTING_READ(SDEIER); 1758*9edbd4a0SFrançois Tigeot } 1759*9edbd4a0SFrançois Tigeot 1760*9edbd4a0SFrançois Tigeot gt_iir = I915_READ(GTIIR); 1761*9edbd4a0SFrançois Tigeot if (gt_iir) { 1762*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 6) 1763*9edbd4a0SFrançois Tigeot snb_gt_irq_handler(dev, dev_priv, gt_iir); 1764*9edbd4a0SFrançois Tigeot else 1765*9edbd4a0SFrançois Tigeot ilk_gt_irq_handler(dev, dev_priv, gt_iir); 1766e3adcf8fSFrançois Tigeot I915_WRITE(GTIIR, gt_iir); 1767*9edbd4a0SFrançois Tigeot } 1768e3adcf8fSFrançois Tigeot 1769*9edbd4a0SFrançois Tigeot de_iir = I915_READ(DEIIR); 1770*9edbd4a0SFrançois Tigeot if (de_iir) { 1771*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 7) 1772*9edbd4a0SFrançois Tigeot ivb_display_irq_handler(dev, de_iir); 1773*9edbd4a0SFrançois Tigeot else 1774*9edbd4a0SFrançois Tigeot ilk_display_irq_handler(dev, de_iir); 1775*9edbd4a0SFrançois Tigeot I915_WRITE(DEIIR, de_iir); 1776*9edbd4a0SFrançois Tigeot } 1777*9edbd4a0SFrançois Tigeot 1778*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 6) { 1779*9edbd4a0SFrançois Tigeot u32 pm_iir = I915_READ(GEN6_PMIIR); 1780*9edbd4a0SFrançois Tigeot if (pm_iir) { 1781*9edbd4a0SFrançois Tigeot gen6_rps_irq_handler(dev_priv, pm_iir); 1782*9edbd4a0SFrançois Tigeot I915_WRITE(GEN6_PMIIR, pm_iir); 1783*9edbd4a0SFrançois Tigeot } 1784*9edbd4a0SFrançois Tigeot } 1785*9edbd4a0SFrançois Tigeot 1786e3adcf8fSFrançois Tigeot I915_WRITE(DEIER, de_ier); 1787e3adcf8fSFrançois Tigeot POSTING_READ(DEIER); 1788*9edbd4a0SFrançois Tigeot if (!HAS_PCH_NOP(dev)) { 1789a2fdbec6SFrançois Tigeot I915_WRITE(SDEIER, sde_ier); 1790a2fdbec6SFrançois Tigeot POSTING_READ(SDEIER); 1791e3adcf8fSFrançois Tigeot } 1792e3adcf8fSFrançois Tigeot 1793*9edbd4a0SFrançois Tigeot } 1794*9edbd4a0SFrançois Tigeot 1795*9edbd4a0SFrançois Tigeot static irqreturn_t gen8_irq_handler(void *arg) 1796*9edbd4a0SFrançois Tigeot { 1797*9edbd4a0SFrançois Tigeot struct drm_device *dev = arg; 1798*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1799*9edbd4a0SFrançois Tigeot u32 master_ctl; 1800*9edbd4a0SFrançois Tigeot uint32_t tmp = 0; 1801*9edbd4a0SFrançois Tigeot enum i915_pipe pipe; 1802*9edbd4a0SFrançois Tigeot 1803*9edbd4a0SFrançois Tigeot atomic_inc(&dev_priv->irq_received); 1804*9edbd4a0SFrançois Tigeot 1805*9edbd4a0SFrançois Tigeot master_ctl = I915_READ(GEN8_MASTER_IRQ); 1806*9edbd4a0SFrançois Tigeot master_ctl &= ~GEN8_MASTER_IRQ_CONTROL; 1807*9edbd4a0SFrançois Tigeot if (!master_ctl) 1808*9edbd4a0SFrançois Tigeot return; 1809*9edbd4a0SFrançois Tigeot 1810*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, 0); 1811*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_MASTER_IRQ); 1812*9edbd4a0SFrançois Tigeot 1813*9edbd4a0SFrançois Tigeot gen8_gt_irq_handler(dev, dev_priv, master_ctl); 1814*9edbd4a0SFrançois Tigeot 1815*9edbd4a0SFrançois Tigeot if (master_ctl & GEN8_DE_MISC_IRQ) { 1816*9edbd4a0SFrançois Tigeot tmp = I915_READ(GEN8_DE_MISC_IIR); 1817*9edbd4a0SFrançois Tigeot if (tmp & GEN8_DE_MISC_GSE) 1818*9edbd4a0SFrançois Tigeot intel_opregion_asle_intr(dev); 1819*9edbd4a0SFrançois Tigeot else if (tmp) 1820*9edbd4a0SFrançois Tigeot DRM_ERROR("Unexpected DE Misc interrupt\n"); 1821*9edbd4a0SFrançois Tigeot else 1822*9edbd4a0SFrançois Tigeot DRM_ERROR("The master control interrupt lied (DE MISC)!\n"); 1823*9edbd4a0SFrançois Tigeot 1824*9edbd4a0SFrançois Tigeot if (tmp) { 1825*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_DE_MISC_IIR, tmp); 1826*9edbd4a0SFrançois Tigeot } 1827*9edbd4a0SFrançois Tigeot } 1828*9edbd4a0SFrançois Tigeot 1829*9edbd4a0SFrançois Tigeot if (master_ctl & GEN8_DE_PORT_IRQ) { 1830*9edbd4a0SFrançois Tigeot tmp = I915_READ(GEN8_DE_PORT_IIR); 1831*9edbd4a0SFrançois Tigeot if (tmp & GEN8_AUX_CHANNEL_A) 1832*9edbd4a0SFrançois Tigeot dp_aux_irq_handler(dev); 1833*9edbd4a0SFrançois Tigeot else if (tmp) 1834*9edbd4a0SFrançois Tigeot DRM_ERROR("Unexpected DE Port interrupt\n"); 1835*9edbd4a0SFrançois Tigeot else 1836*9edbd4a0SFrançois Tigeot DRM_ERROR("The master control interrupt lied (DE PORT)!\n"); 1837*9edbd4a0SFrançois Tigeot 1838*9edbd4a0SFrançois Tigeot if (tmp) { 1839*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_DE_PORT_IIR, tmp); 1840*9edbd4a0SFrançois Tigeot } 1841*9edbd4a0SFrançois Tigeot } 1842*9edbd4a0SFrançois Tigeot 1843*9edbd4a0SFrançois Tigeot for_each_pipe(pipe) { 1844*9edbd4a0SFrançois Tigeot uint32_t pipe_iir; 1845*9edbd4a0SFrançois Tigeot 1846*9edbd4a0SFrançois Tigeot if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe))) 1847*9edbd4a0SFrançois Tigeot continue; 1848*9edbd4a0SFrançois Tigeot 1849*9edbd4a0SFrançois Tigeot pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe)); 1850*9edbd4a0SFrançois Tigeot if (pipe_iir & GEN8_PIPE_VBLANK) 1851*9edbd4a0SFrançois Tigeot drm_handle_vblank(dev, pipe); 1852*9edbd4a0SFrançois Tigeot 1853*9edbd4a0SFrançois Tigeot if (pipe_iir & GEN8_PIPE_FLIP_DONE) { 1854*9edbd4a0SFrançois Tigeot intel_prepare_page_flip(dev, pipe); 1855*9edbd4a0SFrançois Tigeot intel_finish_page_flip_plane(dev, pipe); 1856*9edbd4a0SFrançois Tigeot } 1857*9edbd4a0SFrançois Tigeot 1858*9edbd4a0SFrançois Tigeot if (pipe_iir & GEN8_PIPE_CDCLK_CRC_DONE) 1859*9edbd4a0SFrançois Tigeot hsw_pipe_crc_irq_handler(dev, pipe); 1860*9edbd4a0SFrançois Tigeot 1861*9edbd4a0SFrançois Tigeot if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) { 1862*9edbd4a0SFrançois Tigeot if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, 1863*9edbd4a0SFrançois Tigeot false)) 1864*9edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n", 1865*9edbd4a0SFrançois Tigeot pipe_name(pipe)); 1866*9edbd4a0SFrançois Tigeot } 1867*9edbd4a0SFrançois Tigeot 1868*9edbd4a0SFrançois Tigeot if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) { 1869*9edbd4a0SFrançois Tigeot DRM_ERROR("Fault errors on pipe %c\n: 0x%08x", 1870*9edbd4a0SFrançois Tigeot pipe_name(pipe), 1871*9edbd4a0SFrançois Tigeot pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS); 1872*9edbd4a0SFrançois Tigeot } 1873*9edbd4a0SFrançois Tigeot 1874*9edbd4a0SFrançois Tigeot if (pipe_iir) { 1875*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir); 1876*9edbd4a0SFrançois Tigeot } else 1877*9edbd4a0SFrançois Tigeot DRM_ERROR("The master control interrupt lied (DE PIPE)!\n"); 1878*9edbd4a0SFrançois Tigeot } 1879*9edbd4a0SFrançois Tigeot 1880*9edbd4a0SFrançois Tigeot if (!HAS_PCH_NOP(dev) && master_ctl & GEN8_DE_PCH_IRQ) { 1881*9edbd4a0SFrançois Tigeot /* 1882*9edbd4a0SFrançois Tigeot * FIXME(BDW): Assume for now that the new interrupt handling 1883*9edbd4a0SFrançois Tigeot * scheme also closed the SDE interrupt handling race we've seen 1884*9edbd4a0SFrançois Tigeot * on older pch-split platforms. But this needs testing. 1885*9edbd4a0SFrançois Tigeot */ 1886*9edbd4a0SFrançois Tigeot u32 pch_iir = I915_READ(SDEIIR); 1887*9edbd4a0SFrançois Tigeot 1888*9edbd4a0SFrançois Tigeot cpt_irq_handler(dev, pch_iir); 1889*9edbd4a0SFrançois Tigeot 1890*9edbd4a0SFrançois Tigeot if (pch_iir) { 1891*9edbd4a0SFrançois Tigeot I915_WRITE(SDEIIR, pch_iir); 1892*9edbd4a0SFrançois Tigeot } 1893*9edbd4a0SFrançois Tigeot } 1894*9edbd4a0SFrançois Tigeot 1895*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); 1896*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_MASTER_IRQ); 1897*9edbd4a0SFrançois Tigeot 1898*9edbd4a0SFrançois Tigeot } 1899*9edbd4a0SFrançois Tigeot 1900*9edbd4a0SFrançois Tigeot static void i915_error_wake_up(struct drm_i915_private *dev_priv, 1901*9edbd4a0SFrançois Tigeot bool reset_completed) 1902*9edbd4a0SFrançois Tigeot { 1903*9edbd4a0SFrançois Tigeot struct intel_ring_buffer *ring; 1904*9edbd4a0SFrançois Tigeot int i; 1905*9edbd4a0SFrançois Tigeot 1906*9edbd4a0SFrançois Tigeot /* 1907*9edbd4a0SFrançois Tigeot * Notify all waiters for GPU completion events that reset state has 1908*9edbd4a0SFrançois Tigeot * been changed, and that they need to restart their wait after 1909*9edbd4a0SFrançois Tigeot * checking for potential errors (and bail out to drop locks if there is 1910*9edbd4a0SFrançois Tigeot * a gpu reset pending so that i915_error_work_func can acquire them). 1911*9edbd4a0SFrançois Tigeot */ 1912*9edbd4a0SFrançois Tigeot 1913*9edbd4a0SFrançois Tigeot /* Wake up __wait_seqno, potentially holding dev->struct_mutex. */ 1914*9edbd4a0SFrançois Tigeot for_each_ring(ring, dev_priv, i) 1915*9edbd4a0SFrançois Tigeot wake_up_all(&ring->irq_queue); 1916*9edbd4a0SFrançois Tigeot 1917*9edbd4a0SFrançois Tigeot /* Wake up intel_crtc_wait_for_pending_flips, holding crtc->mutex. */ 1918*9edbd4a0SFrançois Tigeot wake_up_all(&dev_priv->pending_flip_queue); 1919*9edbd4a0SFrançois Tigeot 1920*9edbd4a0SFrançois Tigeot /* 1921*9edbd4a0SFrançois Tigeot * Signal tasks blocked in i915_gem_wait_for_error that the pending 1922*9edbd4a0SFrançois Tigeot * reset state is cleared. 1923*9edbd4a0SFrançois Tigeot */ 1924*9edbd4a0SFrançois Tigeot if (reset_completed) 1925*9edbd4a0SFrançois Tigeot wake_up_all(&dev_priv->gpu_error.reset_queue); 1926*9edbd4a0SFrançois Tigeot } 1927*9edbd4a0SFrançois Tigeot 1928e3adcf8fSFrançois Tigeot /** 1929e3adcf8fSFrançois Tigeot * i915_error_work_func - do process context error handling work 1930e3adcf8fSFrançois Tigeot * @work: work struct 1931e3adcf8fSFrançois Tigeot * 1932e3adcf8fSFrançois Tigeot * Fire an error uevent so userspace can see that a hang or error 1933e3adcf8fSFrançois Tigeot * was detected. 1934e3adcf8fSFrançois Tigeot */ 1935abf1f4f4SFrançois Tigeot static void i915_error_work_func(struct work_struct *work) 1936e3adcf8fSFrançois Tigeot { 1937a2fdbec6SFrançois Tigeot struct i915_gpu_error *error = container_of(work, struct i915_gpu_error, 1938a2fdbec6SFrançois Tigeot work); 1939a2fdbec6SFrançois Tigeot drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t, 1940a2fdbec6SFrançois Tigeot gpu_error); 1941e3adcf8fSFrançois Tigeot struct drm_device *dev = dev_priv->dev; 1942a2fdbec6SFrançois Tigeot #if 0 1943*9edbd4a0SFrançois Tigeot char *error_event[] = { I915_ERROR_UEVENT "=1", NULL }; 1944*9edbd4a0SFrançois Tigeot char *reset_event[] = { I915_RESET_UEVENT "=1", NULL }; 1945*9edbd4a0SFrançois Tigeot char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL }; 1946a2fdbec6SFrançois Tigeot #endif 1947*9edbd4a0SFrançois Tigeot int ret; 1948e3adcf8fSFrançois Tigeot 1949*9edbd4a0SFrançois Tigeot /* kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, error_event); */ 1950e3adcf8fSFrançois Tigeot 1951a2fdbec6SFrançois Tigeot /* 1952a2fdbec6SFrançois Tigeot * Note that there's only one work item which does gpu resets, so we 1953a2fdbec6SFrançois Tigeot * need not worry about concurrent gpu resets potentially incrementing 1954a2fdbec6SFrançois Tigeot * error->reset_counter twice. We only need to take care of another 1955a2fdbec6SFrançois Tigeot * racing irq/hangcheck declaring the gpu dead for a second time. A 1956a2fdbec6SFrançois Tigeot * quick check for that is good enough: schedule_work ensures the 1957a2fdbec6SFrançois Tigeot * correct ordering between hang detection and this work item, and since 1958a2fdbec6SFrançois Tigeot * the reset in-progress bit is only ever set by code outside of this 1959a2fdbec6SFrançois Tigeot * work we don't need to worry about any other races. 1960a2fdbec6SFrançois Tigeot */ 1961a2fdbec6SFrançois Tigeot if (i915_reset_in_progress(error) && !i915_terminally_wedged(error)) { 1962abf1f4f4SFrançois Tigeot DRM_DEBUG_DRIVER("resetting chip\n"); 1963a2fdbec6SFrançois Tigeot #if 0 1964*9edbd4a0SFrançois Tigeot kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, 1965a2fdbec6SFrançois Tigeot reset_event); 1966a2fdbec6SFrançois Tigeot #endif 1967a2fdbec6SFrançois Tigeot 1968*9edbd4a0SFrançois Tigeot /* 1969*9edbd4a0SFrançois Tigeot * All state reset _must_ be completed before we update the 1970*9edbd4a0SFrançois Tigeot * reset counter, for otherwise waiters might miss the reset 1971*9edbd4a0SFrançois Tigeot * pending state and not properly drop locks, resulting in 1972*9edbd4a0SFrançois Tigeot * deadlocks with the reset work. 1973*9edbd4a0SFrançois Tigeot */ 1974a2fdbec6SFrançois Tigeot ret = i915_reset(dev); 1975a2fdbec6SFrançois Tigeot 1976*9edbd4a0SFrançois Tigeot intel_display_handle_reset(dev); 1977*9edbd4a0SFrançois Tigeot 1978a2fdbec6SFrançois Tigeot if (ret == 0) { 1979a2fdbec6SFrançois Tigeot /* 1980a2fdbec6SFrançois Tigeot * After all the gem state is reset, increment the reset 1981a2fdbec6SFrançois Tigeot * counter and wake up everyone waiting for the reset to 1982a2fdbec6SFrançois Tigeot * complete. 1983a2fdbec6SFrançois Tigeot * 1984a2fdbec6SFrançois Tigeot * Since unlock operations are a one-sided barrier only, 1985a2fdbec6SFrançois Tigeot * we need to insert a barrier here to order any seqno 1986a2fdbec6SFrançois Tigeot * updates before 1987a2fdbec6SFrançois Tigeot * the counter increment. 1988a2fdbec6SFrançois Tigeot */ 1989a2fdbec6SFrançois Tigeot cpu_sfence(); 1990a2fdbec6SFrançois Tigeot atomic_inc(&dev_priv->gpu_error.reset_counter); 1991a2fdbec6SFrançois Tigeot 1992a2fdbec6SFrançois Tigeot #if 0 1993*9edbd4a0SFrançois Tigeot kobject_uevent_env(&dev->primary->kdev->kobj, 1994a2fdbec6SFrançois Tigeot KOBJ_CHANGE, reset_done_event); 1995a2fdbec6SFrançois Tigeot #endif 1996a2fdbec6SFrançois Tigeot } else { 1997*9edbd4a0SFrançois Tigeot atomic_set_mask(I915_WEDGED, &error->reset_counter); 1998e3adcf8fSFrançois Tigeot } 1999a2fdbec6SFrançois Tigeot 2000*9edbd4a0SFrançois Tigeot /* 2001*9edbd4a0SFrançois Tigeot * Note: The wake_up also serves as a memory barrier so that 2002*9edbd4a0SFrançois Tigeot * waiters see the update value of the reset counter atomic_t. 2003e3adcf8fSFrançois Tigeot */ 2004*9edbd4a0SFrançois Tigeot i915_error_wake_up(dev_priv, true); 2005e3adcf8fSFrançois Tigeot } 2006e3adcf8fSFrançois Tigeot } 2007e3adcf8fSFrançois Tigeot 2008e9243325SFrançois Tigeot static void i915_report_and_clear_eir(struct drm_device *dev) 2009e9243325SFrançois Tigeot { 2010e9243325SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 201100640ec9SFrançois Tigeot uint32_t instdone[I915_NUM_INSTDONE_REG]; 2012e9243325SFrançois Tigeot u32 eir = I915_READ(EIR); 201300640ec9SFrançois Tigeot int pipe, i; 2014e9243325SFrançois Tigeot 2015e9243325SFrançois Tigeot if (!eir) 2016e9243325SFrançois Tigeot return; 2017e9243325SFrançois Tigeot 201800640ec9SFrançois Tigeot pr_err("render error detected, EIR: 0x%08x\n", eir); 201900640ec9SFrançois Tigeot 2020*9edbd4a0SFrançois Tigeot #if 0 202100640ec9SFrançois Tigeot i915_get_extra_instdone(dev, instdone); 2022*9edbd4a0SFrançois Tigeot #endif 2023e9243325SFrançois Tigeot 2024e9243325SFrançois Tigeot if (IS_G4X(dev)) { 2025e9243325SFrançois Tigeot if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) { 2026e9243325SFrançois Tigeot u32 ipeir = I915_READ(IPEIR_I965); 2027e9243325SFrançois Tigeot 202800640ec9SFrançois Tigeot pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR_I965)); 202900640ec9SFrançois Tigeot pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR_I965)); 203000640ec9SFrançois Tigeot for (i = 0; i < ARRAY_SIZE(instdone); i++) 203100640ec9SFrançois Tigeot pr_err(" INSTDONE_%d: 0x%08x\n", i, instdone[i]); 203200640ec9SFrançois Tigeot pr_err(" INSTPS: 0x%08x\n", I915_READ(INSTPS)); 203300640ec9SFrançois Tigeot pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD_I965)); 2034e9243325SFrançois Tigeot I915_WRITE(IPEIR_I965, ipeir); 2035e9243325SFrançois Tigeot POSTING_READ(IPEIR_I965); 2036e9243325SFrançois Tigeot } 2037e9243325SFrançois Tigeot if (eir & GM45_ERROR_PAGE_TABLE) { 2038e9243325SFrançois Tigeot u32 pgtbl_err = I915_READ(PGTBL_ER); 203900640ec9SFrançois Tigeot pr_err("page table error\n"); 204000640ec9SFrançois Tigeot pr_err(" PGTBL_ER: 0x%08x\n", pgtbl_err); 2041e9243325SFrançois Tigeot I915_WRITE(PGTBL_ER, pgtbl_err); 2042e9243325SFrançois Tigeot POSTING_READ(PGTBL_ER); 2043e9243325SFrançois Tigeot } 2044e9243325SFrançois Tigeot } 2045e9243325SFrançois Tigeot 2046e9243325SFrançois Tigeot if (!IS_GEN2(dev)) { 2047e9243325SFrançois Tigeot if (eir & I915_ERROR_PAGE_TABLE) { 2048e9243325SFrançois Tigeot u32 pgtbl_err = I915_READ(PGTBL_ER); 204900640ec9SFrançois Tigeot pr_err("page table error\n"); 205000640ec9SFrançois Tigeot pr_err(" PGTBL_ER: 0x%08x\n", pgtbl_err); 2051e9243325SFrançois Tigeot I915_WRITE(PGTBL_ER, pgtbl_err); 2052e9243325SFrançois Tigeot POSTING_READ(PGTBL_ER); 2053e9243325SFrançois Tigeot } 2054e9243325SFrançois Tigeot } 2055e9243325SFrançois Tigeot 2056e9243325SFrançois Tigeot if (eir & I915_ERROR_MEMORY_REFRESH) { 205700640ec9SFrançois Tigeot pr_err("memory refresh error:\n"); 2058e9243325SFrançois Tigeot for_each_pipe(pipe) 205900640ec9SFrançois Tigeot pr_err("pipe %c stat: 0x%08x\n", 2060e9243325SFrançois Tigeot pipe_name(pipe), I915_READ(PIPESTAT(pipe))); 2061e9243325SFrançois Tigeot /* pipestat has already been acked */ 2062e9243325SFrançois Tigeot } 2063e9243325SFrançois Tigeot if (eir & I915_ERROR_INSTRUCTION) { 206400640ec9SFrançois Tigeot pr_err("instruction error\n"); 206500640ec9SFrançois Tigeot pr_err(" INSTPM: 0x%08x\n", I915_READ(INSTPM)); 206600640ec9SFrançois Tigeot for (i = 0; i < ARRAY_SIZE(instdone); i++) 206700640ec9SFrançois Tigeot pr_err(" INSTDONE_%d: 0x%08x\n", i, instdone[i]); 2068e9243325SFrançois Tigeot if (INTEL_INFO(dev)->gen < 4) { 2069e9243325SFrançois Tigeot u32 ipeir = I915_READ(IPEIR); 2070e9243325SFrançois Tigeot 207100640ec9SFrançois Tigeot pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR)); 207200640ec9SFrançois Tigeot pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR)); 207300640ec9SFrançois Tigeot pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD)); 2074e9243325SFrançois Tigeot I915_WRITE(IPEIR, ipeir); 2075e9243325SFrançois Tigeot POSTING_READ(IPEIR); 2076e9243325SFrançois Tigeot } else { 2077e9243325SFrançois Tigeot u32 ipeir = I915_READ(IPEIR_I965); 2078e9243325SFrançois Tigeot 207900640ec9SFrançois Tigeot pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR_I965)); 208000640ec9SFrançois Tigeot pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR_I965)); 208100640ec9SFrançois Tigeot pr_err(" INSTPS: 0x%08x\n", I915_READ(INSTPS)); 208200640ec9SFrançois Tigeot pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD_I965)); 2083e9243325SFrançois Tigeot I915_WRITE(IPEIR_I965, ipeir); 2084e9243325SFrançois Tigeot POSTING_READ(IPEIR_I965); 2085e9243325SFrançois Tigeot } 2086e9243325SFrançois Tigeot } 2087e9243325SFrançois Tigeot 2088e9243325SFrançois Tigeot I915_WRITE(EIR, eir); 2089e9243325SFrançois Tigeot POSTING_READ(EIR); 2090e9243325SFrançois Tigeot eir = I915_READ(EIR); 2091e9243325SFrançois Tigeot if (eir) { 2092e9243325SFrançois Tigeot /* 2093e9243325SFrançois Tigeot * some errors might have become stuck, 2094e9243325SFrançois Tigeot * mask them. 2095e9243325SFrançois Tigeot */ 2096e9243325SFrançois Tigeot DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir); 2097e9243325SFrançois Tigeot I915_WRITE(EMR, I915_READ(EMR) | eir); 2098e9243325SFrançois Tigeot I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 2099e9243325SFrançois Tigeot } 2100e9243325SFrançois Tigeot } 2101e9243325SFrançois Tigeot 2102e9243325SFrançois Tigeot /** 2103e9243325SFrançois Tigeot * i915_handle_error - handle an error interrupt 2104e9243325SFrançois Tigeot * @dev: drm device 2105e9243325SFrançois Tigeot * 2106e9243325SFrançois Tigeot * Do some basic checking of regsiter state at error interrupt time and 2107e9243325SFrançois Tigeot * dump it to the syslog. Also call i915_capture_error_state() to make 2108e9243325SFrançois Tigeot * sure we get a record and make it available in debugfs. Fire a uevent 2109e9243325SFrançois Tigeot * so userspace knows something bad happened (should trigger collection 2110e9243325SFrançois Tigeot * of a ring dump etc.). 2111e9243325SFrançois Tigeot */ 2112e9243325SFrançois Tigeot void i915_handle_error(struct drm_device *dev, bool wedged) 2113e9243325SFrançois Tigeot { 2114e9243325SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2115e9243325SFrançois Tigeot 2116*9edbd4a0SFrançois Tigeot #if 0 2117e9243325SFrançois Tigeot i915_capture_error_state(dev); 2118*9edbd4a0SFrançois Tigeot #endif 2119e9243325SFrançois Tigeot i915_report_and_clear_eir(dev); 2120e9243325SFrançois Tigeot 2121e9243325SFrançois Tigeot if (wedged) { 2122a2fdbec6SFrançois Tigeot atomic_set_mask(I915_RESET_IN_PROGRESS_FLAG, 2123a2fdbec6SFrançois Tigeot &dev_priv->gpu_error.reset_counter); 2124e9243325SFrançois Tigeot 2125e9243325SFrançois Tigeot /* 2126*9edbd4a0SFrançois Tigeot * Wakeup waiting processes so that the reset work function 2127*9edbd4a0SFrançois Tigeot * i915_error_work_func doesn't deadlock trying to grab various 2128*9edbd4a0SFrançois Tigeot * locks. By bumping the reset counter first, the woken 2129*9edbd4a0SFrançois Tigeot * processes will see a reset in progress and back off, 2130*9edbd4a0SFrançois Tigeot * releasing their locks and then wait for the reset completion. 2131*9edbd4a0SFrançois Tigeot * We must do this for _all_ gpu waiters that might hold locks 2132*9edbd4a0SFrançois Tigeot * that the reset work needs to acquire. 2133*9edbd4a0SFrançois Tigeot * 2134*9edbd4a0SFrançois Tigeot * Note: The wake_up serves as the required memory barrier to 2135*9edbd4a0SFrançois Tigeot * ensure that the waiters see the updated value of the reset 2136*9edbd4a0SFrançois Tigeot * counter atomic_t. 2137e9243325SFrançois Tigeot */ 2138*9edbd4a0SFrançois Tigeot i915_error_wake_up(dev_priv, false); 2139e9243325SFrançois Tigeot } 2140e9243325SFrançois Tigeot 2141*9edbd4a0SFrançois Tigeot /* 2142*9edbd4a0SFrançois Tigeot * Our reset work can grab modeset locks (since it needs to reset the 2143*9edbd4a0SFrançois Tigeot * state of outstanding pagelips). Hence it must not be run on our own 2144*9edbd4a0SFrançois Tigeot * dev-priv->wq work queue for otherwise the flush_work in the pageflip 2145*9edbd4a0SFrançois Tigeot * code will deadlock. 2146*9edbd4a0SFrançois Tigeot */ 2147*9edbd4a0SFrançois Tigeot schedule_work(&dev_priv->gpu_error.work); 2148e9243325SFrançois Tigeot } 2149e9243325SFrançois Tigeot 21508e26cdf6SFrançois Tigeot static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe) 2151e9243325SFrançois Tigeot { 2152e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 2153e9243325SFrançois Tigeot struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; 2154e9243325SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 2155e9243325SFrançois Tigeot struct drm_i915_gem_object *obj; 2156e9243325SFrançois Tigeot struct intel_unpin_work *work; 2157e9243325SFrançois Tigeot bool stall_detected; 2158e9243325SFrançois Tigeot 2159e9243325SFrançois Tigeot /* Ignore early vblank irqs */ 2160e9243325SFrançois Tigeot if (intel_crtc == NULL) 2161e9243325SFrançois Tigeot return; 2162e9243325SFrançois Tigeot 2163e9243325SFrançois Tigeot lockmgr(&dev->event_lock, LK_EXCLUSIVE); 2164e9243325SFrançois Tigeot work = intel_crtc->unpin_work; 2165e9243325SFrançois Tigeot 216600640ec9SFrançois Tigeot if (work == NULL || 216700640ec9SFrançois Tigeot atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE || 2168e9243325SFrançois Tigeot !work->enable_stall_check) { 2169e9243325SFrançois Tigeot /* Either the pending flip IRQ arrived, or we're too early. Don't check */ 2170e9243325SFrançois Tigeot lockmgr(&dev->event_lock, LK_RELEASE); 2171e9243325SFrançois Tigeot return; 2172e9243325SFrançois Tigeot } 2173e9243325SFrançois Tigeot 2174e9243325SFrançois Tigeot /* Potential stall - if we see that the flip has happened, assume a missed interrupt */ 2175e9243325SFrançois Tigeot obj = work->pending_flip_obj; 2176e9243325SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 4) { 2177e9243325SFrançois Tigeot int dspsurf = DSPSURF(intel_crtc->plane); 217800640ec9SFrançois Tigeot stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) == 2179*9edbd4a0SFrançois Tigeot i915_gem_obj_ggtt_offset(obj); 2180e9243325SFrançois Tigeot } else { 2181e9243325SFrançois Tigeot int dspaddr = DSPADDR(intel_crtc->plane); 2182*9edbd4a0SFrançois Tigeot stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) + 2183e9243325SFrançois Tigeot crtc->y * crtc->fb->pitches[0] + 2184e9243325SFrançois Tigeot crtc->x * crtc->fb->bits_per_pixel/8); 2185e9243325SFrançois Tigeot } 2186e9243325SFrançois Tigeot 2187e9243325SFrançois Tigeot lockmgr(&dev->event_lock, LK_RELEASE); 2188e9243325SFrançois Tigeot 2189e9243325SFrançois Tigeot if (stall_detected) { 219000640ec9SFrançois Tigeot DRM_DEBUG_DRIVER("Pageflip stall detected\n"); 2191e9243325SFrançois Tigeot intel_prepare_page_flip(dev, intel_crtc->plane); 2192e9243325SFrançois Tigeot } 2193e9243325SFrançois Tigeot } 2194e9243325SFrançois Tigeot 2195e9243325SFrançois Tigeot /* Called from drm generic code, passed 'crtc' which 2196e9243325SFrançois Tigeot * we use as a pipe index 2197e9243325SFrançois Tigeot */ 219800640ec9SFrançois Tigeot static int i915_enable_vblank(struct drm_device *dev, int pipe) 2199e9243325SFrançois Tigeot { 2200e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2201e9243325SFrançois Tigeot 2202e9243325SFrançois Tigeot if (!i915_pipe_enabled(dev, pipe)) 2203e9243325SFrançois Tigeot return -EINVAL; 2204e9243325SFrançois Tigeot 2205e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 2206e9243325SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 4) 2207e9243325SFrançois Tigeot i915_enable_pipestat(dev_priv, pipe, 2208e9243325SFrançois Tigeot PIPE_START_VBLANK_INTERRUPT_ENABLE); 2209e9243325SFrançois Tigeot else 2210e9243325SFrançois Tigeot i915_enable_pipestat(dev_priv, pipe, 2211e9243325SFrançois Tigeot PIPE_VBLANK_INTERRUPT_ENABLE); 2212e9243325SFrançois Tigeot 2213e9243325SFrançois Tigeot /* maintain vblank delivery even in deep C-states */ 2214e9243325SFrançois Tigeot if (dev_priv->info->gen == 3) 221500640ec9SFrançois Tigeot I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_AGPBUSY_DIS)); 2216e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 2217e9243325SFrançois Tigeot 2218e9243325SFrançois Tigeot return 0; 2219e9243325SFrançois Tigeot } 2220e9243325SFrançois Tigeot 222100640ec9SFrançois Tigeot static int ironlake_enable_vblank(struct drm_device *dev, int pipe) 2222e9243325SFrançois Tigeot { 2223e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2224*9edbd4a0SFrançois Tigeot uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) : 2225*9edbd4a0SFrançois Tigeot DE_PIPE_VBLANK(pipe); 2226e9243325SFrançois Tigeot 2227e9243325SFrançois Tigeot if (!i915_pipe_enabled(dev, pipe)) 2228e9243325SFrançois Tigeot return -EINVAL; 2229e9243325SFrançois Tigeot 2230e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 2231*9edbd4a0SFrançois Tigeot ironlake_enable_display_irq(dev_priv, bit); 2232e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 2233e9243325SFrançois Tigeot 2234e9243325SFrançois Tigeot return 0; 2235e9243325SFrançois Tigeot } 2236e9243325SFrançois Tigeot 2237e9243325SFrançois Tigeot static int valleyview_enable_vblank(struct drm_device *dev, int pipe) 2238e9243325SFrançois Tigeot { 2239e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2240e9243325SFrançois Tigeot u32 imr; 2241e9243325SFrançois Tigeot 2242e9243325SFrançois Tigeot if (!i915_pipe_enabled(dev, pipe)) 2243e9243325SFrançois Tigeot return -EINVAL; 2244e9243325SFrançois Tigeot 2245e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 2246e9243325SFrançois Tigeot imr = I915_READ(VLV_IMR); 2247*9edbd4a0SFrançois Tigeot if (pipe == PIPE_A) 2248e9243325SFrançois Tigeot imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; 2249e9243325SFrançois Tigeot else 2250e9243325SFrançois Tigeot imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; 2251e9243325SFrançois Tigeot I915_WRITE(VLV_IMR, imr); 2252e9243325SFrançois Tigeot i915_enable_pipestat(dev_priv, pipe, 2253e9243325SFrançois Tigeot PIPE_START_VBLANK_INTERRUPT_ENABLE); 2254e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 2255e9243325SFrançois Tigeot 2256e9243325SFrançois Tigeot return 0; 2257e9243325SFrançois Tigeot } 2258e9243325SFrançois Tigeot 2259*9edbd4a0SFrançois Tigeot static int gen8_enable_vblank(struct drm_device *dev, int pipe) 2260*9edbd4a0SFrançois Tigeot { 2261*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2262*9edbd4a0SFrançois Tigeot 2263*9edbd4a0SFrançois Tigeot if (!i915_pipe_enabled(dev, pipe)) 2264*9edbd4a0SFrançois Tigeot return -EINVAL; 2265*9edbd4a0SFrançois Tigeot 2266*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 2267*9edbd4a0SFrançois Tigeot dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_VBLANK; 2268*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); 2269*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); 2270*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 2271*9edbd4a0SFrançois Tigeot return 0; 2272*9edbd4a0SFrançois Tigeot } 2273*9edbd4a0SFrançois Tigeot 2274e9243325SFrançois Tigeot /* Called from drm generic code, passed 'crtc' which 2275e9243325SFrançois Tigeot * we use as a pipe index 2276e9243325SFrançois Tigeot */ 227700640ec9SFrançois Tigeot static void i915_disable_vblank(struct drm_device *dev, int pipe) 2278e9243325SFrançois Tigeot { 2279e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2280e9243325SFrançois Tigeot 2281e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 2282e9243325SFrançois Tigeot if (dev_priv->info->gen == 3) 228300640ec9SFrançois Tigeot I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_DIS)); 2284e9243325SFrançois Tigeot 2285e9243325SFrançois Tigeot i915_disable_pipestat(dev_priv, pipe, 2286e9243325SFrançois Tigeot PIPE_VBLANK_INTERRUPT_ENABLE | 2287e9243325SFrançois Tigeot PIPE_START_VBLANK_INTERRUPT_ENABLE); 2288e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 2289e9243325SFrançois Tigeot } 2290e9243325SFrançois Tigeot 229100640ec9SFrançois Tigeot static void ironlake_disable_vblank(struct drm_device *dev, int pipe) 2292e9243325SFrançois Tigeot { 2293e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2294*9edbd4a0SFrançois Tigeot uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) : 2295*9edbd4a0SFrançois Tigeot DE_PIPE_VBLANK(pipe); 2296e9243325SFrançois Tigeot 2297e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 2298*9edbd4a0SFrançois Tigeot ironlake_disable_display_irq(dev_priv, bit); 2299e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 2300e9243325SFrançois Tigeot } 2301e9243325SFrançois Tigeot 2302e9243325SFrançois Tigeot static void valleyview_disable_vblank(struct drm_device *dev, int pipe) 2303e9243325SFrançois Tigeot { 2304e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2305e9243325SFrançois Tigeot u32 imr; 2306e9243325SFrançois Tigeot 2307e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 2308e9243325SFrançois Tigeot i915_disable_pipestat(dev_priv, pipe, 2309e9243325SFrançois Tigeot PIPE_START_VBLANK_INTERRUPT_ENABLE); 2310e9243325SFrançois Tigeot imr = I915_READ(VLV_IMR); 2311*9edbd4a0SFrançois Tigeot if (pipe == PIPE_A) 2312e9243325SFrançois Tigeot imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; 2313e9243325SFrançois Tigeot else 2314e9243325SFrançois Tigeot imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; 2315e9243325SFrançois Tigeot I915_WRITE(VLV_IMR, imr); 2316e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 2317e9243325SFrançois Tigeot } 2318e9243325SFrançois Tigeot 2319*9edbd4a0SFrançois Tigeot static void gen8_disable_vblank(struct drm_device *dev, int pipe) 2320*9edbd4a0SFrançois Tigeot { 2321*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2322*9edbd4a0SFrançois Tigeot 2323*9edbd4a0SFrançois Tigeot if (!i915_pipe_enabled(dev, pipe)) 2324*9edbd4a0SFrançois Tigeot return; 2325*9edbd4a0SFrançois Tigeot 2326*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 2327*9edbd4a0SFrançois Tigeot dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_VBLANK; 2328*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); 2329*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); 2330*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 2331*9edbd4a0SFrançois Tigeot } 2332*9edbd4a0SFrançois Tigeot 2333e9243325SFrançois Tigeot static u32 2334e9243325SFrançois Tigeot ring_last_seqno(struct intel_ring_buffer *ring) 2335e9243325SFrançois Tigeot { 233600640ec9SFrançois Tigeot return list_entry(ring->request_list.prev, 233700640ec9SFrançois Tigeot struct drm_i915_gem_request, list)->seqno; 2338e9243325SFrançois Tigeot } 2339e9243325SFrançois Tigeot 23405d0b1887SFrançois Tigeot static bool 23415d0b1887SFrançois Tigeot ring_idle(struct intel_ring_buffer *ring, u32 seqno) 2342e9243325SFrançois Tigeot { 23435d0b1887SFrançois Tigeot return (list_empty(&ring->request_list) || 23445d0b1887SFrançois Tigeot i915_seqno_passed(seqno, ring_last_seqno(ring))); 2345e9243325SFrançois Tigeot } 2346e9243325SFrançois Tigeot 23475d0b1887SFrançois Tigeot static struct intel_ring_buffer * 23485d0b1887SFrançois Tigeot semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno) 23498e26cdf6SFrançois Tigeot { 23508e26cdf6SFrançois Tigeot struct drm_i915_private *dev_priv = ring->dev->dev_private; 23515d0b1887SFrançois Tigeot u32 cmd, ipehr, acthd, acthd_min; 23528e26cdf6SFrançois Tigeot 23538e26cdf6SFrançois Tigeot ipehr = I915_READ(RING_IPEHR(ring->mmio_base)); 23548e26cdf6SFrançois Tigeot if ((ipehr & ~(0x3 << 16)) != 23558e26cdf6SFrançois Tigeot (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER)) 23565d0b1887SFrançois Tigeot return NULL; 23578e26cdf6SFrançois Tigeot 23588e26cdf6SFrançois Tigeot /* ACTHD is likely pointing to the dword after the actual command, 23598e26cdf6SFrançois Tigeot * so scan backwards until we find the MBOX. 23608e26cdf6SFrançois Tigeot */ 23615d0b1887SFrançois Tigeot acthd = intel_ring_get_active_head(ring) & HEAD_ADDR; 23628e26cdf6SFrançois Tigeot acthd_min = max((int)acthd - 3 * 4, 0); 23638e26cdf6SFrançois Tigeot do { 23648e26cdf6SFrançois Tigeot cmd = ioread32(ring->virtual_start + acthd); 23658e26cdf6SFrançois Tigeot if (cmd == ipehr) 23668e26cdf6SFrançois Tigeot break; 23678e26cdf6SFrançois Tigeot 23688e26cdf6SFrançois Tigeot acthd -= 4; 23698e26cdf6SFrançois Tigeot if (acthd < acthd_min) 23705d0b1887SFrançois Tigeot return NULL; 23718e26cdf6SFrançois Tigeot } while (1); 23728e26cdf6SFrançois Tigeot 23735d0b1887SFrançois Tigeot *seqno = ioread32(ring->virtual_start+acthd+4)+1; 23745d0b1887SFrançois Tigeot return &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3]; 23758e26cdf6SFrançois Tigeot } 23768e26cdf6SFrançois Tigeot 23775d0b1887SFrançois Tigeot static int semaphore_passed(struct intel_ring_buffer *ring) 23785d0b1887SFrançois Tigeot { 23795d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = ring->dev->dev_private; 23805d0b1887SFrançois Tigeot struct intel_ring_buffer *signaller; 23815d0b1887SFrançois Tigeot u32 seqno, ctl; 23825d0b1887SFrançois Tigeot 23835d0b1887SFrançois Tigeot ring->hangcheck.deadlock = true; 23845d0b1887SFrançois Tigeot 23855d0b1887SFrançois Tigeot signaller = semaphore_waits_for(ring, &seqno); 23865d0b1887SFrançois Tigeot if (signaller == NULL || signaller->hangcheck.deadlock) 23875d0b1887SFrançois Tigeot return -1; 23885d0b1887SFrançois Tigeot 23895d0b1887SFrançois Tigeot /* cursory check for an unkickable deadlock */ 23905d0b1887SFrançois Tigeot ctl = I915_READ_CTL(signaller); 23915d0b1887SFrançois Tigeot if (ctl & RING_WAIT_SEMAPHORE && semaphore_passed(signaller) < 0) 23925d0b1887SFrançois Tigeot return -1; 23935d0b1887SFrançois Tigeot 23945d0b1887SFrançois Tigeot return i915_seqno_passed(signaller->get_seqno(signaller, false), seqno); 23955d0b1887SFrançois Tigeot } 23965d0b1887SFrançois Tigeot 23975d0b1887SFrançois Tigeot static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv) 23985d0b1887SFrançois Tigeot { 23995d0b1887SFrançois Tigeot struct intel_ring_buffer *ring; 24005d0b1887SFrançois Tigeot int i; 24015d0b1887SFrançois Tigeot 24025d0b1887SFrançois Tigeot for_each_ring(ring, dev_priv, i) 24035d0b1887SFrançois Tigeot ring->hangcheck.deadlock = false; 24045d0b1887SFrançois Tigeot } 24055d0b1887SFrançois Tigeot 24065d0b1887SFrançois Tigeot static enum intel_ring_hangcheck_action 24075d0b1887SFrançois Tigeot ring_stuck(struct intel_ring_buffer *ring, u32 acthd) 2408e9243325SFrançois Tigeot { 2409e9243325SFrançois Tigeot struct drm_device *dev = ring->dev; 2410e9243325SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 24115d0b1887SFrançois Tigeot u32 tmp; 24128e26cdf6SFrançois Tigeot 24135d0b1887SFrançois Tigeot if (ring->hangcheck.acthd != acthd) 2414*9edbd4a0SFrançois Tigeot return HANGCHECK_ACTIVE; 2415e9243325SFrançois Tigeot 24165d0b1887SFrançois Tigeot if (IS_GEN2(dev)) 2417*9edbd4a0SFrançois Tigeot return HANGCHECK_HUNG; 241800640ec9SFrançois Tigeot 241900640ec9SFrançois Tigeot /* Is the chip hanging on a WAIT_FOR_EVENT? 242000640ec9SFrançois Tigeot * If so we can simply poke the RB_WAIT bit 242100640ec9SFrançois Tigeot * and break the hang. This should work on 242200640ec9SFrançois Tigeot * all but the second generation chipsets. 242300640ec9SFrançois Tigeot */ 24245d0b1887SFrançois Tigeot tmp = I915_READ_CTL(ring); 24255d0b1887SFrançois Tigeot if (tmp & RING_WAIT) { 24265d0b1887SFrançois Tigeot DRM_ERROR("Kicking stuck wait on %s\n", 24275d0b1887SFrançois Tigeot ring->name); 2428*9edbd4a0SFrançois Tigeot i915_handle_error(dev, false); 24295d0b1887SFrançois Tigeot I915_WRITE_CTL(ring, tmp); 2430*9edbd4a0SFrançois Tigeot return HANGCHECK_KICK; 24315d0b1887SFrançois Tigeot } 24325d0b1887SFrançois Tigeot 24335d0b1887SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 6 && tmp & RING_WAIT_SEMAPHORE) { 24345d0b1887SFrançois Tigeot switch (semaphore_passed(ring)) { 24355d0b1887SFrançois Tigeot default: 2436*9edbd4a0SFrançois Tigeot return HANGCHECK_HUNG; 24375d0b1887SFrançois Tigeot case 1: 24385d0b1887SFrançois Tigeot DRM_ERROR("Kicking stuck semaphore on %s\n", 24395d0b1887SFrançois Tigeot ring->name); 2440*9edbd4a0SFrançois Tigeot i915_handle_error(dev, false); 24415d0b1887SFrançois Tigeot I915_WRITE_CTL(ring, tmp); 2442*9edbd4a0SFrançois Tigeot return HANGCHECK_KICK; 24435d0b1887SFrançois Tigeot case 0: 2444*9edbd4a0SFrançois Tigeot return HANGCHECK_WAIT; 24455d0b1887SFrançois Tigeot } 244600640ec9SFrançois Tigeot } 244700640ec9SFrançois Tigeot 2448*9edbd4a0SFrançois Tigeot return HANGCHECK_HUNG; 244900640ec9SFrançois Tigeot } 245000640ec9SFrançois Tigeot 2451e9243325SFrançois Tigeot /** 2452e9243325SFrançois Tigeot * This is called when the chip hasn't reported back with completed 24535d0b1887SFrançois Tigeot * batchbuffers in a long time. We keep track per ring seqno progress and 24545d0b1887SFrançois Tigeot * if there are no progress, hangcheck score for that ring is increased. 24555d0b1887SFrançois Tigeot * Further, acthd is inspected to see if the ring is stuck. On stuck case 24565d0b1887SFrançois Tigeot * we kick the ring. If we see no progress on three subsequent calls 24575d0b1887SFrançois Tigeot * we assume chip is wedged and try to fix it by resetting the chip. 2458e9243325SFrançois Tigeot */ 2459*9edbd4a0SFrançois Tigeot static void i915_hangcheck_elapsed(unsigned long data) 2460e9243325SFrançois Tigeot { 2461e9243325SFrançois Tigeot struct drm_device *dev = (struct drm_device *)data; 2462e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 246300640ec9SFrançois Tigeot struct intel_ring_buffer *ring; 246400640ec9SFrançois Tigeot int i; 24655d0b1887SFrançois Tigeot int busy_count = 0, rings_hung = 0; 24665d0b1887SFrançois Tigeot bool stuck[I915_NUM_RINGS] = { 0 }; 24675d0b1887SFrançois Tigeot #define BUSY 1 24685d0b1887SFrançois Tigeot #define KICK 5 24695d0b1887SFrançois Tigeot #define HUNG 20 24705d0b1887SFrançois Tigeot #define FIRE 30 2471e9243325SFrançois Tigeot 2472e9243325SFrançois Tigeot if (!i915_enable_hangcheck) 2473e9243325SFrançois Tigeot return; 2474e9243325SFrançois Tigeot 247500640ec9SFrançois Tigeot for_each_ring(ring, dev_priv, i) { 24765d0b1887SFrançois Tigeot u32 seqno, acthd; 24775d0b1887SFrançois Tigeot bool busy = true; 247800640ec9SFrançois Tigeot 24795d0b1887SFrançois Tigeot semaphore_clear_deadlocks(dev_priv); 248000640ec9SFrançois Tigeot 24815d0b1887SFrançois Tigeot seqno = ring->get_seqno(ring, false); 24825d0b1887SFrançois Tigeot acthd = intel_ring_get_active_head(ring); 248300640ec9SFrançois Tigeot 24845d0b1887SFrançois Tigeot if (ring->hangcheck.seqno == seqno) { 24855d0b1887SFrançois Tigeot if (ring_idle(ring, seqno)) { 2486*9edbd4a0SFrançois Tigeot ring->hangcheck.action = HANGCHECK_IDLE; 2487*9edbd4a0SFrançois Tigeot 24885d0b1887SFrançois Tigeot if (waitqueue_active(&ring->irq_queue)) { 24895d0b1887SFrançois Tigeot /* Issue a wake-up to catch stuck h/w. */ 2490*9edbd4a0SFrançois Tigeot if (!test_and_set_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings)) { 2491*9edbd4a0SFrançois Tigeot if (!(dev_priv->gpu_error.test_irq_rings & intel_ring_flag(ring))) 24925d0b1887SFrançois Tigeot DRM_ERROR("Hangcheck timer elapsed... %s idle\n", 24935d0b1887SFrançois Tigeot ring->name); 2494*9edbd4a0SFrançois Tigeot else 2495*9edbd4a0SFrançois Tigeot DRM_INFO("Fake missed irq on %s\n", 2496*9edbd4a0SFrançois Tigeot ring->name); 24975d0b1887SFrançois Tigeot wake_up_all(&ring->irq_queue); 2498*9edbd4a0SFrançois Tigeot } 2499*9edbd4a0SFrançois Tigeot /* Safeguard against driver failure */ 2500*9edbd4a0SFrançois Tigeot ring->hangcheck.score += BUSY; 25015d0b1887SFrançois Tigeot } else 25025d0b1887SFrançois Tigeot busy = false; 2503e9243325SFrançois Tigeot } else { 25045d0b1887SFrançois Tigeot /* We always increment the hangcheck score 25055d0b1887SFrançois Tigeot * if the ring is busy and still processing 25065d0b1887SFrançois Tigeot * the same request, so that no single request 25075d0b1887SFrançois Tigeot * can run indefinitely (such as a chain of 25085d0b1887SFrançois Tigeot * batches). The only time we do not increment 25095d0b1887SFrançois Tigeot * the hangcheck score on this ring, if this 25105d0b1887SFrançois Tigeot * ring is in a legitimate wait for another 25115d0b1887SFrançois Tigeot * ring. In that case the waiting ring is a 25125d0b1887SFrançois Tigeot * victim and we want to be sure we catch the 25135d0b1887SFrançois Tigeot * right culprit. Then every time we do kick 25145d0b1887SFrançois Tigeot * the ring, add a small increment to the 25155d0b1887SFrançois Tigeot * score so that we can catch a batch that is 25165d0b1887SFrançois Tigeot * being repeatedly kicked and so responsible 25175d0b1887SFrançois Tigeot * for stalling the machine. 25185d0b1887SFrançois Tigeot */ 25195d0b1887SFrançois Tigeot ring->hangcheck.action = ring_stuck(ring, 25205d0b1887SFrançois Tigeot acthd); 25215d0b1887SFrançois Tigeot 25225d0b1887SFrançois Tigeot switch (ring->hangcheck.action) { 2523*9edbd4a0SFrançois Tigeot case HANGCHECK_IDLE: 2524*9edbd4a0SFrançois Tigeot case HANGCHECK_WAIT: 25255d0b1887SFrançois Tigeot break; 2526*9edbd4a0SFrançois Tigeot case HANGCHECK_ACTIVE: 2527*9edbd4a0SFrançois Tigeot ring->hangcheck.score += BUSY; 25285d0b1887SFrançois Tigeot break; 2529*9edbd4a0SFrançois Tigeot case HANGCHECK_KICK: 2530*9edbd4a0SFrançois Tigeot ring->hangcheck.score += KICK; 25315d0b1887SFrançois Tigeot break; 2532*9edbd4a0SFrançois Tigeot case HANGCHECK_HUNG: 2533*9edbd4a0SFrançois Tigeot ring->hangcheck.score += HUNG; 25345d0b1887SFrançois Tigeot stuck[i] = true; 25355d0b1887SFrançois Tigeot break; 25365d0b1887SFrançois Tigeot } 25375d0b1887SFrançois Tigeot } 25385d0b1887SFrançois Tigeot } else { 2539*9edbd4a0SFrançois Tigeot ring->hangcheck.action = HANGCHECK_ACTIVE; 2540*9edbd4a0SFrançois Tigeot 25415d0b1887SFrançois Tigeot /* Gradually reduce the count so that we catch DoS 25425d0b1887SFrançois Tigeot * attempts across multiple batches. 25435d0b1887SFrançois Tigeot */ 25445d0b1887SFrançois Tigeot if (ring->hangcheck.score > 0) 25455d0b1887SFrançois Tigeot ring->hangcheck.score--; 2546e9243325SFrançois Tigeot } 2547e9243325SFrançois Tigeot 25485d0b1887SFrançois Tigeot ring->hangcheck.seqno = seqno; 25495d0b1887SFrançois Tigeot ring->hangcheck.acthd = acthd; 25505d0b1887SFrançois Tigeot busy_count += busy; 25515d0b1887SFrançois Tigeot } 25525d0b1887SFrançois Tigeot 25535d0b1887SFrançois Tigeot for_each_ring(ring, dev_priv, i) { 25545d0b1887SFrançois Tigeot if (ring->hangcheck.score > FIRE) { 2555*9edbd4a0SFrançois Tigeot DRM_INFO("%s on %s\n", 25565d0b1887SFrançois Tigeot stuck[i] ? "stuck" : "no progress", 25575d0b1887SFrançois Tigeot ring->name); 25585d0b1887SFrançois Tigeot rings_hung++; 25595d0b1887SFrançois Tigeot } 25605d0b1887SFrançois Tigeot } 25615d0b1887SFrançois Tigeot 25625d0b1887SFrançois Tigeot if (rings_hung) 25635d0b1887SFrançois Tigeot return i915_handle_error(dev, true); 25645d0b1887SFrançois Tigeot 25655d0b1887SFrançois Tigeot if (busy_count) 25665d0b1887SFrançois Tigeot /* Reset timer case chip hangs without another request 25675d0b1887SFrançois Tigeot * being added */ 2568*9edbd4a0SFrançois Tigeot i915_queue_hangcheck(dev); 2569*9edbd4a0SFrançois Tigeot } 2570*9edbd4a0SFrançois Tigeot 2571*9edbd4a0SFrançois Tigeot void i915_queue_hangcheck(struct drm_device *dev) 2572*9edbd4a0SFrançois Tigeot { 2573*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2574*9edbd4a0SFrançois Tigeot if (!i915_enable_hangcheck) 2575*9edbd4a0SFrançois Tigeot return; 2576*9edbd4a0SFrançois Tigeot 2577a2fdbec6SFrançois Tigeot mod_timer(&dev_priv->gpu_error.hangcheck_timer, 2578*9edbd4a0SFrançois Tigeot round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); 25795d0b1887SFrançois Tigeot } 25805d0b1887SFrançois Tigeot 25815d0b1887SFrançois Tigeot static void ibx_irq_preinstall(struct drm_device *dev) 25825d0b1887SFrançois Tigeot { 25835d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 25845d0b1887SFrançois Tigeot 25855d0b1887SFrançois Tigeot if (HAS_PCH_NOP(dev)) 25865d0b1887SFrançois Tigeot return; 25875d0b1887SFrançois Tigeot 25885d0b1887SFrançois Tigeot /* south display irq */ 25895d0b1887SFrançois Tigeot I915_WRITE(SDEIMR, 0xffffffff); 25905d0b1887SFrançois Tigeot /* 25915d0b1887SFrançois Tigeot * SDEIER is also touched by the interrupt handler to work around missed 25925d0b1887SFrançois Tigeot * PCH interrupts. Hence we can't update it after the interrupt handler 25935d0b1887SFrançois Tigeot * is enabled - instead we unconditionally enable all PCH interrupt 25945d0b1887SFrançois Tigeot * sources here, but then only unmask them as needed with SDEIMR. 25955d0b1887SFrançois Tigeot */ 25965d0b1887SFrançois Tigeot I915_WRITE(SDEIER, 0xffffffff); 25975d0b1887SFrançois Tigeot POSTING_READ(SDEIER); 2598e9243325SFrançois Tigeot } 2599e9243325SFrançois Tigeot 2600*9edbd4a0SFrançois Tigeot static void gen5_gt_irq_preinstall(struct drm_device *dev) 2601*9edbd4a0SFrançois Tigeot { 2602*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2603*9edbd4a0SFrançois Tigeot 2604*9edbd4a0SFrançois Tigeot /* and GT */ 2605*9edbd4a0SFrançois Tigeot I915_WRITE(GTIMR, 0xffffffff); 2606*9edbd4a0SFrançois Tigeot I915_WRITE(GTIER, 0x0); 2607*9edbd4a0SFrançois Tigeot POSTING_READ(GTIER); 2608*9edbd4a0SFrançois Tigeot 2609*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 6) { 2610*9edbd4a0SFrançois Tigeot /* and PM */ 2611*9edbd4a0SFrançois Tigeot I915_WRITE(GEN6_PMIMR, 0xffffffff); 2612*9edbd4a0SFrançois Tigeot I915_WRITE(GEN6_PMIER, 0x0); 2613*9edbd4a0SFrançois Tigeot POSTING_READ(GEN6_PMIER); 2614*9edbd4a0SFrançois Tigeot } 2615*9edbd4a0SFrançois Tigeot } 2616*9edbd4a0SFrançois Tigeot 2617e9243325SFrançois Tigeot /* drm_dma.h hooks 2618e9243325SFrançois Tigeot */ 261900640ec9SFrançois Tigeot static void ironlake_irq_preinstall(struct drm_device *dev) 2620e9243325SFrançois Tigeot { 2621e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2622e9243325SFrançois Tigeot 2623e9243325SFrançois Tigeot atomic_set(&dev_priv->irq_received, 0); 2624e9243325SFrançois Tigeot 2625e9243325SFrançois Tigeot I915_WRITE(HWSTAM, 0xeffe); 2626e9243325SFrançois Tigeot 2627e9243325SFrançois Tigeot I915_WRITE(DEIMR, 0xffffffff); 2628e9243325SFrançois Tigeot I915_WRITE(DEIER, 0x0); 2629e9243325SFrançois Tigeot POSTING_READ(DEIER); 2630e9243325SFrançois Tigeot 2631*9edbd4a0SFrançois Tigeot gen5_gt_irq_preinstall(dev); 26325d0b1887SFrançois Tigeot 26335d0b1887SFrançois Tigeot ibx_irq_preinstall(dev); 2634e9243325SFrançois Tigeot } 2635e9243325SFrançois Tigeot 2636e9243325SFrançois Tigeot static void valleyview_irq_preinstall(struct drm_device *dev) 2637e9243325SFrançois Tigeot { 2638e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2639e9243325SFrançois Tigeot int pipe; 2640e9243325SFrançois Tigeot 2641e9243325SFrançois Tigeot atomic_set(&dev_priv->irq_received, 0); 2642e9243325SFrançois Tigeot 2643e9243325SFrançois Tigeot /* VLV magic */ 2644e9243325SFrançois Tigeot I915_WRITE(VLV_IMR, 0); 2645e9243325SFrançois Tigeot I915_WRITE(RING_IMR(RENDER_RING_BASE), 0); 2646e9243325SFrançois Tigeot I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0); 2647e9243325SFrançois Tigeot I915_WRITE(RING_IMR(BLT_RING_BASE), 0); 2648e9243325SFrançois Tigeot 2649e9243325SFrançois Tigeot /* and GT */ 2650e9243325SFrançois Tigeot I915_WRITE(GTIIR, I915_READ(GTIIR)); 2651e9243325SFrançois Tigeot I915_WRITE(GTIIR, I915_READ(GTIIR)); 2652*9edbd4a0SFrançois Tigeot 2653*9edbd4a0SFrançois Tigeot gen5_gt_irq_preinstall(dev); 2654e9243325SFrançois Tigeot 2655e9243325SFrançois Tigeot I915_WRITE(DPINVGTT, 0xff); 2656e9243325SFrançois Tigeot 2657e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, 0); 2658e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 2659e9243325SFrançois Tigeot for_each_pipe(pipe) 2660e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0xffff); 2661e9243325SFrançois Tigeot I915_WRITE(VLV_IIR, 0xffffffff); 2662e9243325SFrançois Tigeot I915_WRITE(VLV_IMR, 0xffffffff); 2663e9243325SFrançois Tigeot I915_WRITE(VLV_IER, 0x0); 2664e9243325SFrançois Tigeot POSTING_READ(VLV_IER); 2665e9243325SFrançois Tigeot } 2666e9243325SFrançois Tigeot 2667*9edbd4a0SFrançois Tigeot static void gen8_irq_preinstall(struct drm_device *dev) 2668*9edbd4a0SFrançois Tigeot { 2669*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2670*9edbd4a0SFrançois Tigeot int pipe; 2671*9edbd4a0SFrançois Tigeot 2672*9edbd4a0SFrançois Tigeot atomic_set(&dev_priv->irq_received, 0); 2673*9edbd4a0SFrançois Tigeot 2674*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, 0); 2675*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_MASTER_IRQ); 2676*9edbd4a0SFrançois Tigeot 2677*9edbd4a0SFrançois Tigeot /* IIR can theoretically queue up two events. Be paranoid */ 2678*9edbd4a0SFrançois Tigeot #define GEN8_IRQ_INIT_NDX(type, which) do { \ 2679*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ 2680*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_##type##_IMR(which)); \ 2681*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IER(which), 0); \ 2682*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ 2683*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_##type##_IIR(which)); \ 2684*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ 2685*9edbd4a0SFrançois Tigeot } while (0) 2686*9edbd4a0SFrançois Tigeot 2687*9edbd4a0SFrançois Tigeot #define GEN8_IRQ_INIT(type) do { \ 2688*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ 2689*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_##type##_IMR); \ 2690*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IER, 0); \ 2691*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ 2692*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_##type##_IIR); \ 2693*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ 2694*9edbd4a0SFrançois Tigeot } while (0) 2695*9edbd4a0SFrançois Tigeot 2696*9edbd4a0SFrançois Tigeot GEN8_IRQ_INIT_NDX(GT, 0); 2697*9edbd4a0SFrançois Tigeot GEN8_IRQ_INIT_NDX(GT, 1); 2698*9edbd4a0SFrançois Tigeot GEN8_IRQ_INIT_NDX(GT, 2); 2699*9edbd4a0SFrançois Tigeot GEN8_IRQ_INIT_NDX(GT, 3); 2700*9edbd4a0SFrançois Tigeot 2701*9edbd4a0SFrançois Tigeot for_each_pipe(pipe) { 2702*9edbd4a0SFrançois Tigeot GEN8_IRQ_INIT_NDX(DE_PIPE, pipe); 2703*9edbd4a0SFrançois Tigeot } 2704*9edbd4a0SFrançois Tigeot 2705*9edbd4a0SFrançois Tigeot GEN8_IRQ_INIT(DE_PORT); 2706*9edbd4a0SFrançois Tigeot GEN8_IRQ_INIT(DE_MISC); 2707*9edbd4a0SFrançois Tigeot GEN8_IRQ_INIT(PCU); 2708*9edbd4a0SFrançois Tigeot #undef GEN8_IRQ_INIT 2709*9edbd4a0SFrançois Tigeot #undef GEN8_IRQ_INIT_NDX 2710*9edbd4a0SFrançois Tigeot 2711*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_PCU_IIR); 2712*9edbd4a0SFrançois Tigeot 2713*9edbd4a0SFrançois Tigeot ibx_irq_preinstall(dev); 2714*9edbd4a0SFrançois Tigeot } 2715*9edbd4a0SFrançois Tigeot 27168e26cdf6SFrançois Tigeot static void ibx_hpd_irq_setup(struct drm_device *dev) 27178e26cdf6SFrançois Tigeot { 27188e26cdf6SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 27198e26cdf6SFrançois Tigeot struct drm_mode_config *mode_config = &dev->mode_config; 27208e26cdf6SFrançois Tigeot struct intel_encoder *intel_encoder; 2721*9edbd4a0SFrançois Tigeot u32 hotplug_irqs, hotplug, enabled_irqs = 0; 27228e26cdf6SFrançois Tigeot 27238e26cdf6SFrançois Tigeot if (HAS_PCH_IBX(dev)) { 2724*9edbd4a0SFrançois Tigeot hotplug_irqs = SDE_HOTPLUG_MASK; 27258e26cdf6SFrançois Tigeot list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) 27268e26cdf6SFrançois Tigeot if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) 2727*9edbd4a0SFrançois Tigeot enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin]; 27288e26cdf6SFrançois Tigeot } else { 2729*9edbd4a0SFrançois Tigeot hotplug_irqs = SDE_HOTPLUG_MASK_CPT; 27308e26cdf6SFrançois Tigeot list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) 27318e26cdf6SFrançois Tigeot if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) 2732*9edbd4a0SFrançois Tigeot enabled_irqs |= hpd_cpt[intel_encoder->hpd_pin]; 27338e26cdf6SFrançois Tigeot } 27348e26cdf6SFrançois Tigeot 2735*9edbd4a0SFrançois Tigeot ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); 27368e26cdf6SFrançois Tigeot 2737e9243325SFrançois Tigeot /* 2738e9243325SFrançois Tigeot * Enable digital hotplug on the PCH, and configure the DP short pulse 2739e9243325SFrançois Tigeot * duration to 2ms (which is the minimum in the Display Port spec) 2740e9243325SFrançois Tigeot * 2741e9243325SFrançois Tigeot * This register is the same on all known PCH chips. 2742e9243325SFrançois Tigeot */ 2743e9243325SFrançois Tigeot hotplug = I915_READ(PCH_PORT_HOTPLUG); 2744e9243325SFrançois Tigeot hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK); 2745e9243325SFrançois Tigeot hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms; 2746e9243325SFrançois Tigeot hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms; 2747e9243325SFrançois Tigeot hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms; 2748e9243325SFrançois Tigeot I915_WRITE(PCH_PORT_HOTPLUG, hotplug); 2749e9243325SFrançois Tigeot } 2750e9243325SFrançois Tigeot 2751a2fdbec6SFrançois Tigeot static void ibx_irq_postinstall(struct drm_device *dev) 2752a2fdbec6SFrançois Tigeot { 2753a2fdbec6SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2754a2fdbec6SFrançois Tigeot u32 mask; 2755a2fdbec6SFrançois Tigeot 27568e26cdf6SFrançois Tigeot if (HAS_PCH_NOP(dev)) 27578e26cdf6SFrançois Tigeot return; 2758a2fdbec6SFrançois Tigeot 27595d0b1887SFrançois Tigeot if (HAS_PCH_IBX(dev)) { 2760*9edbd4a0SFrançois Tigeot mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; 27615d0b1887SFrançois Tigeot } else { 2762*9edbd4a0SFrançois Tigeot mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; 27635d0b1887SFrançois Tigeot 27645d0b1887SFrançois Tigeot I915_WRITE(SERR_INT, I915_READ(SERR_INT)); 27655d0b1887SFrançois Tigeot } 27665d0b1887SFrançois Tigeot 2767a2fdbec6SFrançois Tigeot I915_WRITE(SDEIIR, I915_READ(SDEIIR)); 2768a2fdbec6SFrançois Tigeot I915_WRITE(SDEIMR, ~mask); 2769a2fdbec6SFrançois Tigeot } 2770a2fdbec6SFrançois Tigeot 2771*9edbd4a0SFrançois Tigeot static void gen5_gt_irq_postinstall(struct drm_device *dev) 2772*9edbd4a0SFrançois Tigeot { 2773*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2774*9edbd4a0SFrançois Tigeot u32 pm_irqs, gt_irqs; 2775*9edbd4a0SFrançois Tigeot 2776*9edbd4a0SFrançois Tigeot pm_irqs = gt_irqs = 0; 2777*9edbd4a0SFrançois Tigeot 2778*9edbd4a0SFrançois Tigeot dev_priv->gt_irq_mask = ~0; 2779*9edbd4a0SFrançois Tigeot if (HAS_L3_DPF(dev)) { 2780*9edbd4a0SFrançois Tigeot /* L3 parity interrupt is always unmasked. */ 2781*9edbd4a0SFrançois Tigeot dev_priv->gt_irq_mask = ~GT_PARITY_ERROR(dev); 2782*9edbd4a0SFrançois Tigeot gt_irqs |= GT_PARITY_ERROR(dev); 2783*9edbd4a0SFrançois Tigeot } 2784*9edbd4a0SFrançois Tigeot 2785*9edbd4a0SFrançois Tigeot gt_irqs |= GT_RENDER_USER_INTERRUPT; 2786*9edbd4a0SFrançois Tigeot if (IS_GEN5(dev)) { 2787*9edbd4a0SFrançois Tigeot gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT | 2788*9edbd4a0SFrançois Tigeot ILK_BSD_USER_INTERRUPT; 2789*9edbd4a0SFrançois Tigeot } else { 2790*9edbd4a0SFrançois Tigeot gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT; 2791*9edbd4a0SFrançois Tigeot } 2792*9edbd4a0SFrançois Tigeot 2793*9edbd4a0SFrançois Tigeot I915_WRITE(GTIIR, I915_READ(GTIIR)); 2794*9edbd4a0SFrançois Tigeot I915_WRITE(GTIMR, dev_priv->gt_irq_mask); 2795*9edbd4a0SFrançois Tigeot I915_WRITE(GTIER, gt_irqs); 2796*9edbd4a0SFrançois Tigeot POSTING_READ(GTIER); 2797*9edbd4a0SFrançois Tigeot 2798*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 6) { 2799*9edbd4a0SFrançois Tigeot pm_irqs |= GEN6_PM_RPS_EVENTS; 2800*9edbd4a0SFrançois Tigeot 2801*9edbd4a0SFrançois Tigeot if (HAS_VEBOX(dev)) 2802*9edbd4a0SFrançois Tigeot pm_irqs |= PM_VEBOX_USER_INTERRUPT; 2803*9edbd4a0SFrançois Tigeot 2804*9edbd4a0SFrançois Tigeot dev_priv->pm_irq_mask = 0xffffffff; 2805*9edbd4a0SFrançois Tigeot I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); 2806*9edbd4a0SFrançois Tigeot I915_WRITE(GEN6_PMIMR, dev_priv->pm_irq_mask); 2807*9edbd4a0SFrançois Tigeot I915_WRITE(GEN6_PMIER, pm_irqs); 2808*9edbd4a0SFrançois Tigeot POSTING_READ(GEN6_PMIER); 2809*9edbd4a0SFrançois Tigeot } 2810*9edbd4a0SFrançois Tigeot } 2811*9edbd4a0SFrançois Tigeot 2812e9243325SFrançois Tigeot static int ironlake_irq_postinstall(struct drm_device *dev) 2813e9243325SFrançois Tigeot { 2814e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2815*9edbd4a0SFrançois Tigeot u32 display_mask, extra_mask; 2816*9edbd4a0SFrançois Tigeot 2817*9edbd4a0SFrançois Tigeot if (INTEL_INFO(dev)->gen >= 7) { 2818*9edbd4a0SFrançois Tigeot display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | 2819*9edbd4a0SFrançois Tigeot DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB | 2820*9edbd4a0SFrançois Tigeot DE_PLANEB_FLIP_DONE_IVB | 2821*9edbd4a0SFrançois Tigeot DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB); 2822*9edbd4a0SFrançois Tigeot extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB | 2823*9edbd4a0SFrançois Tigeot DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB); 2824*9edbd4a0SFrançois Tigeot 2825*9edbd4a0SFrançois Tigeot I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); 2826*9edbd4a0SFrançois Tigeot } else { 2827*9edbd4a0SFrançois Tigeot display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | 2828a2fdbec6SFrançois Tigeot DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | 2829*9edbd4a0SFrançois Tigeot DE_AUX_CHANNEL_A | 2830*9edbd4a0SFrançois Tigeot DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE | 2831*9edbd4a0SFrançois Tigeot DE_POISON); 2832*9edbd4a0SFrançois Tigeot extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT | 2833*9edbd4a0SFrançois Tigeot DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN; 2834*9edbd4a0SFrançois Tigeot } 2835e9243325SFrançois Tigeot 2836e9243325SFrançois Tigeot dev_priv->irq_mask = ~display_mask; 2837e9243325SFrançois Tigeot 2838e9243325SFrançois Tigeot /* should always can generate irq */ 2839e9243325SFrançois Tigeot I915_WRITE(DEIIR, I915_READ(DEIIR)); 2840e9243325SFrançois Tigeot I915_WRITE(DEIMR, dev_priv->irq_mask); 2841*9edbd4a0SFrançois Tigeot I915_WRITE(DEIER, display_mask | extra_mask); 2842e9243325SFrançois Tigeot POSTING_READ(DEIER); 2843e9243325SFrançois Tigeot 2844*9edbd4a0SFrançois Tigeot gen5_gt_irq_postinstall(dev); 2845e9243325SFrançois Tigeot 2846a2fdbec6SFrançois Tigeot ibx_irq_postinstall(dev); 2847e9243325SFrançois Tigeot 2848e9243325SFrançois Tigeot if (IS_IRONLAKE_M(dev)) { 28495d0b1887SFrançois Tigeot /* Enable PCU event interrupts 28505d0b1887SFrançois Tigeot * 28515d0b1887SFrançois Tigeot * spinlocking not required here for correctness since interrupt 28525d0b1887SFrançois Tigeot * setup is guaranteed to run in single-threaded context. But we 28535d0b1887SFrançois Tigeot * need it to make the assert_spin_locked happy. */ 28545d0b1887SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 2855e9243325SFrançois Tigeot ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT); 28565d0b1887SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 2857e9243325SFrançois Tigeot } 2858e9243325SFrançois Tigeot 2859e9243325SFrançois Tigeot return 0; 2860e9243325SFrançois Tigeot } 2861e9243325SFrançois Tigeot 2862e9243325SFrançois Tigeot static int valleyview_irq_postinstall(struct drm_device *dev) 2863e9243325SFrançois Tigeot { 2864e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2865e9243325SFrançois Tigeot u32 enable_mask; 2866*9edbd4a0SFrançois Tigeot u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV | 2867*9edbd4a0SFrançois Tigeot PIPE_CRC_DONE_ENABLE; 2868e9243325SFrançois Tigeot 2869e9243325SFrançois Tigeot enable_mask = I915_DISPLAY_PORT_INTERRUPT; 2870e9243325SFrançois Tigeot enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 2871e9243325SFrançois Tigeot I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | 2872e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 2873e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; 2874e9243325SFrançois Tigeot 2875e9243325SFrançois Tigeot /* 2876e9243325SFrançois Tigeot *Leave vblank interrupts masked initially. enable/disable will 2877e9243325SFrançois Tigeot * toggle them based on usage. 2878e9243325SFrançois Tigeot */ 2879e9243325SFrançois Tigeot dev_priv->irq_mask = (~enable_mask) | 2880e9243325SFrançois Tigeot I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | 2881e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; 2882e9243325SFrançois Tigeot 2883a2fdbec6SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, 0); 2884a2fdbec6SFrançois Tigeot POSTING_READ(PORT_HOTPLUG_EN); 2885a2fdbec6SFrançois Tigeot 2886e9243325SFrançois Tigeot I915_WRITE(VLV_IMR, dev_priv->irq_mask); 2887e9243325SFrançois Tigeot I915_WRITE(VLV_IER, enable_mask); 2888e9243325SFrançois Tigeot I915_WRITE(VLV_IIR, 0xffffffff); 2889e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(0), 0xffff); 2890e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(1), 0xffff); 2891e9243325SFrançois Tigeot POSTING_READ(VLV_IER); 2892e9243325SFrançois Tigeot 2893*9edbd4a0SFrançois Tigeot /* Interrupt setup is already guaranteed to be single-threaded, this is 2894*9edbd4a0SFrançois Tigeot * just to make the assert_spin_locked check happy. */ 2895*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 2896*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, pipestat_enable); 2897*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE); 2898*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_B, pipestat_enable); 2899*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 2900e9243325SFrançois Tigeot 2901e9243325SFrançois Tigeot I915_WRITE(VLV_IIR, 0xffffffff); 2902e9243325SFrançois Tigeot I915_WRITE(VLV_IIR, 0xffffffff); 2903e9243325SFrançois Tigeot 2904*9edbd4a0SFrançois Tigeot gen5_gt_irq_postinstall(dev); 2905e9243325SFrançois Tigeot 2906e9243325SFrançois Tigeot /* ack & enable invalid PTE error interrupts */ 2907e9243325SFrançois Tigeot #if 0 /* FIXME: add support to irq handler for checking these bits */ 2908e9243325SFrançois Tigeot I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK); 2909e9243325SFrançois Tigeot I915_WRITE(DPINVGTT, DPINVGTT_EN_MASK); 2910e9243325SFrançois Tigeot #endif 2911e9243325SFrançois Tigeot 2912e9243325SFrançois Tigeot I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); 2913a2fdbec6SFrançois Tigeot 2914a2fdbec6SFrançois Tigeot return 0; 2915a2fdbec6SFrançois Tigeot } 2916a2fdbec6SFrançois Tigeot 2917*9edbd4a0SFrançois Tigeot static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) 2918*9edbd4a0SFrançois Tigeot { 2919*9edbd4a0SFrançois Tigeot int i; 2920*9edbd4a0SFrançois Tigeot 2921*9edbd4a0SFrançois Tigeot /* These are interrupts we'll toggle with the ring mask register */ 2922*9edbd4a0SFrançois Tigeot uint32_t gt_interrupts[] = { 2923*9edbd4a0SFrançois Tigeot GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | 2924*9edbd4a0SFrançois Tigeot GT_RENDER_L3_PARITY_ERROR_INTERRUPT | 2925*9edbd4a0SFrançois Tigeot GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT, 2926*9edbd4a0SFrançois Tigeot GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT | 2927*9edbd4a0SFrançois Tigeot GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT, 2928*9edbd4a0SFrançois Tigeot 0, 2929*9edbd4a0SFrançois Tigeot GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT 2930*9edbd4a0SFrançois Tigeot }; 2931*9edbd4a0SFrançois Tigeot 2932*9edbd4a0SFrançois Tigeot for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) { 2933*9edbd4a0SFrançois Tigeot u32 tmp = I915_READ(GEN8_GT_IIR(i)); 2934*9edbd4a0SFrançois Tigeot if (tmp) 2935*9edbd4a0SFrançois Tigeot DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n", 2936*9edbd4a0SFrançois Tigeot i, tmp); 2937*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_GT_IMR(i), ~gt_interrupts[i]); 2938*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_GT_IER(i), gt_interrupts[i]); 2939*9edbd4a0SFrançois Tigeot } 2940*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_GT_IER(0)); 2941*9edbd4a0SFrançois Tigeot } 2942*9edbd4a0SFrançois Tigeot 2943*9edbd4a0SFrançois Tigeot static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) 2944*9edbd4a0SFrançois Tigeot { 2945*9edbd4a0SFrançois Tigeot struct drm_device *dev = dev_priv->dev; 2946*9edbd4a0SFrançois Tigeot uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE | 2947*9edbd4a0SFrançois Tigeot GEN8_PIPE_CDCLK_CRC_DONE | 2948*9edbd4a0SFrançois Tigeot GEN8_DE_PIPE_IRQ_FAULT_ERRORS; 2949*9edbd4a0SFrançois Tigeot uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK | 2950*9edbd4a0SFrançois Tigeot GEN8_PIPE_FIFO_UNDERRUN; 2951*9edbd4a0SFrançois Tigeot int pipe; 2952*9edbd4a0SFrançois Tigeot dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked; 2953*9edbd4a0SFrançois Tigeot dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked; 2954*9edbd4a0SFrançois Tigeot dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked; 2955*9edbd4a0SFrançois Tigeot 2956*9edbd4a0SFrançois Tigeot for_each_pipe(pipe) { 2957*9edbd4a0SFrançois Tigeot u32 tmp = I915_READ(GEN8_DE_PIPE_IIR(pipe)); 2958*9edbd4a0SFrançois Tigeot if (tmp) 2959*9edbd4a0SFrançois Tigeot DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n", 2960*9edbd4a0SFrançois Tigeot pipe, tmp); 2961*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); 2962*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_DE_PIPE_IER(pipe), de_pipe_enables); 2963*9edbd4a0SFrançois Tigeot } 2964*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_DE_PIPE_ISR(0)); 2965*9edbd4a0SFrançois Tigeot 2966*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_DE_PORT_IMR, ~GEN8_AUX_CHANNEL_A); 2967*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_DE_PORT_IER, GEN8_AUX_CHANNEL_A); 2968*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_DE_PORT_IER); 2969*9edbd4a0SFrançois Tigeot } 2970*9edbd4a0SFrançois Tigeot 2971*9edbd4a0SFrançois Tigeot static int gen8_irq_postinstall(struct drm_device *dev) 2972*9edbd4a0SFrançois Tigeot { 2973*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2974*9edbd4a0SFrançois Tigeot 2975*9edbd4a0SFrançois Tigeot gen8_gt_irq_postinstall(dev_priv); 2976*9edbd4a0SFrançois Tigeot gen8_de_irq_postinstall(dev_priv); 2977*9edbd4a0SFrançois Tigeot 2978*9edbd4a0SFrançois Tigeot ibx_irq_postinstall(dev); 2979*9edbd4a0SFrançois Tigeot 2980*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL); 2981*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_MASTER_IRQ); 2982*9edbd4a0SFrançois Tigeot 2983*9edbd4a0SFrançois Tigeot return 0; 2984*9edbd4a0SFrançois Tigeot } 2985*9edbd4a0SFrançois Tigeot 2986*9edbd4a0SFrançois Tigeot static void gen8_irq_uninstall(struct drm_device *dev) 2987*9edbd4a0SFrançois Tigeot { 2988*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2989*9edbd4a0SFrançois Tigeot int pipe; 2990*9edbd4a0SFrançois Tigeot 2991*9edbd4a0SFrançois Tigeot if (!dev_priv) 2992*9edbd4a0SFrançois Tigeot return; 2993*9edbd4a0SFrançois Tigeot 2994*9edbd4a0SFrançois Tigeot atomic_set(&dev_priv->irq_received, 0); 2995*9edbd4a0SFrançois Tigeot 2996*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_MASTER_IRQ, 0); 2997*9edbd4a0SFrançois Tigeot 2998*9edbd4a0SFrançois Tigeot #define GEN8_IRQ_FINI_NDX(type, which) do { \ 2999*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ 3000*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IER(which), 0); \ 3001*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ 3002*9edbd4a0SFrançois Tigeot } while (0) 3003*9edbd4a0SFrançois Tigeot 3004*9edbd4a0SFrançois Tigeot #define GEN8_IRQ_FINI(type) do { \ 3005*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ 3006*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IER, 0); \ 3007*9edbd4a0SFrançois Tigeot I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ 3008*9edbd4a0SFrançois Tigeot } while (0) 3009*9edbd4a0SFrançois Tigeot 3010*9edbd4a0SFrançois Tigeot GEN8_IRQ_FINI_NDX(GT, 0); 3011*9edbd4a0SFrançois Tigeot GEN8_IRQ_FINI_NDX(GT, 1); 3012*9edbd4a0SFrançois Tigeot GEN8_IRQ_FINI_NDX(GT, 2); 3013*9edbd4a0SFrançois Tigeot GEN8_IRQ_FINI_NDX(GT, 3); 3014*9edbd4a0SFrançois Tigeot 3015*9edbd4a0SFrançois Tigeot for_each_pipe(pipe) { 3016*9edbd4a0SFrançois Tigeot GEN8_IRQ_FINI_NDX(DE_PIPE, pipe); 3017*9edbd4a0SFrançois Tigeot } 3018*9edbd4a0SFrançois Tigeot 3019*9edbd4a0SFrançois Tigeot GEN8_IRQ_FINI(DE_PORT); 3020*9edbd4a0SFrançois Tigeot GEN8_IRQ_FINI(DE_MISC); 3021*9edbd4a0SFrançois Tigeot GEN8_IRQ_FINI(PCU); 3022*9edbd4a0SFrançois Tigeot #undef GEN8_IRQ_FINI 3023*9edbd4a0SFrançois Tigeot #undef GEN8_IRQ_FINI_NDX 3024*9edbd4a0SFrançois Tigeot 3025*9edbd4a0SFrançois Tigeot POSTING_READ(GEN8_PCU_IIR); 3026*9edbd4a0SFrançois Tigeot } 3027*9edbd4a0SFrançois Tigeot 3028e9243325SFrançois Tigeot static void valleyview_irq_uninstall(struct drm_device *dev) 3029e9243325SFrançois Tigeot { 3030e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3031e9243325SFrançois Tigeot int pipe; 3032e9243325SFrançois Tigeot 3033e9243325SFrançois Tigeot if (!dev_priv) 3034e9243325SFrançois Tigeot return; 3035e9243325SFrançois Tigeot 30368e26cdf6SFrançois Tigeot del_timer_sync(&dev_priv->hotplug_reenable_timer); 30378e26cdf6SFrançois Tigeot 3038e9243325SFrançois Tigeot for_each_pipe(pipe) 3039e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0xffff); 3040e9243325SFrançois Tigeot 3041e9243325SFrançois Tigeot I915_WRITE(HWSTAM, 0xffffffff); 3042e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, 0); 3043e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 3044e9243325SFrançois Tigeot for_each_pipe(pipe) 3045e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0xffff); 3046e9243325SFrançois Tigeot I915_WRITE(VLV_IIR, 0xffffffff); 3047e9243325SFrançois Tigeot I915_WRITE(VLV_IMR, 0xffffffff); 3048e9243325SFrançois Tigeot I915_WRITE(VLV_IER, 0x0); 3049e9243325SFrançois Tigeot POSTING_READ(VLV_IER); 3050e9243325SFrançois Tigeot } 3051e9243325SFrançois Tigeot 3052e9243325SFrançois Tigeot static void ironlake_irq_uninstall(struct drm_device *dev) 3053e9243325SFrançois Tigeot { 3054e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3055e9243325SFrançois Tigeot 3056e9243325SFrançois Tigeot if (!dev_priv) 3057e9243325SFrançois Tigeot return; 3058e9243325SFrançois Tigeot 30598e26cdf6SFrançois Tigeot del_timer_sync(&dev_priv->hotplug_reenable_timer); 30608e26cdf6SFrançois Tigeot 3061e9243325SFrançois Tigeot I915_WRITE(HWSTAM, 0xffffffff); 3062e9243325SFrançois Tigeot 3063e9243325SFrançois Tigeot I915_WRITE(DEIMR, 0xffffffff); 3064e9243325SFrançois Tigeot I915_WRITE(DEIER, 0x0); 3065e9243325SFrançois Tigeot I915_WRITE(DEIIR, I915_READ(DEIIR)); 30665d0b1887SFrançois Tigeot if (IS_GEN7(dev)) 30675d0b1887SFrançois Tigeot I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); 3068e9243325SFrançois Tigeot 3069e9243325SFrançois Tigeot I915_WRITE(GTIMR, 0xffffffff); 3070e9243325SFrançois Tigeot I915_WRITE(GTIER, 0x0); 3071e9243325SFrançois Tigeot I915_WRITE(GTIIR, I915_READ(GTIIR)); 3072e9243325SFrançois Tigeot 30738e26cdf6SFrançois Tigeot if (HAS_PCH_NOP(dev)) 30748e26cdf6SFrançois Tigeot return; 30758e26cdf6SFrançois Tigeot 3076e9243325SFrançois Tigeot I915_WRITE(SDEIMR, 0xffffffff); 3077e9243325SFrançois Tigeot I915_WRITE(SDEIER, 0x0); 3078e9243325SFrançois Tigeot I915_WRITE(SDEIIR, I915_READ(SDEIIR)); 30795d0b1887SFrançois Tigeot if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev)) 30805d0b1887SFrançois Tigeot I915_WRITE(SERR_INT, I915_READ(SERR_INT)); 3081e9243325SFrançois Tigeot } 3082e9243325SFrançois Tigeot 3083e9243325SFrançois Tigeot static void i8xx_irq_preinstall(struct drm_device * dev) 3084e9243325SFrançois Tigeot { 3085e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3086e9243325SFrançois Tigeot int pipe; 3087e9243325SFrançois Tigeot 3088e9243325SFrançois Tigeot atomic_set(&dev_priv->irq_received, 0); 3089e9243325SFrançois Tigeot 3090e9243325SFrançois Tigeot for_each_pipe(pipe) 3091e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 3092e9243325SFrançois Tigeot I915_WRITE16(IMR, 0xffff); 3093e9243325SFrançois Tigeot I915_WRITE16(IER, 0x0); 3094e9243325SFrançois Tigeot POSTING_READ16(IER); 3095e9243325SFrançois Tigeot } 3096e9243325SFrançois Tigeot 3097e9243325SFrançois Tigeot static int i8xx_irq_postinstall(struct drm_device *dev) 3098e9243325SFrançois Tigeot { 3099e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3100e9243325SFrançois Tigeot 3101e9243325SFrançois Tigeot I915_WRITE16(EMR, 3102e9243325SFrançois Tigeot ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); 3103e9243325SFrançois Tigeot 3104e9243325SFrançois Tigeot /* Unmask the interrupts that we always want on. */ 3105e9243325SFrançois Tigeot dev_priv->irq_mask = 3106e9243325SFrançois Tigeot ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 3107e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 3108e9243325SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 3109e9243325SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | 3110e9243325SFrançois Tigeot I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 3111e9243325SFrançois Tigeot I915_WRITE16(IMR, dev_priv->irq_mask); 3112e9243325SFrançois Tigeot 3113e9243325SFrançois Tigeot I915_WRITE16(IER, 3114e9243325SFrançois Tigeot I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 3115e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 3116e9243325SFrançois Tigeot I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | 3117e9243325SFrançois Tigeot I915_USER_INTERRUPT); 3118e9243325SFrançois Tigeot POSTING_READ16(IER); 3119e9243325SFrançois Tigeot 3120*9edbd4a0SFrançois Tigeot /* Interrupt setup is already guaranteed to be single-threaded, this is 3121*9edbd4a0SFrançois Tigeot * just to make the assert_spin_locked check happy. */ 3122*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3123*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE); 3124*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE); 3125*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3126*9edbd4a0SFrançois Tigeot 3127e9243325SFrançois Tigeot return 0; 3128e9243325SFrançois Tigeot } 3129e9243325SFrançois Tigeot 31308e26cdf6SFrançois Tigeot /* 31318e26cdf6SFrançois Tigeot * Returns true when a page flip has completed. 31328e26cdf6SFrançois Tigeot */ 31338e26cdf6SFrançois Tigeot static bool i8xx_handle_vblank(struct drm_device *dev, 3134*9edbd4a0SFrançois Tigeot int plane, int pipe, u32 iir) 31358e26cdf6SFrançois Tigeot { 31368e26cdf6SFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 3137*9edbd4a0SFrançois Tigeot u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); 31388e26cdf6SFrançois Tigeot 31398e26cdf6SFrançois Tigeot if (!drm_handle_vblank(dev, pipe)) 31408e26cdf6SFrançois Tigeot return false; 31418e26cdf6SFrançois Tigeot 31428e26cdf6SFrançois Tigeot if ((iir & flip_pending) == 0) 31438e26cdf6SFrançois Tigeot return false; 31448e26cdf6SFrançois Tigeot 3145*9edbd4a0SFrançois Tigeot intel_prepare_page_flip(dev, plane); 31468e26cdf6SFrançois Tigeot 31478e26cdf6SFrançois Tigeot /* We detect FlipDone by looking for the change in PendingFlip from '1' 31488e26cdf6SFrançois Tigeot * to '0' on the following vblank, i.e. IIR has the Pendingflip 31498e26cdf6SFrançois Tigeot * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence 31508e26cdf6SFrançois Tigeot * the flip is completed (no longer pending). Since this doesn't raise 31518e26cdf6SFrançois Tigeot * an interrupt per se, we watch for the change at vblank. 31528e26cdf6SFrançois Tigeot */ 31538e26cdf6SFrançois Tigeot if (I915_READ16(ISR) & flip_pending) 31548e26cdf6SFrançois Tigeot return false; 31558e26cdf6SFrançois Tigeot 31568e26cdf6SFrançois Tigeot intel_finish_page_flip(dev, pipe); 31578e26cdf6SFrançois Tigeot 31588e26cdf6SFrançois Tigeot return true; 31598e26cdf6SFrançois Tigeot } 31608e26cdf6SFrançois Tigeot 3161e9243325SFrançois Tigeot static irqreturn_t i8xx_irq_handler(void *arg) 3162e9243325SFrançois Tigeot { 3163e9243325SFrançois Tigeot struct drm_device *dev = (struct drm_device *) arg; 3164e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3165e9243325SFrançois Tigeot u16 iir, new_iir; 3166e9243325SFrançois Tigeot u32 pipe_stats[2]; 3167e9243325SFrançois Tigeot int pipe; 3168e9243325SFrançois Tigeot u16 flip_mask = 3169e9243325SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 3170e9243325SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 3171e9243325SFrançois Tigeot 3172e9243325SFrançois Tigeot atomic_inc(&dev_priv->irq_received); 3173e9243325SFrançois Tigeot 3174e9243325SFrançois Tigeot iir = I915_READ16(IIR); 3175e9243325SFrançois Tigeot if (iir == 0) 3176e9243325SFrançois Tigeot return; 3177e9243325SFrançois Tigeot 3178e9243325SFrançois Tigeot while (iir & ~flip_mask) { 3179e9243325SFrançois Tigeot /* Can't rely on pipestat interrupt bit in iir as it might 3180e9243325SFrançois Tigeot * have been cleared after the pipestat interrupt was received. 3181e9243325SFrançois Tigeot * It doesn't set the bit in iir again, but it still produces 3182e9243325SFrançois Tigeot * interrupts (for non-MSI). 3183e9243325SFrançois Tigeot */ 3184e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3185e9243325SFrançois Tigeot if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) 3186e9243325SFrançois Tigeot i915_handle_error(dev, false); 3187e9243325SFrançois Tigeot 3188e9243325SFrançois Tigeot for_each_pipe(pipe) { 3189e9243325SFrançois Tigeot int reg = PIPESTAT(pipe); 3190e9243325SFrançois Tigeot pipe_stats[pipe] = I915_READ(reg); 3191e9243325SFrançois Tigeot 3192e9243325SFrançois Tigeot /* 3193e9243325SFrançois Tigeot * Clear the PIPE*STAT regs before the IIR 3194e9243325SFrançois Tigeot */ 3195e9243325SFrançois Tigeot if (pipe_stats[pipe] & 0x8000ffff) { 3196e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 3197e9243325SFrançois Tigeot DRM_DEBUG_DRIVER("pipe %c underrun\n", 3198e9243325SFrançois Tigeot pipe_name(pipe)); 3199e9243325SFrançois Tigeot I915_WRITE(reg, pipe_stats[pipe]); 3200e9243325SFrançois Tigeot } 3201e9243325SFrançois Tigeot } 3202e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3203e9243325SFrançois Tigeot 3204e9243325SFrançois Tigeot I915_WRITE16(IIR, iir & ~flip_mask); 3205e9243325SFrançois Tigeot new_iir = I915_READ16(IIR); /* Flush posted writes */ 3206e9243325SFrançois Tigeot 3207e9243325SFrançois Tigeot i915_update_dri1_breadcrumb(dev); 3208e9243325SFrançois Tigeot 3209e9243325SFrançois Tigeot if (iir & I915_USER_INTERRUPT) 3210e9243325SFrançois Tigeot notify_ring(dev, &dev_priv->ring[RCS]); 3211e9243325SFrançois Tigeot 3212*9edbd4a0SFrançois Tigeot for_each_pipe(pipe) { 3213*9edbd4a0SFrançois Tigeot int plane = pipe; 3214*9edbd4a0SFrançois Tigeot if (HAS_FBC(dev)) 3215*9edbd4a0SFrançois Tigeot plane = !plane; 3216e9243325SFrançois Tigeot 3217*9edbd4a0SFrançois Tigeot if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && 3218*9edbd4a0SFrançois Tigeot i8xx_handle_vblank(dev, plane, pipe, iir)) 3219*9edbd4a0SFrançois Tigeot flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); 3220*9edbd4a0SFrançois Tigeot 3221*9edbd4a0SFrançois Tigeot if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) 3222*9edbd4a0SFrançois Tigeot i9xx_pipe_crc_irq_handler(dev, pipe); 3223*9edbd4a0SFrançois Tigeot } 3224e9243325SFrançois Tigeot 3225e9243325SFrançois Tigeot iir = new_iir; 3226e9243325SFrançois Tigeot } 3227e9243325SFrançois Tigeot 3228e9243325SFrançois Tigeot } 3229e9243325SFrançois Tigeot 3230e9243325SFrançois Tigeot static void i8xx_irq_uninstall(struct drm_device * dev) 3231e9243325SFrançois Tigeot { 3232e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3233e9243325SFrançois Tigeot int pipe; 3234e9243325SFrançois Tigeot 3235e9243325SFrançois Tigeot for_each_pipe(pipe) { 3236e9243325SFrançois Tigeot /* Clear enable bits; then clear status bits */ 3237e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 3238e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe))); 3239e9243325SFrançois Tigeot } 3240e9243325SFrançois Tigeot I915_WRITE16(IMR, 0xffff); 3241e9243325SFrançois Tigeot I915_WRITE16(IER, 0x0); 3242e9243325SFrançois Tigeot I915_WRITE16(IIR, I915_READ16(IIR)); 3243e9243325SFrançois Tigeot } 3244e9243325SFrançois Tigeot 3245e9243325SFrançois Tigeot static void i915_irq_preinstall(struct drm_device * dev) 3246e9243325SFrançois Tigeot { 3247e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3248e9243325SFrançois Tigeot int pipe; 3249e9243325SFrançois Tigeot 3250e9243325SFrançois Tigeot atomic_set(&dev_priv->irq_received, 0); 3251e9243325SFrançois Tigeot 3252e9243325SFrançois Tigeot if (I915_HAS_HOTPLUG(dev)) { 3253e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, 0); 3254e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 3255e9243325SFrançois Tigeot } 3256e9243325SFrançois Tigeot 3257e9243325SFrançois Tigeot I915_WRITE16(HWSTAM, 0xeffe); 3258e9243325SFrançois Tigeot for_each_pipe(pipe) 3259e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 3260e9243325SFrançois Tigeot I915_WRITE(IMR, 0xffffffff); 3261e9243325SFrançois Tigeot I915_WRITE(IER, 0x0); 3262e9243325SFrançois Tigeot POSTING_READ(IER); 3263e9243325SFrançois Tigeot } 3264e9243325SFrançois Tigeot 3265e9243325SFrançois Tigeot static int i915_irq_postinstall(struct drm_device *dev) 3266e9243325SFrançois Tigeot { 3267e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3268e9243325SFrançois Tigeot u32 enable_mask; 3269e9243325SFrançois Tigeot 3270e9243325SFrançois Tigeot I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); 3271e9243325SFrançois Tigeot 3272e9243325SFrançois Tigeot /* Unmask the interrupts that we always want on. */ 3273e9243325SFrançois Tigeot dev_priv->irq_mask = 3274e9243325SFrançois Tigeot ~(I915_ASLE_INTERRUPT | 3275e9243325SFrançois Tigeot I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 3276e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 3277e9243325SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 3278e9243325SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | 3279e9243325SFrançois Tigeot I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 3280e9243325SFrançois Tigeot 3281e9243325SFrançois Tigeot enable_mask = 3282e9243325SFrançois Tigeot I915_ASLE_INTERRUPT | 3283e9243325SFrançois Tigeot I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 3284e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 3285e9243325SFrançois Tigeot I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | 3286e9243325SFrançois Tigeot I915_USER_INTERRUPT; 3287e9243325SFrançois Tigeot 3288e9243325SFrançois Tigeot if (I915_HAS_HOTPLUG(dev)) { 3289a2fdbec6SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, 0); 3290a2fdbec6SFrançois Tigeot POSTING_READ(PORT_HOTPLUG_EN); 3291a2fdbec6SFrançois Tigeot 3292e9243325SFrançois Tigeot /* Enable in IER... */ 3293e9243325SFrançois Tigeot enable_mask |= I915_DISPLAY_PORT_INTERRUPT; 3294e9243325SFrançois Tigeot /* and unmask in IMR */ 3295e9243325SFrançois Tigeot dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT; 3296e9243325SFrançois Tigeot } 3297e9243325SFrançois Tigeot 3298e9243325SFrançois Tigeot I915_WRITE(IMR, dev_priv->irq_mask); 3299e9243325SFrançois Tigeot I915_WRITE(IER, enable_mask); 3300e9243325SFrançois Tigeot POSTING_READ(IER); 3301e9243325SFrançois Tigeot 33025d0b1887SFrançois Tigeot i915_enable_asle_pipestat(dev); 3303e9243325SFrançois Tigeot 3304*9edbd4a0SFrançois Tigeot /* Interrupt setup is already guaranteed to be single-threaded, this is 3305*9edbd4a0SFrançois Tigeot * just to make the assert_spin_locked check happy. */ 3306*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3307*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE); 3308*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE); 3309*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3310*9edbd4a0SFrançois Tigeot 3311a2fdbec6SFrançois Tigeot return 0; 3312a2fdbec6SFrançois Tigeot } 3313a2fdbec6SFrançois Tigeot 33148e26cdf6SFrançois Tigeot /* 33158e26cdf6SFrançois Tigeot * Returns true when a page flip has completed. 33168e26cdf6SFrançois Tigeot */ 33178e26cdf6SFrançois Tigeot static bool i915_handle_vblank(struct drm_device *dev, 33188e26cdf6SFrançois Tigeot int plane, int pipe, u32 iir) 3319a2fdbec6SFrançois Tigeot { 33208e26cdf6SFrançois Tigeot drm_i915_private_t *dev_priv = dev->dev_private; 33218e26cdf6SFrançois Tigeot u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); 3322a2fdbec6SFrançois Tigeot 33238e26cdf6SFrançois Tigeot if (!drm_handle_vblank(dev, pipe)) 33248e26cdf6SFrançois Tigeot return false; 3325a2fdbec6SFrançois Tigeot 33268e26cdf6SFrançois Tigeot if ((iir & flip_pending) == 0) 33278e26cdf6SFrançois Tigeot return false; 3328e9243325SFrançois Tigeot 33298e26cdf6SFrançois Tigeot intel_prepare_page_flip(dev, plane); 3330e9243325SFrançois Tigeot 33318e26cdf6SFrançois Tigeot /* We detect FlipDone by looking for the change in PendingFlip from '1' 33328e26cdf6SFrançois Tigeot * to '0' on the following vblank, i.e. IIR has the Pendingflip 33338e26cdf6SFrançois Tigeot * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence 33348e26cdf6SFrançois Tigeot * the flip is completed (no longer pending). Since this doesn't raise 33358e26cdf6SFrançois Tigeot * an interrupt per se, we watch for the change at vblank. 33368e26cdf6SFrançois Tigeot */ 33378e26cdf6SFrançois Tigeot if (I915_READ(ISR) & flip_pending) 33388e26cdf6SFrançois Tigeot return false; 33398e26cdf6SFrançois Tigeot 33408e26cdf6SFrançois Tigeot intel_finish_page_flip(dev, pipe); 33418e26cdf6SFrançois Tigeot 33428e26cdf6SFrançois Tigeot return true; 3343e9243325SFrançois Tigeot } 3344e9243325SFrançois Tigeot 3345e9243325SFrançois Tigeot static irqreturn_t i915_irq_handler(void *arg) 3346e9243325SFrançois Tigeot { 3347e9243325SFrançois Tigeot struct drm_device *dev = (struct drm_device *) arg; 3348e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3349e9243325SFrançois Tigeot u32 iir, new_iir, pipe_stats[I915_MAX_PIPES]; 3350e9243325SFrançois Tigeot u32 flip_mask = 3351e9243325SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 3352e9243325SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 3353e9243325SFrançois Tigeot int pipe; 3354e9243325SFrançois Tigeot 3355e9243325SFrançois Tigeot atomic_inc(&dev_priv->irq_received); 3356e9243325SFrançois Tigeot 3357e9243325SFrançois Tigeot iir = I915_READ(IIR); 3358e9243325SFrançois Tigeot do { 3359e9243325SFrançois Tigeot bool irq_received = (iir & ~flip_mask) != 0; 3360e9243325SFrançois Tigeot bool blc_event = false; 3361e9243325SFrançois Tigeot 3362e9243325SFrançois Tigeot /* Can't rely on pipestat interrupt bit in iir as it might 3363e9243325SFrançois Tigeot * have been cleared after the pipestat interrupt was received. 3364e9243325SFrançois Tigeot * It doesn't set the bit in iir again, but it still produces 3365e9243325SFrançois Tigeot * interrupts (for non-MSI). 3366e9243325SFrançois Tigeot */ 3367e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3368e9243325SFrançois Tigeot if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) 3369e9243325SFrançois Tigeot i915_handle_error(dev, false); 3370e9243325SFrançois Tigeot 3371e9243325SFrançois Tigeot for_each_pipe(pipe) { 3372e9243325SFrançois Tigeot int reg = PIPESTAT(pipe); 3373e9243325SFrançois Tigeot pipe_stats[pipe] = I915_READ(reg); 3374e9243325SFrançois Tigeot 3375e9243325SFrançois Tigeot /* Clear the PIPE*STAT regs before the IIR */ 3376e9243325SFrançois Tigeot if (pipe_stats[pipe] & 0x8000ffff) { 3377e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 3378e9243325SFrançois Tigeot DRM_DEBUG_DRIVER("pipe %c underrun\n", 3379e9243325SFrançois Tigeot pipe_name(pipe)); 3380e9243325SFrançois Tigeot I915_WRITE(reg, pipe_stats[pipe]); 3381e9243325SFrançois Tigeot irq_received = true; 3382e9243325SFrançois Tigeot } 3383e9243325SFrançois Tigeot } 3384e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3385e9243325SFrançois Tigeot 3386e9243325SFrançois Tigeot if (!irq_received) 3387e9243325SFrançois Tigeot break; 3388e9243325SFrançois Tigeot 3389e9243325SFrançois Tigeot /* Consume port. Then clear IIR or we'll miss events */ 3390e9243325SFrançois Tigeot if ((I915_HAS_HOTPLUG(dev)) && 3391e9243325SFrançois Tigeot (iir & I915_DISPLAY_PORT_INTERRUPT)) { 3392e9243325SFrançois Tigeot u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); 33938e26cdf6SFrançois Tigeot u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; 3394e9243325SFrançois Tigeot 3395e9243325SFrançois Tigeot DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", 3396e9243325SFrançois Tigeot hotplug_status); 33975d0b1887SFrançois Tigeot 33985d0b1887SFrançois Tigeot intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); 33995d0b1887SFrançois Tigeot 3400e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); 3401e9243325SFrançois Tigeot POSTING_READ(PORT_HOTPLUG_STAT); 3402e9243325SFrançois Tigeot } 3403e9243325SFrançois Tigeot 3404e9243325SFrançois Tigeot I915_WRITE(IIR, iir & ~flip_mask); 3405e9243325SFrançois Tigeot new_iir = I915_READ(IIR); /* Flush posted writes */ 3406e9243325SFrançois Tigeot 3407e9243325SFrançois Tigeot if (iir & I915_USER_INTERRUPT) 3408e9243325SFrançois Tigeot notify_ring(dev, &dev_priv->ring[RCS]); 3409e9243325SFrançois Tigeot 3410e9243325SFrançois Tigeot for_each_pipe(pipe) { 3411e9243325SFrançois Tigeot int plane = pipe; 3412*9edbd4a0SFrançois Tigeot if (HAS_FBC(dev)) 3413e9243325SFrançois Tigeot plane = !plane; 34148e26cdf6SFrançois Tigeot 3415e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && 34168e26cdf6SFrançois Tigeot i915_handle_vblank(dev, plane, pipe, iir)) 34178e26cdf6SFrançois Tigeot flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); 3418e9243325SFrançois Tigeot 3419e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) 3420e9243325SFrançois Tigeot blc_event = true; 3421*9edbd4a0SFrançois Tigeot 3422*9edbd4a0SFrançois Tigeot if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) 3423*9edbd4a0SFrançois Tigeot i9xx_pipe_crc_irq_handler(dev, pipe); 3424e9243325SFrançois Tigeot } 3425e9243325SFrançois Tigeot 3426e9243325SFrançois Tigeot if (blc_event || (iir & I915_ASLE_INTERRUPT)) 3427e9243325SFrançois Tigeot intel_opregion_asle_intr(dev); 3428e9243325SFrançois Tigeot 3429e9243325SFrançois Tigeot /* With MSI, interrupts are only generated when iir 3430e9243325SFrançois Tigeot * transitions from zero to nonzero. If another bit got 3431e9243325SFrançois Tigeot * set while we were handling the existing iir bits, then 3432e9243325SFrançois Tigeot * we would never get another interrupt. 3433e9243325SFrançois Tigeot * 3434e9243325SFrançois Tigeot * This is fine on non-MSI as well, as if we hit this path 3435e9243325SFrançois Tigeot * we avoid exiting the interrupt handler only to generate 3436e9243325SFrançois Tigeot * another one. 3437e9243325SFrançois Tigeot * 3438e9243325SFrançois Tigeot * Note that for MSI this could cause a stray interrupt report 3439e9243325SFrançois Tigeot * if an interrupt landed in the time between writing IIR and 3440e9243325SFrançois Tigeot * the posting read. This should be rare enough to never 3441e9243325SFrançois Tigeot * trigger the 99% of 100,000 interrupts test for disabling 3442e9243325SFrançois Tigeot * stray interrupts. 3443e9243325SFrançois Tigeot */ 3444e9243325SFrançois Tigeot iir = new_iir; 3445e9243325SFrançois Tigeot } while (iir & ~flip_mask); 3446e9243325SFrançois Tigeot 3447e9243325SFrançois Tigeot i915_update_dri1_breadcrumb(dev); 3448*9edbd4a0SFrançois Tigeot 3449e9243325SFrançois Tigeot } 3450e9243325SFrançois Tigeot 3451e9243325SFrançois Tigeot static void i915_irq_uninstall(struct drm_device * dev) 3452e9243325SFrançois Tigeot { 3453e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3454e9243325SFrançois Tigeot int pipe; 3455e9243325SFrançois Tigeot 34568e26cdf6SFrançois Tigeot del_timer_sync(&dev_priv->hotplug_reenable_timer); 34578e26cdf6SFrançois Tigeot 3458e9243325SFrançois Tigeot if (I915_HAS_HOTPLUG(dev)) { 3459e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, 0); 3460e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 3461e9243325SFrançois Tigeot } 3462e9243325SFrançois Tigeot 3463e9243325SFrançois Tigeot I915_WRITE16(HWSTAM, 0xffff); 3464e9243325SFrançois Tigeot for_each_pipe(pipe) { 3465e9243325SFrançois Tigeot /* Clear enable bits; then clear status bits */ 3466e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 3467e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe))); 3468e9243325SFrançois Tigeot } 3469e9243325SFrançois Tigeot I915_WRITE(IMR, 0xffffffff); 3470e9243325SFrançois Tigeot I915_WRITE(IER, 0x0); 3471e9243325SFrançois Tigeot 3472e9243325SFrançois Tigeot I915_WRITE(IIR, I915_READ(IIR)); 3473e9243325SFrançois Tigeot } 3474e9243325SFrançois Tigeot 3475e9243325SFrançois Tigeot static void i965_irq_preinstall(struct drm_device * dev) 3476e9243325SFrançois Tigeot { 3477e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3478e9243325SFrançois Tigeot int pipe; 3479e9243325SFrançois Tigeot 3480e9243325SFrançois Tigeot atomic_set(&dev_priv->irq_received, 0); 3481e9243325SFrançois Tigeot 3482e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, 0); 3483e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 3484e9243325SFrançois Tigeot 3485e9243325SFrançois Tigeot I915_WRITE(HWSTAM, 0xeffe); 3486e9243325SFrançois Tigeot for_each_pipe(pipe) 3487e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 3488e9243325SFrançois Tigeot I915_WRITE(IMR, 0xffffffff); 3489e9243325SFrançois Tigeot I915_WRITE(IER, 0x0); 3490e9243325SFrançois Tigeot POSTING_READ(IER); 3491e9243325SFrançois Tigeot } 3492e9243325SFrançois Tigeot 3493e9243325SFrançois Tigeot static int i965_irq_postinstall(struct drm_device *dev) 3494e9243325SFrançois Tigeot { 3495e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3496e9243325SFrançois Tigeot u32 enable_mask; 3497e9243325SFrançois Tigeot u32 error_mask; 3498e9243325SFrançois Tigeot 3499e9243325SFrançois Tigeot /* Unmask the interrupts that we always want on. */ 3500e9243325SFrançois Tigeot dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT | 3501e9243325SFrançois Tigeot I915_DISPLAY_PORT_INTERRUPT | 3502e9243325SFrançois Tigeot I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 3503e9243325SFrançois Tigeot I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 3504e9243325SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 3505e9243325SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | 3506e9243325SFrançois Tigeot I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 3507e9243325SFrançois Tigeot 3508e9243325SFrançois Tigeot enable_mask = ~dev_priv->irq_mask; 35098e26cdf6SFrançois Tigeot enable_mask &= ~(I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 35108e26cdf6SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); 3511e9243325SFrançois Tigeot enable_mask |= I915_USER_INTERRUPT; 3512e9243325SFrançois Tigeot 3513e9243325SFrançois Tigeot if (IS_G4X(dev)) 3514e9243325SFrançois Tigeot enable_mask |= I915_BSD_USER_INTERRUPT; 3515e9243325SFrançois Tigeot 3516*9edbd4a0SFrançois Tigeot /* Interrupt setup is already guaranteed to be single-threaded, this is 3517*9edbd4a0SFrançois Tigeot * just to make the assert_spin_locked check happy. */ 3518*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3519*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE); 3520*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE); 3521*9edbd4a0SFrançois Tigeot i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE); 3522*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3523e9243325SFrançois Tigeot 3524e9243325SFrançois Tigeot /* 3525e9243325SFrançois Tigeot * Enable some error detection, note the instruction error mask 3526e9243325SFrançois Tigeot * bit is reserved, so we leave it masked. 3527e9243325SFrançois Tigeot */ 3528e9243325SFrançois Tigeot if (IS_G4X(dev)) { 3529e9243325SFrançois Tigeot error_mask = ~(GM45_ERROR_PAGE_TABLE | 3530e9243325SFrançois Tigeot GM45_ERROR_MEM_PRIV | 3531e9243325SFrançois Tigeot GM45_ERROR_CP_PRIV | 3532e9243325SFrançois Tigeot I915_ERROR_MEMORY_REFRESH); 3533e9243325SFrançois Tigeot } else { 3534e9243325SFrançois Tigeot error_mask = ~(I915_ERROR_PAGE_TABLE | 3535e9243325SFrançois Tigeot I915_ERROR_MEMORY_REFRESH); 3536e9243325SFrançois Tigeot } 3537e9243325SFrançois Tigeot I915_WRITE(EMR, error_mask); 3538e9243325SFrançois Tigeot 3539e9243325SFrançois Tigeot I915_WRITE(IMR, dev_priv->irq_mask); 3540e9243325SFrançois Tigeot I915_WRITE(IER, enable_mask); 3541e9243325SFrançois Tigeot POSTING_READ(IER); 3542e9243325SFrançois Tigeot 3543a2fdbec6SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, 0); 3544a2fdbec6SFrançois Tigeot POSTING_READ(PORT_HOTPLUG_EN); 3545a2fdbec6SFrançois Tigeot 35465d0b1887SFrançois Tigeot i915_enable_asle_pipestat(dev); 3547a2fdbec6SFrançois Tigeot 3548a2fdbec6SFrançois Tigeot return 0; 3549a2fdbec6SFrançois Tigeot } 3550a2fdbec6SFrançois Tigeot 35518e26cdf6SFrançois Tigeot static void i915_hpd_irq_setup(struct drm_device *dev) 3552a2fdbec6SFrançois Tigeot { 3553a2fdbec6SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 35548e26cdf6SFrançois Tigeot struct drm_mode_config *mode_config = &dev->mode_config; 35558e26cdf6SFrançois Tigeot struct intel_encoder *intel_encoder; 3556a2fdbec6SFrançois Tigeot u32 hotplug_en; 3557a2fdbec6SFrançois Tigeot 3558*9edbd4a0SFrançois Tigeot assert_spin_locked(&dev_priv->irq_lock); 3559*9edbd4a0SFrançois Tigeot 35608e26cdf6SFrançois Tigeot if (I915_HAS_HOTPLUG(dev)) { 35618e26cdf6SFrançois Tigeot hotplug_en = I915_READ(PORT_HOTPLUG_EN); 35628e26cdf6SFrançois Tigeot hotplug_en &= ~HOTPLUG_INT_EN_MASK; 3563e9243325SFrançois Tigeot /* Note HDMI and DP share hotplug bits */ 35648e26cdf6SFrançois Tigeot /* enable bits are the same for all generations */ 35658e26cdf6SFrançois Tigeot list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) 35668e26cdf6SFrançois Tigeot if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) 35678e26cdf6SFrançois Tigeot hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin]; 3568e9243325SFrançois Tigeot /* Programming the CRT detection parameters tends 3569e9243325SFrançois Tigeot to generate a spurious hotplug event about three 3570e9243325SFrançois Tigeot seconds later. So just do it once. 3571e9243325SFrançois Tigeot */ 3572e9243325SFrançois Tigeot if (IS_G4X(dev)) 3573e9243325SFrançois Tigeot hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; 35748e26cdf6SFrançois Tigeot hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK; 3575e9243325SFrançois Tigeot hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; 3576e9243325SFrançois Tigeot 3577e9243325SFrançois Tigeot /* Ignore TV since it's buggy */ 3578e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 3579e9243325SFrançois Tigeot } 35808e26cdf6SFrançois Tigeot } 3581e9243325SFrançois Tigeot 358200640ec9SFrançois Tigeot static irqreturn_t i965_irq_handler(void *arg) 3583e9243325SFrançois Tigeot { 3584e9243325SFrançois Tigeot struct drm_device *dev = (struct drm_device *) arg; 3585e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3586e9243325SFrançois Tigeot u32 iir, new_iir; 3587e9243325SFrançois Tigeot u32 pipe_stats[I915_MAX_PIPES]; 3588e9243325SFrançois Tigeot int irq_received; 3589e9243325SFrançois Tigeot int pipe; 35908e26cdf6SFrançois Tigeot u32 flip_mask = 35918e26cdf6SFrançois Tigeot I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 35928e26cdf6SFrançois Tigeot I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 3593e9243325SFrançois Tigeot 3594e9243325SFrançois Tigeot atomic_inc(&dev_priv->irq_received); 3595e9243325SFrançois Tigeot 3596e9243325SFrançois Tigeot iir = I915_READ(IIR); 3597e9243325SFrançois Tigeot 3598e9243325SFrançois Tigeot for (;;) { 3599e9243325SFrançois Tigeot bool blc_event = false; 3600e9243325SFrançois Tigeot 36018e26cdf6SFrançois Tigeot irq_received = (iir & ~flip_mask) != 0; 3602e9243325SFrançois Tigeot 3603e9243325SFrançois Tigeot /* Can't rely on pipestat interrupt bit in iir as it might 3604e9243325SFrançois Tigeot * have been cleared after the pipestat interrupt was received. 3605e9243325SFrançois Tigeot * It doesn't set the bit in iir again, but it still produces 3606e9243325SFrançois Tigeot * interrupts (for non-MSI). 3607e9243325SFrançois Tigeot */ 3608e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3609e9243325SFrançois Tigeot if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) 3610e9243325SFrançois Tigeot i915_handle_error(dev, false); 3611e9243325SFrançois Tigeot 3612e9243325SFrançois Tigeot for_each_pipe(pipe) { 3613e9243325SFrançois Tigeot int reg = PIPESTAT(pipe); 3614e9243325SFrançois Tigeot pipe_stats[pipe] = I915_READ(reg); 3615e9243325SFrançois Tigeot 3616e9243325SFrançois Tigeot /* 3617e9243325SFrançois Tigeot * Clear the PIPE*STAT regs before the IIR 3618e9243325SFrançois Tigeot */ 3619e9243325SFrançois Tigeot if (pipe_stats[pipe] & 0x8000ffff) { 3620e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 3621e9243325SFrançois Tigeot DRM_DEBUG_DRIVER("pipe %c underrun\n", 3622e9243325SFrançois Tigeot pipe_name(pipe)); 3623e9243325SFrançois Tigeot I915_WRITE(reg, pipe_stats[pipe]); 3624e9243325SFrançois Tigeot irq_received = 1; 3625e9243325SFrançois Tigeot } 3626e9243325SFrançois Tigeot } 3627e9243325SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3628e9243325SFrançois Tigeot 3629e9243325SFrançois Tigeot if (!irq_received) 3630e9243325SFrançois Tigeot break; 3631e9243325SFrançois Tigeot 3632*9edbd4a0SFrançois Tigeot 3633e9243325SFrançois Tigeot /* Consume port. Then clear IIR or we'll miss events */ 3634e9243325SFrançois Tigeot if (iir & I915_DISPLAY_PORT_INTERRUPT) { 3635e9243325SFrançois Tigeot u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); 36368e26cdf6SFrançois Tigeot u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ? 36378e26cdf6SFrançois Tigeot HOTPLUG_INT_STATUS_G4X : 36385d0b1887SFrançois Tigeot HOTPLUG_INT_STATUS_I915); 3639e9243325SFrançois Tigeot 3640e9243325SFrançois Tigeot DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", 3641e9243325SFrançois Tigeot hotplug_status); 36425d0b1887SFrançois Tigeot 36435d0b1887SFrançois Tigeot intel_hpd_irq_handler(dev, hotplug_trigger, 3644*9edbd4a0SFrançois Tigeot IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915); 3645*9edbd4a0SFrançois Tigeot 3646*9edbd4a0SFrançois Tigeot if (IS_G4X(dev) && 3647*9edbd4a0SFrançois Tigeot (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)) 3648*9edbd4a0SFrançois Tigeot dp_aux_irq_handler(dev); 36495d0b1887SFrançois Tigeot 3650e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); 3651e9243325SFrançois Tigeot I915_READ(PORT_HOTPLUG_STAT); 3652e9243325SFrançois Tigeot } 3653e9243325SFrançois Tigeot 36548e26cdf6SFrançois Tigeot I915_WRITE(IIR, iir & ~flip_mask); 3655e9243325SFrançois Tigeot new_iir = I915_READ(IIR); /* Flush posted writes */ 3656e9243325SFrançois Tigeot 3657e9243325SFrançois Tigeot if (iir & I915_USER_INTERRUPT) 3658e9243325SFrançois Tigeot notify_ring(dev, &dev_priv->ring[RCS]); 3659e9243325SFrançois Tigeot if (iir & I915_BSD_USER_INTERRUPT) 3660e9243325SFrançois Tigeot notify_ring(dev, &dev_priv->ring[VCS]); 3661e9243325SFrançois Tigeot 3662e9243325SFrançois Tigeot for_each_pipe(pipe) { 3663e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && 36648e26cdf6SFrançois Tigeot i915_handle_vblank(dev, pipe, pipe, iir)) 36658e26cdf6SFrançois Tigeot flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe); 3666e9243325SFrançois Tigeot 3667e9243325SFrançois Tigeot if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) 3668e9243325SFrançois Tigeot blc_event = true; 3669*9edbd4a0SFrançois Tigeot 3670*9edbd4a0SFrançois Tigeot if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) 3671*9edbd4a0SFrançois Tigeot i9xx_pipe_crc_irq_handler(dev, pipe); 3672e9243325SFrançois Tigeot } 3673e9243325SFrançois Tigeot 3674*9edbd4a0SFrançois Tigeot 3675e9243325SFrançois Tigeot if (blc_event || (iir & I915_ASLE_INTERRUPT)) 3676e9243325SFrançois Tigeot intel_opregion_asle_intr(dev); 3677e9243325SFrançois Tigeot 3678a2fdbec6SFrançois Tigeot if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) 3679a2fdbec6SFrançois Tigeot gmbus_irq_handler(dev); 3680a2fdbec6SFrançois Tigeot 3681e9243325SFrançois Tigeot /* With MSI, interrupts are only generated when iir 3682e9243325SFrançois Tigeot * transitions from zero to nonzero. If another bit got 3683e9243325SFrançois Tigeot * set while we were handling the existing iir bits, then 3684e9243325SFrançois Tigeot * we would never get another interrupt. 3685e9243325SFrançois Tigeot * 3686e9243325SFrançois Tigeot * This is fine on non-MSI as well, as if we hit this path 3687e9243325SFrançois Tigeot * we avoid exiting the interrupt handler only to generate 3688e9243325SFrançois Tigeot * another one. 3689e9243325SFrançois Tigeot * 3690e9243325SFrançois Tigeot * Note that for MSI this could cause a stray interrupt report 3691e9243325SFrançois Tigeot * if an interrupt landed in the time between writing IIR and 3692e9243325SFrançois Tigeot * the posting read. This should be rare enough to never 3693e9243325SFrançois Tigeot * trigger the 99% of 100,000 interrupts test for disabling 3694e9243325SFrançois Tigeot * stray interrupts. 3695e9243325SFrançois Tigeot */ 3696e9243325SFrançois Tigeot iir = new_iir; 3697e9243325SFrançois Tigeot } 3698e9243325SFrançois Tigeot 3699e9243325SFrançois Tigeot i915_update_dri1_breadcrumb(dev); 3700*9edbd4a0SFrançois Tigeot 3701e9243325SFrançois Tigeot } 3702e9243325SFrançois Tigeot 3703e9243325SFrançois Tigeot static void i965_irq_uninstall(struct drm_device * dev) 3704e9243325SFrançois Tigeot { 3705e9243325SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 3706e9243325SFrançois Tigeot int pipe; 3707e9243325SFrançois Tigeot 3708e9243325SFrançois Tigeot if (!dev_priv) 3709e9243325SFrançois Tigeot return; 3710e9243325SFrançois Tigeot 37118e26cdf6SFrançois Tigeot del_timer_sync(&dev_priv->hotplug_reenable_timer); 37128e26cdf6SFrançois Tigeot 3713e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_EN, 0); 3714e9243325SFrançois Tigeot I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 3715e9243325SFrançois Tigeot 3716e9243325SFrançois Tigeot I915_WRITE(HWSTAM, 0xffffffff); 3717e9243325SFrançois Tigeot for_each_pipe(pipe) 3718e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 0); 3719e9243325SFrançois Tigeot I915_WRITE(IMR, 0xffffffff); 3720e9243325SFrançois Tigeot I915_WRITE(IER, 0x0); 3721e9243325SFrançois Tigeot 3722e9243325SFrançois Tigeot for_each_pipe(pipe) 3723e9243325SFrançois Tigeot I915_WRITE(PIPESTAT(pipe), 3724e9243325SFrançois Tigeot I915_READ(PIPESTAT(pipe)) & 0x8000ffff); 3725e9243325SFrançois Tigeot I915_WRITE(IIR, I915_READ(IIR)); 3726e9243325SFrançois Tigeot } 3727e9243325SFrançois Tigeot 37288e26cdf6SFrançois Tigeot static void i915_reenable_hotplug_timer_func(unsigned long data) 37298e26cdf6SFrançois Tigeot { 37308e26cdf6SFrançois Tigeot drm_i915_private_t *dev_priv = (drm_i915_private_t *)data; 37318e26cdf6SFrançois Tigeot struct drm_device *dev = dev_priv->dev; 37328e26cdf6SFrançois Tigeot struct drm_mode_config *mode_config = &dev->mode_config; 37338e26cdf6SFrançois Tigeot int i; 37348e26cdf6SFrançois Tigeot 37358e26cdf6SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 37368e26cdf6SFrançois Tigeot for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) { 37378e26cdf6SFrançois Tigeot struct drm_connector *connector; 37388e26cdf6SFrançois Tigeot 37398e26cdf6SFrançois Tigeot if (dev_priv->hpd_stats[i].hpd_mark != HPD_DISABLED) 37408e26cdf6SFrançois Tigeot continue; 37418e26cdf6SFrançois Tigeot 37428e26cdf6SFrançois Tigeot dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; 37438e26cdf6SFrançois Tigeot 37448e26cdf6SFrançois Tigeot list_for_each_entry(connector, &mode_config->connector_list, head) { 37458e26cdf6SFrançois Tigeot struct intel_connector *intel_connector = to_intel_connector(connector); 37468e26cdf6SFrançois Tigeot 37478e26cdf6SFrançois Tigeot if (intel_connector->encoder->hpd_pin == i) { 37488e26cdf6SFrançois Tigeot if (connector->polled != intel_connector->polled) 37498e26cdf6SFrançois Tigeot DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", 37508e26cdf6SFrançois Tigeot drm_get_connector_name(connector)); 37518e26cdf6SFrançois Tigeot connector->polled = intel_connector->polled; 37528e26cdf6SFrançois Tigeot if (!connector->polled) 37538e26cdf6SFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_HPD; 37548e26cdf6SFrançois Tigeot } 37558e26cdf6SFrançois Tigeot } 37568e26cdf6SFrançois Tigeot } 37578e26cdf6SFrançois Tigeot if (dev_priv->display.hpd_irq_setup) 37588e26cdf6SFrançois Tigeot dev_priv->display.hpd_irq_setup(dev); 37598e26cdf6SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 37608e26cdf6SFrançois Tigeot } 37618e26cdf6SFrançois Tigeot 3762e9243325SFrançois Tigeot void intel_irq_init(struct drm_device *dev) 3763e9243325SFrançois Tigeot { 3764e9243325SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 3765e9243325SFrançois Tigeot 3766e9243325SFrançois Tigeot INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); 3767a2fdbec6SFrançois Tigeot INIT_WORK(&dev_priv->gpu_error.work, i915_error_work_func); 3768e9243325SFrançois Tigeot INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); 376900640ec9SFrançois Tigeot INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); 3770e9243325SFrançois Tigeot 3771a2fdbec6SFrançois Tigeot setup_timer(&dev_priv->gpu_error.hangcheck_timer, 3772a2fdbec6SFrançois Tigeot i915_hangcheck_elapsed, 3773a2fdbec6SFrançois Tigeot (unsigned long) dev); 37748e26cdf6SFrançois Tigeot setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func, 37758e26cdf6SFrançois Tigeot (unsigned long) dev_priv); 3776a2fdbec6SFrançois Tigeot 3777a2fdbec6SFrançois Tigeot pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); 3778a2fdbec6SFrançois Tigeot 3779*9edbd4a0SFrançois Tigeot if (IS_GEN2(dev)) { 3780*9edbd4a0SFrançois Tigeot dev->max_vblank_count = 0; 3781*9edbd4a0SFrançois Tigeot dev->driver->get_vblank_counter = i8xx_get_vblank_counter; 3782*9edbd4a0SFrançois Tigeot } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { 3783e9243325SFrançois Tigeot dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ 3784e9243325SFrançois Tigeot dev->driver->get_vblank_counter = gm45_get_vblank_counter; 3785*9edbd4a0SFrançois Tigeot } else { 3786*9edbd4a0SFrançois Tigeot dev->driver->get_vblank_counter = i915_get_vblank_counter; 3787*9edbd4a0SFrançois Tigeot dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ 3788e9243325SFrançois Tigeot } 3789e9243325SFrançois Tigeot 3790*9edbd4a0SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_MODESET)) { 3791e9243325SFrançois Tigeot dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; 3792e9243325SFrançois Tigeot dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; 3793*9edbd4a0SFrançois Tigeot } 3794e9243325SFrançois Tigeot 3795e9243325SFrançois Tigeot if (IS_VALLEYVIEW(dev)) { 3796e9243325SFrançois Tigeot dev->driver->irq_handler = valleyview_irq_handler; 3797e9243325SFrançois Tigeot dev->driver->irq_preinstall = valleyview_irq_preinstall; 3798e9243325SFrançois Tigeot dev->driver->irq_postinstall = valleyview_irq_postinstall; 3799e9243325SFrançois Tigeot dev->driver->irq_uninstall = valleyview_irq_uninstall; 3800e9243325SFrançois Tigeot dev->driver->enable_vblank = valleyview_enable_vblank; 3801e9243325SFrançois Tigeot dev->driver->disable_vblank = valleyview_disable_vblank; 38028e26cdf6SFrançois Tigeot dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; 3803*9edbd4a0SFrançois Tigeot } else if (IS_GEN8(dev)) { 3804*9edbd4a0SFrançois Tigeot dev->driver->irq_handler = gen8_irq_handler; 3805*9edbd4a0SFrançois Tigeot dev->driver->irq_preinstall = gen8_irq_preinstall; 3806*9edbd4a0SFrançois Tigeot dev->driver->irq_postinstall = gen8_irq_postinstall; 3807*9edbd4a0SFrançois Tigeot dev->driver->irq_uninstall = gen8_irq_uninstall; 3808*9edbd4a0SFrançois Tigeot dev->driver->enable_vblank = gen8_enable_vblank; 3809*9edbd4a0SFrançois Tigeot dev->driver->disable_vblank = gen8_disable_vblank; 38108e26cdf6SFrançois Tigeot dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; 3811e9243325SFrançois Tigeot } else if (HAS_PCH_SPLIT(dev)) { 3812e9243325SFrançois Tigeot dev->driver->irq_handler = ironlake_irq_handler; 3813e9243325SFrançois Tigeot dev->driver->irq_preinstall = ironlake_irq_preinstall; 3814e9243325SFrançois Tigeot dev->driver->irq_postinstall = ironlake_irq_postinstall; 3815e9243325SFrançois Tigeot dev->driver->irq_uninstall = ironlake_irq_uninstall; 3816e9243325SFrançois Tigeot dev->driver->enable_vblank = ironlake_enable_vblank; 3817e9243325SFrançois Tigeot dev->driver->disable_vblank = ironlake_disable_vblank; 38188e26cdf6SFrançois Tigeot dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; 3819e9243325SFrançois Tigeot } else { 3820e9243325SFrançois Tigeot if (INTEL_INFO(dev)->gen == 2) { 3821e9243325SFrançois Tigeot dev->driver->irq_preinstall = i8xx_irq_preinstall; 3822e9243325SFrançois Tigeot dev->driver->irq_postinstall = i8xx_irq_postinstall; 3823e9243325SFrançois Tigeot dev->driver->irq_handler = i8xx_irq_handler; 3824e9243325SFrançois Tigeot dev->driver->irq_uninstall = i8xx_irq_uninstall; 3825e9243325SFrançois Tigeot } else if (INTEL_INFO(dev)->gen == 3) { 3826e9243325SFrançois Tigeot dev->driver->irq_preinstall = i915_irq_preinstall; 3827e9243325SFrançois Tigeot dev->driver->irq_postinstall = i915_irq_postinstall; 3828e9243325SFrançois Tigeot dev->driver->irq_uninstall = i915_irq_uninstall; 3829e9243325SFrançois Tigeot dev->driver->irq_handler = i915_irq_handler; 3830a2fdbec6SFrançois Tigeot dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; 3831e9243325SFrançois Tigeot } else { 3832e9243325SFrançois Tigeot dev->driver->irq_preinstall = i965_irq_preinstall; 3833e9243325SFrançois Tigeot dev->driver->irq_postinstall = i965_irq_postinstall; 3834e9243325SFrançois Tigeot dev->driver->irq_uninstall = i965_irq_uninstall; 3835e9243325SFrançois Tigeot dev->driver->irq_handler = i965_irq_handler; 38368e26cdf6SFrançois Tigeot dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; 3837e9243325SFrançois Tigeot } 3838e9243325SFrançois Tigeot dev->driver->enable_vblank = i915_enable_vblank; 3839e9243325SFrançois Tigeot dev->driver->disable_vblank = i915_disable_vblank; 3840e9243325SFrançois Tigeot } 3841e9243325SFrançois Tigeot } 3842a2fdbec6SFrançois Tigeot 3843a2fdbec6SFrançois Tigeot void intel_hpd_init(struct drm_device *dev) 3844a2fdbec6SFrançois Tigeot { 3845a2fdbec6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 38468e26cdf6SFrançois Tigeot struct drm_mode_config *mode_config = &dev->mode_config; 38478e26cdf6SFrançois Tigeot struct drm_connector *connector; 38488e26cdf6SFrançois Tigeot int i; 3849a2fdbec6SFrançois Tigeot 38508e26cdf6SFrançois Tigeot for (i = 1; i < HPD_NUM_PINS; i++) { 38518e26cdf6SFrançois Tigeot dev_priv->hpd_stats[i].hpd_cnt = 0; 38528e26cdf6SFrançois Tigeot dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; 38538e26cdf6SFrançois Tigeot } 38548e26cdf6SFrançois Tigeot list_for_each_entry(connector, &mode_config->connector_list, head) { 38558e26cdf6SFrançois Tigeot struct intel_connector *intel_connector = to_intel_connector(connector); 38568e26cdf6SFrançois Tigeot connector->polled = intel_connector->polled; 38578e26cdf6SFrançois Tigeot if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) 38588e26cdf6SFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_HPD; 38598e26cdf6SFrançois Tigeot } 38605d0b1887SFrançois Tigeot 38615d0b1887SFrançois Tigeot /* Interrupt setup is already guaranteed to be single-threaded, this is 38625d0b1887SFrançois Tigeot * just to make the assert_spin_locked checks happy. */ 38635d0b1887SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3864a2fdbec6SFrançois Tigeot if (dev_priv->display.hpd_irq_setup) 3865a2fdbec6SFrançois Tigeot dev_priv->display.hpd_irq_setup(dev); 38665d0b1887SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3867a2fdbec6SFrançois Tigeot } 3868*9edbd4a0SFrançois Tigeot 3869*9edbd4a0SFrançois Tigeot /* Disable interrupts so we can allow Package C8+. */ 3870*9edbd4a0SFrançois Tigeot void hsw_pc8_disable_interrupts(struct drm_device *dev) 3871*9edbd4a0SFrançois Tigeot { 3872*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 3873*9edbd4a0SFrançois Tigeot 3874*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3875*9edbd4a0SFrançois Tigeot 3876*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.deimr = I915_READ(DEIMR); 3877*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.sdeimr = I915_READ(SDEIMR); 3878*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.gtimr = I915_READ(GTIMR); 3879*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.gtier = I915_READ(GTIER); 3880*9edbd4a0SFrançois Tigeot dev_priv->pc8.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR); 3881*9edbd4a0SFrançois Tigeot 3882*9edbd4a0SFrançois Tigeot ironlake_disable_display_irq(dev_priv, 0xffffffff); 3883*9edbd4a0SFrançois Tigeot ibx_disable_display_interrupt(dev_priv, 0xffffffff); 3884*9edbd4a0SFrançois Tigeot ilk_disable_gt_irq(dev_priv, 0xffffffff); 3885*9edbd4a0SFrançois Tigeot snb_disable_pm_irq(dev_priv, 0xffffffff); 3886*9edbd4a0SFrançois Tigeot 3887*9edbd4a0SFrançois Tigeot dev_priv->pc8.irqs_disabled = true; 3888*9edbd4a0SFrançois Tigeot 3889*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3890*9edbd4a0SFrançois Tigeot } 3891*9edbd4a0SFrançois Tigeot 3892*9edbd4a0SFrançois Tigeot /* Restore interrupts so we can recover from Package C8+. */ 3893*9edbd4a0SFrançois Tigeot void hsw_pc8_restore_interrupts(struct drm_device *dev) 3894*9edbd4a0SFrançois Tigeot { 3895*9edbd4a0SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 3896*9edbd4a0SFrançois Tigeot uint32_t val; 3897*9edbd4a0SFrançois Tigeot 3898*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE); 3899*9edbd4a0SFrançois Tigeot 3900*9edbd4a0SFrançois Tigeot val = I915_READ(DEIMR); 3901*9edbd4a0SFrançois Tigeot WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val); 3902*9edbd4a0SFrançois Tigeot 3903*9edbd4a0SFrançois Tigeot val = I915_READ(SDEIMR); 3904*9edbd4a0SFrançois Tigeot WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val); 3905*9edbd4a0SFrançois Tigeot 3906*9edbd4a0SFrançois Tigeot val = I915_READ(GTIMR); 3907*9edbd4a0SFrançois Tigeot WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val); 3908*9edbd4a0SFrançois Tigeot 3909*9edbd4a0SFrançois Tigeot val = I915_READ(GEN6_PMIMR); 3910*9edbd4a0SFrançois Tigeot WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val); 3911*9edbd4a0SFrançois Tigeot 3912*9edbd4a0SFrançois Tigeot dev_priv->pc8.irqs_disabled = false; 3913*9edbd4a0SFrançois Tigeot 3914*9edbd4a0SFrançois Tigeot ironlake_enable_display_irq(dev_priv, ~dev_priv->pc8.regsave.deimr); 3915*9edbd4a0SFrançois Tigeot ibx_enable_display_interrupt(dev_priv, ~dev_priv->pc8.regsave.sdeimr); 3916*9edbd4a0SFrançois Tigeot ilk_enable_gt_irq(dev_priv, ~dev_priv->pc8.regsave.gtimr); 3917*9edbd4a0SFrançois Tigeot snb_enable_pm_irq(dev_priv, ~dev_priv->pc8.regsave.gen6_pmimr); 3918*9edbd4a0SFrançois Tigeot I915_WRITE(GTIER, dev_priv->pc8.regsave.gtier); 3919*9edbd4a0SFrançois Tigeot 3920*9edbd4a0SFrançois Tigeot lockmgr(&dev_priv->irq_lock, LK_RELEASE); 3921*9edbd4a0SFrançois Tigeot } 3922