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 29c0e09200SDave Airlie #include "drmP.h" 30c0e09200SDave Airlie #include "drm.h" 31c0e09200SDave Airlie #include "i915_drm.h" 32c0e09200SDave Airlie #include "i915_drv.h" 33c0e09200SDave Airlie 34c0e09200SDave Airlie #define MAX_NOPID ((u32)~0) 35c0e09200SDave Airlie 367c463586SKeith Packard /** 377c463586SKeith Packard * Interrupts that are always left unmasked. 387c463586SKeith Packard * 397c463586SKeith Packard * Since pipe events are edge-triggered from the PIPESTAT register to IIR, 407c463586SKeith Packard * we leave them always unmasked in IMR and then control enabling them through 417c463586SKeith Packard * PIPESTAT alone. 427c463586SKeith Packard */ 437c463586SKeith Packard #define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \ 440a3e67a4SJesse Barnes I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ 458ee1c3dbSMatthew Garrett I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) 46ed4cb414SEric Anholt 477c463586SKeith Packard /** Interrupts that we mask and unmask at runtime. */ 487c463586SKeith Packard #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) 497c463586SKeith Packard 507c463586SKeith Packard /** These are all of the interrupts used by the driver */ 517c463586SKeith Packard #define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \ 527c463586SKeith Packard I915_INTERRUPT_ENABLE_VAR) 537c463586SKeith Packard 548ee1c3dbSMatthew Garrett void 55ed4cb414SEric Anholt i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) 56ed4cb414SEric Anholt { 57ed4cb414SEric Anholt if ((dev_priv->irq_mask_reg & mask) != 0) { 58ed4cb414SEric Anholt dev_priv->irq_mask_reg &= ~mask; 59ed4cb414SEric Anholt I915_WRITE(IMR, dev_priv->irq_mask_reg); 60ed4cb414SEric Anholt (void) I915_READ(IMR); 61ed4cb414SEric Anholt } 62ed4cb414SEric Anholt } 63ed4cb414SEric Anholt 64ed4cb414SEric Anholt static inline void 65ed4cb414SEric Anholt i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) 66ed4cb414SEric Anholt { 67ed4cb414SEric Anholt if ((dev_priv->irq_mask_reg & mask) != mask) { 68ed4cb414SEric Anholt dev_priv->irq_mask_reg |= mask; 69ed4cb414SEric Anholt I915_WRITE(IMR, dev_priv->irq_mask_reg); 70ed4cb414SEric Anholt (void) I915_READ(IMR); 71ed4cb414SEric Anholt } 72ed4cb414SEric Anholt } 73ed4cb414SEric Anholt 747c463586SKeith Packard static inline u32 757c463586SKeith Packard i915_pipestat(int pipe) 767c463586SKeith Packard { 777c463586SKeith Packard if (pipe == 0) 787c463586SKeith Packard return PIPEASTAT; 797c463586SKeith Packard if (pipe == 1) 807c463586SKeith Packard return PIPEBSTAT; 817c463586SKeith Packard BUG_ON(1); 827c463586SKeith Packard } 837c463586SKeith Packard 847c463586SKeith Packard void 857c463586SKeith Packard i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) 867c463586SKeith Packard { 877c463586SKeith Packard if ((dev_priv->pipestat[pipe] & mask) != mask) { 887c463586SKeith Packard u32 reg = i915_pipestat(pipe); 897c463586SKeith Packard 907c463586SKeith Packard dev_priv->pipestat[pipe] |= mask; 917c463586SKeith Packard /* Enable the interrupt, clear any pending status */ 927c463586SKeith Packard I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16)); 937c463586SKeith Packard (void) I915_READ(reg); 947c463586SKeith Packard } 957c463586SKeith Packard } 967c463586SKeith Packard 977c463586SKeith Packard void 987c463586SKeith Packard i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) 997c463586SKeith Packard { 1007c463586SKeith Packard if ((dev_priv->pipestat[pipe] & mask) != 0) { 1017c463586SKeith Packard u32 reg = i915_pipestat(pipe); 1027c463586SKeith Packard 1037c463586SKeith Packard dev_priv->pipestat[pipe] &= ~mask; 1047c463586SKeith Packard I915_WRITE(reg, dev_priv->pipestat[pipe]); 1057c463586SKeith Packard (void) I915_READ(reg); 1067c463586SKeith Packard } 1077c463586SKeith Packard } 1087c463586SKeith Packard 109c0e09200SDave Airlie /** 1100a3e67a4SJesse Barnes * i915_pipe_enabled - check if a pipe is enabled 1110a3e67a4SJesse Barnes * @dev: DRM device 1120a3e67a4SJesse Barnes * @pipe: pipe to check 1130a3e67a4SJesse Barnes * 1140a3e67a4SJesse Barnes * Reading certain registers when the pipe is disabled can hang the chip. 1150a3e67a4SJesse Barnes * Use this routine to make sure the PLL is running and the pipe is active 1160a3e67a4SJesse Barnes * before reading such registers if unsure. 1170a3e67a4SJesse Barnes */ 1180a3e67a4SJesse Barnes static int 1190a3e67a4SJesse Barnes i915_pipe_enabled(struct drm_device *dev, int pipe) 1200a3e67a4SJesse Barnes { 1210a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1220a3e67a4SJesse Barnes unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; 1230a3e67a4SJesse Barnes 1240a3e67a4SJesse Barnes if (I915_READ(pipeconf) & PIPEACONF_ENABLE) 1250a3e67a4SJesse Barnes return 1; 1260a3e67a4SJesse Barnes 1270a3e67a4SJesse Barnes return 0; 1280a3e67a4SJesse Barnes } 1290a3e67a4SJesse Barnes 13042f52ef8SKeith Packard /* Called from drm generic code, passed a 'crtc', which 13142f52ef8SKeith Packard * we use as a pipe index 13242f52ef8SKeith Packard */ 13342f52ef8SKeith Packard u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) 1340a3e67a4SJesse Barnes { 1350a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1360a3e67a4SJesse Barnes unsigned long high_frame; 1370a3e67a4SJesse Barnes unsigned long low_frame; 1380a3e67a4SJesse Barnes u32 high1, high2, low, count; 1390a3e67a4SJesse Barnes 1400a3e67a4SJesse Barnes high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; 1410a3e67a4SJesse Barnes low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; 1420a3e67a4SJesse Barnes 1430a3e67a4SJesse Barnes if (!i915_pipe_enabled(dev, pipe)) { 1440a3e67a4SJesse Barnes DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); 1450a3e67a4SJesse Barnes return 0; 1460a3e67a4SJesse Barnes } 1470a3e67a4SJesse Barnes 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 { 1540a3e67a4SJesse Barnes high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> 1550a3e67a4SJesse Barnes PIPE_FRAME_HIGH_SHIFT); 1560a3e67a4SJesse Barnes low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> 1570a3e67a4SJesse Barnes PIPE_FRAME_LOW_SHIFT); 1580a3e67a4SJesse Barnes high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> 1590a3e67a4SJesse Barnes PIPE_FRAME_HIGH_SHIFT); 1600a3e67a4SJesse Barnes } while (high1 != high2); 1610a3e67a4SJesse Barnes 1620a3e67a4SJesse Barnes count = (high1 << 8) | low; 1630a3e67a4SJesse Barnes 1640a3e67a4SJesse Barnes return count; 1650a3e67a4SJesse Barnes } 1660a3e67a4SJesse Barnes 167c0e09200SDave Airlie irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) 168c0e09200SDave Airlie { 169c0e09200SDave Airlie struct drm_device *dev = (struct drm_device *) arg; 170c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 171*cdfbc41fSEric Anholt u32 iir, new_iir; 172*cdfbc41fSEric Anholt u32 pipea_stats, pipeb_stats; 1730a3e67a4SJesse Barnes int vblank = 0; 1747c463586SKeith Packard unsigned long irqflags; 175c0e09200SDave Airlie 176630681d9SEric Anholt atomic_inc(&dev_priv->irq_received); 177630681d9SEric Anholt 178ed4cb414SEric Anholt iir = I915_READ(IIR); 179c0e09200SDave Airlie 180*cdfbc41fSEric Anholt if (iir == 0) 181c0e09200SDave Airlie return IRQ_NONE; 182c0e09200SDave Airlie 183*cdfbc41fSEric Anholt do { 184*cdfbc41fSEric Anholt pipea_stats = 0; 185*cdfbc41fSEric Anholt pipeb_stats = 0; 1860a3e67a4SJesse Barnes /* 1877c463586SKeith Packard * Clear the PIPE(A|B)STAT regs before the IIR 1880a3e67a4SJesse Barnes */ 1890a3e67a4SJesse Barnes if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { 190*cdfbc41fSEric Anholt spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 1910a3e67a4SJesse Barnes pipea_stats = I915_READ(PIPEASTAT); 1928ee1c3dbSMatthew Garrett I915_WRITE(PIPEASTAT, pipea_stats); 193*cdfbc41fSEric Anholt spin_unlock_irqrestore(&dev_priv->user_irq_lock, 194*cdfbc41fSEric Anholt irqflags); 1950a3e67a4SJesse Barnes } 1967c463586SKeith Packard 1970a3e67a4SJesse Barnes if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { 198*cdfbc41fSEric Anholt spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 1990a3e67a4SJesse Barnes pipeb_stats = I915_READ(PIPEBSTAT); 2000a3e67a4SJesse Barnes I915_WRITE(PIPEBSTAT, pipeb_stats); 201*cdfbc41fSEric Anholt spin_unlock_irqrestore(&dev_priv->user_irq_lock, 202*cdfbc41fSEric Anholt irqflags); 203c0e09200SDave Airlie } 204c0e09200SDave Airlie 205673a394bSEric Anholt I915_WRITE(IIR, iir); 206*cdfbc41fSEric Anholt new_iir = I915_READ(IIR); /* Flush posted writes */ 2077c463586SKeith Packard 208c99b058fSKristian Høgsberg if (dev_priv->sarea_priv) 209c99b058fSKristian Høgsberg dev_priv->sarea_priv->last_dispatch = 210c99b058fSKristian Høgsberg READ_BREADCRUMB(dev_priv); 2110a3e67a4SJesse Barnes 212673a394bSEric Anholt if (iir & I915_USER_INTERRUPT) { 213673a394bSEric Anholt dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); 214673a394bSEric Anholt DRM_WAKEUP(&dev_priv->irq_queue); 215673a394bSEric Anholt } 216673a394bSEric Anholt 2177c463586SKeith Packard if (pipea_stats & I915_VBLANK_INTERRUPT_STATUS) { 2187c463586SKeith Packard vblank++; 2197c463586SKeith Packard drm_handle_vblank(dev, 0); 2207c463586SKeith Packard } 2217c463586SKeith Packard 2227c463586SKeith Packard if (pipeb_stats & I915_VBLANK_INTERRUPT_STATUS) { 2237c463586SKeith Packard vblank++; 2247c463586SKeith Packard drm_handle_vblank(dev, 1); 2257c463586SKeith Packard } 2267c463586SKeith Packard 2277c463586SKeith Packard if ((pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) || 2287c463586SKeith Packard (iir & I915_ASLE_INTERRUPT)) 229673a394bSEric Anholt opregion_asle_intr(dev); 2300a3e67a4SJesse Barnes 231*cdfbc41fSEric Anholt /* With MSI, interrupts are only generated when iir 232*cdfbc41fSEric Anholt * transitions from zero to nonzero. If another bit got 233*cdfbc41fSEric Anholt * set while we were handling the existing iir bits, then 234*cdfbc41fSEric Anholt * we would never get another interrupt. 235*cdfbc41fSEric Anholt * 236*cdfbc41fSEric Anholt * This is fine on non-MSI as well, as if we hit this path 237*cdfbc41fSEric Anholt * we avoid exiting the interrupt handler only to generate 238*cdfbc41fSEric Anholt * another one. 239*cdfbc41fSEric Anholt * 240*cdfbc41fSEric Anholt * Note that for MSI this could cause a stray interrupt report 241*cdfbc41fSEric Anholt * if an interrupt landed in the time between writing IIR and 242*cdfbc41fSEric Anholt * the posting read. This should be rare enough to never 243*cdfbc41fSEric Anholt * trigger the 99% of 100,000 interrupts test for disabling 244*cdfbc41fSEric Anholt * stray interrupts. 245*cdfbc41fSEric Anholt */ 246*cdfbc41fSEric Anholt iir = new_iir; 247*cdfbc41fSEric Anholt } while (iir != 0); 248*cdfbc41fSEric Anholt 249c0e09200SDave Airlie return IRQ_HANDLED; 250c0e09200SDave Airlie } 251c0e09200SDave Airlie 252c0e09200SDave Airlie static int i915_emit_irq(struct drm_device * dev) 253c0e09200SDave Airlie { 254c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 255c0e09200SDave Airlie RING_LOCALS; 256c0e09200SDave Airlie 257c0e09200SDave Airlie i915_kernel_lost_context(dev); 258c0e09200SDave Airlie 259c0e09200SDave Airlie DRM_DEBUG("\n"); 260c0e09200SDave Airlie 261c99b058fSKristian Høgsberg dev_priv->counter++; 262c0e09200SDave Airlie if (dev_priv->counter > 0x7FFFFFFFUL) 263c99b058fSKristian Høgsberg dev_priv->counter = 1; 264c99b058fSKristian Høgsberg if (dev_priv->sarea_priv) 265c99b058fSKristian Høgsberg dev_priv->sarea_priv->last_enqueue = dev_priv->counter; 266c0e09200SDave Airlie 2670baf823aSKeith Packard BEGIN_LP_RING(4); 268585fb111SJesse Barnes OUT_RING(MI_STORE_DWORD_INDEX); 2690baf823aSKeith Packard OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); 270c0e09200SDave Airlie OUT_RING(dev_priv->counter); 271585fb111SJesse Barnes OUT_RING(MI_USER_INTERRUPT); 272c0e09200SDave Airlie ADVANCE_LP_RING(); 273c0e09200SDave Airlie 274c0e09200SDave Airlie return dev_priv->counter; 275c0e09200SDave Airlie } 276c0e09200SDave Airlie 277673a394bSEric Anholt void i915_user_irq_get(struct drm_device *dev) 278ed4cb414SEric Anholt { 279ed4cb414SEric Anholt drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 280e9d21d7fSKeith Packard unsigned long irqflags; 281ed4cb414SEric Anholt 282e9d21d7fSKeith Packard spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 283ed4cb414SEric Anholt if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) 284ed4cb414SEric Anholt i915_enable_irq(dev_priv, I915_USER_INTERRUPT); 285e9d21d7fSKeith Packard spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 286ed4cb414SEric Anholt } 287ed4cb414SEric Anholt 2880a3e67a4SJesse Barnes void i915_user_irq_put(struct drm_device *dev) 289ed4cb414SEric Anholt { 290ed4cb414SEric Anholt drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 291e9d21d7fSKeith Packard unsigned long irqflags; 292ed4cb414SEric Anholt 293e9d21d7fSKeith Packard spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 294ed4cb414SEric Anholt BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); 295ed4cb414SEric Anholt if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) 296ed4cb414SEric Anholt i915_disable_irq(dev_priv, I915_USER_INTERRUPT); 297e9d21d7fSKeith Packard spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 298ed4cb414SEric Anholt } 299ed4cb414SEric Anholt 300c0e09200SDave Airlie static int i915_wait_irq(struct drm_device * dev, int irq_nr) 301c0e09200SDave Airlie { 302c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 303c0e09200SDave Airlie int ret = 0; 304c0e09200SDave Airlie 305c0e09200SDave Airlie DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, 306c0e09200SDave Airlie READ_BREADCRUMB(dev_priv)); 307c0e09200SDave Airlie 308ed4cb414SEric Anholt if (READ_BREADCRUMB(dev_priv) >= irq_nr) { 309c99b058fSKristian Høgsberg if (dev_priv->sarea_priv) { 310c99b058fSKristian Høgsberg dev_priv->sarea_priv->last_dispatch = 311c99b058fSKristian Høgsberg READ_BREADCRUMB(dev_priv); 312c99b058fSKristian Høgsberg } 313c0e09200SDave Airlie return 0; 314ed4cb414SEric Anholt } 315c0e09200SDave Airlie 316c99b058fSKristian Høgsberg if (dev_priv->sarea_priv) 317c0e09200SDave Airlie dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; 318c0e09200SDave Airlie 319ed4cb414SEric Anholt i915_user_irq_get(dev); 320c0e09200SDave Airlie DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, 321c0e09200SDave Airlie READ_BREADCRUMB(dev_priv) >= irq_nr); 322ed4cb414SEric Anholt i915_user_irq_put(dev); 323c0e09200SDave Airlie 324c0e09200SDave Airlie if (ret == -EBUSY) { 325c0e09200SDave Airlie DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", 326c0e09200SDave Airlie READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); 327c0e09200SDave Airlie } 328c0e09200SDave Airlie 329c99b058fSKristian Høgsberg if (dev_priv->sarea_priv) 330c99b058fSKristian Høgsberg dev_priv->sarea_priv->last_dispatch = 331c99b058fSKristian Høgsberg READ_BREADCRUMB(dev_priv); 332c0e09200SDave Airlie 333c0e09200SDave Airlie return ret; 334c0e09200SDave Airlie } 335c0e09200SDave Airlie 336c0e09200SDave Airlie /* Needs the lock as it touches the ring. 337c0e09200SDave Airlie */ 338c0e09200SDave Airlie int i915_irq_emit(struct drm_device *dev, void *data, 339c0e09200SDave Airlie struct drm_file *file_priv) 340c0e09200SDave Airlie { 341c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 342c0e09200SDave Airlie drm_i915_irq_emit_t *emit = data; 343c0e09200SDave Airlie int result; 344c0e09200SDave Airlie 345546b0974SEric Anholt RING_LOCK_TEST_WITH_RETURN(dev, file_priv); 346c0e09200SDave Airlie 347c0e09200SDave Airlie if (!dev_priv) { 348c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 349c0e09200SDave Airlie return -EINVAL; 350c0e09200SDave Airlie } 351546b0974SEric Anholt mutex_lock(&dev->struct_mutex); 352c0e09200SDave Airlie result = i915_emit_irq(dev); 353546b0974SEric Anholt mutex_unlock(&dev->struct_mutex); 354c0e09200SDave Airlie 355c0e09200SDave Airlie if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { 356c0e09200SDave Airlie DRM_ERROR("copy_to_user\n"); 357c0e09200SDave Airlie return -EFAULT; 358c0e09200SDave Airlie } 359c0e09200SDave Airlie 360c0e09200SDave Airlie return 0; 361c0e09200SDave Airlie } 362c0e09200SDave Airlie 363c0e09200SDave Airlie /* Doesn't need the hardware lock. 364c0e09200SDave Airlie */ 365c0e09200SDave Airlie int i915_irq_wait(struct drm_device *dev, void *data, 366c0e09200SDave Airlie struct drm_file *file_priv) 367c0e09200SDave Airlie { 368c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 369c0e09200SDave Airlie drm_i915_irq_wait_t *irqwait = data; 370c0e09200SDave Airlie 371c0e09200SDave Airlie if (!dev_priv) { 372c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 373c0e09200SDave Airlie return -EINVAL; 374c0e09200SDave Airlie } 375c0e09200SDave Airlie 376c0e09200SDave Airlie return i915_wait_irq(dev, irqwait->irq_seq); 377c0e09200SDave Airlie } 378c0e09200SDave Airlie 37942f52ef8SKeith Packard /* Called from drm generic code, passed 'crtc' which 38042f52ef8SKeith Packard * we use as a pipe index 38142f52ef8SKeith Packard */ 38242f52ef8SKeith Packard int i915_enable_vblank(struct drm_device *dev, int pipe) 3830a3e67a4SJesse Barnes { 3840a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 385e9d21d7fSKeith Packard unsigned long irqflags; 3860a3e67a4SJesse Barnes 387e9d21d7fSKeith Packard spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 3880a3e67a4SJesse Barnes if (IS_I965G(dev)) 3897c463586SKeith Packard i915_enable_pipestat(dev_priv, pipe, 3907c463586SKeith Packard PIPE_START_VBLANK_INTERRUPT_ENABLE); 3910a3e67a4SJesse Barnes else 3927c463586SKeith Packard i915_enable_pipestat(dev_priv, pipe, 3937c463586SKeith Packard PIPE_VBLANK_INTERRUPT_ENABLE); 394e9d21d7fSKeith Packard spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 3950a3e67a4SJesse Barnes return 0; 3960a3e67a4SJesse Barnes } 3970a3e67a4SJesse Barnes 39842f52ef8SKeith Packard /* Called from drm generic code, passed 'crtc' which 39942f52ef8SKeith Packard * we use as a pipe index 40042f52ef8SKeith Packard */ 40142f52ef8SKeith Packard void i915_disable_vblank(struct drm_device *dev, int pipe) 4020a3e67a4SJesse Barnes { 4030a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 404e9d21d7fSKeith Packard unsigned long irqflags; 4050a3e67a4SJesse Barnes 406e9d21d7fSKeith Packard spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 4077c463586SKeith Packard i915_disable_pipestat(dev_priv, pipe, 4087c463586SKeith Packard PIPE_VBLANK_INTERRUPT_ENABLE | 4097c463586SKeith Packard PIPE_START_VBLANK_INTERRUPT_ENABLE); 410e9d21d7fSKeith Packard spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 4110a3e67a4SJesse Barnes } 4120a3e67a4SJesse Barnes 413c0e09200SDave Airlie /* Set the vblank monitor pipe 414c0e09200SDave Airlie */ 415c0e09200SDave Airlie int i915_vblank_pipe_set(struct drm_device *dev, void *data, 416c0e09200SDave Airlie struct drm_file *file_priv) 417c0e09200SDave Airlie { 418c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 419c0e09200SDave Airlie 420c0e09200SDave Airlie if (!dev_priv) { 421c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 422c0e09200SDave Airlie return -EINVAL; 423c0e09200SDave Airlie } 424c0e09200SDave Airlie 425c0e09200SDave Airlie return 0; 426c0e09200SDave Airlie } 427c0e09200SDave Airlie 428c0e09200SDave Airlie int i915_vblank_pipe_get(struct drm_device *dev, void *data, 429c0e09200SDave Airlie struct drm_file *file_priv) 430c0e09200SDave Airlie { 431c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 432c0e09200SDave Airlie drm_i915_vblank_pipe_t *pipe = data; 433c0e09200SDave Airlie 434c0e09200SDave Airlie if (!dev_priv) { 435c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 436c0e09200SDave Airlie return -EINVAL; 437c0e09200SDave Airlie } 438c0e09200SDave Airlie 4390a3e67a4SJesse Barnes pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; 440c0e09200SDave Airlie 441c0e09200SDave Airlie return 0; 442c0e09200SDave Airlie } 443c0e09200SDave Airlie 444c0e09200SDave Airlie /** 445c0e09200SDave Airlie * Schedule buffer swap at given vertical blank. 446c0e09200SDave Airlie */ 447c0e09200SDave Airlie int i915_vblank_swap(struct drm_device *dev, void *data, 448c0e09200SDave Airlie struct drm_file *file_priv) 449c0e09200SDave Airlie { 450bd95e0a4SEric Anholt /* The delayed swap mechanism was fundamentally racy, and has been 451bd95e0a4SEric Anholt * removed. The model was that the client requested a delayed flip/swap 452bd95e0a4SEric Anholt * from the kernel, then waited for vblank before continuing to perform 453bd95e0a4SEric Anholt * rendering. The problem was that the kernel might wake the client 454bd95e0a4SEric Anholt * up before it dispatched the vblank swap (since the lock has to be 455bd95e0a4SEric Anholt * held while touching the ringbuffer), in which case the client would 456bd95e0a4SEric Anholt * clear and start the next frame before the swap occurred, and 457bd95e0a4SEric Anholt * flicker would occur in addition to likely missing the vblank. 458bd95e0a4SEric Anholt * 459bd95e0a4SEric Anholt * In the absence of this ioctl, userland falls back to a correct path 460bd95e0a4SEric Anholt * of waiting for a vblank, then dispatching the swap on its own. 461bd95e0a4SEric Anholt * Context switching to userland and back is plenty fast enough for 462bd95e0a4SEric Anholt * meeting the requirements of vblank swapping. 4630a3e67a4SJesse Barnes */ 464c0e09200SDave Airlie return -EINVAL; 465c0e09200SDave Airlie } 466c0e09200SDave Airlie 467c0e09200SDave Airlie /* drm_dma.h hooks 468c0e09200SDave Airlie */ 469c0e09200SDave Airlie void i915_driver_irq_preinstall(struct drm_device * dev) 470c0e09200SDave Airlie { 471c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 472c0e09200SDave Airlie 4730a3e67a4SJesse Barnes I915_WRITE(HWSTAM, 0xeffe); 4747c463586SKeith Packard I915_WRITE(PIPEASTAT, 0); 4757c463586SKeith Packard I915_WRITE(PIPEBSTAT, 0); 4760a3e67a4SJesse Barnes I915_WRITE(IMR, 0xffffffff); 477ed4cb414SEric Anholt I915_WRITE(IER, 0x0); 4787c463586SKeith Packard (void) I915_READ(IER); 479c0e09200SDave Airlie } 480c0e09200SDave Airlie 4810a3e67a4SJesse Barnes int i915_driver_irq_postinstall(struct drm_device *dev) 482c0e09200SDave Airlie { 483c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 4840a3e67a4SJesse Barnes int ret, num_pipes = 2; 485c0e09200SDave Airlie 4860a3e67a4SJesse Barnes ret = drm_vblank_init(dev, num_pipes); 4870a3e67a4SJesse Barnes if (ret) 4880a3e67a4SJesse Barnes return ret; 4890a3e67a4SJesse Barnes 4900a3e67a4SJesse Barnes dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; 491ed4cb414SEric Anholt 4920a3e67a4SJesse Barnes dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ 4930a3e67a4SJesse Barnes 4947c463586SKeith Packard /* Unmask the interrupts that we always want on. */ 4957c463586SKeith Packard dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX; 4968ee1c3dbSMatthew Garrett 4977c463586SKeith Packard dev_priv->pipestat[0] = 0; 4987c463586SKeith Packard dev_priv->pipestat[1] = 0; 4997c463586SKeith Packard 5007c463586SKeith Packard /* Disable pipe interrupt enables, clear pending pipe status */ 5017c463586SKeith Packard I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); 5027c463586SKeith Packard I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); 5037c463586SKeith Packard /* Clear pending interrupt status */ 5047c463586SKeith Packard I915_WRITE(IIR, I915_READ(IIR)); 5057c463586SKeith Packard 506ed4cb414SEric Anholt I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK); 5077c463586SKeith Packard I915_WRITE(IMR, dev_priv->irq_mask_reg); 508ed4cb414SEric Anholt (void) I915_READ(IER); 509ed4cb414SEric Anholt 5108ee1c3dbSMatthew Garrett opregion_enable_asle(dev); 511c0e09200SDave Airlie DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); 5120a3e67a4SJesse Barnes 5130a3e67a4SJesse Barnes return 0; 514c0e09200SDave Airlie } 515c0e09200SDave Airlie 516c0e09200SDave Airlie void i915_driver_irq_uninstall(struct drm_device * dev) 517c0e09200SDave Airlie { 518c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 519c0e09200SDave Airlie 520c0e09200SDave Airlie if (!dev_priv) 521c0e09200SDave Airlie return; 522c0e09200SDave Airlie 5230a3e67a4SJesse Barnes dev_priv->vblank_pipe = 0; 5240a3e67a4SJesse Barnes 5250a3e67a4SJesse Barnes I915_WRITE(HWSTAM, 0xffffffff); 5267c463586SKeith Packard I915_WRITE(PIPEASTAT, 0); 5277c463586SKeith Packard I915_WRITE(PIPEBSTAT, 0); 5280a3e67a4SJesse Barnes I915_WRITE(IMR, 0xffffffff); 529ed4cb414SEric Anholt I915_WRITE(IER, 0x0); 530c0e09200SDave Airlie 5317c463586SKeith Packard I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); 5327c463586SKeith Packard I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); 5337c463586SKeith Packard I915_WRITE(IIR, I915_READ(IIR)); 534c0e09200SDave Airlie } 535