1*c0e09200SDave Airlie /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*- 2*c0e09200SDave Airlie */ 3*c0e09200SDave Airlie /* 4*c0e09200SDave Airlie * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 5*c0e09200SDave Airlie * All Rights Reserved. 6*c0e09200SDave Airlie * 7*c0e09200SDave Airlie * Permission is hereby granted, free of charge, to any person obtaining a 8*c0e09200SDave Airlie * copy of this software and associated documentation files (the 9*c0e09200SDave Airlie * "Software"), to deal in the Software without restriction, including 10*c0e09200SDave Airlie * without limitation the rights to use, copy, modify, merge, publish, 11*c0e09200SDave Airlie * distribute, sub license, and/or sell copies of the Software, and to 12*c0e09200SDave Airlie * permit persons to whom the Software is furnished to do so, subject to 13*c0e09200SDave Airlie * the following conditions: 14*c0e09200SDave Airlie * 15*c0e09200SDave Airlie * The above copyright notice and this permission notice (including the 16*c0e09200SDave Airlie * next paragraph) shall be included in all copies or substantial portions 17*c0e09200SDave Airlie * of the Software. 18*c0e09200SDave Airlie * 19*c0e09200SDave Airlie * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20*c0e09200SDave Airlie * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21*c0e09200SDave Airlie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22*c0e09200SDave Airlie * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 23*c0e09200SDave Airlie * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24*c0e09200SDave Airlie * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25*c0e09200SDave Airlie * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26*c0e09200SDave Airlie * 27*c0e09200SDave Airlie */ 28*c0e09200SDave Airlie 29*c0e09200SDave Airlie #include "drmP.h" 30*c0e09200SDave Airlie #include "drm.h" 31*c0e09200SDave Airlie #include "i915_drm.h" 32*c0e09200SDave Airlie #include "i915_drv.h" 33*c0e09200SDave Airlie 34*c0e09200SDave Airlie #define USER_INT_FLAG (1<<1) 35*c0e09200SDave Airlie #define VSYNC_PIPEB_FLAG (1<<5) 36*c0e09200SDave Airlie #define VSYNC_PIPEA_FLAG (1<<7) 37*c0e09200SDave Airlie 38*c0e09200SDave Airlie #define MAX_NOPID ((u32)~0) 39*c0e09200SDave Airlie 40*c0e09200SDave Airlie /** 41*c0e09200SDave Airlie * Emit blits for scheduled buffer swaps. 42*c0e09200SDave Airlie * 43*c0e09200SDave Airlie * This function will be called with the HW lock held. 44*c0e09200SDave Airlie */ 45*c0e09200SDave Airlie static void i915_vblank_tasklet(struct drm_device *dev) 46*c0e09200SDave Airlie { 47*c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 48*c0e09200SDave Airlie unsigned long irqflags; 49*c0e09200SDave Airlie struct list_head *list, *tmp, hits, *hit; 50*c0e09200SDave Airlie int nhits, nrects, slice[2], upper[2], lower[2], i; 51*c0e09200SDave Airlie unsigned counter[2] = { atomic_read(&dev->vbl_received), 52*c0e09200SDave Airlie atomic_read(&dev->vbl_received2) }; 53*c0e09200SDave Airlie struct drm_drawable_info *drw; 54*c0e09200SDave Airlie drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; 55*c0e09200SDave Airlie u32 cpp = dev_priv->cpp; 56*c0e09200SDave Airlie u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | 57*c0e09200SDave Airlie XY_SRC_COPY_BLT_WRITE_ALPHA | 58*c0e09200SDave Airlie XY_SRC_COPY_BLT_WRITE_RGB) 59*c0e09200SDave Airlie : XY_SRC_COPY_BLT_CMD; 60*c0e09200SDave Airlie u32 src_pitch = sarea_priv->pitch * cpp; 61*c0e09200SDave Airlie u32 dst_pitch = sarea_priv->pitch * cpp; 62*c0e09200SDave Airlie u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24); 63*c0e09200SDave Airlie RING_LOCALS; 64*c0e09200SDave Airlie 65*c0e09200SDave Airlie if (IS_I965G(dev) && sarea_priv->front_tiled) { 66*c0e09200SDave Airlie cmd |= XY_SRC_COPY_BLT_DST_TILED; 67*c0e09200SDave Airlie dst_pitch >>= 2; 68*c0e09200SDave Airlie } 69*c0e09200SDave Airlie if (IS_I965G(dev) && sarea_priv->back_tiled) { 70*c0e09200SDave Airlie cmd |= XY_SRC_COPY_BLT_SRC_TILED; 71*c0e09200SDave Airlie src_pitch >>= 2; 72*c0e09200SDave Airlie } 73*c0e09200SDave Airlie 74*c0e09200SDave Airlie DRM_DEBUG("\n"); 75*c0e09200SDave Airlie 76*c0e09200SDave Airlie INIT_LIST_HEAD(&hits); 77*c0e09200SDave Airlie 78*c0e09200SDave Airlie nhits = nrects = 0; 79*c0e09200SDave Airlie 80*c0e09200SDave Airlie spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); 81*c0e09200SDave Airlie 82*c0e09200SDave Airlie /* Find buffer swaps scheduled for this vertical blank */ 83*c0e09200SDave Airlie list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { 84*c0e09200SDave Airlie drm_i915_vbl_swap_t *vbl_swap = 85*c0e09200SDave Airlie list_entry(list, drm_i915_vbl_swap_t, head); 86*c0e09200SDave Airlie 87*c0e09200SDave Airlie if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) 88*c0e09200SDave Airlie continue; 89*c0e09200SDave Airlie 90*c0e09200SDave Airlie list_del(list); 91*c0e09200SDave Airlie dev_priv->swaps_pending--; 92*c0e09200SDave Airlie 93*c0e09200SDave Airlie spin_unlock(&dev_priv->swaps_lock); 94*c0e09200SDave Airlie spin_lock(&dev->drw_lock); 95*c0e09200SDave Airlie 96*c0e09200SDave Airlie drw = drm_get_drawable_info(dev, vbl_swap->drw_id); 97*c0e09200SDave Airlie 98*c0e09200SDave Airlie if (!drw) { 99*c0e09200SDave Airlie spin_unlock(&dev->drw_lock); 100*c0e09200SDave Airlie drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); 101*c0e09200SDave Airlie spin_lock(&dev_priv->swaps_lock); 102*c0e09200SDave Airlie continue; 103*c0e09200SDave Airlie } 104*c0e09200SDave Airlie 105*c0e09200SDave Airlie list_for_each(hit, &hits) { 106*c0e09200SDave Airlie drm_i915_vbl_swap_t *swap_cmp = 107*c0e09200SDave Airlie list_entry(hit, drm_i915_vbl_swap_t, head); 108*c0e09200SDave Airlie struct drm_drawable_info *drw_cmp = 109*c0e09200SDave Airlie drm_get_drawable_info(dev, swap_cmp->drw_id); 110*c0e09200SDave Airlie 111*c0e09200SDave Airlie if (drw_cmp && 112*c0e09200SDave Airlie drw_cmp->rects[0].y1 > drw->rects[0].y1) { 113*c0e09200SDave Airlie list_add_tail(list, hit); 114*c0e09200SDave Airlie break; 115*c0e09200SDave Airlie } 116*c0e09200SDave Airlie } 117*c0e09200SDave Airlie 118*c0e09200SDave Airlie spin_unlock(&dev->drw_lock); 119*c0e09200SDave Airlie 120*c0e09200SDave Airlie /* List of hits was empty, or we reached the end of it */ 121*c0e09200SDave Airlie if (hit == &hits) 122*c0e09200SDave Airlie list_add_tail(list, hits.prev); 123*c0e09200SDave Airlie 124*c0e09200SDave Airlie nhits++; 125*c0e09200SDave Airlie 126*c0e09200SDave Airlie spin_lock(&dev_priv->swaps_lock); 127*c0e09200SDave Airlie } 128*c0e09200SDave Airlie 129*c0e09200SDave Airlie if (nhits == 0) { 130*c0e09200SDave Airlie spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); 131*c0e09200SDave Airlie return; 132*c0e09200SDave Airlie } 133*c0e09200SDave Airlie 134*c0e09200SDave Airlie spin_unlock(&dev_priv->swaps_lock); 135*c0e09200SDave Airlie 136*c0e09200SDave Airlie i915_kernel_lost_context(dev); 137*c0e09200SDave Airlie 138*c0e09200SDave Airlie if (IS_I965G(dev)) { 139*c0e09200SDave Airlie BEGIN_LP_RING(4); 140*c0e09200SDave Airlie 141*c0e09200SDave Airlie OUT_RING(GFX_OP_DRAWRECT_INFO_I965); 142*c0e09200SDave Airlie OUT_RING(0); 143*c0e09200SDave Airlie OUT_RING(((sarea_priv->width - 1) & 0xffff) | ((sarea_priv->height - 1) << 16)); 144*c0e09200SDave Airlie OUT_RING(0); 145*c0e09200SDave Airlie ADVANCE_LP_RING(); 146*c0e09200SDave Airlie } else { 147*c0e09200SDave Airlie BEGIN_LP_RING(6); 148*c0e09200SDave Airlie 149*c0e09200SDave Airlie OUT_RING(GFX_OP_DRAWRECT_INFO); 150*c0e09200SDave Airlie OUT_RING(0); 151*c0e09200SDave Airlie OUT_RING(0); 152*c0e09200SDave Airlie OUT_RING(sarea_priv->width | sarea_priv->height << 16); 153*c0e09200SDave Airlie OUT_RING(sarea_priv->width | sarea_priv->height << 16); 154*c0e09200SDave Airlie OUT_RING(0); 155*c0e09200SDave Airlie 156*c0e09200SDave Airlie ADVANCE_LP_RING(); 157*c0e09200SDave Airlie } 158*c0e09200SDave Airlie 159*c0e09200SDave Airlie sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; 160*c0e09200SDave Airlie 161*c0e09200SDave Airlie upper[0] = upper[1] = 0; 162*c0e09200SDave Airlie slice[0] = max(sarea_priv->pipeA_h / nhits, 1); 163*c0e09200SDave Airlie slice[1] = max(sarea_priv->pipeB_h / nhits, 1); 164*c0e09200SDave Airlie lower[0] = sarea_priv->pipeA_y + slice[0]; 165*c0e09200SDave Airlie lower[1] = sarea_priv->pipeB_y + slice[0]; 166*c0e09200SDave Airlie 167*c0e09200SDave Airlie spin_lock(&dev->drw_lock); 168*c0e09200SDave Airlie 169*c0e09200SDave Airlie /* Emit blits for buffer swaps, partitioning both outputs into as many 170*c0e09200SDave Airlie * slices as there are buffer swaps scheduled in order to avoid tearing 171*c0e09200SDave Airlie * (based on the assumption that a single buffer swap would always 172*c0e09200SDave Airlie * complete before scanout starts). 173*c0e09200SDave Airlie */ 174*c0e09200SDave Airlie for (i = 0; i++ < nhits; 175*c0e09200SDave Airlie upper[0] = lower[0], lower[0] += slice[0], 176*c0e09200SDave Airlie upper[1] = lower[1], lower[1] += slice[1]) { 177*c0e09200SDave Airlie if (i == nhits) 178*c0e09200SDave Airlie lower[0] = lower[1] = sarea_priv->height; 179*c0e09200SDave Airlie 180*c0e09200SDave Airlie list_for_each(hit, &hits) { 181*c0e09200SDave Airlie drm_i915_vbl_swap_t *swap_hit = 182*c0e09200SDave Airlie list_entry(hit, drm_i915_vbl_swap_t, head); 183*c0e09200SDave Airlie struct drm_clip_rect *rect; 184*c0e09200SDave Airlie int num_rects, pipe; 185*c0e09200SDave Airlie unsigned short top, bottom; 186*c0e09200SDave Airlie 187*c0e09200SDave Airlie drw = drm_get_drawable_info(dev, swap_hit->drw_id); 188*c0e09200SDave Airlie 189*c0e09200SDave Airlie if (!drw) 190*c0e09200SDave Airlie continue; 191*c0e09200SDave Airlie 192*c0e09200SDave Airlie rect = drw->rects; 193*c0e09200SDave Airlie pipe = swap_hit->pipe; 194*c0e09200SDave Airlie top = upper[pipe]; 195*c0e09200SDave Airlie bottom = lower[pipe]; 196*c0e09200SDave Airlie 197*c0e09200SDave Airlie for (num_rects = drw->num_rects; num_rects--; rect++) { 198*c0e09200SDave Airlie int y1 = max(rect->y1, top); 199*c0e09200SDave Airlie int y2 = min(rect->y2, bottom); 200*c0e09200SDave Airlie 201*c0e09200SDave Airlie if (y1 >= y2) 202*c0e09200SDave Airlie continue; 203*c0e09200SDave Airlie 204*c0e09200SDave Airlie BEGIN_LP_RING(8); 205*c0e09200SDave Airlie 206*c0e09200SDave Airlie OUT_RING(cmd); 207*c0e09200SDave Airlie OUT_RING(ropcpp | dst_pitch); 208*c0e09200SDave Airlie OUT_RING((y1 << 16) | rect->x1); 209*c0e09200SDave Airlie OUT_RING((y2 << 16) | rect->x2); 210*c0e09200SDave Airlie OUT_RING(sarea_priv->front_offset); 211*c0e09200SDave Airlie OUT_RING((y1 << 16) | rect->x1); 212*c0e09200SDave Airlie OUT_RING(src_pitch); 213*c0e09200SDave Airlie OUT_RING(sarea_priv->back_offset); 214*c0e09200SDave Airlie 215*c0e09200SDave Airlie ADVANCE_LP_RING(); 216*c0e09200SDave Airlie } 217*c0e09200SDave Airlie } 218*c0e09200SDave Airlie } 219*c0e09200SDave Airlie 220*c0e09200SDave Airlie spin_unlock_irqrestore(&dev->drw_lock, irqflags); 221*c0e09200SDave Airlie 222*c0e09200SDave Airlie list_for_each_safe(hit, tmp, &hits) { 223*c0e09200SDave Airlie drm_i915_vbl_swap_t *swap_hit = 224*c0e09200SDave Airlie list_entry(hit, drm_i915_vbl_swap_t, head); 225*c0e09200SDave Airlie 226*c0e09200SDave Airlie list_del(hit); 227*c0e09200SDave Airlie 228*c0e09200SDave Airlie drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER); 229*c0e09200SDave Airlie } 230*c0e09200SDave Airlie } 231*c0e09200SDave Airlie 232*c0e09200SDave Airlie irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) 233*c0e09200SDave Airlie { 234*c0e09200SDave Airlie struct drm_device *dev = (struct drm_device *) arg; 235*c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 236*c0e09200SDave Airlie u16 temp; 237*c0e09200SDave Airlie u32 pipea_stats, pipeb_stats; 238*c0e09200SDave Airlie 239*c0e09200SDave Airlie pipea_stats = I915_READ(I915REG_PIPEASTAT); 240*c0e09200SDave Airlie pipeb_stats = I915_READ(I915REG_PIPEBSTAT); 241*c0e09200SDave Airlie 242*c0e09200SDave Airlie temp = I915_READ16(I915REG_INT_IDENTITY_R); 243*c0e09200SDave Airlie 244*c0e09200SDave Airlie temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); 245*c0e09200SDave Airlie 246*c0e09200SDave Airlie DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); 247*c0e09200SDave Airlie 248*c0e09200SDave Airlie if (temp == 0) 249*c0e09200SDave Airlie return IRQ_NONE; 250*c0e09200SDave Airlie 251*c0e09200SDave Airlie I915_WRITE16(I915REG_INT_IDENTITY_R, temp); 252*c0e09200SDave Airlie (void) I915_READ16(I915REG_INT_IDENTITY_R); 253*c0e09200SDave Airlie DRM_READMEMORYBARRIER(); 254*c0e09200SDave Airlie 255*c0e09200SDave Airlie dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); 256*c0e09200SDave Airlie 257*c0e09200SDave Airlie if (temp & USER_INT_FLAG) 258*c0e09200SDave Airlie DRM_WAKEUP(&dev_priv->irq_queue); 259*c0e09200SDave Airlie 260*c0e09200SDave Airlie if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { 261*c0e09200SDave Airlie int vblank_pipe = dev_priv->vblank_pipe; 262*c0e09200SDave Airlie 263*c0e09200SDave Airlie if ((vblank_pipe & 264*c0e09200SDave Airlie (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) 265*c0e09200SDave Airlie == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { 266*c0e09200SDave Airlie if (temp & VSYNC_PIPEA_FLAG) 267*c0e09200SDave Airlie atomic_inc(&dev->vbl_received); 268*c0e09200SDave Airlie if (temp & VSYNC_PIPEB_FLAG) 269*c0e09200SDave Airlie atomic_inc(&dev->vbl_received2); 270*c0e09200SDave Airlie } else if (((temp & VSYNC_PIPEA_FLAG) && 271*c0e09200SDave Airlie (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || 272*c0e09200SDave Airlie ((temp & VSYNC_PIPEB_FLAG) && 273*c0e09200SDave Airlie (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) 274*c0e09200SDave Airlie atomic_inc(&dev->vbl_received); 275*c0e09200SDave Airlie 276*c0e09200SDave Airlie DRM_WAKEUP(&dev->vbl_queue); 277*c0e09200SDave Airlie drm_vbl_send_signals(dev); 278*c0e09200SDave Airlie 279*c0e09200SDave Airlie if (dev_priv->swaps_pending > 0) 280*c0e09200SDave Airlie drm_locked_tasklet(dev, i915_vblank_tasklet); 281*c0e09200SDave Airlie I915_WRITE(I915REG_PIPEASTAT, 282*c0e09200SDave Airlie pipea_stats|I915_VBLANK_INTERRUPT_ENABLE| 283*c0e09200SDave Airlie I915_VBLANK_CLEAR); 284*c0e09200SDave Airlie I915_WRITE(I915REG_PIPEBSTAT, 285*c0e09200SDave Airlie pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE| 286*c0e09200SDave Airlie I915_VBLANK_CLEAR); 287*c0e09200SDave Airlie } 288*c0e09200SDave Airlie 289*c0e09200SDave Airlie return IRQ_HANDLED; 290*c0e09200SDave Airlie } 291*c0e09200SDave Airlie 292*c0e09200SDave Airlie static int i915_emit_irq(struct drm_device * dev) 293*c0e09200SDave Airlie { 294*c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 295*c0e09200SDave Airlie RING_LOCALS; 296*c0e09200SDave Airlie 297*c0e09200SDave Airlie i915_kernel_lost_context(dev); 298*c0e09200SDave Airlie 299*c0e09200SDave Airlie DRM_DEBUG("\n"); 300*c0e09200SDave Airlie 301*c0e09200SDave Airlie dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; 302*c0e09200SDave Airlie 303*c0e09200SDave Airlie if (dev_priv->counter > 0x7FFFFFFFUL) 304*c0e09200SDave Airlie dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; 305*c0e09200SDave Airlie 306*c0e09200SDave Airlie BEGIN_LP_RING(6); 307*c0e09200SDave Airlie OUT_RING(CMD_STORE_DWORD_IDX); 308*c0e09200SDave Airlie OUT_RING(20); 309*c0e09200SDave Airlie OUT_RING(dev_priv->counter); 310*c0e09200SDave Airlie OUT_RING(0); 311*c0e09200SDave Airlie OUT_RING(0); 312*c0e09200SDave Airlie OUT_RING(GFX_OP_USER_INTERRUPT); 313*c0e09200SDave Airlie ADVANCE_LP_RING(); 314*c0e09200SDave Airlie 315*c0e09200SDave Airlie return dev_priv->counter; 316*c0e09200SDave Airlie } 317*c0e09200SDave Airlie 318*c0e09200SDave Airlie static int i915_wait_irq(struct drm_device * dev, int irq_nr) 319*c0e09200SDave Airlie { 320*c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 321*c0e09200SDave Airlie int ret = 0; 322*c0e09200SDave Airlie 323*c0e09200SDave Airlie DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, 324*c0e09200SDave Airlie READ_BREADCRUMB(dev_priv)); 325*c0e09200SDave Airlie 326*c0e09200SDave Airlie if (READ_BREADCRUMB(dev_priv) >= irq_nr) 327*c0e09200SDave Airlie return 0; 328*c0e09200SDave Airlie 329*c0e09200SDave Airlie dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; 330*c0e09200SDave Airlie 331*c0e09200SDave Airlie DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, 332*c0e09200SDave Airlie READ_BREADCRUMB(dev_priv) >= irq_nr); 333*c0e09200SDave Airlie 334*c0e09200SDave Airlie if (ret == -EBUSY) { 335*c0e09200SDave Airlie DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", 336*c0e09200SDave Airlie READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); 337*c0e09200SDave Airlie } 338*c0e09200SDave Airlie 339*c0e09200SDave Airlie dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); 340*c0e09200SDave Airlie return ret; 341*c0e09200SDave Airlie } 342*c0e09200SDave Airlie 343*c0e09200SDave Airlie static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence, 344*c0e09200SDave Airlie atomic_t *counter) 345*c0e09200SDave Airlie { 346*c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 347*c0e09200SDave Airlie unsigned int cur_vblank; 348*c0e09200SDave Airlie int ret = 0; 349*c0e09200SDave Airlie 350*c0e09200SDave Airlie if (!dev_priv) { 351*c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 352*c0e09200SDave Airlie return -EINVAL; 353*c0e09200SDave Airlie } 354*c0e09200SDave Airlie 355*c0e09200SDave Airlie DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, 356*c0e09200SDave Airlie (((cur_vblank = atomic_read(counter)) 357*c0e09200SDave Airlie - *sequence) <= (1<<23))); 358*c0e09200SDave Airlie 359*c0e09200SDave Airlie *sequence = cur_vblank; 360*c0e09200SDave Airlie 361*c0e09200SDave Airlie return ret; 362*c0e09200SDave Airlie } 363*c0e09200SDave Airlie 364*c0e09200SDave Airlie 365*c0e09200SDave Airlie int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) 366*c0e09200SDave Airlie { 367*c0e09200SDave Airlie return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); 368*c0e09200SDave Airlie } 369*c0e09200SDave Airlie 370*c0e09200SDave Airlie int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) 371*c0e09200SDave Airlie { 372*c0e09200SDave Airlie return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); 373*c0e09200SDave Airlie } 374*c0e09200SDave Airlie 375*c0e09200SDave Airlie /* Needs the lock as it touches the ring. 376*c0e09200SDave Airlie */ 377*c0e09200SDave Airlie int i915_irq_emit(struct drm_device *dev, void *data, 378*c0e09200SDave Airlie struct drm_file *file_priv) 379*c0e09200SDave Airlie { 380*c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 381*c0e09200SDave Airlie drm_i915_irq_emit_t *emit = data; 382*c0e09200SDave Airlie int result; 383*c0e09200SDave Airlie 384*c0e09200SDave Airlie LOCK_TEST_WITH_RETURN(dev, file_priv); 385*c0e09200SDave Airlie 386*c0e09200SDave Airlie if (!dev_priv) { 387*c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 388*c0e09200SDave Airlie return -EINVAL; 389*c0e09200SDave Airlie } 390*c0e09200SDave Airlie 391*c0e09200SDave Airlie result = i915_emit_irq(dev); 392*c0e09200SDave Airlie 393*c0e09200SDave Airlie if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { 394*c0e09200SDave Airlie DRM_ERROR("copy_to_user\n"); 395*c0e09200SDave Airlie return -EFAULT; 396*c0e09200SDave Airlie } 397*c0e09200SDave Airlie 398*c0e09200SDave Airlie return 0; 399*c0e09200SDave Airlie } 400*c0e09200SDave Airlie 401*c0e09200SDave Airlie /* Doesn't need the hardware lock. 402*c0e09200SDave Airlie */ 403*c0e09200SDave Airlie int i915_irq_wait(struct drm_device *dev, void *data, 404*c0e09200SDave Airlie struct drm_file *file_priv) 405*c0e09200SDave Airlie { 406*c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 407*c0e09200SDave Airlie drm_i915_irq_wait_t *irqwait = data; 408*c0e09200SDave Airlie 409*c0e09200SDave Airlie if (!dev_priv) { 410*c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 411*c0e09200SDave Airlie return -EINVAL; 412*c0e09200SDave Airlie } 413*c0e09200SDave Airlie 414*c0e09200SDave Airlie return i915_wait_irq(dev, irqwait->irq_seq); 415*c0e09200SDave Airlie } 416*c0e09200SDave Airlie 417*c0e09200SDave Airlie static void i915_enable_interrupt (struct drm_device *dev) 418*c0e09200SDave Airlie { 419*c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 420*c0e09200SDave Airlie u16 flag; 421*c0e09200SDave Airlie 422*c0e09200SDave Airlie flag = 0; 423*c0e09200SDave Airlie if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) 424*c0e09200SDave Airlie flag |= VSYNC_PIPEA_FLAG; 425*c0e09200SDave Airlie if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) 426*c0e09200SDave Airlie flag |= VSYNC_PIPEB_FLAG; 427*c0e09200SDave Airlie 428*c0e09200SDave Airlie I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); 429*c0e09200SDave Airlie } 430*c0e09200SDave Airlie 431*c0e09200SDave Airlie /* Set the vblank monitor pipe 432*c0e09200SDave Airlie */ 433*c0e09200SDave Airlie int i915_vblank_pipe_set(struct drm_device *dev, void *data, 434*c0e09200SDave Airlie struct drm_file *file_priv) 435*c0e09200SDave Airlie { 436*c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 437*c0e09200SDave Airlie drm_i915_vblank_pipe_t *pipe = data; 438*c0e09200SDave Airlie 439*c0e09200SDave Airlie if (!dev_priv) { 440*c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 441*c0e09200SDave Airlie return -EINVAL; 442*c0e09200SDave Airlie } 443*c0e09200SDave Airlie 444*c0e09200SDave Airlie if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { 445*c0e09200SDave Airlie DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe); 446*c0e09200SDave Airlie return -EINVAL; 447*c0e09200SDave Airlie } 448*c0e09200SDave Airlie 449*c0e09200SDave Airlie dev_priv->vblank_pipe = pipe->pipe; 450*c0e09200SDave Airlie 451*c0e09200SDave Airlie i915_enable_interrupt (dev); 452*c0e09200SDave Airlie 453*c0e09200SDave Airlie return 0; 454*c0e09200SDave Airlie } 455*c0e09200SDave Airlie 456*c0e09200SDave Airlie int i915_vblank_pipe_get(struct drm_device *dev, void *data, 457*c0e09200SDave Airlie struct drm_file *file_priv) 458*c0e09200SDave Airlie { 459*c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 460*c0e09200SDave Airlie drm_i915_vblank_pipe_t *pipe = data; 461*c0e09200SDave Airlie u16 flag; 462*c0e09200SDave Airlie 463*c0e09200SDave Airlie if (!dev_priv) { 464*c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 465*c0e09200SDave Airlie return -EINVAL; 466*c0e09200SDave Airlie } 467*c0e09200SDave Airlie 468*c0e09200SDave Airlie flag = I915_READ(I915REG_INT_ENABLE_R); 469*c0e09200SDave Airlie pipe->pipe = 0; 470*c0e09200SDave Airlie if (flag & VSYNC_PIPEA_FLAG) 471*c0e09200SDave Airlie pipe->pipe |= DRM_I915_VBLANK_PIPE_A; 472*c0e09200SDave Airlie if (flag & VSYNC_PIPEB_FLAG) 473*c0e09200SDave Airlie pipe->pipe |= DRM_I915_VBLANK_PIPE_B; 474*c0e09200SDave Airlie 475*c0e09200SDave Airlie return 0; 476*c0e09200SDave Airlie } 477*c0e09200SDave Airlie 478*c0e09200SDave Airlie /** 479*c0e09200SDave Airlie * Schedule buffer swap at given vertical blank. 480*c0e09200SDave Airlie */ 481*c0e09200SDave Airlie int i915_vblank_swap(struct drm_device *dev, void *data, 482*c0e09200SDave Airlie struct drm_file *file_priv) 483*c0e09200SDave Airlie { 484*c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 485*c0e09200SDave Airlie drm_i915_vblank_swap_t *swap = data; 486*c0e09200SDave Airlie drm_i915_vbl_swap_t *vbl_swap; 487*c0e09200SDave Airlie unsigned int pipe, seqtype, curseq; 488*c0e09200SDave Airlie unsigned long irqflags; 489*c0e09200SDave Airlie struct list_head *list; 490*c0e09200SDave Airlie 491*c0e09200SDave Airlie if (!dev_priv) { 492*c0e09200SDave Airlie DRM_ERROR("%s called with no initialization\n", __func__); 493*c0e09200SDave Airlie return -EINVAL; 494*c0e09200SDave Airlie } 495*c0e09200SDave Airlie 496*c0e09200SDave Airlie if (dev_priv->sarea_priv->rotation) { 497*c0e09200SDave Airlie DRM_DEBUG("Rotation not supported\n"); 498*c0e09200SDave Airlie return -EINVAL; 499*c0e09200SDave Airlie } 500*c0e09200SDave Airlie 501*c0e09200SDave Airlie if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | 502*c0e09200SDave Airlie _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { 503*c0e09200SDave Airlie DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); 504*c0e09200SDave Airlie return -EINVAL; 505*c0e09200SDave Airlie } 506*c0e09200SDave Airlie 507*c0e09200SDave Airlie pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; 508*c0e09200SDave Airlie 509*c0e09200SDave Airlie seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); 510*c0e09200SDave Airlie 511*c0e09200SDave Airlie if (!(dev_priv->vblank_pipe & (1 << pipe))) { 512*c0e09200SDave Airlie DRM_ERROR("Invalid pipe %d\n", pipe); 513*c0e09200SDave Airlie return -EINVAL; 514*c0e09200SDave Airlie } 515*c0e09200SDave Airlie 516*c0e09200SDave Airlie spin_lock_irqsave(&dev->drw_lock, irqflags); 517*c0e09200SDave Airlie 518*c0e09200SDave Airlie if (!drm_get_drawable_info(dev, swap->drawable)) { 519*c0e09200SDave Airlie spin_unlock_irqrestore(&dev->drw_lock, irqflags); 520*c0e09200SDave Airlie DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); 521*c0e09200SDave Airlie return -EINVAL; 522*c0e09200SDave Airlie } 523*c0e09200SDave Airlie 524*c0e09200SDave Airlie spin_unlock_irqrestore(&dev->drw_lock, irqflags); 525*c0e09200SDave Airlie 526*c0e09200SDave Airlie curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); 527*c0e09200SDave Airlie 528*c0e09200SDave Airlie if (seqtype == _DRM_VBLANK_RELATIVE) 529*c0e09200SDave Airlie swap->sequence += curseq; 530*c0e09200SDave Airlie 531*c0e09200SDave Airlie if ((curseq - swap->sequence) <= (1<<23)) { 532*c0e09200SDave Airlie if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) { 533*c0e09200SDave Airlie swap->sequence = curseq + 1; 534*c0e09200SDave Airlie } else { 535*c0e09200SDave Airlie DRM_DEBUG("Missed target sequence\n"); 536*c0e09200SDave Airlie return -EINVAL; 537*c0e09200SDave Airlie } 538*c0e09200SDave Airlie } 539*c0e09200SDave Airlie 540*c0e09200SDave Airlie spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); 541*c0e09200SDave Airlie 542*c0e09200SDave Airlie list_for_each(list, &dev_priv->vbl_swaps.head) { 543*c0e09200SDave Airlie vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); 544*c0e09200SDave Airlie 545*c0e09200SDave Airlie if (vbl_swap->drw_id == swap->drawable && 546*c0e09200SDave Airlie vbl_swap->pipe == pipe && 547*c0e09200SDave Airlie vbl_swap->sequence == swap->sequence) { 548*c0e09200SDave Airlie spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); 549*c0e09200SDave Airlie DRM_DEBUG("Already scheduled\n"); 550*c0e09200SDave Airlie return 0; 551*c0e09200SDave Airlie } 552*c0e09200SDave Airlie } 553*c0e09200SDave Airlie 554*c0e09200SDave Airlie spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); 555*c0e09200SDave Airlie 556*c0e09200SDave Airlie if (dev_priv->swaps_pending >= 100) { 557*c0e09200SDave Airlie DRM_DEBUG("Too many swaps queued\n"); 558*c0e09200SDave Airlie return -EBUSY; 559*c0e09200SDave Airlie } 560*c0e09200SDave Airlie 561*c0e09200SDave Airlie vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER); 562*c0e09200SDave Airlie 563*c0e09200SDave Airlie if (!vbl_swap) { 564*c0e09200SDave Airlie DRM_ERROR("Failed to allocate memory to queue swap\n"); 565*c0e09200SDave Airlie return -ENOMEM; 566*c0e09200SDave Airlie } 567*c0e09200SDave Airlie 568*c0e09200SDave Airlie DRM_DEBUG("\n"); 569*c0e09200SDave Airlie 570*c0e09200SDave Airlie vbl_swap->drw_id = swap->drawable; 571*c0e09200SDave Airlie vbl_swap->pipe = pipe; 572*c0e09200SDave Airlie vbl_swap->sequence = swap->sequence; 573*c0e09200SDave Airlie 574*c0e09200SDave Airlie spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); 575*c0e09200SDave Airlie 576*c0e09200SDave Airlie list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head); 577*c0e09200SDave Airlie dev_priv->swaps_pending++; 578*c0e09200SDave Airlie 579*c0e09200SDave Airlie spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); 580*c0e09200SDave Airlie 581*c0e09200SDave Airlie return 0; 582*c0e09200SDave Airlie } 583*c0e09200SDave Airlie 584*c0e09200SDave Airlie /* drm_dma.h hooks 585*c0e09200SDave Airlie */ 586*c0e09200SDave Airlie void i915_driver_irq_preinstall(struct drm_device * dev) 587*c0e09200SDave Airlie { 588*c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 589*c0e09200SDave Airlie 590*c0e09200SDave Airlie I915_WRITE16(I915REG_HWSTAM, 0xfffe); 591*c0e09200SDave Airlie I915_WRITE16(I915REG_INT_MASK_R, 0x0); 592*c0e09200SDave Airlie I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); 593*c0e09200SDave Airlie } 594*c0e09200SDave Airlie 595*c0e09200SDave Airlie void i915_driver_irq_postinstall(struct drm_device * dev) 596*c0e09200SDave Airlie { 597*c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 598*c0e09200SDave Airlie 599*c0e09200SDave Airlie spin_lock_init(&dev_priv->swaps_lock); 600*c0e09200SDave Airlie INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); 601*c0e09200SDave Airlie dev_priv->swaps_pending = 0; 602*c0e09200SDave Airlie 603*c0e09200SDave Airlie if (!dev_priv->vblank_pipe) 604*c0e09200SDave Airlie dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; 605*c0e09200SDave Airlie i915_enable_interrupt(dev); 606*c0e09200SDave Airlie DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); 607*c0e09200SDave Airlie } 608*c0e09200SDave Airlie 609*c0e09200SDave Airlie void i915_driver_irq_uninstall(struct drm_device * dev) 610*c0e09200SDave Airlie { 611*c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 612*c0e09200SDave Airlie u16 temp; 613*c0e09200SDave Airlie 614*c0e09200SDave Airlie if (!dev_priv) 615*c0e09200SDave Airlie return; 616*c0e09200SDave Airlie 617*c0e09200SDave Airlie I915_WRITE16(I915REG_HWSTAM, 0xffff); 618*c0e09200SDave Airlie I915_WRITE16(I915REG_INT_MASK_R, 0xffff); 619*c0e09200SDave Airlie I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); 620*c0e09200SDave Airlie 621*c0e09200SDave Airlie temp = I915_READ16(I915REG_INT_IDENTITY_R); 622*c0e09200SDave Airlie I915_WRITE16(I915REG_INT_IDENTITY_R, temp); 623*c0e09200SDave Airlie } 624