1c0e09200SDave Airlie /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*- 2c0e09200SDave Airlie */ 3c0e09200SDave Airlie /* 4c0e09200SDave Airlie * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 5c0e09200SDave Airlie * All Rights Reserved. 6c0e09200SDave Airlie * 7c0e09200SDave Airlie * Permission is hereby granted, free of charge, to any person obtaining a 8c0e09200SDave Airlie * copy of this software and associated documentation files (the 9c0e09200SDave Airlie * "Software"), to deal in the Software without restriction, including 10c0e09200SDave Airlie * without limitation the rights to use, copy, modify, merge, publish, 11c0e09200SDave Airlie * distribute, sub license, and/or sell copies of the Software, and to 12c0e09200SDave Airlie * permit persons to whom the Software is furnished to do so, subject to 13c0e09200SDave Airlie * the following conditions: 14c0e09200SDave Airlie * 15c0e09200SDave Airlie * The above copyright notice and this permission notice (including the 16c0e09200SDave Airlie * next paragraph) shall be included in all copies or substantial portions 17c0e09200SDave Airlie * of the Software. 18c0e09200SDave Airlie * 19c0e09200SDave Airlie * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20c0e09200SDave Airlie * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21c0e09200SDave Airlie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22c0e09200SDave Airlie * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 23c0e09200SDave Airlie * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24c0e09200SDave Airlie * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25c0e09200SDave Airlie * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26c0e09200SDave Airlie * 27c0e09200SDave Airlie */ 28c0e09200SDave Airlie 29a70491ccSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 30a70491ccSJoe Perches 3163eeaf38SJesse Barnes #include <linux/sysrq.h> 325a0e3ad6STejun Heo #include <linux/slab.h> 33c0e09200SDave Airlie #include "drmP.h" 34c0e09200SDave Airlie #include "drm.h" 35c0e09200SDave Airlie #include "i915_drm.h" 36c0e09200SDave Airlie #include "i915_drv.h" 371c5d22f7SChris Wilson #include "i915_trace.h" 3879e53945SJesse Barnes #include "intel_drv.h" 39c0e09200SDave Airlie 40036a4a7dSZhenyu Wang /* For display hotplug interrupt */ 41995b6762SChris Wilson static void 42f2b115e6SAdam Jackson ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) 43036a4a7dSZhenyu Wang { 441ec14ad3SChris Wilson if ((dev_priv->irq_mask & mask) != 0) { 451ec14ad3SChris Wilson dev_priv->irq_mask &= ~mask; 461ec14ad3SChris Wilson I915_WRITE(DEIMR, dev_priv->irq_mask); 473143a2bfSChris Wilson POSTING_READ(DEIMR); 48036a4a7dSZhenyu Wang } 49036a4a7dSZhenyu Wang } 50036a4a7dSZhenyu Wang 51036a4a7dSZhenyu Wang static inline void 52f2b115e6SAdam Jackson ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) 53036a4a7dSZhenyu Wang { 541ec14ad3SChris Wilson if ((dev_priv->irq_mask & mask) != mask) { 551ec14ad3SChris Wilson dev_priv->irq_mask |= mask; 561ec14ad3SChris Wilson I915_WRITE(DEIMR, dev_priv->irq_mask); 573143a2bfSChris Wilson POSTING_READ(DEIMR); 58036a4a7dSZhenyu Wang } 59036a4a7dSZhenyu Wang } 60036a4a7dSZhenyu Wang 617c463586SKeith Packard void 627c463586SKeith Packard i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) 637c463586SKeith Packard { 647c463586SKeith Packard if ((dev_priv->pipestat[pipe] & mask) != mask) { 659db4a9c7SJesse Barnes u32 reg = PIPESTAT(pipe); 667c463586SKeith Packard 677c463586SKeith Packard dev_priv->pipestat[pipe] |= mask; 687c463586SKeith Packard /* Enable the interrupt, clear any pending status */ 697c463586SKeith Packard I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16)); 703143a2bfSChris Wilson POSTING_READ(reg); 717c463586SKeith Packard } 727c463586SKeith Packard } 737c463586SKeith Packard 747c463586SKeith Packard void 757c463586SKeith Packard i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) 767c463586SKeith Packard { 777c463586SKeith Packard if ((dev_priv->pipestat[pipe] & mask) != 0) { 789db4a9c7SJesse Barnes u32 reg = PIPESTAT(pipe); 797c463586SKeith Packard 807c463586SKeith Packard dev_priv->pipestat[pipe] &= ~mask; 817c463586SKeith Packard I915_WRITE(reg, dev_priv->pipestat[pipe]); 823143a2bfSChris Wilson POSTING_READ(reg); 837c463586SKeith Packard } 847c463586SKeith Packard } 857c463586SKeith Packard 86c0e09200SDave Airlie /** 8701c66889SZhao Yakui * intel_enable_asle - enable ASLE interrupt for OpRegion 8801c66889SZhao Yakui */ 8901c66889SZhao Yakui void intel_enable_asle(struct drm_device *dev) 9001c66889SZhao Yakui { 911ec14ad3SChris Wilson drm_i915_private_t *dev_priv = dev->dev_private; 921ec14ad3SChris Wilson unsigned long irqflags; 931ec14ad3SChris Wilson 947e231dbeSJesse Barnes /* FIXME: opregion/asle for VLV */ 957e231dbeSJesse Barnes if (IS_VALLEYVIEW(dev)) 967e231dbeSJesse Barnes return; 977e231dbeSJesse Barnes 981ec14ad3SChris Wilson spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 9901c66889SZhao Yakui 100c619eed4SEric Anholt if (HAS_PCH_SPLIT(dev)) 101f2b115e6SAdam Jackson ironlake_enable_display_irq(dev_priv, DE_GSE); 102edcb49caSZhao Yakui else { 10301c66889SZhao Yakui i915_enable_pipestat(dev_priv, 1, 104d874bcffSJesse Barnes PIPE_LEGACY_BLC_EVENT_ENABLE); 105a6c45cf0SChris Wilson if (INTEL_INFO(dev)->gen >= 4) 106edcb49caSZhao Yakui i915_enable_pipestat(dev_priv, 0, 107d874bcffSJesse Barnes PIPE_LEGACY_BLC_EVENT_ENABLE); 108edcb49caSZhao Yakui } 1091ec14ad3SChris Wilson 1101ec14ad3SChris Wilson spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 11101c66889SZhao Yakui } 11201c66889SZhao Yakui 11301c66889SZhao Yakui /** 1140a3e67a4SJesse Barnes * i915_pipe_enabled - check if a pipe is enabled 1150a3e67a4SJesse Barnes * @dev: DRM device 1160a3e67a4SJesse Barnes * @pipe: pipe to check 1170a3e67a4SJesse Barnes * 1180a3e67a4SJesse Barnes * Reading certain registers when the pipe is disabled can hang the chip. 1190a3e67a4SJesse Barnes * Use this routine to make sure the PLL is running and the pipe is active 1200a3e67a4SJesse Barnes * before reading such registers if unsure. 1210a3e67a4SJesse Barnes */ 1220a3e67a4SJesse Barnes static int 1230a3e67a4SJesse Barnes i915_pipe_enabled(struct drm_device *dev, int pipe) 1240a3e67a4SJesse Barnes { 1250a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1265eddb70bSChris Wilson return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE; 1270a3e67a4SJesse Barnes } 1280a3e67a4SJesse Barnes 12942f52ef8SKeith Packard /* Called from drm generic code, passed a 'crtc', which 13042f52ef8SKeith Packard * we use as a pipe index 13142f52ef8SKeith Packard */ 132f71d4af4SJesse Barnes static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) 1330a3e67a4SJesse Barnes { 1340a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1350a3e67a4SJesse Barnes unsigned long high_frame; 1360a3e67a4SJesse Barnes unsigned long low_frame; 1375eddb70bSChris Wilson u32 high1, high2, low; 1380a3e67a4SJesse Barnes 1390a3e67a4SJesse Barnes if (!i915_pipe_enabled(dev, pipe)) { 14044d98a61SZhao Yakui DRM_DEBUG_DRIVER("trying to get vblank count for disabled " 1419db4a9c7SJesse Barnes "pipe %c\n", pipe_name(pipe)); 1420a3e67a4SJesse Barnes return 0; 1430a3e67a4SJesse Barnes } 1440a3e67a4SJesse Barnes 1459db4a9c7SJesse Barnes high_frame = PIPEFRAME(pipe); 1469db4a9c7SJesse Barnes low_frame = PIPEFRAMEPIXEL(pipe); 1475eddb70bSChris Wilson 1480a3e67a4SJesse Barnes /* 1490a3e67a4SJesse Barnes * High & low register fields aren't synchronized, so make sure 1500a3e67a4SJesse Barnes * we get a low value that's stable across two reads of the high 1510a3e67a4SJesse Barnes * register. 1520a3e67a4SJesse Barnes */ 1530a3e67a4SJesse Barnes do { 1545eddb70bSChris Wilson high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; 1555eddb70bSChris Wilson low = I915_READ(low_frame) & PIPE_FRAME_LOW_MASK; 1565eddb70bSChris Wilson high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; 1570a3e67a4SJesse Barnes } while (high1 != high2); 1580a3e67a4SJesse Barnes 1595eddb70bSChris Wilson high1 >>= PIPE_FRAME_HIGH_SHIFT; 1605eddb70bSChris Wilson low >>= PIPE_FRAME_LOW_SHIFT; 1615eddb70bSChris Wilson return (high1 << 8) | low; 1620a3e67a4SJesse Barnes } 1630a3e67a4SJesse Barnes 164f71d4af4SJesse Barnes static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) 1659880b7a5SJesse Barnes { 1669880b7a5SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1679db4a9c7SJesse Barnes int reg = PIPE_FRMCOUNT_GM45(pipe); 1689880b7a5SJesse Barnes 1699880b7a5SJesse Barnes if (!i915_pipe_enabled(dev, pipe)) { 17044d98a61SZhao Yakui DRM_DEBUG_DRIVER("trying to get vblank count for disabled " 1719db4a9c7SJesse Barnes "pipe %c\n", pipe_name(pipe)); 1729880b7a5SJesse Barnes return 0; 1739880b7a5SJesse Barnes } 1749880b7a5SJesse Barnes 1759880b7a5SJesse Barnes return I915_READ(reg); 1769880b7a5SJesse Barnes } 1779880b7a5SJesse Barnes 178f71d4af4SJesse Barnes static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, 1790af7e4dfSMario Kleiner int *vpos, int *hpos) 1800af7e4dfSMario Kleiner { 1810af7e4dfSMario Kleiner drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1820af7e4dfSMario Kleiner u32 vbl = 0, position = 0; 1830af7e4dfSMario Kleiner int vbl_start, vbl_end, htotal, vtotal; 1840af7e4dfSMario Kleiner bool in_vbl = true; 1850af7e4dfSMario Kleiner int ret = 0; 1860af7e4dfSMario Kleiner 1870af7e4dfSMario Kleiner if (!i915_pipe_enabled(dev, pipe)) { 1880af7e4dfSMario Kleiner DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " 1899db4a9c7SJesse Barnes "pipe %c\n", pipe_name(pipe)); 1900af7e4dfSMario Kleiner return 0; 1910af7e4dfSMario Kleiner } 1920af7e4dfSMario Kleiner 1930af7e4dfSMario Kleiner /* Get vtotal. */ 1940af7e4dfSMario Kleiner vtotal = 1 + ((I915_READ(VTOTAL(pipe)) >> 16) & 0x1fff); 1950af7e4dfSMario Kleiner 1960af7e4dfSMario Kleiner if (INTEL_INFO(dev)->gen >= 4) { 1970af7e4dfSMario Kleiner /* No obvious pixelcount register. Only query vertical 1980af7e4dfSMario Kleiner * scanout position from Display scan line register. 1990af7e4dfSMario Kleiner */ 2000af7e4dfSMario Kleiner position = I915_READ(PIPEDSL(pipe)); 2010af7e4dfSMario Kleiner 2020af7e4dfSMario Kleiner /* Decode into vertical scanout position. Don't have 2030af7e4dfSMario Kleiner * horizontal scanout position. 2040af7e4dfSMario Kleiner */ 2050af7e4dfSMario Kleiner *vpos = position & 0x1fff; 2060af7e4dfSMario Kleiner *hpos = 0; 2070af7e4dfSMario Kleiner } else { 2080af7e4dfSMario Kleiner /* Have access to pixelcount since start of frame. 2090af7e4dfSMario Kleiner * We can split this into vertical and horizontal 2100af7e4dfSMario Kleiner * scanout position. 2110af7e4dfSMario Kleiner */ 2120af7e4dfSMario Kleiner position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; 2130af7e4dfSMario Kleiner 2140af7e4dfSMario Kleiner htotal = 1 + ((I915_READ(HTOTAL(pipe)) >> 16) & 0x1fff); 2150af7e4dfSMario Kleiner *vpos = position / htotal; 2160af7e4dfSMario Kleiner *hpos = position - (*vpos * htotal); 2170af7e4dfSMario Kleiner } 2180af7e4dfSMario Kleiner 2190af7e4dfSMario Kleiner /* Query vblank area. */ 2200af7e4dfSMario Kleiner vbl = I915_READ(VBLANK(pipe)); 2210af7e4dfSMario Kleiner 2220af7e4dfSMario Kleiner /* Test position against vblank region. */ 2230af7e4dfSMario Kleiner vbl_start = vbl & 0x1fff; 2240af7e4dfSMario Kleiner vbl_end = (vbl >> 16) & 0x1fff; 2250af7e4dfSMario Kleiner 2260af7e4dfSMario Kleiner if ((*vpos < vbl_start) || (*vpos > vbl_end)) 2270af7e4dfSMario Kleiner in_vbl = false; 2280af7e4dfSMario Kleiner 2290af7e4dfSMario Kleiner /* Inside "upper part" of vblank area? Apply corrective offset: */ 2300af7e4dfSMario Kleiner if (in_vbl && (*vpos >= vbl_start)) 2310af7e4dfSMario Kleiner *vpos = *vpos - vtotal; 2320af7e4dfSMario Kleiner 2330af7e4dfSMario Kleiner /* Readouts valid? */ 2340af7e4dfSMario Kleiner if (vbl > 0) 2350af7e4dfSMario Kleiner ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; 2360af7e4dfSMario Kleiner 2370af7e4dfSMario Kleiner /* In vblank? */ 2380af7e4dfSMario Kleiner if (in_vbl) 2390af7e4dfSMario Kleiner ret |= DRM_SCANOUTPOS_INVBL; 2400af7e4dfSMario Kleiner 2410af7e4dfSMario Kleiner return ret; 2420af7e4dfSMario Kleiner } 2430af7e4dfSMario Kleiner 244f71d4af4SJesse Barnes static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, 2450af7e4dfSMario Kleiner int *max_error, 2460af7e4dfSMario Kleiner struct timeval *vblank_time, 2470af7e4dfSMario Kleiner unsigned flags) 2480af7e4dfSMario Kleiner { 2494041b853SChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 2504041b853SChris Wilson struct drm_crtc *crtc; 2510af7e4dfSMario Kleiner 2524041b853SChris Wilson if (pipe < 0 || pipe >= dev_priv->num_pipe) { 2534041b853SChris Wilson DRM_ERROR("Invalid crtc %d\n", pipe); 2540af7e4dfSMario Kleiner return -EINVAL; 2550af7e4dfSMario Kleiner } 2560af7e4dfSMario Kleiner 2570af7e4dfSMario Kleiner /* Get drm_crtc to timestamp: */ 2584041b853SChris Wilson crtc = intel_get_crtc_for_pipe(dev, pipe); 2594041b853SChris Wilson if (crtc == NULL) { 2604041b853SChris Wilson DRM_ERROR("Invalid crtc %d\n", pipe); 2614041b853SChris Wilson return -EINVAL; 2624041b853SChris Wilson } 2634041b853SChris Wilson 2644041b853SChris Wilson if (!crtc->enabled) { 2654041b853SChris Wilson DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); 2664041b853SChris Wilson return -EBUSY; 2674041b853SChris Wilson } 2680af7e4dfSMario Kleiner 2690af7e4dfSMario Kleiner /* Helper routine in DRM core does all the work: */ 2704041b853SChris Wilson return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, 2714041b853SChris Wilson vblank_time, flags, 2724041b853SChris Wilson crtc); 2730af7e4dfSMario Kleiner } 2740af7e4dfSMario Kleiner 2755ca58282SJesse Barnes /* 2765ca58282SJesse Barnes * Handle hotplug events outside the interrupt handler proper. 2775ca58282SJesse Barnes */ 2785ca58282SJesse Barnes static void i915_hotplug_work_func(struct work_struct *work) 2795ca58282SJesse Barnes { 2805ca58282SJesse Barnes drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, 2815ca58282SJesse Barnes hotplug_work); 2825ca58282SJesse Barnes struct drm_device *dev = dev_priv->dev; 283c31c4ba3SKeith Packard struct drm_mode_config *mode_config = &dev->mode_config; 2844ef69c7aSChris Wilson struct intel_encoder *encoder; 2855ca58282SJesse Barnes 286a65e34c7SKeith Packard mutex_lock(&mode_config->mutex); 287e67189abSJesse Barnes DRM_DEBUG_KMS("running encoder hotplug functions\n"); 288e67189abSJesse Barnes 2894ef69c7aSChris Wilson list_for_each_entry(encoder, &mode_config->encoder_list, base.head) 2904ef69c7aSChris Wilson if (encoder->hot_plug) 2914ef69c7aSChris Wilson encoder->hot_plug(encoder); 292c31c4ba3SKeith Packard 29340ee3381SKeith Packard mutex_unlock(&mode_config->mutex); 29440ee3381SKeith Packard 2955ca58282SJesse Barnes /* Just fire off a uevent and let userspace tell us what to do */ 296eb1f8e4fSDave Airlie drm_helper_hpd_irq_event(dev); 2975ca58282SJesse Barnes } 2985ca58282SJesse Barnes 299f97108d1SJesse Barnes static void i915_handle_rps_change(struct drm_device *dev) 300f97108d1SJesse Barnes { 301f97108d1SJesse Barnes drm_i915_private_t *dev_priv = dev->dev_private; 302b5b72e89SMatthew Garrett u32 busy_up, busy_down, max_avg, min_avg; 303f97108d1SJesse Barnes u8 new_delay = dev_priv->cur_delay; 304f97108d1SJesse Barnes 3057648fa99SJesse Barnes I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG); 306b5b72e89SMatthew Garrett busy_up = I915_READ(RCPREVBSYTUPAVG); 307b5b72e89SMatthew Garrett busy_down = I915_READ(RCPREVBSYTDNAVG); 308f97108d1SJesse Barnes max_avg = I915_READ(RCBMAXAVG); 309f97108d1SJesse Barnes min_avg = I915_READ(RCBMINAVG); 310f97108d1SJesse Barnes 311f97108d1SJesse Barnes /* Handle RCS change request from hw */ 312b5b72e89SMatthew Garrett if (busy_up > max_avg) { 313f97108d1SJesse Barnes if (dev_priv->cur_delay != dev_priv->max_delay) 314f97108d1SJesse Barnes new_delay = dev_priv->cur_delay - 1; 315f97108d1SJesse Barnes if (new_delay < dev_priv->max_delay) 316f97108d1SJesse Barnes new_delay = dev_priv->max_delay; 317b5b72e89SMatthew Garrett } else if (busy_down < min_avg) { 318f97108d1SJesse Barnes if (dev_priv->cur_delay != dev_priv->min_delay) 319f97108d1SJesse Barnes new_delay = dev_priv->cur_delay + 1; 320f97108d1SJesse Barnes if (new_delay > dev_priv->min_delay) 321f97108d1SJesse Barnes new_delay = dev_priv->min_delay; 322f97108d1SJesse Barnes } 323f97108d1SJesse Barnes 3247648fa99SJesse Barnes if (ironlake_set_drps(dev, new_delay)) 325f97108d1SJesse Barnes dev_priv->cur_delay = new_delay; 326f97108d1SJesse Barnes 327f97108d1SJesse Barnes return; 328f97108d1SJesse Barnes } 329f97108d1SJesse Barnes 330549f7365SChris Wilson static void notify_ring(struct drm_device *dev, 331549f7365SChris Wilson struct intel_ring_buffer *ring) 332549f7365SChris Wilson { 333549f7365SChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 3349862e600SChris Wilson 335475553deSChris Wilson if (ring->obj == NULL) 336475553deSChris Wilson return; 337475553deSChris Wilson 3386d171cb4SChris Wilson trace_i915_gem_request_complete(ring, ring->get_seqno(ring)); 3399862e600SChris Wilson 340549f7365SChris Wilson wake_up_all(&ring->irq_queue); 3413e0dc6b0SBen Widawsky if (i915_enable_hangcheck) { 342549f7365SChris Wilson dev_priv->hangcheck_count = 0; 343549f7365SChris Wilson mod_timer(&dev_priv->hangcheck_timer, 3443e0dc6b0SBen Widawsky jiffies + 3453e0dc6b0SBen Widawsky msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); 3463e0dc6b0SBen Widawsky } 347549f7365SChris Wilson } 348549f7365SChris Wilson 3494912d041SBen Widawsky static void gen6_pm_rps_work(struct work_struct *work) 3503b8d8d91SJesse Barnes { 3514912d041SBen Widawsky drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, 3524912d041SBen Widawsky rps_work); 3534912d041SBen Widawsky u32 pm_iir, pm_imr; 354*7b9e0ae6SChris Wilson u8 new_delay; 3553b8d8d91SJesse Barnes 3564912d041SBen Widawsky spin_lock_irq(&dev_priv->rps_lock); 3574912d041SBen Widawsky pm_iir = dev_priv->pm_iir; 3584912d041SBen Widawsky dev_priv->pm_iir = 0; 3594912d041SBen Widawsky pm_imr = I915_READ(GEN6_PMIMR); 360a9e2641dSDaniel Vetter I915_WRITE(GEN6_PMIMR, 0); 3614912d041SBen Widawsky spin_unlock_irq(&dev_priv->rps_lock); 3624912d041SBen Widawsky 363*7b9e0ae6SChris Wilson if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0) 3643b8d8d91SJesse Barnes return; 3653b8d8d91SJesse Barnes 3664912d041SBen Widawsky mutex_lock(&dev_priv->dev->struct_mutex); 367*7b9e0ae6SChris Wilson 368*7b9e0ae6SChris Wilson if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) 3693b8d8d91SJesse Barnes new_delay = dev_priv->cur_delay + 1; 370*7b9e0ae6SChris Wilson else 3713b8d8d91SJesse Barnes new_delay = dev_priv->cur_delay - 1; 3723b8d8d91SJesse Barnes 3734912d041SBen Widawsky gen6_set_rps(dev_priv->dev, new_delay); 3743b8d8d91SJesse Barnes 3754912d041SBen Widawsky mutex_unlock(&dev_priv->dev->struct_mutex); 3763b8d8d91SJesse Barnes } 3773b8d8d91SJesse Barnes 378e7b4c6b1SDaniel Vetter static void snb_gt_irq_handler(struct drm_device *dev, 379e7b4c6b1SDaniel Vetter struct drm_i915_private *dev_priv, 380e7b4c6b1SDaniel Vetter u32 gt_iir) 381e7b4c6b1SDaniel Vetter { 382e7b4c6b1SDaniel Vetter 383e7b4c6b1SDaniel Vetter if (gt_iir & (GEN6_RENDER_USER_INTERRUPT | 384e7b4c6b1SDaniel Vetter GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT)) 385e7b4c6b1SDaniel Vetter notify_ring(dev, &dev_priv->ring[RCS]); 386e7b4c6b1SDaniel Vetter if (gt_iir & GEN6_BSD_USER_INTERRUPT) 387e7b4c6b1SDaniel Vetter notify_ring(dev, &dev_priv->ring[VCS]); 388e7b4c6b1SDaniel Vetter if (gt_iir & GEN6_BLITTER_USER_INTERRUPT) 389e7b4c6b1SDaniel Vetter notify_ring(dev, &dev_priv->ring[BCS]); 390e7b4c6b1SDaniel Vetter 391e7b4c6b1SDaniel Vetter if (gt_iir & (GT_GEN6_BLT_CS_ERROR_INTERRUPT | 392e7b4c6b1SDaniel Vetter GT_GEN6_BSD_CS_ERROR_INTERRUPT | 393e7b4c6b1SDaniel Vetter GT_RENDER_CS_ERROR_INTERRUPT)) { 394e7b4c6b1SDaniel Vetter DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir); 395e7b4c6b1SDaniel Vetter i915_handle_error(dev, false); 396e7b4c6b1SDaniel Vetter } 397e7b4c6b1SDaniel Vetter } 398e7b4c6b1SDaniel Vetter 399fc6826d1SChris Wilson static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, 400fc6826d1SChris Wilson u32 pm_iir) 401fc6826d1SChris Wilson { 402fc6826d1SChris Wilson unsigned long flags; 403fc6826d1SChris Wilson 404fc6826d1SChris Wilson /* 405fc6826d1SChris Wilson * IIR bits should never already be set because IMR should 406fc6826d1SChris Wilson * prevent an interrupt from being shown in IIR. The warning 407fc6826d1SChris Wilson * displays a case where we've unsafely cleared 408fc6826d1SChris Wilson * dev_priv->pm_iir. Although missing an interrupt of the same 409fc6826d1SChris Wilson * type is not a problem, it displays a problem in the logic. 410fc6826d1SChris Wilson * 411fc6826d1SChris Wilson * The mask bit in IMR is cleared by rps_work. 412fc6826d1SChris Wilson */ 413fc6826d1SChris Wilson 414fc6826d1SChris Wilson spin_lock_irqsave(&dev_priv->rps_lock, flags); 415fc6826d1SChris Wilson WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); 416fc6826d1SChris Wilson dev_priv->pm_iir |= pm_iir; 417fc6826d1SChris Wilson I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); 418fc6826d1SChris Wilson POSTING_READ(GEN6_PMIMR); 419fc6826d1SChris Wilson spin_unlock_irqrestore(&dev_priv->rps_lock, flags); 420fc6826d1SChris Wilson 421fc6826d1SChris Wilson queue_work(dev_priv->wq, &dev_priv->rps_work); 422fc6826d1SChris Wilson } 423fc6826d1SChris Wilson 4247e231dbeSJesse Barnes static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS) 4257e231dbeSJesse Barnes { 4267e231dbeSJesse Barnes struct drm_device *dev = (struct drm_device *) arg; 4277e231dbeSJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 4287e231dbeSJesse Barnes u32 iir, gt_iir, pm_iir; 4297e231dbeSJesse Barnes irqreturn_t ret = IRQ_NONE; 4307e231dbeSJesse Barnes unsigned long irqflags; 4317e231dbeSJesse Barnes int pipe; 4327e231dbeSJesse Barnes u32 pipe_stats[I915_MAX_PIPES]; 4337e231dbeSJesse Barnes u32 vblank_status; 4347e231dbeSJesse Barnes int vblank = 0; 4357e231dbeSJesse Barnes bool blc_event; 4367e231dbeSJesse Barnes 4377e231dbeSJesse Barnes atomic_inc(&dev_priv->irq_received); 4387e231dbeSJesse Barnes 4397e231dbeSJesse Barnes vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS | 4407e231dbeSJesse Barnes PIPE_VBLANK_INTERRUPT_STATUS; 4417e231dbeSJesse Barnes 4427e231dbeSJesse Barnes while (true) { 4437e231dbeSJesse Barnes iir = I915_READ(VLV_IIR); 4447e231dbeSJesse Barnes gt_iir = I915_READ(GTIIR); 4457e231dbeSJesse Barnes pm_iir = I915_READ(GEN6_PMIIR); 4467e231dbeSJesse Barnes 4477e231dbeSJesse Barnes if (gt_iir == 0 && pm_iir == 0 && iir == 0) 4487e231dbeSJesse Barnes goto out; 4497e231dbeSJesse Barnes 4507e231dbeSJesse Barnes ret = IRQ_HANDLED; 4517e231dbeSJesse Barnes 452e7b4c6b1SDaniel Vetter snb_gt_irq_handler(dev, dev_priv, gt_iir); 4537e231dbeSJesse Barnes 4547e231dbeSJesse Barnes spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 4557e231dbeSJesse Barnes for_each_pipe(pipe) { 4567e231dbeSJesse Barnes int reg = PIPESTAT(pipe); 4577e231dbeSJesse Barnes pipe_stats[pipe] = I915_READ(reg); 4587e231dbeSJesse Barnes 4597e231dbeSJesse Barnes /* 4607e231dbeSJesse Barnes * Clear the PIPE*STAT regs before the IIR 4617e231dbeSJesse Barnes */ 4627e231dbeSJesse Barnes if (pipe_stats[pipe] & 0x8000ffff) { 4637e231dbeSJesse Barnes if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 4647e231dbeSJesse Barnes DRM_DEBUG_DRIVER("pipe %c underrun\n", 4657e231dbeSJesse Barnes pipe_name(pipe)); 4667e231dbeSJesse Barnes I915_WRITE(reg, pipe_stats[pipe]); 4677e231dbeSJesse Barnes } 4687e231dbeSJesse Barnes } 4697e231dbeSJesse Barnes spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 4707e231dbeSJesse Barnes 4717e231dbeSJesse Barnes /* Consume port. Then clear IIR or we'll miss events */ 4727e231dbeSJesse Barnes if (iir & I915_DISPLAY_PORT_INTERRUPT) { 4737e231dbeSJesse Barnes u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); 4747e231dbeSJesse Barnes 4757e231dbeSJesse Barnes DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", 4767e231dbeSJesse Barnes hotplug_status); 4777e231dbeSJesse Barnes if (hotplug_status & dev_priv->hotplug_supported_mask) 4787e231dbeSJesse Barnes queue_work(dev_priv->wq, 4797e231dbeSJesse Barnes &dev_priv->hotplug_work); 4807e231dbeSJesse Barnes 4817e231dbeSJesse Barnes I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); 4827e231dbeSJesse Barnes I915_READ(PORT_HOTPLUG_STAT); 4837e231dbeSJesse Barnes } 4847e231dbeSJesse Barnes 4857e231dbeSJesse Barnes 4867e231dbeSJesse Barnes if (iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) { 4877e231dbeSJesse Barnes drm_handle_vblank(dev, 0); 4887e231dbeSJesse Barnes vblank++; 4897e231dbeSJesse Barnes intel_finish_page_flip(dev, 0); 4907e231dbeSJesse Barnes } 4917e231dbeSJesse Barnes 4927e231dbeSJesse Barnes if (iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) { 4937e231dbeSJesse Barnes drm_handle_vblank(dev, 1); 4947e231dbeSJesse Barnes vblank++; 4957e231dbeSJesse Barnes intel_finish_page_flip(dev, 0); 4967e231dbeSJesse Barnes } 4977e231dbeSJesse Barnes 4987e231dbeSJesse Barnes if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) 4997e231dbeSJesse Barnes blc_event = true; 5007e231dbeSJesse Barnes 501fc6826d1SChris Wilson if (pm_iir & GEN6_PM_DEFERRED_EVENTS) 502fc6826d1SChris Wilson gen6_queue_rps_work(dev_priv, pm_iir); 5037e231dbeSJesse Barnes 5047e231dbeSJesse Barnes I915_WRITE(GTIIR, gt_iir); 5057e231dbeSJesse Barnes I915_WRITE(GEN6_PMIIR, pm_iir); 5067e231dbeSJesse Barnes I915_WRITE(VLV_IIR, iir); 5077e231dbeSJesse Barnes } 5087e231dbeSJesse Barnes 5097e231dbeSJesse Barnes out: 5107e231dbeSJesse Barnes return ret; 5117e231dbeSJesse Barnes } 5127e231dbeSJesse Barnes 5139adab8b5SChris Wilson static void pch_irq_handler(struct drm_device *dev, u32 pch_iir) 514776ad806SJesse Barnes { 515776ad806SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 5169db4a9c7SJesse Barnes int pipe; 517776ad806SJesse Barnes 518776ad806SJesse Barnes if (pch_iir & SDE_AUDIO_POWER_MASK) 519776ad806SJesse Barnes DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", 520776ad806SJesse Barnes (pch_iir & SDE_AUDIO_POWER_MASK) >> 521776ad806SJesse Barnes SDE_AUDIO_POWER_SHIFT); 522776ad806SJesse Barnes 523776ad806SJesse Barnes if (pch_iir & SDE_GMBUS) 524776ad806SJesse Barnes DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n"); 525776ad806SJesse Barnes 526776ad806SJesse Barnes if (pch_iir & SDE_AUDIO_HDCP_MASK) 527776ad806SJesse Barnes DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n"); 528776ad806SJesse Barnes 529776ad806SJesse Barnes if (pch_iir & SDE_AUDIO_TRANS_MASK) 530776ad806SJesse Barnes DRM_DEBUG_DRIVER("PCH transcoder audio interrupt\n"); 531776ad806SJesse Barnes 532776ad806SJesse Barnes if (pch_iir & SDE_POISON) 533776ad806SJesse Barnes DRM_ERROR("PCH poison interrupt\n"); 534776ad806SJesse Barnes 5359db4a9c7SJesse Barnes if (pch_iir & SDE_FDI_MASK) 5369db4a9c7SJesse Barnes for_each_pipe(pipe) 5379db4a9c7SJesse Barnes DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n", 5389db4a9c7SJesse Barnes pipe_name(pipe), 5399db4a9c7SJesse Barnes I915_READ(FDI_RX_IIR(pipe))); 540776ad806SJesse Barnes 541776ad806SJesse Barnes if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) 542776ad806SJesse Barnes DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n"); 543776ad806SJesse Barnes 544776ad806SJesse Barnes if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) 545776ad806SJesse Barnes DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n"); 546776ad806SJesse Barnes 547776ad806SJesse Barnes if (pch_iir & SDE_TRANSB_FIFO_UNDER) 548776ad806SJesse Barnes DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n"); 549776ad806SJesse Barnes if (pch_iir & SDE_TRANSA_FIFO_UNDER) 550776ad806SJesse Barnes DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); 551776ad806SJesse Barnes } 552776ad806SJesse Barnes 553f71d4af4SJesse Barnes static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) 554b1f14ad0SJesse Barnes { 555b1f14ad0SJesse Barnes struct drm_device *dev = (struct drm_device *) arg; 556b1f14ad0SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 5570e43406bSChris Wilson u32 de_iir, gt_iir, de_ier, pm_iir; 5580e43406bSChris Wilson irqreturn_t ret = IRQ_NONE; 5590e43406bSChris Wilson int i; 560b1f14ad0SJesse Barnes 561b1f14ad0SJesse Barnes atomic_inc(&dev_priv->irq_received); 562b1f14ad0SJesse Barnes 563b1f14ad0SJesse Barnes /* disable master interrupt before clearing iir */ 564b1f14ad0SJesse Barnes de_ier = I915_READ(DEIER); 565b1f14ad0SJesse Barnes I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); 5660e43406bSChris Wilson 5670e43406bSChris Wilson gt_iir = I915_READ(GTIIR); 5680e43406bSChris Wilson if (gt_iir) { 5690e43406bSChris Wilson snb_gt_irq_handler(dev, dev_priv, gt_iir); 5700e43406bSChris Wilson I915_WRITE(GTIIR, gt_iir); 5710e43406bSChris Wilson ret = IRQ_HANDLED; 5720e43406bSChris Wilson } 573b1f14ad0SJesse Barnes 574b1f14ad0SJesse Barnes de_iir = I915_READ(DEIIR); 5750e43406bSChris Wilson if (de_iir) { 576b1f14ad0SJesse Barnes if (de_iir & DE_GSE_IVB) 577b1f14ad0SJesse Barnes intel_opregion_gse_intr(dev); 578b1f14ad0SJesse Barnes 5790e43406bSChris Wilson for (i = 0; i < 3; i++) { 5800e43406bSChris Wilson if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) { 5810e43406bSChris Wilson intel_prepare_page_flip(dev, i); 5820e43406bSChris Wilson intel_finish_page_flip_plane(dev, i); 583b1f14ad0SJesse Barnes } 5840e43406bSChris Wilson if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i))) 5850e43406bSChris Wilson drm_handle_vblank(dev, i); 586b1f14ad0SJesse Barnes } 587b1f14ad0SJesse Barnes 588b1f14ad0SJesse Barnes /* check event from PCH */ 589b1f14ad0SJesse Barnes if (de_iir & DE_PCH_EVENT_IVB) { 5900e43406bSChris Wilson u32 pch_iir = I915_READ(SDEIIR); 5910e43406bSChris Wilson 592b1f14ad0SJesse Barnes if (pch_iir & SDE_HOTPLUG_MASK_CPT) 593b1f14ad0SJesse Barnes queue_work(dev_priv->wq, &dev_priv->hotplug_work); 5949adab8b5SChris Wilson pch_irq_handler(dev, pch_iir); 5950e43406bSChris Wilson 5960e43406bSChris Wilson /* clear PCH hotplug event before clear CPU irq */ 5970e43406bSChris Wilson I915_WRITE(SDEIIR, pch_iir); 598b1f14ad0SJesse Barnes } 599b1f14ad0SJesse Barnes 6000e43406bSChris Wilson I915_WRITE(DEIIR, de_iir); 6010e43406bSChris Wilson ret = IRQ_HANDLED; 6020e43406bSChris Wilson } 6030e43406bSChris Wilson 6040e43406bSChris Wilson pm_iir = I915_READ(GEN6_PMIIR); 6050e43406bSChris Wilson if (pm_iir) { 606fc6826d1SChris Wilson if (pm_iir & GEN6_PM_DEFERRED_EVENTS) 607fc6826d1SChris Wilson gen6_queue_rps_work(dev_priv, pm_iir); 608b1f14ad0SJesse Barnes I915_WRITE(GEN6_PMIIR, pm_iir); 6090e43406bSChris Wilson ret = IRQ_HANDLED; 6100e43406bSChris Wilson } 611b1f14ad0SJesse Barnes 612b1f14ad0SJesse Barnes I915_WRITE(DEIER, de_ier); 613b1f14ad0SJesse Barnes POSTING_READ(DEIER); 614b1f14ad0SJesse Barnes 615b1f14ad0SJesse Barnes return ret; 616b1f14ad0SJesse Barnes } 617b1f14ad0SJesse Barnes 618e7b4c6b1SDaniel Vetter static void ilk_gt_irq_handler(struct drm_device *dev, 619e7b4c6b1SDaniel Vetter struct drm_i915_private *dev_priv, 620e7b4c6b1SDaniel Vetter u32 gt_iir) 621e7b4c6b1SDaniel Vetter { 622e7b4c6b1SDaniel Vetter if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) 623e7b4c6b1SDaniel Vetter notify_ring(dev, &dev_priv->ring[RCS]); 624e7b4c6b1SDaniel Vetter if (gt_iir & GT_BSD_USER_INTERRUPT) 625e7b4c6b1SDaniel Vetter notify_ring(dev, &dev_priv->ring[VCS]); 626e7b4c6b1SDaniel Vetter } 627e7b4c6b1SDaniel Vetter 628f71d4af4SJesse Barnes static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) 629036a4a7dSZhenyu Wang { 6304697995bSJesse Barnes struct drm_device *dev = (struct drm_device *) arg; 631036a4a7dSZhenyu Wang drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 632036a4a7dSZhenyu Wang int ret = IRQ_NONE; 6333b8d8d91SJesse Barnes u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; 6342d7b8366SYuanhan Liu u32 hotplug_mask; 635881f47b6SXiang, Haihao 6364697995bSJesse Barnes atomic_inc(&dev_priv->irq_received); 6374697995bSJesse Barnes 6382d109a84SZou, Nanhai /* disable master interrupt before clearing iir */ 6392d109a84SZou, Nanhai de_ier = I915_READ(DEIER); 6402d109a84SZou, Nanhai I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); 6413143a2bfSChris Wilson POSTING_READ(DEIER); 6422d109a84SZou, Nanhai 643036a4a7dSZhenyu Wang de_iir = I915_READ(DEIIR); 644036a4a7dSZhenyu Wang gt_iir = I915_READ(GTIIR); 645c650156aSZhenyu Wang pch_iir = I915_READ(SDEIIR); 6463b8d8d91SJesse Barnes pm_iir = I915_READ(GEN6_PMIIR); 647036a4a7dSZhenyu Wang 6483b8d8d91SJesse Barnes if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && 6493b8d8d91SJesse Barnes (!IS_GEN6(dev) || pm_iir == 0)) 650c7c85101SZou Nan hai goto done; 651036a4a7dSZhenyu Wang 6522d7b8366SYuanhan Liu if (HAS_PCH_CPT(dev)) 6532d7b8366SYuanhan Liu hotplug_mask = SDE_HOTPLUG_MASK_CPT; 6542d7b8366SYuanhan Liu else 6552d7b8366SYuanhan Liu hotplug_mask = SDE_HOTPLUG_MASK; 6562d7b8366SYuanhan Liu 657036a4a7dSZhenyu Wang ret = IRQ_HANDLED; 658036a4a7dSZhenyu Wang 659e7b4c6b1SDaniel Vetter if (IS_GEN5(dev)) 660e7b4c6b1SDaniel Vetter ilk_gt_irq_handler(dev, dev_priv, gt_iir); 661e7b4c6b1SDaniel Vetter else 662e7b4c6b1SDaniel Vetter snb_gt_irq_handler(dev, dev_priv, gt_iir); 663036a4a7dSZhenyu Wang 66401c66889SZhao Yakui if (de_iir & DE_GSE) 6653b617967SChris Wilson intel_opregion_gse_intr(dev); 66601c66889SZhao Yakui 667f072d2e7SZhenyu Wang if (de_iir & DE_PLANEA_FLIP_DONE) { 668013d5aa2SJesse Barnes intel_prepare_page_flip(dev, 0); 6692bbda389SChris Wilson intel_finish_page_flip_plane(dev, 0); 670013d5aa2SJesse Barnes } 671013d5aa2SJesse Barnes 672f072d2e7SZhenyu Wang if (de_iir & DE_PLANEB_FLIP_DONE) { 673f072d2e7SZhenyu Wang intel_prepare_page_flip(dev, 1); 6742bbda389SChris Wilson intel_finish_page_flip_plane(dev, 1); 675013d5aa2SJesse Barnes } 676c062df61SLi Peng 677f072d2e7SZhenyu Wang if (de_iir & DE_PIPEA_VBLANK) 678f072d2e7SZhenyu Wang drm_handle_vblank(dev, 0); 679f072d2e7SZhenyu Wang 680f072d2e7SZhenyu Wang if (de_iir & DE_PIPEB_VBLANK) 681f072d2e7SZhenyu Wang drm_handle_vblank(dev, 1); 682f072d2e7SZhenyu Wang 683c650156aSZhenyu Wang /* check event from PCH */ 684776ad806SJesse Barnes if (de_iir & DE_PCH_EVENT) { 685776ad806SJesse Barnes if (pch_iir & hotplug_mask) 686c650156aSZhenyu Wang queue_work(dev_priv->wq, &dev_priv->hotplug_work); 6879adab8b5SChris Wilson pch_irq_handler(dev, pch_iir); 688776ad806SJesse Barnes } 689c650156aSZhenyu Wang 690f97108d1SJesse Barnes if (de_iir & DE_PCU_EVENT) { 6917648fa99SJesse Barnes I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); 692f97108d1SJesse Barnes i915_handle_rps_change(dev); 693f97108d1SJesse Barnes } 694f97108d1SJesse Barnes 695fc6826d1SChris Wilson if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) 696fc6826d1SChris Wilson gen6_queue_rps_work(dev_priv, pm_iir); 6973b8d8d91SJesse Barnes 698c7c85101SZou Nan hai /* should clear PCH hotplug event before clear CPU irq */ 699c7c85101SZou Nan hai I915_WRITE(SDEIIR, pch_iir); 700c7c85101SZou Nan hai I915_WRITE(GTIIR, gt_iir); 701c7c85101SZou Nan hai I915_WRITE(DEIIR, de_iir); 7024912d041SBen Widawsky I915_WRITE(GEN6_PMIIR, pm_iir); 703036a4a7dSZhenyu Wang 704c7c85101SZou Nan hai done: 7052d109a84SZou, Nanhai I915_WRITE(DEIER, de_ier); 7063143a2bfSChris Wilson POSTING_READ(DEIER); 7072d109a84SZou, Nanhai 708036a4a7dSZhenyu Wang return ret; 709036a4a7dSZhenyu Wang } 710036a4a7dSZhenyu Wang 7118a905236SJesse Barnes /** 7128a905236SJesse Barnes * i915_error_work_func - do process context error handling work 7138a905236SJesse Barnes * @work: work struct 7148a905236SJesse Barnes * 7158a905236SJesse Barnes * Fire an error uevent so userspace can see that a hang or error 7168a905236SJesse Barnes * was detected. 7178a905236SJesse Barnes */ 7188a905236SJesse Barnes static void i915_error_work_func(struct work_struct *work) 7198a905236SJesse Barnes { 7208a905236SJesse Barnes drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, 7218a905236SJesse Barnes error_work); 7228a905236SJesse Barnes struct drm_device *dev = dev_priv->dev; 723f316a42cSBen Gamari char *error_event[] = { "ERROR=1", NULL }; 724f316a42cSBen Gamari char *reset_event[] = { "RESET=1", NULL }; 725f316a42cSBen Gamari char *reset_done_event[] = { "ERROR=0", NULL }; 7268a905236SJesse Barnes 727f316a42cSBen Gamari kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); 7288a905236SJesse Barnes 729ba1234d1SBen Gamari if (atomic_read(&dev_priv->mm.wedged)) { 73044d98a61SZhao Yakui DRM_DEBUG_DRIVER("resetting chip\n"); 731f316a42cSBen Gamari kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); 732d4b8bb2aSDaniel Vetter if (!i915_reset(dev)) { 733ba1234d1SBen Gamari atomic_set(&dev_priv->mm.wedged, 0); 734f316a42cSBen Gamari kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); 735f316a42cSBen Gamari } 73630dbf0c0SChris Wilson complete_all(&dev_priv->error_completion); 737f316a42cSBen Gamari } 7388a905236SJesse Barnes } 7398a905236SJesse Barnes 7403bd3c932SChris Wilson #ifdef CONFIG_DEBUG_FS 7419df30794SChris Wilson static struct drm_i915_error_object * 742bcfb2e28SChris Wilson i915_error_object_create(struct drm_i915_private *dev_priv, 74305394f39SChris Wilson struct drm_i915_gem_object *src) 7449df30794SChris Wilson { 7459df30794SChris Wilson struct drm_i915_error_object *dst; 7469df30794SChris Wilson int page, page_count; 747e56660ddSChris Wilson u32 reloc_offset; 7489df30794SChris Wilson 74905394f39SChris Wilson if (src == NULL || src->pages == NULL) 7509df30794SChris Wilson return NULL; 7519df30794SChris Wilson 75205394f39SChris Wilson page_count = src->base.size / PAGE_SIZE; 7539df30794SChris Wilson 7549df30794SChris Wilson dst = kmalloc(sizeof(*dst) + page_count * sizeof(u32 *), GFP_ATOMIC); 7559df30794SChris Wilson if (dst == NULL) 7569df30794SChris Wilson return NULL; 7579df30794SChris Wilson 75805394f39SChris Wilson reloc_offset = src->gtt_offset; 7599df30794SChris Wilson for (page = 0; page < page_count; page++) { 760788885aeSAndrew Morton unsigned long flags; 761e56660ddSChris Wilson void *d; 762788885aeSAndrew Morton 763e56660ddSChris Wilson d = kmalloc(PAGE_SIZE, GFP_ATOMIC); 7649df30794SChris Wilson if (d == NULL) 7659df30794SChris Wilson goto unwind; 766e56660ddSChris Wilson 767788885aeSAndrew Morton local_irq_save(flags); 76874898d7eSDaniel Vetter if (reloc_offset < dev_priv->mm.gtt_mappable_end && 76974898d7eSDaniel Vetter src->has_global_gtt_mapping) { 770172975aaSChris Wilson void __iomem *s; 771172975aaSChris Wilson 772172975aaSChris Wilson /* Simply ignore tiling or any overlapping fence. 773172975aaSChris Wilson * It's part of the error state, and this hopefully 774172975aaSChris Wilson * captures what the GPU read. 775172975aaSChris Wilson */ 776172975aaSChris Wilson 777e56660ddSChris Wilson s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, 7783e4d3af5SPeter Zijlstra reloc_offset); 779e56660ddSChris Wilson memcpy_fromio(d, s, PAGE_SIZE); 7803e4d3af5SPeter Zijlstra io_mapping_unmap_atomic(s); 781172975aaSChris Wilson } else { 782172975aaSChris Wilson void *s; 783172975aaSChris Wilson 784172975aaSChris Wilson drm_clflush_pages(&src->pages[page], 1); 785172975aaSChris Wilson 786172975aaSChris Wilson s = kmap_atomic(src->pages[page]); 787172975aaSChris Wilson memcpy(d, s, PAGE_SIZE); 788172975aaSChris Wilson kunmap_atomic(s); 789172975aaSChris Wilson 790172975aaSChris Wilson drm_clflush_pages(&src->pages[page], 1); 791172975aaSChris Wilson } 792788885aeSAndrew Morton local_irq_restore(flags); 793e56660ddSChris Wilson 7949df30794SChris Wilson dst->pages[page] = d; 795e56660ddSChris Wilson 796e56660ddSChris Wilson reloc_offset += PAGE_SIZE; 7979df30794SChris Wilson } 7989df30794SChris Wilson dst->page_count = page_count; 79905394f39SChris Wilson dst->gtt_offset = src->gtt_offset; 8009df30794SChris Wilson 8019df30794SChris Wilson return dst; 8029df30794SChris Wilson 8039df30794SChris Wilson unwind: 8049df30794SChris Wilson while (page--) 8059df30794SChris Wilson kfree(dst->pages[page]); 8069df30794SChris Wilson kfree(dst); 8079df30794SChris Wilson return NULL; 8089df30794SChris Wilson } 8099df30794SChris Wilson 8109df30794SChris Wilson static void 8119df30794SChris Wilson i915_error_object_free(struct drm_i915_error_object *obj) 8129df30794SChris Wilson { 8139df30794SChris Wilson int page; 8149df30794SChris Wilson 8159df30794SChris Wilson if (obj == NULL) 8169df30794SChris Wilson return; 8179df30794SChris Wilson 8189df30794SChris Wilson for (page = 0; page < obj->page_count; page++) 8199df30794SChris Wilson kfree(obj->pages[page]); 8209df30794SChris Wilson 8219df30794SChris Wilson kfree(obj); 8229df30794SChris Wilson } 8239df30794SChris Wilson 824742cbee8SDaniel Vetter void 825742cbee8SDaniel Vetter i915_error_state_free(struct kref *error_ref) 8269df30794SChris Wilson { 827742cbee8SDaniel Vetter struct drm_i915_error_state *error = container_of(error_ref, 828742cbee8SDaniel Vetter typeof(*error), ref); 829e2f973d5SChris Wilson int i; 830e2f973d5SChris Wilson 83152d39a21SChris Wilson for (i = 0; i < ARRAY_SIZE(error->ring); i++) { 83252d39a21SChris Wilson i915_error_object_free(error->ring[i].batchbuffer); 83352d39a21SChris Wilson i915_error_object_free(error->ring[i].ringbuffer); 83452d39a21SChris Wilson kfree(error->ring[i].requests); 83552d39a21SChris Wilson } 836e2f973d5SChris Wilson 8379df30794SChris Wilson kfree(error->active_bo); 8386ef3d427SChris Wilson kfree(error->overlay); 8399df30794SChris Wilson kfree(error); 8409df30794SChris Wilson } 8411b50247aSChris Wilson static void capture_bo(struct drm_i915_error_buffer *err, 8421b50247aSChris Wilson struct drm_i915_gem_object *obj) 843c724e8a9SChris Wilson { 844c724e8a9SChris Wilson err->size = obj->base.size; 845c724e8a9SChris Wilson err->name = obj->base.name; 846c724e8a9SChris Wilson err->seqno = obj->last_rendering_seqno; 847c724e8a9SChris Wilson err->gtt_offset = obj->gtt_offset; 848c724e8a9SChris Wilson err->read_domains = obj->base.read_domains; 849c724e8a9SChris Wilson err->write_domain = obj->base.write_domain; 850c724e8a9SChris Wilson err->fence_reg = obj->fence_reg; 851c724e8a9SChris Wilson err->pinned = 0; 852c724e8a9SChris Wilson if (obj->pin_count > 0) 853c724e8a9SChris Wilson err->pinned = 1; 854c724e8a9SChris Wilson if (obj->user_pin_count > 0) 855c724e8a9SChris Wilson err->pinned = -1; 856c724e8a9SChris Wilson err->tiling = obj->tiling_mode; 857c724e8a9SChris Wilson err->dirty = obj->dirty; 858c724e8a9SChris Wilson err->purgeable = obj->madv != I915_MADV_WILLNEED; 85996154f2fSDaniel Vetter err->ring = obj->ring ? obj->ring->id : -1; 86093dfb40cSChris Wilson err->cache_level = obj->cache_level; 8611b50247aSChris Wilson } 862c724e8a9SChris Wilson 8631b50247aSChris Wilson static u32 capture_active_bo(struct drm_i915_error_buffer *err, 8641b50247aSChris Wilson int count, struct list_head *head) 8651b50247aSChris Wilson { 8661b50247aSChris Wilson struct drm_i915_gem_object *obj; 8671b50247aSChris Wilson int i = 0; 8681b50247aSChris Wilson 8691b50247aSChris Wilson list_for_each_entry(obj, head, mm_list) { 8701b50247aSChris Wilson capture_bo(err++, obj); 871c724e8a9SChris Wilson if (++i == count) 872c724e8a9SChris Wilson break; 8731b50247aSChris Wilson } 874c724e8a9SChris Wilson 8751b50247aSChris Wilson return i; 8761b50247aSChris Wilson } 8771b50247aSChris Wilson 8781b50247aSChris Wilson static u32 capture_pinned_bo(struct drm_i915_error_buffer *err, 8791b50247aSChris Wilson int count, struct list_head *head) 8801b50247aSChris Wilson { 8811b50247aSChris Wilson struct drm_i915_gem_object *obj; 8821b50247aSChris Wilson int i = 0; 8831b50247aSChris Wilson 8841b50247aSChris Wilson list_for_each_entry(obj, head, gtt_list) { 8851b50247aSChris Wilson if (obj->pin_count == 0) 8861b50247aSChris Wilson continue; 8871b50247aSChris Wilson 8881b50247aSChris Wilson capture_bo(err++, obj); 8891b50247aSChris Wilson if (++i == count) 8901b50247aSChris Wilson break; 891c724e8a9SChris Wilson } 892c724e8a9SChris Wilson 893c724e8a9SChris Wilson return i; 894c724e8a9SChris Wilson } 895c724e8a9SChris Wilson 896748ebc60SChris Wilson static void i915_gem_record_fences(struct drm_device *dev, 897748ebc60SChris Wilson struct drm_i915_error_state *error) 898748ebc60SChris Wilson { 899748ebc60SChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 900748ebc60SChris Wilson int i; 901748ebc60SChris Wilson 902748ebc60SChris Wilson /* Fences */ 903748ebc60SChris Wilson switch (INTEL_INFO(dev)->gen) { 904775d17b6SDaniel Vetter case 7: 905748ebc60SChris Wilson case 6: 906748ebc60SChris Wilson for (i = 0; i < 16; i++) 907748ebc60SChris Wilson error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); 908748ebc60SChris Wilson break; 909748ebc60SChris Wilson case 5: 910748ebc60SChris Wilson case 4: 911748ebc60SChris Wilson for (i = 0; i < 16; i++) 912748ebc60SChris Wilson error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); 913748ebc60SChris Wilson break; 914748ebc60SChris Wilson case 3: 915748ebc60SChris Wilson if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) 916748ebc60SChris Wilson for (i = 0; i < 8; i++) 917748ebc60SChris Wilson error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); 918748ebc60SChris Wilson case 2: 919748ebc60SChris Wilson for (i = 0; i < 8; i++) 920748ebc60SChris Wilson error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); 921748ebc60SChris Wilson break; 922748ebc60SChris Wilson 923748ebc60SChris Wilson } 924748ebc60SChris Wilson } 925748ebc60SChris Wilson 926bcfb2e28SChris Wilson static struct drm_i915_error_object * 927bcfb2e28SChris Wilson i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, 928bcfb2e28SChris Wilson struct intel_ring_buffer *ring) 929bcfb2e28SChris Wilson { 930bcfb2e28SChris Wilson struct drm_i915_gem_object *obj; 931bcfb2e28SChris Wilson u32 seqno; 932bcfb2e28SChris Wilson 933bcfb2e28SChris Wilson if (!ring->get_seqno) 934bcfb2e28SChris Wilson return NULL; 935bcfb2e28SChris Wilson 936bcfb2e28SChris Wilson seqno = ring->get_seqno(ring); 937bcfb2e28SChris Wilson list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { 938bcfb2e28SChris Wilson if (obj->ring != ring) 939bcfb2e28SChris Wilson continue; 940bcfb2e28SChris Wilson 941c37d9a5dSChris Wilson if (i915_seqno_passed(seqno, obj->last_rendering_seqno)) 942bcfb2e28SChris Wilson continue; 943bcfb2e28SChris Wilson 944bcfb2e28SChris Wilson if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0) 945bcfb2e28SChris Wilson continue; 946bcfb2e28SChris Wilson 947bcfb2e28SChris Wilson /* We need to copy these to an anonymous buffer as the simplest 948bcfb2e28SChris Wilson * method to avoid being overwritten by userspace. 949bcfb2e28SChris Wilson */ 950bcfb2e28SChris Wilson return i915_error_object_create(dev_priv, obj); 951bcfb2e28SChris Wilson } 952bcfb2e28SChris Wilson 953bcfb2e28SChris Wilson return NULL; 954bcfb2e28SChris Wilson } 955bcfb2e28SChris Wilson 956d27b1e0eSDaniel Vetter static void i915_record_ring_state(struct drm_device *dev, 957d27b1e0eSDaniel Vetter struct drm_i915_error_state *error, 958d27b1e0eSDaniel Vetter struct intel_ring_buffer *ring) 959d27b1e0eSDaniel Vetter { 960d27b1e0eSDaniel Vetter struct drm_i915_private *dev_priv = dev->dev_private; 961d27b1e0eSDaniel Vetter 96233f3f518SDaniel Vetter if (INTEL_INFO(dev)->gen >= 6) { 96333f3f518SDaniel Vetter error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring)); 9647e3b8737SDaniel Vetter error->semaphore_mboxes[ring->id][0] 9657e3b8737SDaniel Vetter = I915_READ(RING_SYNC_0(ring->mmio_base)); 9667e3b8737SDaniel Vetter error->semaphore_mboxes[ring->id][1] 9677e3b8737SDaniel Vetter = I915_READ(RING_SYNC_1(ring->mmio_base)); 96833f3f518SDaniel Vetter } 969c1cd90edSDaniel Vetter 970d27b1e0eSDaniel Vetter if (INTEL_INFO(dev)->gen >= 4) { 9719d2f41faSDaniel Vetter error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base)); 972d27b1e0eSDaniel Vetter error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base)); 973d27b1e0eSDaniel Vetter error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base)); 974d27b1e0eSDaniel Vetter error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base)); 975c1cd90edSDaniel Vetter error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base)); 976d27b1e0eSDaniel Vetter if (ring->id == RCS) { 977d27b1e0eSDaniel Vetter error->instdone1 = I915_READ(INSTDONE1); 978d27b1e0eSDaniel Vetter error->bbaddr = I915_READ64(BB_ADDR); 979d27b1e0eSDaniel Vetter } 980d27b1e0eSDaniel Vetter } else { 9819d2f41faSDaniel Vetter error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX); 982d27b1e0eSDaniel Vetter error->ipeir[ring->id] = I915_READ(IPEIR); 983d27b1e0eSDaniel Vetter error->ipehr[ring->id] = I915_READ(IPEHR); 984d27b1e0eSDaniel Vetter error->instdone[ring->id] = I915_READ(INSTDONE); 985d27b1e0eSDaniel Vetter } 986d27b1e0eSDaniel Vetter 9879574b3feSBen Widawsky error->waiting[ring->id] = waitqueue_active(&ring->irq_queue); 988c1cd90edSDaniel Vetter error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base)); 989d27b1e0eSDaniel Vetter error->seqno[ring->id] = ring->get_seqno(ring); 990d27b1e0eSDaniel Vetter error->acthd[ring->id] = intel_ring_get_active_head(ring); 991c1cd90edSDaniel Vetter error->head[ring->id] = I915_READ_HEAD(ring); 992c1cd90edSDaniel Vetter error->tail[ring->id] = I915_READ_TAIL(ring); 9937e3b8737SDaniel Vetter 9947e3b8737SDaniel Vetter error->cpu_ring_head[ring->id] = ring->head; 9957e3b8737SDaniel Vetter error->cpu_ring_tail[ring->id] = ring->tail; 996d27b1e0eSDaniel Vetter } 997d27b1e0eSDaniel Vetter 99852d39a21SChris Wilson static void i915_gem_record_rings(struct drm_device *dev, 99952d39a21SChris Wilson struct drm_i915_error_state *error) 100052d39a21SChris Wilson { 100152d39a21SChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 1002b4519513SChris Wilson struct intel_ring_buffer *ring; 100352d39a21SChris Wilson struct drm_i915_gem_request *request; 100452d39a21SChris Wilson int i, count; 100552d39a21SChris Wilson 1006b4519513SChris Wilson for_each_ring(ring, dev_priv, i) { 100752d39a21SChris Wilson i915_record_ring_state(dev, error, ring); 100852d39a21SChris Wilson 100952d39a21SChris Wilson error->ring[i].batchbuffer = 101052d39a21SChris Wilson i915_error_first_batchbuffer(dev_priv, ring); 101152d39a21SChris Wilson 101252d39a21SChris Wilson error->ring[i].ringbuffer = 101352d39a21SChris Wilson i915_error_object_create(dev_priv, ring->obj); 101452d39a21SChris Wilson 101552d39a21SChris Wilson count = 0; 101652d39a21SChris Wilson list_for_each_entry(request, &ring->request_list, list) 101752d39a21SChris Wilson count++; 101852d39a21SChris Wilson 101952d39a21SChris Wilson error->ring[i].num_requests = count; 102052d39a21SChris Wilson error->ring[i].requests = 102152d39a21SChris Wilson kmalloc(count*sizeof(struct drm_i915_error_request), 102252d39a21SChris Wilson GFP_ATOMIC); 102352d39a21SChris Wilson if (error->ring[i].requests == NULL) { 102452d39a21SChris Wilson error->ring[i].num_requests = 0; 102552d39a21SChris Wilson continue; 102652d39a21SChris Wilson } 102752d39a21SChris Wilson 102852d39a21SChris Wilson count = 0; 102952d39a21SChris Wilson list_for_each_entry(request, &ring->request_list, list) { 103052d39a21SChris Wilson struct drm_i915_error_request *erq; 103152d39a21SChris Wilson 103252d39a21SChris Wilson erq = &error->ring[i].requests[count++]; 103352d39a21SChris Wilson erq->seqno = request->seqno; 103452d39a21SChris Wilson erq->jiffies = request->emitted_jiffies; 1035ee4f42b1SChris Wilson erq->tail = request->tail; 103652d39a21SChris Wilson } 103752d39a21SChris Wilson } 103852d39a21SChris Wilson } 103952d39a21SChris Wilson 10408a905236SJesse Barnes /** 10418a905236SJesse Barnes * i915_capture_error_state - capture an error record for later analysis 10428a905236SJesse Barnes * @dev: drm device 10438a905236SJesse Barnes * 10448a905236SJesse Barnes * Should be called when an error is detected (either a hang or an error 10458a905236SJesse Barnes * interrupt) to capture error state from the time of the error. Fills 10468a905236SJesse Barnes * out a structure which becomes available in debugfs for user level tools 10478a905236SJesse Barnes * to pick up. 10488a905236SJesse Barnes */ 104963eeaf38SJesse Barnes static void i915_capture_error_state(struct drm_device *dev) 105063eeaf38SJesse Barnes { 105163eeaf38SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 105205394f39SChris Wilson struct drm_i915_gem_object *obj; 105363eeaf38SJesse Barnes struct drm_i915_error_state *error; 105463eeaf38SJesse Barnes unsigned long flags; 10559db4a9c7SJesse Barnes int i, pipe; 105663eeaf38SJesse Barnes 105763eeaf38SJesse Barnes spin_lock_irqsave(&dev_priv->error_lock, flags); 10589df30794SChris Wilson error = dev_priv->first_error; 10599df30794SChris Wilson spin_unlock_irqrestore(&dev_priv->error_lock, flags); 10609df30794SChris Wilson if (error) 10619df30794SChris Wilson return; 106263eeaf38SJesse Barnes 10639db4a9c7SJesse Barnes /* Account for pipe specific data like PIPE*STAT */ 106433f3f518SDaniel Vetter error = kzalloc(sizeof(*error), GFP_ATOMIC); 106563eeaf38SJesse Barnes if (!error) { 10669df30794SChris Wilson DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); 10679df30794SChris Wilson return; 106863eeaf38SJesse Barnes } 106963eeaf38SJesse Barnes 1070b6f7833bSChris Wilson DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n", 1071b6f7833bSChris Wilson dev->primary->index); 10722fa772f3SChris Wilson 1073742cbee8SDaniel Vetter kref_init(&error->ref); 107463eeaf38SJesse Barnes error->eir = I915_READ(EIR); 107563eeaf38SJesse Barnes error->pgtbl_er = I915_READ(PGTBL_ER); 1076be998e2eSBen Widawsky 1077be998e2eSBen Widawsky if (HAS_PCH_SPLIT(dev)) 1078be998e2eSBen Widawsky error->ier = I915_READ(DEIER) | I915_READ(GTIER); 1079be998e2eSBen Widawsky else if (IS_VALLEYVIEW(dev)) 1080be998e2eSBen Widawsky error->ier = I915_READ(GTIER) | I915_READ(VLV_IER); 1081be998e2eSBen Widawsky else if (IS_GEN2(dev)) 1082be998e2eSBen Widawsky error->ier = I915_READ16(IER); 1083be998e2eSBen Widawsky else 1084be998e2eSBen Widawsky error->ier = I915_READ(IER); 1085be998e2eSBen Widawsky 10869db4a9c7SJesse Barnes for_each_pipe(pipe) 10879db4a9c7SJesse Barnes error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); 1088d27b1e0eSDaniel Vetter 108933f3f518SDaniel Vetter if (INTEL_INFO(dev)->gen >= 6) { 1090f406839fSChris Wilson error->error = I915_READ(ERROR_GEN6); 109133f3f518SDaniel Vetter error->done_reg = I915_READ(DONE_REG); 109233f3f518SDaniel Vetter } 1093add354ddSChris Wilson 1094748ebc60SChris Wilson i915_gem_record_fences(dev, error); 109552d39a21SChris Wilson i915_gem_record_rings(dev, error); 10969df30794SChris Wilson 1097c724e8a9SChris Wilson /* Record buffers on the active and pinned lists. */ 10989df30794SChris Wilson error->active_bo = NULL; 1099c724e8a9SChris Wilson error->pinned_bo = NULL; 11009df30794SChris Wilson 1101bcfb2e28SChris Wilson i = 0; 1102bcfb2e28SChris Wilson list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) 1103bcfb2e28SChris Wilson i++; 1104bcfb2e28SChris Wilson error->active_bo_count = i; 11051b50247aSChris Wilson list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) 11061b50247aSChris Wilson if (obj->pin_count) 1107bcfb2e28SChris Wilson i++; 1108bcfb2e28SChris Wilson error->pinned_bo_count = i - error->active_bo_count; 1109c724e8a9SChris Wilson 11108e934dbfSChris Wilson error->active_bo = NULL; 11118e934dbfSChris Wilson error->pinned_bo = NULL; 1112bcfb2e28SChris Wilson if (i) { 1113bcfb2e28SChris Wilson error->active_bo = kmalloc(sizeof(*error->active_bo)*i, 11149df30794SChris Wilson GFP_ATOMIC); 1115c724e8a9SChris Wilson if (error->active_bo) 1116c724e8a9SChris Wilson error->pinned_bo = 1117c724e8a9SChris Wilson error->active_bo + error->active_bo_count; 11189df30794SChris Wilson } 1119c724e8a9SChris Wilson 1120c724e8a9SChris Wilson if (error->active_bo) 1121c724e8a9SChris Wilson error->active_bo_count = 11221b50247aSChris Wilson capture_active_bo(error->active_bo, 1123c724e8a9SChris Wilson error->active_bo_count, 1124c724e8a9SChris Wilson &dev_priv->mm.active_list); 1125c724e8a9SChris Wilson 1126c724e8a9SChris Wilson if (error->pinned_bo) 1127c724e8a9SChris Wilson error->pinned_bo_count = 11281b50247aSChris Wilson capture_pinned_bo(error->pinned_bo, 1129c724e8a9SChris Wilson error->pinned_bo_count, 11301b50247aSChris Wilson &dev_priv->mm.gtt_list); 113163eeaf38SJesse Barnes 11328a905236SJesse Barnes do_gettimeofday(&error->time); 11338a905236SJesse Barnes 11346ef3d427SChris Wilson error->overlay = intel_overlay_capture_error_state(dev); 1135c4a1d9e4SChris Wilson error->display = intel_display_capture_error_state(dev); 11366ef3d427SChris Wilson 11379df30794SChris Wilson spin_lock_irqsave(&dev_priv->error_lock, flags); 11389df30794SChris Wilson if (dev_priv->first_error == NULL) { 113963eeaf38SJesse Barnes dev_priv->first_error = error; 11409df30794SChris Wilson error = NULL; 11419df30794SChris Wilson } 114263eeaf38SJesse Barnes spin_unlock_irqrestore(&dev_priv->error_lock, flags); 11439df30794SChris Wilson 11449df30794SChris Wilson if (error) 1145742cbee8SDaniel Vetter i915_error_state_free(&error->ref); 11469df30794SChris Wilson } 11479df30794SChris Wilson 11489df30794SChris Wilson void i915_destroy_error_state(struct drm_device *dev) 11499df30794SChris Wilson { 11509df30794SChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 11519df30794SChris Wilson struct drm_i915_error_state *error; 11526dc0e816SBen Widawsky unsigned long flags; 11539df30794SChris Wilson 11546dc0e816SBen Widawsky spin_lock_irqsave(&dev_priv->error_lock, flags); 11559df30794SChris Wilson error = dev_priv->first_error; 11569df30794SChris Wilson dev_priv->first_error = NULL; 11576dc0e816SBen Widawsky spin_unlock_irqrestore(&dev_priv->error_lock, flags); 11589df30794SChris Wilson 11599df30794SChris Wilson if (error) 1160742cbee8SDaniel Vetter kref_put(&error->ref, i915_error_state_free); 116163eeaf38SJesse Barnes } 11623bd3c932SChris Wilson #else 11633bd3c932SChris Wilson #define i915_capture_error_state(x) 11643bd3c932SChris Wilson #endif 116563eeaf38SJesse Barnes 116635aed2e6SChris Wilson static void i915_report_and_clear_eir(struct drm_device *dev) 1167c0e09200SDave Airlie { 11688a905236SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 116963eeaf38SJesse Barnes u32 eir = I915_READ(EIR); 11709db4a9c7SJesse Barnes int pipe; 117163eeaf38SJesse Barnes 117235aed2e6SChris Wilson if (!eir) 117335aed2e6SChris Wilson return; 117463eeaf38SJesse Barnes 1175a70491ccSJoe Perches pr_err("render error detected, EIR: 0x%08x\n", eir); 11768a905236SJesse Barnes 11778a905236SJesse Barnes if (IS_G4X(dev)) { 11788a905236SJesse Barnes if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) { 11798a905236SJesse Barnes u32 ipeir = I915_READ(IPEIR_I965); 11808a905236SJesse Barnes 1181a70491ccSJoe Perches pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR_I965)); 1182a70491ccSJoe Perches pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR_I965)); 1183a70491ccSJoe Perches pr_err(" INSTDONE: 0x%08x\n", 11848a905236SJesse Barnes I915_READ(INSTDONE_I965)); 1185a70491ccSJoe Perches pr_err(" INSTPS: 0x%08x\n", I915_READ(INSTPS)); 1186a70491ccSJoe Perches pr_err(" INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1)); 1187a70491ccSJoe Perches pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD_I965)); 11888a905236SJesse Barnes I915_WRITE(IPEIR_I965, ipeir); 11893143a2bfSChris Wilson POSTING_READ(IPEIR_I965); 11908a905236SJesse Barnes } 11918a905236SJesse Barnes if (eir & GM45_ERROR_PAGE_TABLE) { 11928a905236SJesse Barnes u32 pgtbl_err = I915_READ(PGTBL_ER); 1193a70491ccSJoe Perches pr_err("page table error\n"); 1194a70491ccSJoe Perches pr_err(" PGTBL_ER: 0x%08x\n", pgtbl_err); 11958a905236SJesse Barnes I915_WRITE(PGTBL_ER, pgtbl_err); 11963143a2bfSChris Wilson POSTING_READ(PGTBL_ER); 11978a905236SJesse Barnes } 11988a905236SJesse Barnes } 11998a905236SJesse Barnes 1200a6c45cf0SChris Wilson if (!IS_GEN2(dev)) { 120163eeaf38SJesse Barnes if (eir & I915_ERROR_PAGE_TABLE) { 120263eeaf38SJesse Barnes u32 pgtbl_err = I915_READ(PGTBL_ER); 1203a70491ccSJoe Perches pr_err("page table error\n"); 1204a70491ccSJoe Perches pr_err(" PGTBL_ER: 0x%08x\n", pgtbl_err); 120563eeaf38SJesse Barnes I915_WRITE(PGTBL_ER, pgtbl_err); 12063143a2bfSChris Wilson POSTING_READ(PGTBL_ER); 120763eeaf38SJesse Barnes } 12088a905236SJesse Barnes } 12098a905236SJesse Barnes 121063eeaf38SJesse Barnes if (eir & I915_ERROR_MEMORY_REFRESH) { 1211a70491ccSJoe Perches pr_err("memory refresh error:\n"); 12129db4a9c7SJesse Barnes for_each_pipe(pipe) 1213a70491ccSJoe Perches pr_err("pipe %c stat: 0x%08x\n", 12149db4a9c7SJesse Barnes pipe_name(pipe), I915_READ(PIPESTAT(pipe))); 121563eeaf38SJesse Barnes /* pipestat has already been acked */ 121663eeaf38SJesse Barnes } 121763eeaf38SJesse Barnes if (eir & I915_ERROR_INSTRUCTION) { 1218a70491ccSJoe Perches pr_err("instruction error\n"); 1219a70491ccSJoe Perches pr_err(" INSTPM: 0x%08x\n", I915_READ(INSTPM)); 1220a6c45cf0SChris Wilson if (INTEL_INFO(dev)->gen < 4) { 122163eeaf38SJesse Barnes u32 ipeir = I915_READ(IPEIR); 122263eeaf38SJesse Barnes 1223a70491ccSJoe Perches pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR)); 1224a70491ccSJoe Perches pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR)); 1225a70491ccSJoe Perches pr_err(" INSTDONE: 0x%08x\n", I915_READ(INSTDONE)); 1226a70491ccSJoe Perches pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD)); 122763eeaf38SJesse Barnes I915_WRITE(IPEIR, ipeir); 12283143a2bfSChris Wilson POSTING_READ(IPEIR); 122963eeaf38SJesse Barnes } else { 123063eeaf38SJesse Barnes u32 ipeir = I915_READ(IPEIR_I965); 123163eeaf38SJesse Barnes 1232a70491ccSJoe Perches pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR_I965)); 1233a70491ccSJoe Perches pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR_I965)); 1234a70491ccSJoe Perches pr_err(" INSTDONE: 0x%08x\n", 123563eeaf38SJesse Barnes I915_READ(INSTDONE_I965)); 1236a70491ccSJoe Perches pr_err(" INSTPS: 0x%08x\n", I915_READ(INSTPS)); 1237a70491ccSJoe Perches pr_err(" INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1)); 1238a70491ccSJoe Perches pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD_I965)); 123963eeaf38SJesse Barnes I915_WRITE(IPEIR_I965, ipeir); 12403143a2bfSChris Wilson POSTING_READ(IPEIR_I965); 124163eeaf38SJesse Barnes } 124263eeaf38SJesse Barnes } 124363eeaf38SJesse Barnes 124463eeaf38SJesse Barnes I915_WRITE(EIR, eir); 12453143a2bfSChris Wilson POSTING_READ(EIR); 124663eeaf38SJesse Barnes eir = I915_READ(EIR); 124763eeaf38SJesse Barnes if (eir) { 124863eeaf38SJesse Barnes /* 124963eeaf38SJesse Barnes * some errors might have become stuck, 125063eeaf38SJesse Barnes * mask them. 125163eeaf38SJesse Barnes */ 125263eeaf38SJesse Barnes DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir); 125363eeaf38SJesse Barnes I915_WRITE(EMR, I915_READ(EMR) | eir); 125463eeaf38SJesse Barnes I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 125563eeaf38SJesse Barnes } 125635aed2e6SChris Wilson } 125735aed2e6SChris Wilson 125835aed2e6SChris Wilson /** 125935aed2e6SChris Wilson * i915_handle_error - handle an error interrupt 126035aed2e6SChris Wilson * @dev: drm device 126135aed2e6SChris Wilson * 126235aed2e6SChris Wilson * Do some basic checking of regsiter state at error interrupt time and 126335aed2e6SChris Wilson * dump it to the syslog. Also call i915_capture_error_state() to make 126435aed2e6SChris Wilson * sure we get a record and make it available in debugfs. Fire a uevent 126535aed2e6SChris Wilson * so userspace knows something bad happened (should trigger collection 126635aed2e6SChris Wilson * of a ring dump etc.). 126735aed2e6SChris Wilson */ 1268527f9e90SChris Wilson void i915_handle_error(struct drm_device *dev, bool wedged) 126935aed2e6SChris Wilson { 127035aed2e6SChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 1271b4519513SChris Wilson struct intel_ring_buffer *ring; 1272b4519513SChris Wilson int i; 127335aed2e6SChris Wilson 127435aed2e6SChris Wilson i915_capture_error_state(dev); 127535aed2e6SChris Wilson i915_report_and_clear_eir(dev); 12768a905236SJesse Barnes 1277ba1234d1SBen Gamari if (wedged) { 127830dbf0c0SChris Wilson INIT_COMPLETION(dev_priv->error_completion); 1279ba1234d1SBen Gamari atomic_set(&dev_priv->mm.wedged, 1); 1280ba1234d1SBen Gamari 128111ed50ecSBen Gamari /* 128211ed50ecSBen Gamari * Wakeup waiting processes so they don't hang 128311ed50ecSBen Gamari */ 1284b4519513SChris Wilson for_each_ring(ring, dev_priv, i) 1285b4519513SChris Wilson wake_up_all(&ring->irq_queue); 128611ed50ecSBen Gamari } 128711ed50ecSBen Gamari 12889c9fe1f8SEric Anholt queue_work(dev_priv->wq, &dev_priv->error_work); 12898a905236SJesse Barnes } 12908a905236SJesse Barnes 12914e5359cdSSimon Farnsworth static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) 12924e5359cdSSimon Farnsworth { 12934e5359cdSSimon Farnsworth drm_i915_private_t *dev_priv = dev->dev_private; 12944e5359cdSSimon Farnsworth struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; 12954e5359cdSSimon Farnsworth struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 129605394f39SChris Wilson struct drm_i915_gem_object *obj; 12974e5359cdSSimon Farnsworth struct intel_unpin_work *work; 12984e5359cdSSimon Farnsworth unsigned long flags; 12994e5359cdSSimon Farnsworth bool stall_detected; 13004e5359cdSSimon Farnsworth 13014e5359cdSSimon Farnsworth /* Ignore early vblank irqs */ 13024e5359cdSSimon Farnsworth if (intel_crtc == NULL) 13034e5359cdSSimon Farnsworth return; 13044e5359cdSSimon Farnsworth 13054e5359cdSSimon Farnsworth spin_lock_irqsave(&dev->event_lock, flags); 13064e5359cdSSimon Farnsworth work = intel_crtc->unpin_work; 13074e5359cdSSimon Farnsworth 13084e5359cdSSimon Farnsworth if (work == NULL || work->pending || !work->enable_stall_check) { 13094e5359cdSSimon Farnsworth /* Either the pending flip IRQ arrived, or we're too early. Don't check */ 13104e5359cdSSimon Farnsworth spin_unlock_irqrestore(&dev->event_lock, flags); 13114e5359cdSSimon Farnsworth return; 13124e5359cdSSimon Farnsworth } 13134e5359cdSSimon Farnsworth 13144e5359cdSSimon Farnsworth /* Potential stall - if we see that the flip has happened, assume a missed interrupt */ 131505394f39SChris Wilson obj = work->pending_flip_obj; 1316a6c45cf0SChris Wilson if (INTEL_INFO(dev)->gen >= 4) { 13179db4a9c7SJesse Barnes int dspsurf = DSPSURF(intel_crtc->plane); 1318446f2545SArmin Reese stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) == 1319446f2545SArmin Reese obj->gtt_offset; 13204e5359cdSSimon Farnsworth } else { 13219db4a9c7SJesse Barnes int dspaddr = DSPADDR(intel_crtc->plane); 132205394f39SChris Wilson stall_detected = I915_READ(dspaddr) == (obj->gtt_offset + 132301f2c773SVille Syrjälä crtc->y * crtc->fb->pitches[0] + 13244e5359cdSSimon Farnsworth crtc->x * crtc->fb->bits_per_pixel/8); 13254e5359cdSSimon Farnsworth } 13264e5359cdSSimon Farnsworth 13274e5359cdSSimon Farnsworth spin_unlock_irqrestore(&dev->event_lock, flags); 13284e5359cdSSimon Farnsworth 13294e5359cdSSimon Farnsworth if (stall_detected) { 13304e5359cdSSimon Farnsworth DRM_DEBUG_DRIVER("Pageflip stall detected\n"); 13314e5359cdSSimon Farnsworth intel_prepare_page_flip(dev, intel_crtc->plane); 13324e5359cdSSimon Farnsworth } 13334e5359cdSSimon Farnsworth } 13344e5359cdSSimon Farnsworth 133542f52ef8SKeith Packard /* Called from drm generic code, passed 'crtc' which 133642f52ef8SKeith Packard * we use as a pipe index 133742f52ef8SKeith Packard */ 1338f71d4af4SJesse Barnes static int i915_enable_vblank(struct drm_device *dev, int pipe) 13390a3e67a4SJesse Barnes { 13400a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1341e9d21d7fSKeith Packard unsigned long irqflags; 134271e0ffa5SJesse Barnes 13435eddb70bSChris Wilson if (!i915_pipe_enabled(dev, pipe)) 134471e0ffa5SJesse Barnes return -EINVAL; 13450a3e67a4SJesse Barnes 13461ec14ad3SChris Wilson spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 1347f796cf8fSJesse Barnes if (INTEL_INFO(dev)->gen >= 4) 13487c463586SKeith Packard i915_enable_pipestat(dev_priv, pipe, 13497c463586SKeith Packard PIPE_START_VBLANK_INTERRUPT_ENABLE); 13500a3e67a4SJesse Barnes else 13517c463586SKeith Packard i915_enable_pipestat(dev_priv, pipe, 13527c463586SKeith Packard PIPE_VBLANK_INTERRUPT_ENABLE); 13538692d00eSChris Wilson 13548692d00eSChris Wilson /* maintain vblank delivery even in deep C-states */ 13558692d00eSChris Wilson if (dev_priv->info->gen == 3) 13566b26c86dSDaniel Vetter I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_AGPBUSY_DIS)); 13571ec14ad3SChris Wilson spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 13588692d00eSChris Wilson 13590a3e67a4SJesse Barnes return 0; 13600a3e67a4SJesse Barnes } 13610a3e67a4SJesse Barnes 1362f71d4af4SJesse Barnes static int ironlake_enable_vblank(struct drm_device *dev, int pipe) 1363f796cf8fSJesse Barnes { 1364f796cf8fSJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1365f796cf8fSJesse Barnes unsigned long irqflags; 1366f796cf8fSJesse Barnes 1367f796cf8fSJesse Barnes if (!i915_pipe_enabled(dev, pipe)) 1368f796cf8fSJesse Barnes return -EINVAL; 1369f796cf8fSJesse Barnes 1370f796cf8fSJesse Barnes spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 1371f796cf8fSJesse Barnes ironlake_enable_display_irq(dev_priv, (pipe == 0) ? 1372f796cf8fSJesse Barnes DE_PIPEA_VBLANK : DE_PIPEB_VBLANK); 1373f796cf8fSJesse Barnes spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 1374f796cf8fSJesse Barnes 1375f796cf8fSJesse Barnes return 0; 1376f796cf8fSJesse Barnes } 1377f796cf8fSJesse Barnes 1378f71d4af4SJesse Barnes static int ivybridge_enable_vblank(struct drm_device *dev, int pipe) 1379b1f14ad0SJesse Barnes { 1380b1f14ad0SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1381b1f14ad0SJesse Barnes unsigned long irqflags; 1382b1f14ad0SJesse Barnes 1383b1f14ad0SJesse Barnes if (!i915_pipe_enabled(dev, pipe)) 1384b1f14ad0SJesse Barnes return -EINVAL; 1385b1f14ad0SJesse Barnes 1386b1f14ad0SJesse Barnes spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 1387b615b57aSChris Wilson ironlake_enable_display_irq(dev_priv, 1388b615b57aSChris Wilson DE_PIPEA_VBLANK_IVB << (5 * pipe)); 1389b1f14ad0SJesse Barnes spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 1390b1f14ad0SJesse Barnes 1391b1f14ad0SJesse Barnes return 0; 1392b1f14ad0SJesse Barnes } 1393b1f14ad0SJesse Barnes 13947e231dbeSJesse Barnes static int valleyview_enable_vblank(struct drm_device *dev, int pipe) 13957e231dbeSJesse Barnes { 13967e231dbeSJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 13977e231dbeSJesse Barnes unsigned long irqflags; 13987e231dbeSJesse Barnes u32 dpfl, imr; 13997e231dbeSJesse Barnes 14007e231dbeSJesse Barnes if (!i915_pipe_enabled(dev, pipe)) 14017e231dbeSJesse Barnes return -EINVAL; 14027e231dbeSJesse Barnes 14037e231dbeSJesse Barnes spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 14047e231dbeSJesse Barnes dpfl = I915_READ(VLV_DPFLIPSTAT); 14057e231dbeSJesse Barnes imr = I915_READ(VLV_IMR); 14067e231dbeSJesse Barnes if (pipe == 0) { 14077e231dbeSJesse Barnes dpfl |= PIPEA_VBLANK_INT_EN; 14087e231dbeSJesse Barnes imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; 14097e231dbeSJesse Barnes } else { 14107e231dbeSJesse Barnes dpfl |= PIPEA_VBLANK_INT_EN; 14117e231dbeSJesse Barnes imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; 14127e231dbeSJesse Barnes } 14137e231dbeSJesse Barnes I915_WRITE(VLV_DPFLIPSTAT, dpfl); 14147e231dbeSJesse Barnes I915_WRITE(VLV_IMR, imr); 14157e231dbeSJesse Barnes spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 14167e231dbeSJesse Barnes 14177e231dbeSJesse Barnes return 0; 14187e231dbeSJesse Barnes } 14197e231dbeSJesse Barnes 142042f52ef8SKeith Packard /* Called from drm generic code, passed 'crtc' which 142142f52ef8SKeith Packard * we use as a pipe index 142242f52ef8SKeith Packard */ 1423f71d4af4SJesse Barnes static void i915_disable_vblank(struct drm_device *dev, int pipe) 14240a3e67a4SJesse Barnes { 14250a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1426e9d21d7fSKeith Packard unsigned long irqflags; 14270a3e67a4SJesse Barnes 14281ec14ad3SChris Wilson spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 14298692d00eSChris Wilson if (dev_priv->info->gen == 3) 14306b26c86dSDaniel Vetter I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_DIS)); 14318692d00eSChris Wilson 14327c463586SKeith Packard i915_disable_pipestat(dev_priv, pipe, 14337c463586SKeith Packard PIPE_VBLANK_INTERRUPT_ENABLE | 14347c463586SKeith Packard PIPE_START_VBLANK_INTERRUPT_ENABLE); 14351ec14ad3SChris Wilson spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 14360a3e67a4SJesse Barnes } 14370a3e67a4SJesse Barnes 1438f71d4af4SJesse Barnes static void ironlake_disable_vblank(struct drm_device *dev, int pipe) 1439f796cf8fSJesse Barnes { 1440f796cf8fSJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1441f796cf8fSJesse Barnes unsigned long irqflags; 1442f796cf8fSJesse Barnes 1443f796cf8fSJesse Barnes spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 1444f796cf8fSJesse Barnes ironlake_disable_display_irq(dev_priv, (pipe == 0) ? 1445f796cf8fSJesse Barnes DE_PIPEA_VBLANK : DE_PIPEB_VBLANK); 1446f796cf8fSJesse Barnes spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 1447f796cf8fSJesse Barnes } 1448f796cf8fSJesse Barnes 1449f71d4af4SJesse Barnes static void ivybridge_disable_vblank(struct drm_device *dev, int pipe) 1450b1f14ad0SJesse Barnes { 1451b1f14ad0SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1452b1f14ad0SJesse Barnes unsigned long irqflags; 1453b1f14ad0SJesse Barnes 1454b1f14ad0SJesse Barnes spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 1455b615b57aSChris Wilson ironlake_disable_display_irq(dev_priv, 1456b615b57aSChris Wilson DE_PIPEA_VBLANK_IVB << (pipe * 5)); 1457b1f14ad0SJesse Barnes spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 1458b1f14ad0SJesse Barnes } 1459b1f14ad0SJesse Barnes 14607e231dbeSJesse Barnes static void valleyview_disable_vblank(struct drm_device *dev, int pipe) 14617e231dbeSJesse Barnes { 14627e231dbeSJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 14637e231dbeSJesse Barnes unsigned long irqflags; 14647e231dbeSJesse Barnes u32 dpfl, imr; 14657e231dbeSJesse Barnes 14667e231dbeSJesse Barnes spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 14677e231dbeSJesse Barnes dpfl = I915_READ(VLV_DPFLIPSTAT); 14687e231dbeSJesse Barnes imr = I915_READ(VLV_IMR); 14697e231dbeSJesse Barnes if (pipe == 0) { 14707e231dbeSJesse Barnes dpfl &= ~PIPEA_VBLANK_INT_EN; 14717e231dbeSJesse Barnes imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; 14727e231dbeSJesse Barnes } else { 14737e231dbeSJesse Barnes dpfl &= ~PIPEB_VBLANK_INT_EN; 14747e231dbeSJesse Barnes imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; 14757e231dbeSJesse Barnes } 14767e231dbeSJesse Barnes I915_WRITE(VLV_IMR, imr); 14777e231dbeSJesse Barnes I915_WRITE(VLV_DPFLIPSTAT, dpfl); 14787e231dbeSJesse Barnes spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 14797e231dbeSJesse Barnes } 14807e231dbeSJesse Barnes 1481893eead0SChris Wilson static u32 1482893eead0SChris Wilson ring_last_seqno(struct intel_ring_buffer *ring) 1483852835f3SZou Nan hai { 1484893eead0SChris Wilson return list_entry(ring->request_list.prev, 1485893eead0SChris Wilson struct drm_i915_gem_request, list)->seqno; 1486893eead0SChris Wilson } 1487893eead0SChris Wilson 1488893eead0SChris Wilson static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err) 1489893eead0SChris Wilson { 1490893eead0SChris Wilson if (list_empty(&ring->request_list) || 1491893eead0SChris Wilson i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) { 1492893eead0SChris Wilson /* Issue a wake-up to catch stuck h/w. */ 14939574b3feSBen Widawsky if (waitqueue_active(&ring->irq_queue)) { 14949574b3feSBen Widawsky DRM_ERROR("Hangcheck timer elapsed... %s idle\n", 14959574b3feSBen Widawsky ring->name); 1496893eead0SChris Wilson wake_up_all(&ring->irq_queue); 1497893eead0SChris Wilson *err = true; 1498893eead0SChris Wilson } 1499893eead0SChris Wilson return true; 1500893eead0SChris Wilson } 1501893eead0SChris Wilson return false; 1502f65d9421SBen Gamari } 1503f65d9421SBen Gamari 15041ec14ad3SChris Wilson static bool kick_ring(struct intel_ring_buffer *ring) 15051ec14ad3SChris Wilson { 15061ec14ad3SChris Wilson struct drm_device *dev = ring->dev; 15071ec14ad3SChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 15081ec14ad3SChris Wilson u32 tmp = I915_READ_CTL(ring); 15091ec14ad3SChris Wilson if (tmp & RING_WAIT) { 15101ec14ad3SChris Wilson DRM_ERROR("Kicking stuck wait on %s\n", 15111ec14ad3SChris Wilson ring->name); 15121ec14ad3SChris Wilson I915_WRITE_CTL(ring, tmp); 15131ec14ad3SChris Wilson return true; 15141ec14ad3SChris Wilson } 15151ec14ad3SChris Wilson return false; 15161ec14ad3SChris Wilson } 15171ec14ad3SChris Wilson 1518d1e61e7fSChris Wilson static bool i915_hangcheck_hung(struct drm_device *dev) 1519d1e61e7fSChris Wilson { 1520d1e61e7fSChris Wilson drm_i915_private_t *dev_priv = dev->dev_private; 1521d1e61e7fSChris Wilson 1522d1e61e7fSChris Wilson if (dev_priv->hangcheck_count++ > 1) { 1523b4519513SChris Wilson bool hung = true; 1524b4519513SChris Wilson 1525d1e61e7fSChris Wilson DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); 1526d1e61e7fSChris Wilson i915_handle_error(dev, true); 1527d1e61e7fSChris Wilson 1528d1e61e7fSChris Wilson if (!IS_GEN2(dev)) { 1529b4519513SChris Wilson struct intel_ring_buffer *ring; 1530b4519513SChris Wilson int i; 1531b4519513SChris Wilson 1532d1e61e7fSChris Wilson /* Is the chip hanging on a WAIT_FOR_EVENT? 1533d1e61e7fSChris Wilson * If so we can simply poke the RB_WAIT bit 1534d1e61e7fSChris Wilson * and break the hang. This should work on 1535d1e61e7fSChris Wilson * all but the second generation chipsets. 1536d1e61e7fSChris Wilson */ 1537b4519513SChris Wilson for_each_ring(ring, dev_priv, i) 1538b4519513SChris Wilson hung &= !kick_ring(ring); 1539d1e61e7fSChris Wilson } 1540d1e61e7fSChris Wilson 1541b4519513SChris Wilson return hung; 1542d1e61e7fSChris Wilson } 1543d1e61e7fSChris Wilson 1544d1e61e7fSChris Wilson return false; 1545d1e61e7fSChris Wilson } 1546d1e61e7fSChris Wilson 1547f65d9421SBen Gamari /** 1548f65d9421SBen Gamari * This is called when the chip hasn't reported back with completed 1549f65d9421SBen Gamari * batchbuffers in a long time. The first time this is called we simply record 1550f65d9421SBen Gamari * ACTHD. If ACTHD hasn't changed by the time the hangcheck timer elapses 1551f65d9421SBen Gamari * again, we assume the chip is wedged and try to fix it. 1552f65d9421SBen Gamari */ 1553f65d9421SBen Gamari void i915_hangcheck_elapsed(unsigned long data) 1554f65d9421SBen Gamari { 1555f65d9421SBen Gamari struct drm_device *dev = (struct drm_device *)data; 1556f65d9421SBen Gamari drm_i915_private_t *dev_priv = dev->dev_private; 1557b4519513SChris Wilson uint32_t acthd[I915_NUM_RINGS], instdone, instdone1; 1558b4519513SChris Wilson struct intel_ring_buffer *ring; 1559b4519513SChris Wilson bool err = false, idle; 1560b4519513SChris Wilson int i; 1561893eead0SChris Wilson 15623e0dc6b0SBen Widawsky if (!i915_enable_hangcheck) 15633e0dc6b0SBen Widawsky return; 15643e0dc6b0SBen Widawsky 1565b4519513SChris Wilson memset(acthd, 0, sizeof(acthd)); 1566b4519513SChris Wilson idle = true; 1567b4519513SChris Wilson for_each_ring(ring, dev_priv, i) { 1568b4519513SChris Wilson idle &= i915_hangcheck_ring_idle(ring, &err); 1569b4519513SChris Wilson acthd[i] = intel_ring_get_active_head(ring); 1570b4519513SChris Wilson } 1571b4519513SChris Wilson 1572893eead0SChris Wilson /* If all work is done then ACTHD clearly hasn't advanced. */ 1573b4519513SChris Wilson if (idle) { 1574d1e61e7fSChris Wilson if (err) { 1575d1e61e7fSChris Wilson if (i915_hangcheck_hung(dev)) 1576d1e61e7fSChris Wilson return; 1577d1e61e7fSChris Wilson 1578893eead0SChris Wilson goto repeat; 1579d1e61e7fSChris Wilson } 1580d1e61e7fSChris Wilson 1581d1e61e7fSChris Wilson dev_priv->hangcheck_count = 0; 1582893eead0SChris Wilson return; 1583893eead0SChris Wilson } 1584f65d9421SBen Gamari 1585a6c45cf0SChris Wilson if (INTEL_INFO(dev)->gen < 4) { 1586cbb465e7SChris Wilson instdone = I915_READ(INSTDONE); 1587cbb465e7SChris Wilson instdone1 = 0; 1588cbb465e7SChris Wilson } else { 1589cbb465e7SChris Wilson instdone = I915_READ(INSTDONE_I965); 1590cbb465e7SChris Wilson instdone1 = I915_READ(INSTDONE1); 1591cbb465e7SChris Wilson } 1592f65d9421SBen Gamari 1593b4519513SChris Wilson if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 && 1594cbb465e7SChris Wilson dev_priv->last_instdone == instdone && 1595cbb465e7SChris Wilson dev_priv->last_instdone1 == instdone1) { 1596d1e61e7fSChris Wilson if (i915_hangcheck_hung(dev)) 1597f65d9421SBen Gamari return; 1598cbb465e7SChris Wilson } else { 1599cbb465e7SChris Wilson dev_priv->hangcheck_count = 0; 1600cbb465e7SChris Wilson 1601b4519513SChris Wilson memcpy(dev_priv->last_acthd, acthd, sizeof(acthd)); 1602cbb465e7SChris Wilson dev_priv->last_instdone = instdone; 1603cbb465e7SChris Wilson dev_priv->last_instdone1 = instdone1; 1604cbb465e7SChris Wilson } 1605f65d9421SBen Gamari 1606893eead0SChris Wilson repeat: 1607f65d9421SBen Gamari /* Reset timer case chip hangs without another request being added */ 1608b3b079dbSChris Wilson mod_timer(&dev_priv->hangcheck_timer, 1609b3b079dbSChris Wilson jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); 1610f65d9421SBen Gamari } 1611f65d9421SBen Gamari 1612c0e09200SDave Airlie /* drm_dma.h hooks 1613c0e09200SDave Airlie */ 1614f71d4af4SJesse Barnes static void ironlake_irq_preinstall(struct drm_device *dev) 1615036a4a7dSZhenyu Wang { 1616036a4a7dSZhenyu Wang drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1617036a4a7dSZhenyu Wang 16184697995bSJesse Barnes atomic_set(&dev_priv->irq_received, 0); 16194697995bSJesse Barnes 16204697995bSJesse Barnes 1621036a4a7dSZhenyu Wang I915_WRITE(HWSTAM, 0xeffe); 1622bdfcdb63SDaniel Vetter 1623036a4a7dSZhenyu Wang /* XXX hotplug from PCH */ 1624036a4a7dSZhenyu Wang 1625036a4a7dSZhenyu Wang I915_WRITE(DEIMR, 0xffffffff); 1626036a4a7dSZhenyu Wang I915_WRITE(DEIER, 0x0); 16273143a2bfSChris Wilson POSTING_READ(DEIER); 1628036a4a7dSZhenyu Wang 1629036a4a7dSZhenyu Wang /* and GT */ 1630036a4a7dSZhenyu Wang I915_WRITE(GTIMR, 0xffffffff); 1631036a4a7dSZhenyu Wang I915_WRITE(GTIER, 0x0); 16323143a2bfSChris Wilson POSTING_READ(GTIER); 1633c650156aSZhenyu Wang 1634c650156aSZhenyu Wang /* south display irq */ 1635c650156aSZhenyu Wang I915_WRITE(SDEIMR, 0xffffffff); 1636c650156aSZhenyu Wang I915_WRITE(SDEIER, 0x0); 16373143a2bfSChris Wilson POSTING_READ(SDEIER); 1638036a4a7dSZhenyu Wang } 1639036a4a7dSZhenyu Wang 16407e231dbeSJesse Barnes static void valleyview_irq_preinstall(struct drm_device *dev) 16417e231dbeSJesse Barnes { 16427e231dbeSJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 16437e231dbeSJesse Barnes int pipe; 16447e231dbeSJesse Barnes 16457e231dbeSJesse Barnes atomic_set(&dev_priv->irq_received, 0); 16467e231dbeSJesse Barnes 16477e231dbeSJesse Barnes /* VLV magic */ 16487e231dbeSJesse Barnes I915_WRITE(VLV_IMR, 0); 16497e231dbeSJesse Barnes I915_WRITE(RING_IMR(RENDER_RING_BASE), 0); 16507e231dbeSJesse Barnes I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0); 16517e231dbeSJesse Barnes I915_WRITE(RING_IMR(BLT_RING_BASE), 0); 16527e231dbeSJesse Barnes 16537e231dbeSJesse Barnes /* and GT */ 16547e231dbeSJesse Barnes I915_WRITE(GTIIR, I915_READ(GTIIR)); 16557e231dbeSJesse Barnes I915_WRITE(GTIIR, I915_READ(GTIIR)); 16567e231dbeSJesse Barnes I915_WRITE(GTIMR, 0xffffffff); 16577e231dbeSJesse Barnes I915_WRITE(GTIER, 0x0); 16587e231dbeSJesse Barnes POSTING_READ(GTIER); 16597e231dbeSJesse Barnes 16607e231dbeSJesse Barnes I915_WRITE(DPINVGTT, 0xff); 16617e231dbeSJesse Barnes 16627e231dbeSJesse Barnes I915_WRITE(PORT_HOTPLUG_EN, 0); 16637e231dbeSJesse Barnes I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 16647e231dbeSJesse Barnes for_each_pipe(pipe) 16657e231dbeSJesse Barnes I915_WRITE(PIPESTAT(pipe), 0xffff); 16667e231dbeSJesse Barnes I915_WRITE(VLV_IIR, 0xffffffff); 16677e231dbeSJesse Barnes I915_WRITE(VLV_IMR, 0xffffffff); 16687e231dbeSJesse Barnes I915_WRITE(VLV_IER, 0x0); 16697e231dbeSJesse Barnes POSTING_READ(VLV_IER); 16707e231dbeSJesse Barnes } 16717e231dbeSJesse Barnes 16727fe0b973SKeith Packard /* 16737fe0b973SKeith Packard * Enable digital hotplug on the PCH, and configure the DP short pulse 16747fe0b973SKeith Packard * duration to 2ms (which is the minimum in the Display Port spec) 16757fe0b973SKeith Packard * 16767fe0b973SKeith Packard * This register is the same on all known PCH chips. 16777fe0b973SKeith Packard */ 16787fe0b973SKeith Packard 16797fe0b973SKeith Packard static void ironlake_enable_pch_hotplug(struct drm_device *dev) 16807fe0b973SKeith Packard { 16817fe0b973SKeith Packard drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 16827fe0b973SKeith Packard u32 hotplug; 16837fe0b973SKeith Packard 16847fe0b973SKeith Packard hotplug = I915_READ(PCH_PORT_HOTPLUG); 16857fe0b973SKeith Packard hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK); 16867fe0b973SKeith Packard hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms; 16877fe0b973SKeith Packard hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms; 16887fe0b973SKeith Packard hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms; 16897fe0b973SKeith Packard I915_WRITE(PCH_PORT_HOTPLUG, hotplug); 16907fe0b973SKeith Packard } 16917fe0b973SKeith Packard 1692f71d4af4SJesse Barnes static int ironlake_irq_postinstall(struct drm_device *dev) 1693036a4a7dSZhenyu Wang { 1694036a4a7dSZhenyu Wang drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1695036a4a7dSZhenyu Wang /* enable kind of interrupts always enabled */ 1696013d5aa2SJesse Barnes u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | 1697013d5aa2SJesse Barnes DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; 16981ec14ad3SChris Wilson u32 render_irqs; 16992d7b8366SYuanhan Liu u32 hotplug_mask; 1700036a4a7dSZhenyu Wang 17011ec14ad3SChris Wilson dev_priv->irq_mask = ~display_mask; 1702036a4a7dSZhenyu Wang 1703036a4a7dSZhenyu Wang /* should always can generate irq */ 1704036a4a7dSZhenyu Wang I915_WRITE(DEIIR, I915_READ(DEIIR)); 17051ec14ad3SChris Wilson I915_WRITE(DEIMR, dev_priv->irq_mask); 17061ec14ad3SChris Wilson I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK); 17073143a2bfSChris Wilson POSTING_READ(DEIER); 1708036a4a7dSZhenyu Wang 17091ec14ad3SChris Wilson dev_priv->gt_irq_mask = ~0; 1710036a4a7dSZhenyu Wang 1711036a4a7dSZhenyu Wang I915_WRITE(GTIIR, I915_READ(GTIIR)); 17121ec14ad3SChris Wilson I915_WRITE(GTIMR, dev_priv->gt_irq_mask); 1713881f47b6SXiang, Haihao 17141ec14ad3SChris Wilson if (IS_GEN6(dev)) 17151ec14ad3SChris Wilson render_irqs = 17161ec14ad3SChris Wilson GT_USER_INTERRUPT | 1717e2a1e2f0SBen Widawsky GEN6_BSD_USER_INTERRUPT | 1718e2a1e2f0SBen Widawsky GEN6_BLITTER_USER_INTERRUPT; 17191ec14ad3SChris Wilson else 17201ec14ad3SChris Wilson render_irqs = 172188f23b8fSChris Wilson GT_USER_INTERRUPT | 1722c6df541cSChris Wilson GT_PIPE_NOTIFY | 17231ec14ad3SChris Wilson GT_BSD_USER_INTERRUPT; 17241ec14ad3SChris Wilson I915_WRITE(GTIER, render_irqs); 17253143a2bfSChris Wilson POSTING_READ(GTIER); 1726036a4a7dSZhenyu Wang 17272d7b8366SYuanhan Liu if (HAS_PCH_CPT(dev)) { 17289035a97aSChris Wilson hotplug_mask = (SDE_CRT_HOTPLUG_CPT | 17299035a97aSChris Wilson SDE_PORTB_HOTPLUG_CPT | 17309035a97aSChris Wilson SDE_PORTC_HOTPLUG_CPT | 17319035a97aSChris Wilson SDE_PORTD_HOTPLUG_CPT); 17322d7b8366SYuanhan Liu } else { 17339035a97aSChris Wilson hotplug_mask = (SDE_CRT_HOTPLUG | 17349035a97aSChris Wilson SDE_PORTB_HOTPLUG | 17359035a97aSChris Wilson SDE_PORTC_HOTPLUG | 17369035a97aSChris Wilson SDE_PORTD_HOTPLUG | 17379035a97aSChris Wilson SDE_AUX_MASK); 17382d7b8366SYuanhan Liu } 17392d7b8366SYuanhan Liu 17401ec14ad3SChris Wilson dev_priv->pch_irq_mask = ~hotplug_mask; 1741c650156aSZhenyu Wang 1742c650156aSZhenyu Wang I915_WRITE(SDEIIR, I915_READ(SDEIIR)); 17431ec14ad3SChris Wilson I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); 17441ec14ad3SChris Wilson I915_WRITE(SDEIER, hotplug_mask); 17453143a2bfSChris Wilson POSTING_READ(SDEIER); 1746c650156aSZhenyu Wang 17477fe0b973SKeith Packard ironlake_enable_pch_hotplug(dev); 17487fe0b973SKeith Packard 1749f97108d1SJesse Barnes if (IS_IRONLAKE_M(dev)) { 1750f97108d1SJesse Barnes /* Clear & enable PCU event interrupts */ 1751f97108d1SJesse Barnes I915_WRITE(DEIIR, DE_PCU_EVENT); 1752f97108d1SJesse Barnes I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT); 1753f97108d1SJesse Barnes ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT); 1754f97108d1SJesse Barnes } 1755f97108d1SJesse Barnes 1756036a4a7dSZhenyu Wang return 0; 1757036a4a7dSZhenyu Wang } 1758036a4a7dSZhenyu Wang 1759f71d4af4SJesse Barnes static int ivybridge_irq_postinstall(struct drm_device *dev) 1760b1f14ad0SJesse Barnes { 1761b1f14ad0SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1762b1f14ad0SJesse Barnes /* enable kind of interrupts always enabled */ 1763b615b57aSChris Wilson u32 display_mask = 1764b615b57aSChris Wilson DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB | 1765b615b57aSChris Wilson DE_PLANEC_FLIP_DONE_IVB | 1766b615b57aSChris Wilson DE_PLANEB_FLIP_DONE_IVB | 1767b615b57aSChris Wilson DE_PLANEA_FLIP_DONE_IVB; 1768b1f14ad0SJesse Barnes u32 render_irqs; 1769b1f14ad0SJesse Barnes u32 hotplug_mask; 1770b1f14ad0SJesse Barnes 1771b1f14ad0SJesse Barnes dev_priv->irq_mask = ~display_mask; 1772b1f14ad0SJesse Barnes 1773b1f14ad0SJesse Barnes /* should always can generate irq */ 1774b1f14ad0SJesse Barnes I915_WRITE(DEIIR, I915_READ(DEIIR)); 1775b1f14ad0SJesse Barnes I915_WRITE(DEIMR, dev_priv->irq_mask); 1776b615b57aSChris Wilson I915_WRITE(DEIER, 1777b615b57aSChris Wilson display_mask | 1778b615b57aSChris Wilson DE_PIPEC_VBLANK_IVB | 1779b615b57aSChris Wilson DE_PIPEB_VBLANK_IVB | 1780b615b57aSChris Wilson DE_PIPEA_VBLANK_IVB); 1781b1f14ad0SJesse Barnes POSTING_READ(DEIER); 1782b1f14ad0SJesse Barnes 1783b1f14ad0SJesse Barnes dev_priv->gt_irq_mask = ~0; 1784b1f14ad0SJesse Barnes 1785b1f14ad0SJesse Barnes I915_WRITE(GTIIR, I915_READ(GTIIR)); 1786b1f14ad0SJesse Barnes I915_WRITE(GTIMR, dev_priv->gt_irq_mask); 1787b1f14ad0SJesse Barnes 1788e2a1e2f0SBen Widawsky render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT | 1789e2a1e2f0SBen Widawsky GEN6_BLITTER_USER_INTERRUPT; 1790b1f14ad0SJesse Barnes I915_WRITE(GTIER, render_irqs); 1791b1f14ad0SJesse Barnes POSTING_READ(GTIER); 1792b1f14ad0SJesse Barnes 1793b1f14ad0SJesse Barnes hotplug_mask = (SDE_CRT_HOTPLUG_CPT | 1794b1f14ad0SJesse Barnes SDE_PORTB_HOTPLUG_CPT | 1795b1f14ad0SJesse Barnes SDE_PORTC_HOTPLUG_CPT | 1796b1f14ad0SJesse Barnes SDE_PORTD_HOTPLUG_CPT); 1797b1f14ad0SJesse Barnes dev_priv->pch_irq_mask = ~hotplug_mask; 1798b1f14ad0SJesse Barnes 1799b1f14ad0SJesse Barnes I915_WRITE(SDEIIR, I915_READ(SDEIIR)); 1800b1f14ad0SJesse Barnes I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); 1801b1f14ad0SJesse Barnes I915_WRITE(SDEIER, hotplug_mask); 1802b1f14ad0SJesse Barnes POSTING_READ(SDEIER); 1803b1f14ad0SJesse Barnes 18047fe0b973SKeith Packard ironlake_enable_pch_hotplug(dev); 18057fe0b973SKeith Packard 1806b1f14ad0SJesse Barnes return 0; 1807b1f14ad0SJesse Barnes } 1808b1f14ad0SJesse Barnes 18097e231dbeSJesse Barnes static int valleyview_irq_postinstall(struct drm_device *dev) 18107e231dbeSJesse Barnes { 18117e231dbeSJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 18127e231dbeSJesse Barnes u32 render_irqs; 18137e231dbeSJesse Barnes u32 enable_mask; 18147e231dbeSJesse Barnes u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); 18157e231dbeSJesse Barnes u16 msid; 18167e231dbeSJesse Barnes 18177e231dbeSJesse Barnes enable_mask = I915_DISPLAY_PORT_INTERRUPT; 18187e231dbeSJesse Barnes enable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | 18197e231dbeSJesse Barnes I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; 18207e231dbeSJesse Barnes 18217e231dbeSJesse Barnes dev_priv->irq_mask = ~enable_mask; 18227e231dbeSJesse Barnes 18237e231dbeSJesse Barnes dev_priv->pipestat[0] = 0; 18247e231dbeSJesse Barnes dev_priv->pipestat[1] = 0; 18257e231dbeSJesse Barnes 18267e231dbeSJesse Barnes /* Hack for broken MSIs on VLV */ 18277e231dbeSJesse Barnes pci_write_config_dword(dev_priv->dev->pdev, 0x94, 0xfee00000); 18287e231dbeSJesse Barnes pci_read_config_word(dev->pdev, 0x98, &msid); 18297e231dbeSJesse Barnes msid &= 0xff; /* mask out delivery bits */ 18307e231dbeSJesse Barnes msid |= (1<<14); 18317e231dbeSJesse Barnes pci_write_config_word(dev_priv->dev->pdev, 0x98, msid); 18327e231dbeSJesse Barnes 18337e231dbeSJesse Barnes I915_WRITE(VLV_IMR, dev_priv->irq_mask); 18347e231dbeSJesse Barnes I915_WRITE(VLV_IER, enable_mask); 18357e231dbeSJesse Barnes I915_WRITE(VLV_IIR, 0xffffffff); 18367e231dbeSJesse Barnes I915_WRITE(PIPESTAT(0), 0xffff); 18377e231dbeSJesse Barnes I915_WRITE(PIPESTAT(1), 0xffff); 18387e231dbeSJesse Barnes POSTING_READ(VLV_IER); 18397e231dbeSJesse Barnes 18407e231dbeSJesse Barnes I915_WRITE(VLV_IIR, 0xffffffff); 18417e231dbeSJesse Barnes I915_WRITE(VLV_IIR, 0xffffffff); 18427e231dbeSJesse Barnes 18437e231dbeSJesse Barnes render_irqs = GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT | 18447e231dbeSJesse Barnes GT_GEN6_BLT_CS_ERROR_INTERRUPT | 1845e2a1e2f0SBen Widawsky GT_GEN6_BLT_USER_INTERRUPT | 18467e231dbeSJesse Barnes GT_GEN6_BSD_USER_INTERRUPT | 18477e231dbeSJesse Barnes GT_GEN6_BSD_CS_ERROR_INTERRUPT | 18487e231dbeSJesse Barnes GT_GEN7_L3_PARITY_ERROR_INTERRUPT | 18497e231dbeSJesse Barnes GT_PIPE_NOTIFY | 18507e231dbeSJesse Barnes GT_RENDER_CS_ERROR_INTERRUPT | 18517e231dbeSJesse Barnes GT_SYNC_STATUS | 18527e231dbeSJesse Barnes GT_USER_INTERRUPT; 18537e231dbeSJesse Barnes 18547e231dbeSJesse Barnes dev_priv->gt_irq_mask = ~render_irqs; 18557e231dbeSJesse Barnes 18567e231dbeSJesse Barnes I915_WRITE(GTIIR, I915_READ(GTIIR)); 18577e231dbeSJesse Barnes I915_WRITE(GTIIR, I915_READ(GTIIR)); 18587e231dbeSJesse Barnes I915_WRITE(GTIMR, 0); 18597e231dbeSJesse Barnes I915_WRITE(GTIER, render_irqs); 18607e231dbeSJesse Barnes POSTING_READ(GTIER); 18617e231dbeSJesse Barnes 18627e231dbeSJesse Barnes /* ack & enable invalid PTE error interrupts */ 18637e231dbeSJesse Barnes #if 0 /* FIXME: add support to irq handler for checking these bits */ 18647e231dbeSJesse Barnes I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK); 18657e231dbeSJesse Barnes I915_WRITE(DPINVGTT, DPINVGTT_EN_MASK); 18667e231dbeSJesse Barnes #endif 18677e231dbeSJesse Barnes 18687e231dbeSJesse Barnes I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); 18697e231dbeSJesse Barnes #if 0 /* FIXME: check register definitions; some have moved */ 18707e231dbeSJesse Barnes /* Note HDMI and DP share bits */ 18717e231dbeSJesse Barnes if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) 18727e231dbeSJesse Barnes hotplug_en |= HDMIB_HOTPLUG_INT_EN; 18737e231dbeSJesse Barnes if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) 18747e231dbeSJesse Barnes hotplug_en |= HDMIC_HOTPLUG_INT_EN; 18757e231dbeSJesse Barnes if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) 18767e231dbeSJesse Barnes hotplug_en |= HDMID_HOTPLUG_INT_EN; 18777e231dbeSJesse Barnes if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS) 18787e231dbeSJesse Barnes hotplug_en |= SDVOC_HOTPLUG_INT_EN; 18797e231dbeSJesse Barnes if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS) 18807e231dbeSJesse Barnes hotplug_en |= SDVOB_HOTPLUG_INT_EN; 18817e231dbeSJesse Barnes if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { 18827e231dbeSJesse Barnes hotplug_en |= CRT_HOTPLUG_INT_EN; 18837e231dbeSJesse Barnes hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; 18847e231dbeSJesse Barnes } 18857e231dbeSJesse Barnes #endif 18867e231dbeSJesse Barnes 18877e231dbeSJesse Barnes I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 18887e231dbeSJesse Barnes 18897e231dbeSJesse Barnes return 0; 18907e231dbeSJesse Barnes } 18917e231dbeSJesse Barnes 18927e231dbeSJesse Barnes static void valleyview_irq_uninstall(struct drm_device *dev) 18937e231dbeSJesse Barnes { 18947e231dbeSJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 18957e231dbeSJesse Barnes int pipe; 18967e231dbeSJesse Barnes 18977e231dbeSJesse Barnes if (!dev_priv) 18987e231dbeSJesse Barnes return; 18997e231dbeSJesse Barnes 19007e231dbeSJesse Barnes for_each_pipe(pipe) 19017e231dbeSJesse Barnes I915_WRITE(PIPESTAT(pipe), 0xffff); 19027e231dbeSJesse Barnes 19037e231dbeSJesse Barnes I915_WRITE(HWSTAM, 0xffffffff); 19047e231dbeSJesse Barnes I915_WRITE(PORT_HOTPLUG_EN, 0); 19057e231dbeSJesse Barnes I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 19067e231dbeSJesse Barnes for_each_pipe(pipe) 19077e231dbeSJesse Barnes I915_WRITE(PIPESTAT(pipe), 0xffff); 19087e231dbeSJesse Barnes I915_WRITE(VLV_IIR, 0xffffffff); 19097e231dbeSJesse Barnes I915_WRITE(VLV_IMR, 0xffffffff); 19107e231dbeSJesse Barnes I915_WRITE(VLV_IER, 0x0); 19117e231dbeSJesse Barnes POSTING_READ(VLV_IER); 19127e231dbeSJesse Barnes } 19137e231dbeSJesse Barnes 1914f71d4af4SJesse Barnes static void ironlake_irq_uninstall(struct drm_device *dev) 1915036a4a7dSZhenyu Wang { 1916036a4a7dSZhenyu Wang drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 19174697995bSJesse Barnes 19184697995bSJesse Barnes if (!dev_priv) 19194697995bSJesse Barnes return; 19204697995bSJesse Barnes 1921036a4a7dSZhenyu Wang I915_WRITE(HWSTAM, 0xffffffff); 1922036a4a7dSZhenyu Wang 1923036a4a7dSZhenyu Wang I915_WRITE(DEIMR, 0xffffffff); 1924036a4a7dSZhenyu Wang I915_WRITE(DEIER, 0x0); 1925036a4a7dSZhenyu Wang I915_WRITE(DEIIR, I915_READ(DEIIR)); 1926036a4a7dSZhenyu Wang 1927036a4a7dSZhenyu Wang I915_WRITE(GTIMR, 0xffffffff); 1928036a4a7dSZhenyu Wang I915_WRITE(GTIER, 0x0); 1929036a4a7dSZhenyu Wang I915_WRITE(GTIIR, I915_READ(GTIIR)); 1930192aac1fSKeith Packard 1931192aac1fSKeith Packard I915_WRITE(SDEIMR, 0xffffffff); 1932192aac1fSKeith Packard I915_WRITE(SDEIER, 0x0); 1933192aac1fSKeith Packard I915_WRITE(SDEIIR, I915_READ(SDEIIR)); 1934036a4a7dSZhenyu Wang } 1935036a4a7dSZhenyu Wang 1936c2798b19SChris Wilson static void i8xx_irq_preinstall(struct drm_device * dev) 1937c2798b19SChris Wilson { 1938c2798b19SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1939c2798b19SChris Wilson int pipe; 1940c2798b19SChris Wilson 1941c2798b19SChris Wilson atomic_set(&dev_priv->irq_received, 0); 1942c2798b19SChris Wilson 1943c2798b19SChris Wilson for_each_pipe(pipe) 1944c2798b19SChris Wilson I915_WRITE(PIPESTAT(pipe), 0); 1945c2798b19SChris Wilson I915_WRITE16(IMR, 0xffff); 1946c2798b19SChris Wilson I915_WRITE16(IER, 0x0); 1947c2798b19SChris Wilson POSTING_READ16(IER); 1948c2798b19SChris Wilson } 1949c2798b19SChris Wilson 1950c2798b19SChris Wilson static int i8xx_irq_postinstall(struct drm_device *dev) 1951c2798b19SChris Wilson { 1952c2798b19SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1953c2798b19SChris Wilson 1954c2798b19SChris Wilson dev_priv->pipestat[0] = 0; 1955c2798b19SChris Wilson dev_priv->pipestat[1] = 0; 1956c2798b19SChris Wilson 1957c2798b19SChris Wilson I915_WRITE16(EMR, 1958c2798b19SChris Wilson ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); 1959c2798b19SChris Wilson 1960c2798b19SChris Wilson /* Unmask the interrupts that we always want on. */ 1961c2798b19SChris Wilson dev_priv->irq_mask = 1962c2798b19SChris Wilson ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 1963c2798b19SChris Wilson I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 1964c2798b19SChris Wilson I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 1965c2798b19SChris Wilson I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | 1966c2798b19SChris Wilson I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 1967c2798b19SChris Wilson I915_WRITE16(IMR, dev_priv->irq_mask); 1968c2798b19SChris Wilson 1969c2798b19SChris Wilson I915_WRITE16(IER, 1970c2798b19SChris Wilson I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 1971c2798b19SChris Wilson I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 1972c2798b19SChris Wilson I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | 1973c2798b19SChris Wilson I915_USER_INTERRUPT); 1974c2798b19SChris Wilson POSTING_READ16(IER); 1975c2798b19SChris Wilson 1976c2798b19SChris Wilson return 0; 1977c2798b19SChris Wilson } 1978c2798b19SChris Wilson 1979c2798b19SChris Wilson static irqreturn_t i8xx_irq_handler(DRM_IRQ_ARGS) 1980c2798b19SChris Wilson { 1981c2798b19SChris Wilson struct drm_device *dev = (struct drm_device *) arg; 1982c2798b19SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1983c2798b19SChris Wilson u16 iir, new_iir; 1984c2798b19SChris Wilson u32 pipe_stats[2]; 1985c2798b19SChris Wilson unsigned long irqflags; 1986c2798b19SChris Wilson int irq_received; 1987c2798b19SChris Wilson int pipe; 1988c2798b19SChris Wilson u16 flip_mask = 1989c2798b19SChris Wilson I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 1990c2798b19SChris Wilson I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 1991c2798b19SChris Wilson 1992c2798b19SChris Wilson atomic_inc(&dev_priv->irq_received); 1993c2798b19SChris Wilson 1994c2798b19SChris Wilson iir = I915_READ16(IIR); 1995c2798b19SChris Wilson if (iir == 0) 1996c2798b19SChris Wilson return IRQ_NONE; 1997c2798b19SChris Wilson 1998c2798b19SChris Wilson while (iir & ~flip_mask) { 1999c2798b19SChris Wilson /* Can't rely on pipestat interrupt bit in iir as it might 2000c2798b19SChris Wilson * have been cleared after the pipestat interrupt was received. 2001c2798b19SChris Wilson * It doesn't set the bit in iir again, but it still produces 2002c2798b19SChris Wilson * interrupts (for non-MSI). 2003c2798b19SChris Wilson */ 2004c2798b19SChris Wilson spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 2005c2798b19SChris Wilson if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) 2006c2798b19SChris Wilson i915_handle_error(dev, false); 2007c2798b19SChris Wilson 2008c2798b19SChris Wilson for_each_pipe(pipe) { 2009c2798b19SChris Wilson int reg = PIPESTAT(pipe); 2010c2798b19SChris Wilson pipe_stats[pipe] = I915_READ(reg); 2011c2798b19SChris Wilson 2012c2798b19SChris Wilson /* 2013c2798b19SChris Wilson * Clear the PIPE*STAT regs before the IIR 2014c2798b19SChris Wilson */ 2015c2798b19SChris Wilson if (pipe_stats[pipe] & 0x8000ffff) { 2016c2798b19SChris Wilson if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 2017c2798b19SChris Wilson DRM_DEBUG_DRIVER("pipe %c underrun\n", 2018c2798b19SChris Wilson pipe_name(pipe)); 2019c2798b19SChris Wilson I915_WRITE(reg, pipe_stats[pipe]); 2020c2798b19SChris Wilson irq_received = 1; 2021c2798b19SChris Wilson } 2022c2798b19SChris Wilson } 2023c2798b19SChris Wilson spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 2024c2798b19SChris Wilson 2025c2798b19SChris Wilson I915_WRITE16(IIR, iir & ~flip_mask); 2026c2798b19SChris Wilson new_iir = I915_READ16(IIR); /* Flush posted writes */ 2027c2798b19SChris Wilson 2028d05c617eSDaniel Vetter i915_update_dri1_breadcrumb(dev); 2029c2798b19SChris Wilson 2030c2798b19SChris Wilson if (iir & I915_USER_INTERRUPT) 2031c2798b19SChris Wilson notify_ring(dev, &dev_priv->ring[RCS]); 2032c2798b19SChris Wilson 2033c2798b19SChris Wilson if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS && 2034c2798b19SChris Wilson drm_handle_vblank(dev, 0)) { 2035c2798b19SChris Wilson if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { 2036c2798b19SChris Wilson intel_prepare_page_flip(dev, 0); 2037c2798b19SChris Wilson intel_finish_page_flip(dev, 0); 2038c2798b19SChris Wilson flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; 2039c2798b19SChris Wilson } 2040c2798b19SChris Wilson } 2041c2798b19SChris Wilson 2042c2798b19SChris Wilson if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS && 2043c2798b19SChris Wilson drm_handle_vblank(dev, 1)) { 2044c2798b19SChris Wilson if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) { 2045c2798b19SChris Wilson intel_prepare_page_flip(dev, 1); 2046c2798b19SChris Wilson intel_finish_page_flip(dev, 1); 2047c2798b19SChris Wilson flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 2048c2798b19SChris Wilson } 2049c2798b19SChris Wilson } 2050c2798b19SChris Wilson 2051c2798b19SChris Wilson iir = new_iir; 2052c2798b19SChris Wilson } 2053c2798b19SChris Wilson 2054c2798b19SChris Wilson return IRQ_HANDLED; 2055c2798b19SChris Wilson } 2056c2798b19SChris Wilson 2057c2798b19SChris Wilson static void i8xx_irq_uninstall(struct drm_device * dev) 2058c2798b19SChris Wilson { 2059c2798b19SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2060c2798b19SChris Wilson int pipe; 2061c2798b19SChris Wilson 2062c2798b19SChris Wilson for_each_pipe(pipe) { 2063c2798b19SChris Wilson /* Clear enable bits; then clear status bits */ 2064c2798b19SChris Wilson I915_WRITE(PIPESTAT(pipe), 0); 2065c2798b19SChris Wilson I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe))); 2066c2798b19SChris Wilson } 2067c2798b19SChris Wilson I915_WRITE16(IMR, 0xffff); 2068c2798b19SChris Wilson I915_WRITE16(IER, 0x0); 2069c2798b19SChris Wilson I915_WRITE16(IIR, I915_READ16(IIR)); 2070c2798b19SChris Wilson } 2071c2798b19SChris Wilson 2072a266c7d5SChris Wilson static void i915_irq_preinstall(struct drm_device * dev) 2073a266c7d5SChris Wilson { 2074a266c7d5SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2075a266c7d5SChris Wilson int pipe; 2076a266c7d5SChris Wilson 2077a266c7d5SChris Wilson atomic_set(&dev_priv->irq_received, 0); 2078a266c7d5SChris Wilson 2079a266c7d5SChris Wilson if (I915_HAS_HOTPLUG(dev)) { 2080a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_EN, 0); 2081a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 2082a266c7d5SChris Wilson } 2083a266c7d5SChris Wilson 208400d98ebdSChris Wilson I915_WRITE16(HWSTAM, 0xeffe); 2085a266c7d5SChris Wilson for_each_pipe(pipe) 2086a266c7d5SChris Wilson I915_WRITE(PIPESTAT(pipe), 0); 2087a266c7d5SChris Wilson I915_WRITE(IMR, 0xffffffff); 2088a266c7d5SChris Wilson I915_WRITE(IER, 0x0); 2089a266c7d5SChris Wilson POSTING_READ(IER); 2090a266c7d5SChris Wilson } 2091a266c7d5SChris Wilson 2092a266c7d5SChris Wilson static int i915_irq_postinstall(struct drm_device *dev) 2093a266c7d5SChris Wilson { 2094a266c7d5SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 209538bde180SChris Wilson u32 enable_mask; 2096a266c7d5SChris Wilson 2097a266c7d5SChris Wilson dev_priv->pipestat[0] = 0; 2098a266c7d5SChris Wilson dev_priv->pipestat[1] = 0; 2099a266c7d5SChris Wilson 210038bde180SChris Wilson I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); 210138bde180SChris Wilson 210238bde180SChris Wilson /* Unmask the interrupts that we always want on. */ 210338bde180SChris Wilson dev_priv->irq_mask = 210438bde180SChris Wilson ~(I915_ASLE_INTERRUPT | 210538bde180SChris Wilson I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 210638bde180SChris Wilson I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 210738bde180SChris Wilson I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 210838bde180SChris Wilson I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | 210938bde180SChris Wilson I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 211038bde180SChris Wilson 211138bde180SChris Wilson enable_mask = 211238bde180SChris Wilson I915_ASLE_INTERRUPT | 211338bde180SChris Wilson I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 211438bde180SChris Wilson I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 211538bde180SChris Wilson I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | 211638bde180SChris Wilson I915_USER_INTERRUPT; 211738bde180SChris Wilson 2118a266c7d5SChris Wilson if (I915_HAS_HOTPLUG(dev)) { 2119a266c7d5SChris Wilson /* Enable in IER... */ 2120a266c7d5SChris Wilson enable_mask |= I915_DISPLAY_PORT_INTERRUPT; 2121a266c7d5SChris Wilson /* and unmask in IMR */ 2122a266c7d5SChris Wilson dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT; 2123a266c7d5SChris Wilson } 2124a266c7d5SChris Wilson 2125a266c7d5SChris Wilson I915_WRITE(IMR, dev_priv->irq_mask); 2126a266c7d5SChris Wilson I915_WRITE(IER, enable_mask); 2127a266c7d5SChris Wilson POSTING_READ(IER); 2128a266c7d5SChris Wilson 2129a266c7d5SChris Wilson if (I915_HAS_HOTPLUG(dev)) { 2130a266c7d5SChris Wilson u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); 2131a266c7d5SChris Wilson 2132a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) 2133a266c7d5SChris Wilson hotplug_en |= HDMIB_HOTPLUG_INT_EN; 2134a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) 2135a266c7d5SChris Wilson hotplug_en |= HDMIC_HOTPLUG_INT_EN; 2136a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) 2137a266c7d5SChris Wilson hotplug_en |= HDMID_HOTPLUG_INT_EN; 2138a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS) 2139a266c7d5SChris Wilson hotplug_en |= SDVOC_HOTPLUG_INT_EN; 2140a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS) 2141a266c7d5SChris Wilson hotplug_en |= SDVOB_HOTPLUG_INT_EN; 2142a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { 2143a266c7d5SChris Wilson hotplug_en |= CRT_HOTPLUG_INT_EN; 2144a266c7d5SChris Wilson hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; 2145a266c7d5SChris Wilson } 2146a266c7d5SChris Wilson 2147a266c7d5SChris Wilson /* Ignore TV since it's buggy */ 2148a266c7d5SChris Wilson 2149a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 2150a266c7d5SChris Wilson } 2151a266c7d5SChris Wilson 2152a266c7d5SChris Wilson intel_opregion_enable_asle(dev); 2153a266c7d5SChris Wilson 2154a266c7d5SChris Wilson return 0; 2155a266c7d5SChris Wilson } 2156a266c7d5SChris Wilson 2157a266c7d5SChris Wilson static irqreturn_t i915_irq_handler(DRM_IRQ_ARGS) 2158a266c7d5SChris Wilson { 2159a266c7d5SChris Wilson struct drm_device *dev = (struct drm_device *) arg; 2160a266c7d5SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 21618291ee90SChris Wilson u32 iir, new_iir, pipe_stats[I915_MAX_PIPES]; 2162a266c7d5SChris Wilson unsigned long irqflags; 216338bde180SChris Wilson u32 flip_mask = 216438bde180SChris Wilson I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 216538bde180SChris Wilson I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 216638bde180SChris Wilson u32 flip[2] = { 216738bde180SChris Wilson I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT, 216838bde180SChris Wilson I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT 216938bde180SChris Wilson }; 217038bde180SChris Wilson int pipe, ret = IRQ_NONE; 2171a266c7d5SChris Wilson 2172a266c7d5SChris Wilson atomic_inc(&dev_priv->irq_received); 2173a266c7d5SChris Wilson 2174a266c7d5SChris Wilson iir = I915_READ(IIR); 217538bde180SChris Wilson do { 217638bde180SChris Wilson bool irq_received = (iir & ~flip_mask) != 0; 21778291ee90SChris Wilson bool blc_event = false; 2178a266c7d5SChris Wilson 2179a266c7d5SChris Wilson /* Can't rely on pipestat interrupt bit in iir as it might 2180a266c7d5SChris Wilson * have been cleared after the pipestat interrupt was received. 2181a266c7d5SChris Wilson * It doesn't set the bit in iir again, but it still produces 2182a266c7d5SChris Wilson * interrupts (for non-MSI). 2183a266c7d5SChris Wilson */ 2184a266c7d5SChris Wilson spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 2185a266c7d5SChris Wilson if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) 2186a266c7d5SChris Wilson i915_handle_error(dev, false); 2187a266c7d5SChris Wilson 2188a266c7d5SChris Wilson for_each_pipe(pipe) { 2189a266c7d5SChris Wilson int reg = PIPESTAT(pipe); 2190a266c7d5SChris Wilson pipe_stats[pipe] = I915_READ(reg); 2191a266c7d5SChris Wilson 219238bde180SChris Wilson /* Clear the PIPE*STAT regs before the IIR */ 2193a266c7d5SChris Wilson if (pipe_stats[pipe] & 0x8000ffff) { 2194a266c7d5SChris Wilson if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 2195a266c7d5SChris Wilson DRM_DEBUG_DRIVER("pipe %c underrun\n", 2196a266c7d5SChris Wilson pipe_name(pipe)); 2197a266c7d5SChris Wilson I915_WRITE(reg, pipe_stats[pipe]); 219838bde180SChris Wilson irq_received = true; 2199a266c7d5SChris Wilson } 2200a266c7d5SChris Wilson } 2201a266c7d5SChris Wilson spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 2202a266c7d5SChris Wilson 2203a266c7d5SChris Wilson if (!irq_received) 2204a266c7d5SChris Wilson break; 2205a266c7d5SChris Wilson 2206a266c7d5SChris Wilson /* Consume port. Then clear IIR or we'll miss events */ 2207a266c7d5SChris Wilson if ((I915_HAS_HOTPLUG(dev)) && 2208a266c7d5SChris Wilson (iir & I915_DISPLAY_PORT_INTERRUPT)) { 2209a266c7d5SChris Wilson u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); 2210a266c7d5SChris Wilson 2211a266c7d5SChris Wilson DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", 2212a266c7d5SChris Wilson hotplug_status); 2213a266c7d5SChris Wilson if (hotplug_status & dev_priv->hotplug_supported_mask) 2214a266c7d5SChris Wilson queue_work(dev_priv->wq, 2215a266c7d5SChris Wilson &dev_priv->hotplug_work); 2216a266c7d5SChris Wilson 2217a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); 221838bde180SChris Wilson POSTING_READ(PORT_HOTPLUG_STAT); 2219a266c7d5SChris Wilson } 2220a266c7d5SChris Wilson 222138bde180SChris Wilson I915_WRITE(IIR, iir & ~flip_mask); 2222a266c7d5SChris Wilson new_iir = I915_READ(IIR); /* Flush posted writes */ 2223a266c7d5SChris Wilson 2224a266c7d5SChris Wilson if (iir & I915_USER_INTERRUPT) 2225a266c7d5SChris Wilson notify_ring(dev, &dev_priv->ring[RCS]); 2226a266c7d5SChris Wilson 2227a266c7d5SChris Wilson for_each_pipe(pipe) { 222838bde180SChris Wilson int plane = pipe; 222938bde180SChris Wilson if (IS_MOBILE(dev)) 223038bde180SChris Wilson plane = !plane; 22318291ee90SChris Wilson if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && 2232a266c7d5SChris Wilson drm_handle_vblank(dev, pipe)) { 223338bde180SChris Wilson if (iir & flip[plane]) { 223438bde180SChris Wilson intel_prepare_page_flip(dev, plane); 2235a266c7d5SChris Wilson intel_finish_page_flip(dev, pipe); 223638bde180SChris Wilson flip_mask &= ~flip[plane]; 223738bde180SChris Wilson } 2238a266c7d5SChris Wilson } 2239a266c7d5SChris Wilson 2240a266c7d5SChris Wilson if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) 2241a266c7d5SChris Wilson blc_event = true; 2242a266c7d5SChris Wilson } 2243a266c7d5SChris Wilson 2244a266c7d5SChris Wilson if (blc_event || (iir & I915_ASLE_INTERRUPT)) 2245a266c7d5SChris Wilson intel_opregion_asle_intr(dev); 2246a266c7d5SChris Wilson 2247a266c7d5SChris Wilson /* With MSI, interrupts are only generated when iir 2248a266c7d5SChris Wilson * transitions from zero to nonzero. If another bit got 2249a266c7d5SChris Wilson * set while we were handling the existing iir bits, then 2250a266c7d5SChris Wilson * we would never get another interrupt. 2251a266c7d5SChris Wilson * 2252a266c7d5SChris Wilson * This is fine on non-MSI as well, as if we hit this path 2253a266c7d5SChris Wilson * we avoid exiting the interrupt handler only to generate 2254a266c7d5SChris Wilson * another one. 2255a266c7d5SChris Wilson * 2256a266c7d5SChris Wilson * Note that for MSI this could cause a stray interrupt report 2257a266c7d5SChris Wilson * if an interrupt landed in the time between writing IIR and 2258a266c7d5SChris Wilson * the posting read. This should be rare enough to never 2259a266c7d5SChris Wilson * trigger the 99% of 100,000 interrupts test for disabling 2260a266c7d5SChris Wilson * stray interrupts. 2261a266c7d5SChris Wilson */ 226238bde180SChris Wilson ret = IRQ_HANDLED; 2263a266c7d5SChris Wilson iir = new_iir; 226438bde180SChris Wilson } while (iir & ~flip_mask); 2265a266c7d5SChris Wilson 2266d05c617eSDaniel Vetter i915_update_dri1_breadcrumb(dev); 22678291ee90SChris Wilson 2268a266c7d5SChris Wilson return ret; 2269a266c7d5SChris Wilson } 2270a266c7d5SChris Wilson 2271a266c7d5SChris Wilson static void i915_irq_uninstall(struct drm_device * dev) 2272a266c7d5SChris Wilson { 2273a266c7d5SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2274a266c7d5SChris Wilson int pipe; 2275a266c7d5SChris Wilson 2276a266c7d5SChris Wilson if (I915_HAS_HOTPLUG(dev)) { 2277a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_EN, 0); 2278a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 2279a266c7d5SChris Wilson } 2280a266c7d5SChris Wilson 228100d98ebdSChris Wilson I915_WRITE16(HWSTAM, 0xffff); 228255b39755SChris Wilson for_each_pipe(pipe) { 228355b39755SChris Wilson /* Clear enable bits; then clear status bits */ 2284a266c7d5SChris Wilson I915_WRITE(PIPESTAT(pipe), 0); 228555b39755SChris Wilson I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe))); 228655b39755SChris Wilson } 2287a266c7d5SChris Wilson I915_WRITE(IMR, 0xffffffff); 2288a266c7d5SChris Wilson I915_WRITE(IER, 0x0); 2289a266c7d5SChris Wilson 2290a266c7d5SChris Wilson I915_WRITE(IIR, I915_READ(IIR)); 2291a266c7d5SChris Wilson } 2292a266c7d5SChris Wilson 2293a266c7d5SChris Wilson static void i965_irq_preinstall(struct drm_device * dev) 2294a266c7d5SChris Wilson { 2295a266c7d5SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2296a266c7d5SChris Wilson int pipe; 2297a266c7d5SChris Wilson 2298a266c7d5SChris Wilson atomic_set(&dev_priv->irq_received, 0); 2299a266c7d5SChris Wilson 2300a266c7d5SChris Wilson if (I915_HAS_HOTPLUG(dev)) { 2301a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_EN, 0); 2302a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 2303a266c7d5SChris Wilson } 2304a266c7d5SChris Wilson 2305a266c7d5SChris Wilson I915_WRITE(HWSTAM, 0xeffe); 2306a266c7d5SChris Wilson for_each_pipe(pipe) 2307a266c7d5SChris Wilson I915_WRITE(PIPESTAT(pipe), 0); 2308a266c7d5SChris Wilson I915_WRITE(IMR, 0xffffffff); 2309a266c7d5SChris Wilson I915_WRITE(IER, 0x0); 2310a266c7d5SChris Wilson POSTING_READ(IER); 2311a266c7d5SChris Wilson } 2312a266c7d5SChris Wilson 2313a266c7d5SChris Wilson static int i965_irq_postinstall(struct drm_device *dev) 2314a266c7d5SChris Wilson { 2315a266c7d5SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2316bbba0a97SChris Wilson u32 enable_mask; 2317a266c7d5SChris Wilson u32 error_mask; 2318a266c7d5SChris Wilson 2319a266c7d5SChris Wilson /* Unmask the interrupts that we always want on. */ 2320bbba0a97SChris Wilson dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT | 2321bbba0a97SChris Wilson I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | 2322bbba0a97SChris Wilson I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | 2323bbba0a97SChris Wilson I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 2324bbba0a97SChris Wilson I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | 2325bbba0a97SChris Wilson I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 2326bbba0a97SChris Wilson 2327bbba0a97SChris Wilson enable_mask = ~dev_priv->irq_mask; 2328bbba0a97SChris Wilson enable_mask |= I915_USER_INTERRUPT; 2329bbba0a97SChris Wilson 2330bbba0a97SChris Wilson if (IS_G4X(dev)) 2331bbba0a97SChris Wilson enable_mask |= I915_BSD_USER_INTERRUPT; 2332a266c7d5SChris Wilson 2333a266c7d5SChris Wilson dev_priv->pipestat[0] = 0; 2334a266c7d5SChris Wilson dev_priv->pipestat[1] = 0; 2335a266c7d5SChris Wilson 2336a266c7d5SChris Wilson if (I915_HAS_HOTPLUG(dev)) { 2337a266c7d5SChris Wilson /* Enable in IER... */ 2338a266c7d5SChris Wilson enable_mask |= I915_DISPLAY_PORT_INTERRUPT; 2339a266c7d5SChris Wilson /* and unmask in IMR */ 2340a266c7d5SChris Wilson dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT; 2341a266c7d5SChris Wilson } 2342a266c7d5SChris Wilson 2343a266c7d5SChris Wilson /* 2344a266c7d5SChris Wilson * Enable some error detection, note the instruction error mask 2345a266c7d5SChris Wilson * bit is reserved, so we leave it masked. 2346a266c7d5SChris Wilson */ 2347a266c7d5SChris Wilson if (IS_G4X(dev)) { 2348a266c7d5SChris Wilson error_mask = ~(GM45_ERROR_PAGE_TABLE | 2349a266c7d5SChris Wilson GM45_ERROR_MEM_PRIV | 2350a266c7d5SChris Wilson GM45_ERROR_CP_PRIV | 2351a266c7d5SChris Wilson I915_ERROR_MEMORY_REFRESH); 2352a266c7d5SChris Wilson } else { 2353a266c7d5SChris Wilson error_mask = ~(I915_ERROR_PAGE_TABLE | 2354a266c7d5SChris Wilson I915_ERROR_MEMORY_REFRESH); 2355a266c7d5SChris Wilson } 2356a266c7d5SChris Wilson I915_WRITE(EMR, error_mask); 2357a266c7d5SChris Wilson 2358a266c7d5SChris Wilson I915_WRITE(IMR, dev_priv->irq_mask); 2359a266c7d5SChris Wilson I915_WRITE(IER, enable_mask); 2360a266c7d5SChris Wilson POSTING_READ(IER); 2361a266c7d5SChris Wilson 2362a266c7d5SChris Wilson if (I915_HAS_HOTPLUG(dev)) { 2363a266c7d5SChris Wilson u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); 2364a266c7d5SChris Wilson 2365a266c7d5SChris Wilson /* Note HDMI and DP share bits */ 2366a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) 2367a266c7d5SChris Wilson hotplug_en |= HDMIB_HOTPLUG_INT_EN; 2368a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) 2369a266c7d5SChris Wilson hotplug_en |= HDMIC_HOTPLUG_INT_EN; 2370a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) 2371a266c7d5SChris Wilson hotplug_en |= HDMID_HOTPLUG_INT_EN; 2372a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS) 2373a266c7d5SChris Wilson hotplug_en |= SDVOC_HOTPLUG_INT_EN; 2374a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS) 2375a266c7d5SChris Wilson hotplug_en |= SDVOB_HOTPLUG_INT_EN; 2376a266c7d5SChris Wilson if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { 2377a266c7d5SChris Wilson hotplug_en |= CRT_HOTPLUG_INT_EN; 2378a266c7d5SChris Wilson 2379a266c7d5SChris Wilson /* Programming the CRT detection parameters tends 2380a266c7d5SChris Wilson to generate a spurious hotplug event about three 2381a266c7d5SChris Wilson seconds later. So just do it once. 2382a266c7d5SChris Wilson */ 2383a266c7d5SChris Wilson if (IS_G4X(dev)) 2384a266c7d5SChris Wilson hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; 2385a266c7d5SChris Wilson hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; 2386a266c7d5SChris Wilson } 2387a266c7d5SChris Wilson 2388a266c7d5SChris Wilson /* Ignore TV since it's buggy */ 2389a266c7d5SChris Wilson 2390a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 2391a266c7d5SChris Wilson } 2392a266c7d5SChris Wilson 2393a266c7d5SChris Wilson intel_opregion_enable_asle(dev); 2394a266c7d5SChris Wilson 2395a266c7d5SChris Wilson return 0; 2396a266c7d5SChris Wilson } 2397a266c7d5SChris Wilson 2398a266c7d5SChris Wilson static irqreturn_t i965_irq_handler(DRM_IRQ_ARGS) 2399a266c7d5SChris Wilson { 2400a266c7d5SChris Wilson struct drm_device *dev = (struct drm_device *) arg; 2401a266c7d5SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2402a266c7d5SChris Wilson u32 iir, new_iir; 2403a266c7d5SChris Wilson u32 pipe_stats[I915_MAX_PIPES]; 2404a266c7d5SChris Wilson unsigned long irqflags; 2405a266c7d5SChris Wilson int irq_received; 2406a266c7d5SChris Wilson int ret = IRQ_NONE, pipe; 2407a266c7d5SChris Wilson 2408a266c7d5SChris Wilson atomic_inc(&dev_priv->irq_received); 2409a266c7d5SChris Wilson 2410a266c7d5SChris Wilson iir = I915_READ(IIR); 2411a266c7d5SChris Wilson 2412a266c7d5SChris Wilson for (;;) { 24132c8ba29fSChris Wilson bool blc_event = false; 24142c8ba29fSChris Wilson 2415a266c7d5SChris Wilson irq_received = iir != 0; 2416a266c7d5SChris Wilson 2417a266c7d5SChris Wilson /* Can't rely on pipestat interrupt bit in iir as it might 2418a266c7d5SChris Wilson * have been cleared after the pipestat interrupt was received. 2419a266c7d5SChris Wilson * It doesn't set the bit in iir again, but it still produces 2420a266c7d5SChris Wilson * interrupts (for non-MSI). 2421a266c7d5SChris Wilson */ 2422a266c7d5SChris Wilson spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 2423a266c7d5SChris Wilson if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) 2424a266c7d5SChris Wilson i915_handle_error(dev, false); 2425a266c7d5SChris Wilson 2426a266c7d5SChris Wilson for_each_pipe(pipe) { 2427a266c7d5SChris Wilson int reg = PIPESTAT(pipe); 2428a266c7d5SChris Wilson pipe_stats[pipe] = I915_READ(reg); 2429a266c7d5SChris Wilson 2430a266c7d5SChris Wilson /* 2431a266c7d5SChris Wilson * Clear the PIPE*STAT regs before the IIR 2432a266c7d5SChris Wilson */ 2433a266c7d5SChris Wilson if (pipe_stats[pipe] & 0x8000ffff) { 2434a266c7d5SChris Wilson if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) 2435a266c7d5SChris Wilson DRM_DEBUG_DRIVER("pipe %c underrun\n", 2436a266c7d5SChris Wilson pipe_name(pipe)); 2437a266c7d5SChris Wilson I915_WRITE(reg, pipe_stats[pipe]); 2438a266c7d5SChris Wilson irq_received = 1; 2439a266c7d5SChris Wilson } 2440a266c7d5SChris Wilson } 2441a266c7d5SChris Wilson spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 2442a266c7d5SChris Wilson 2443a266c7d5SChris Wilson if (!irq_received) 2444a266c7d5SChris Wilson break; 2445a266c7d5SChris Wilson 2446a266c7d5SChris Wilson ret = IRQ_HANDLED; 2447a266c7d5SChris Wilson 2448a266c7d5SChris Wilson /* Consume port. Then clear IIR or we'll miss events */ 2449a266c7d5SChris Wilson if ((I915_HAS_HOTPLUG(dev)) && 2450a266c7d5SChris Wilson (iir & I915_DISPLAY_PORT_INTERRUPT)) { 2451a266c7d5SChris Wilson u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); 2452a266c7d5SChris Wilson 2453a266c7d5SChris Wilson DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", 2454a266c7d5SChris Wilson hotplug_status); 2455a266c7d5SChris Wilson if (hotplug_status & dev_priv->hotplug_supported_mask) 2456a266c7d5SChris Wilson queue_work(dev_priv->wq, 2457a266c7d5SChris Wilson &dev_priv->hotplug_work); 2458a266c7d5SChris Wilson 2459a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); 2460a266c7d5SChris Wilson I915_READ(PORT_HOTPLUG_STAT); 2461a266c7d5SChris Wilson } 2462a266c7d5SChris Wilson 2463a266c7d5SChris Wilson I915_WRITE(IIR, iir); 2464a266c7d5SChris Wilson new_iir = I915_READ(IIR); /* Flush posted writes */ 2465a266c7d5SChris Wilson 2466a266c7d5SChris Wilson if (iir & I915_USER_INTERRUPT) 2467a266c7d5SChris Wilson notify_ring(dev, &dev_priv->ring[RCS]); 2468a266c7d5SChris Wilson if (iir & I915_BSD_USER_INTERRUPT) 2469a266c7d5SChris Wilson notify_ring(dev, &dev_priv->ring[VCS]); 2470a266c7d5SChris Wilson 24714f7d1e79SChris Wilson if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) 2472a266c7d5SChris Wilson intel_prepare_page_flip(dev, 0); 2473a266c7d5SChris Wilson 24744f7d1e79SChris Wilson if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) 2475a266c7d5SChris Wilson intel_prepare_page_flip(dev, 1); 2476a266c7d5SChris Wilson 2477a266c7d5SChris Wilson for_each_pipe(pipe) { 24782c8ba29fSChris Wilson if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && 2479a266c7d5SChris Wilson drm_handle_vblank(dev, pipe)) { 2480a266c7d5SChris Wilson i915_pageflip_stall_check(dev, pipe); 2481a266c7d5SChris Wilson intel_finish_page_flip(dev, pipe); 2482a266c7d5SChris Wilson } 2483a266c7d5SChris Wilson 2484a266c7d5SChris Wilson if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) 2485a266c7d5SChris Wilson blc_event = true; 2486a266c7d5SChris Wilson } 2487a266c7d5SChris Wilson 2488a266c7d5SChris Wilson 2489a266c7d5SChris Wilson if (blc_event || (iir & I915_ASLE_INTERRUPT)) 2490a266c7d5SChris Wilson intel_opregion_asle_intr(dev); 2491a266c7d5SChris Wilson 2492a266c7d5SChris Wilson /* With MSI, interrupts are only generated when iir 2493a266c7d5SChris Wilson * transitions from zero to nonzero. If another bit got 2494a266c7d5SChris Wilson * set while we were handling the existing iir bits, then 2495a266c7d5SChris Wilson * we would never get another interrupt. 2496a266c7d5SChris Wilson * 2497a266c7d5SChris Wilson * This is fine on non-MSI as well, as if we hit this path 2498a266c7d5SChris Wilson * we avoid exiting the interrupt handler only to generate 2499a266c7d5SChris Wilson * another one. 2500a266c7d5SChris Wilson * 2501a266c7d5SChris Wilson * Note that for MSI this could cause a stray interrupt report 2502a266c7d5SChris Wilson * if an interrupt landed in the time between writing IIR and 2503a266c7d5SChris Wilson * the posting read. This should be rare enough to never 2504a266c7d5SChris Wilson * trigger the 99% of 100,000 interrupts test for disabling 2505a266c7d5SChris Wilson * stray interrupts. 2506a266c7d5SChris Wilson */ 2507a266c7d5SChris Wilson iir = new_iir; 2508a266c7d5SChris Wilson } 2509a266c7d5SChris Wilson 2510d05c617eSDaniel Vetter i915_update_dri1_breadcrumb(dev); 25112c8ba29fSChris Wilson 2512a266c7d5SChris Wilson return ret; 2513a266c7d5SChris Wilson } 2514a266c7d5SChris Wilson 2515a266c7d5SChris Wilson static void i965_irq_uninstall(struct drm_device * dev) 2516a266c7d5SChris Wilson { 2517a266c7d5SChris Wilson drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2518a266c7d5SChris Wilson int pipe; 2519a266c7d5SChris Wilson 2520a266c7d5SChris Wilson if (!dev_priv) 2521a266c7d5SChris Wilson return; 2522a266c7d5SChris Wilson 2523a266c7d5SChris Wilson if (I915_HAS_HOTPLUG(dev)) { 2524a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_EN, 0); 2525a266c7d5SChris Wilson I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); 2526a266c7d5SChris Wilson } 2527a266c7d5SChris Wilson 2528a266c7d5SChris Wilson I915_WRITE(HWSTAM, 0xffffffff); 2529a266c7d5SChris Wilson for_each_pipe(pipe) 2530a266c7d5SChris Wilson I915_WRITE(PIPESTAT(pipe), 0); 2531a266c7d5SChris Wilson I915_WRITE(IMR, 0xffffffff); 2532a266c7d5SChris Wilson I915_WRITE(IER, 0x0); 2533a266c7d5SChris Wilson 2534a266c7d5SChris Wilson for_each_pipe(pipe) 2535a266c7d5SChris Wilson I915_WRITE(PIPESTAT(pipe), 2536a266c7d5SChris Wilson I915_READ(PIPESTAT(pipe)) & 0x8000ffff); 2537a266c7d5SChris Wilson I915_WRITE(IIR, I915_READ(IIR)); 2538a266c7d5SChris Wilson } 2539a266c7d5SChris Wilson 2540f71d4af4SJesse Barnes void intel_irq_init(struct drm_device *dev) 2541f71d4af4SJesse Barnes { 25428b2e326dSChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 25438b2e326dSChris Wilson 25448b2e326dSChris Wilson INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); 25458b2e326dSChris Wilson INIT_WORK(&dev_priv->error_work, i915_error_work_func); 25468b2e326dSChris Wilson INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work); 25478b2e326dSChris Wilson 2548f71d4af4SJesse Barnes dev->driver->get_vblank_counter = i915_get_vblank_counter; 2549f71d4af4SJesse Barnes dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ 25507d4e146fSEugeni Dodonov if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { 2551f71d4af4SJesse Barnes dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ 2552f71d4af4SJesse Barnes dev->driver->get_vblank_counter = gm45_get_vblank_counter; 2553f71d4af4SJesse Barnes } 2554f71d4af4SJesse Barnes 2555c3613de9SKeith Packard if (drm_core_check_feature(dev, DRIVER_MODESET)) 2556f71d4af4SJesse Barnes dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; 2557c3613de9SKeith Packard else 2558c3613de9SKeith Packard dev->driver->get_vblank_timestamp = NULL; 2559f71d4af4SJesse Barnes dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; 2560f71d4af4SJesse Barnes 25617e231dbeSJesse Barnes if (IS_VALLEYVIEW(dev)) { 25627e231dbeSJesse Barnes dev->driver->irq_handler = valleyview_irq_handler; 25637e231dbeSJesse Barnes dev->driver->irq_preinstall = valleyview_irq_preinstall; 25647e231dbeSJesse Barnes dev->driver->irq_postinstall = valleyview_irq_postinstall; 25657e231dbeSJesse Barnes dev->driver->irq_uninstall = valleyview_irq_uninstall; 25667e231dbeSJesse Barnes dev->driver->enable_vblank = valleyview_enable_vblank; 25677e231dbeSJesse Barnes dev->driver->disable_vblank = valleyview_disable_vblank; 25687e231dbeSJesse Barnes } else if (IS_IVYBRIDGE(dev)) { 2569f71d4af4SJesse Barnes /* Share pre & uninstall handlers with ILK/SNB */ 2570f71d4af4SJesse Barnes dev->driver->irq_handler = ivybridge_irq_handler; 2571f71d4af4SJesse Barnes dev->driver->irq_preinstall = ironlake_irq_preinstall; 2572f71d4af4SJesse Barnes dev->driver->irq_postinstall = ivybridge_irq_postinstall; 2573f71d4af4SJesse Barnes dev->driver->irq_uninstall = ironlake_irq_uninstall; 2574f71d4af4SJesse Barnes dev->driver->enable_vblank = ivybridge_enable_vblank; 2575f71d4af4SJesse Barnes dev->driver->disable_vblank = ivybridge_disable_vblank; 25767d4e146fSEugeni Dodonov } else if (IS_HASWELL(dev)) { 25777d4e146fSEugeni Dodonov /* Share interrupts handling with IVB */ 25787d4e146fSEugeni Dodonov dev->driver->irq_handler = ivybridge_irq_handler; 25797d4e146fSEugeni Dodonov dev->driver->irq_preinstall = ironlake_irq_preinstall; 25807d4e146fSEugeni Dodonov dev->driver->irq_postinstall = ivybridge_irq_postinstall; 25817d4e146fSEugeni Dodonov dev->driver->irq_uninstall = ironlake_irq_uninstall; 25827d4e146fSEugeni Dodonov dev->driver->enable_vblank = ivybridge_enable_vblank; 25837d4e146fSEugeni Dodonov dev->driver->disable_vblank = ivybridge_disable_vblank; 2584f71d4af4SJesse Barnes } else if (HAS_PCH_SPLIT(dev)) { 2585f71d4af4SJesse Barnes dev->driver->irq_handler = ironlake_irq_handler; 2586f71d4af4SJesse Barnes dev->driver->irq_preinstall = ironlake_irq_preinstall; 2587f71d4af4SJesse Barnes dev->driver->irq_postinstall = ironlake_irq_postinstall; 2588f71d4af4SJesse Barnes dev->driver->irq_uninstall = ironlake_irq_uninstall; 2589f71d4af4SJesse Barnes dev->driver->enable_vblank = ironlake_enable_vblank; 2590f71d4af4SJesse Barnes dev->driver->disable_vblank = ironlake_disable_vblank; 2591f71d4af4SJesse Barnes } else { 2592c2798b19SChris Wilson if (INTEL_INFO(dev)->gen == 2) { 2593c2798b19SChris Wilson dev->driver->irq_preinstall = i8xx_irq_preinstall; 2594c2798b19SChris Wilson dev->driver->irq_postinstall = i8xx_irq_postinstall; 2595c2798b19SChris Wilson dev->driver->irq_handler = i8xx_irq_handler; 2596c2798b19SChris Wilson dev->driver->irq_uninstall = i8xx_irq_uninstall; 2597a266c7d5SChris Wilson } else if (INTEL_INFO(dev)->gen == 3) { 25984f7d1e79SChris Wilson /* IIR "flip pending" means done if this bit is set */ 25994f7d1e79SChris Wilson I915_WRITE(ECOSKPD, _MASKED_BIT_DISABLE(ECO_FLIP_DONE)); 26004f7d1e79SChris Wilson 2601a266c7d5SChris Wilson dev->driver->irq_preinstall = i915_irq_preinstall; 2602a266c7d5SChris Wilson dev->driver->irq_postinstall = i915_irq_postinstall; 2603a266c7d5SChris Wilson dev->driver->irq_uninstall = i915_irq_uninstall; 2604a266c7d5SChris Wilson dev->driver->irq_handler = i915_irq_handler; 2605c2798b19SChris Wilson } else { 2606a266c7d5SChris Wilson dev->driver->irq_preinstall = i965_irq_preinstall; 2607a266c7d5SChris Wilson dev->driver->irq_postinstall = i965_irq_postinstall; 2608a266c7d5SChris Wilson dev->driver->irq_uninstall = i965_irq_uninstall; 2609a266c7d5SChris Wilson dev->driver->irq_handler = i965_irq_handler; 2610c2798b19SChris Wilson } 2611f71d4af4SJesse Barnes dev->driver->enable_vblank = i915_enable_vblank; 2612f71d4af4SJesse Barnes dev->driver->disable_vblank = i915_disable_vblank; 2613f71d4af4SJesse Barnes } 2614f71d4af4SJesse Barnes } 2615