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