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