diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 514 |
1 files changed, 378 insertions, 136 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index df036118b8b1..baae511c785b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -31,12 +31,92 @@ | |||
31 | #include "i915_drm.h" | 31 | #include "i915_drm.h" |
32 | #include "i915_drv.h" | 32 | #include "i915_drv.h" |
33 | 33 | ||
34 | #define USER_INT_FLAG (1<<1) | ||
35 | #define VSYNC_PIPEB_FLAG (1<<5) | ||
36 | #define VSYNC_PIPEA_FLAG (1<<7) | ||
37 | |||
38 | #define MAX_NOPID ((u32)~0) | 34 | #define MAX_NOPID ((u32)~0) |
39 | 35 | ||
36 | /** These are the interrupts used by the driver */ | ||
37 | #define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \ | ||
38 | I915_ASLE_INTERRUPT | \ | ||
39 | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ | ||
40 | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) | ||
41 | |||
42 | void | ||
43 | i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) | ||
44 | { | ||
45 | if ((dev_priv->irq_mask_reg & mask) != 0) { | ||
46 | dev_priv->irq_mask_reg &= ~mask; | ||
47 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | ||
48 | (void) I915_READ(IMR); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | static inline void | ||
53 | i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) | ||
54 | { | ||
55 | if ((dev_priv->irq_mask_reg & mask) != mask) { | ||
56 | dev_priv->irq_mask_reg |= mask; | ||
57 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | ||
58 | (void) I915_READ(IMR); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * i915_get_pipe - return the the pipe associated with a given plane | ||
64 | * @dev: DRM device | ||
65 | * @plane: plane to look for | ||
66 | * | ||
67 | * The Intel Mesa & 2D drivers call the vblank routines with a plane number | ||
68 | * rather than a pipe number, since they may not always be equal. This routine | ||
69 | * maps the given @plane back to a pipe number. | ||
70 | */ | ||
71 | static int | ||
72 | i915_get_pipe(struct drm_device *dev, int plane) | ||
73 | { | ||
74 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
75 | u32 dspcntr; | ||
76 | |||
77 | dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); | ||
78 | |||
79 | return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0; | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * i915_get_plane - return the the plane associated with a given pipe | ||
84 | * @dev: DRM device | ||
85 | * @pipe: pipe to look for | ||
86 | * | ||
87 | * The Intel Mesa & 2D drivers call the vblank routines with a plane number | ||
88 | * rather than a plane number, since they may not always be equal. This routine | ||
89 | * maps the given @pipe back to a plane number. | ||
90 | */ | ||
91 | static int | ||
92 | i915_get_plane(struct drm_device *dev, int pipe) | ||
93 | { | ||
94 | if (i915_get_pipe(dev, 0) == pipe) | ||
95 | return 0; | ||
96 | return 1; | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * i915_pipe_enabled - check if a pipe is enabled | ||
101 | * @dev: DRM device | ||
102 | * @pipe: pipe to check | ||
103 | * | ||
104 | * Reading certain registers when the pipe is disabled can hang the chip. | ||
105 | * Use this routine to make sure the PLL is running and the pipe is active | ||
106 | * before reading such registers if unsure. | ||
107 | */ | ||
108 | static int | ||
109 | i915_pipe_enabled(struct drm_device *dev, int pipe) | ||
110 | { | ||
111 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
112 | unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; | ||
113 | |||
114 | if (I915_READ(pipeconf) & PIPEACONF_ENABLE) | ||
115 | return 1; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
40 | /** | 120 | /** |
41 | * Emit blits for scheduled buffer swaps. | 121 | * Emit blits for scheduled buffer swaps. |
42 | * | 122 | * |
@@ -48,8 +128,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
48 | unsigned long irqflags; | 128 | unsigned long irqflags; |
49 | struct list_head *list, *tmp, hits, *hit; | 129 | struct list_head *list, *tmp, hits, *hit; |
50 | int nhits, nrects, slice[2], upper[2], lower[2], i; | 130 | int nhits, nrects, slice[2], upper[2], lower[2], i; |
51 | unsigned counter[2] = { atomic_read(&dev->vbl_received), | 131 | unsigned counter[2]; |
52 | atomic_read(&dev->vbl_received2) }; | ||
53 | struct drm_drawable_info *drw; | 132 | struct drm_drawable_info *drw; |
54 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | 133 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; |
55 | u32 cpp = dev_priv->cpp; | 134 | u32 cpp = dev_priv->cpp; |
@@ -71,6 +150,9 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
71 | src_pitch >>= 2; | 150 | src_pitch >>= 2; |
72 | } | 151 | } |
73 | 152 | ||
153 | counter[0] = drm_vblank_count(dev, 0); | ||
154 | counter[1] = drm_vblank_count(dev, 1); | ||
155 | |||
74 | DRM_DEBUG("\n"); | 156 | DRM_DEBUG("\n"); |
75 | 157 | ||
76 | INIT_LIST_HEAD(&hits); | 158 | INIT_LIST_HEAD(&hits); |
@@ -83,12 +165,14 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
83 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { | 165 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { |
84 | drm_i915_vbl_swap_t *vbl_swap = | 166 | drm_i915_vbl_swap_t *vbl_swap = |
85 | list_entry(list, drm_i915_vbl_swap_t, head); | 167 | list_entry(list, drm_i915_vbl_swap_t, head); |
168 | int pipe = i915_get_pipe(dev, vbl_swap->plane); | ||
86 | 169 | ||
87 | if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) | 170 | if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) |
88 | continue; | 171 | continue; |
89 | 172 | ||
90 | list_del(list); | 173 | list_del(list); |
91 | dev_priv->swaps_pending--; | 174 | dev_priv->swaps_pending--; |
175 | drm_vblank_put(dev, pipe); | ||
92 | 176 | ||
93 | spin_unlock(&dev_priv->swaps_lock); | 177 | spin_unlock(&dev_priv->swaps_lock); |
94 | spin_lock(&dev->drw_lock); | 178 | spin_lock(&dev->drw_lock); |
@@ -181,7 +265,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
181 | drm_i915_vbl_swap_t *swap_hit = | 265 | drm_i915_vbl_swap_t *swap_hit = |
182 | list_entry(hit, drm_i915_vbl_swap_t, head); | 266 | list_entry(hit, drm_i915_vbl_swap_t, head); |
183 | struct drm_clip_rect *rect; | 267 | struct drm_clip_rect *rect; |
184 | int num_rects, pipe; | 268 | int num_rects, plane; |
185 | unsigned short top, bottom; | 269 | unsigned short top, bottom; |
186 | 270 | ||
187 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); | 271 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); |
@@ -190,9 +274,9 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
190 | continue; | 274 | continue; |
191 | 275 | ||
192 | rect = drw->rects; | 276 | rect = drw->rects; |
193 | pipe = swap_hit->pipe; | 277 | plane = swap_hit->plane; |
194 | top = upper[pipe]; | 278 | top = upper[plane]; |
195 | bottom = lower[pipe]; | 279 | bottom = lower[plane]; |
196 | 280 | ||
197 | for (num_rects = drw->num_rects; num_rects--; rect++) { | 281 | for (num_rects = drw->num_rects; num_rects--; rect++) { |
198 | int y1 = max(rect->y1, top); | 282 | int y1 = max(rect->y1, top); |
@@ -229,61 +313,139 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
229 | } | 313 | } |
230 | } | 314 | } |
231 | 315 | ||
316 | u32 i915_get_vblank_counter(struct drm_device *dev, int plane) | ||
317 | { | ||
318 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
319 | unsigned long high_frame; | ||
320 | unsigned long low_frame; | ||
321 | u32 high1, high2, low, count; | ||
322 | int pipe; | ||
323 | |||
324 | pipe = i915_get_pipe(dev, plane); | ||
325 | high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; | ||
326 | low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; | ||
327 | |||
328 | if (!i915_pipe_enabled(dev, pipe)) { | ||
329 | DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * High & low register fields aren't synchronized, so make sure | ||
335 | * we get a low value that's stable across two reads of the high | ||
336 | * register. | ||
337 | */ | ||
338 | do { | ||
339 | high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
340 | PIPE_FRAME_HIGH_SHIFT); | ||
341 | low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> | ||
342 | PIPE_FRAME_LOW_SHIFT); | ||
343 | high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
344 | PIPE_FRAME_HIGH_SHIFT); | ||
345 | } while (high1 != high2); | ||
346 | |||
347 | count = (high1 << 8) | low; | ||
348 | |||
349 | return count; | ||
350 | } | ||
351 | |||
352 | void | ||
353 | i915_gem_vblank_work_handler(struct work_struct *work) | ||
354 | { | ||
355 | drm_i915_private_t *dev_priv; | ||
356 | struct drm_device *dev; | ||
357 | |||
358 | dev_priv = container_of(work, drm_i915_private_t, | ||
359 | mm.vblank_work); | ||
360 | dev = dev_priv->dev; | ||
361 | |||
362 | mutex_lock(&dev->struct_mutex); | ||
363 | i915_vblank_tasklet(dev); | ||
364 | mutex_unlock(&dev->struct_mutex); | ||
365 | } | ||
366 | |||
232 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | 367 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) |
233 | { | 368 | { |
234 | struct drm_device *dev = (struct drm_device *) arg; | 369 | struct drm_device *dev = (struct drm_device *) arg; |
235 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 370 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
236 | u16 temp; | 371 | u32 iir; |
237 | u32 pipea_stats, pipeb_stats; | 372 | u32 pipea_stats, pipeb_stats; |
373 | int vblank = 0; | ||
238 | 374 | ||
239 | pipea_stats = I915_READ(I915REG_PIPEASTAT); | 375 | atomic_inc(&dev_priv->irq_received); |
240 | pipeb_stats = I915_READ(I915REG_PIPEBSTAT); | ||
241 | 376 | ||
242 | temp = I915_READ16(I915REG_INT_IDENTITY_R); | 377 | if (dev->pdev->msi_enabled) |
378 | I915_WRITE(IMR, ~0); | ||
379 | iir = I915_READ(IIR); | ||
243 | 380 | ||
244 | temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); | 381 | if (iir == 0) { |
382 | if (dev->pdev->msi_enabled) { | ||
383 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | ||
384 | (void) I915_READ(IMR); | ||
385 | } | ||
386 | return IRQ_NONE; | ||
387 | } | ||
245 | 388 | ||
246 | DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); | 389 | /* |
390 | * Clear the PIPE(A|B)STAT regs before the IIR otherwise | ||
391 | * we may get extra interrupts. | ||
392 | */ | ||
393 | if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { | ||
394 | pipea_stats = I915_READ(PIPEASTAT); | ||
395 | if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)) | ||
396 | pipea_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | | ||
397 | PIPE_VBLANK_INTERRUPT_ENABLE); | ||
398 | else if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| | ||
399 | PIPE_VBLANK_INTERRUPT_STATUS)) { | ||
400 | vblank++; | ||
401 | drm_handle_vblank(dev, i915_get_plane(dev, 0)); | ||
402 | } | ||
247 | 403 | ||
248 | if (temp == 0) | 404 | I915_WRITE(PIPEASTAT, pipea_stats); |
249 | return IRQ_NONE; | 405 | } |
406 | if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { | ||
407 | pipeb_stats = I915_READ(PIPEBSTAT); | ||
408 | /* Ack the event */ | ||
409 | I915_WRITE(PIPEBSTAT, pipeb_stats); | ||
410 | |||
411 | /* The vblank interrupt gets enabled even if we didn't ask for | ||
412 | it, so make sure it's shut down again */ | ||
413 | if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)) | ||
414 | pipeb_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | | ||
415 | PIPE_VBLANK_INTERRUPT_ENABLE); | ||
416 | else if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| | ||
417 | PIPE_VBLANK_INTERRUPT_STATUS)) { | ||
418 | vblank++; | ||
419 | drm_handle_vblank(dev, i915_get_plane(dev, 1)); | ||
420 | } | ||
250 | 421 | ||
251 | I915_WRITE16(I915REG_INT_IDENTITY_R, temp); | 422 | if (pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) |
252 | (void) I915_READ16(I915REG_INT_IDENTITY_R); | 423 | opregion_asle_intr(dev); |
253 | DRM_READMEMORYBARRIER(); | 424 | I915_WRITE(PIPEBSTAT, pipeb_stats); |
425 | } | ||
426 | |||
427 | I915_WRITE(IIR, iir); | ||
428 | if (dev->pdev->msi_enabled) | ||
429 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | ||
430 | (void) I915_READ(IIR); /* Flush posted writes */ | ||
254 | 431 | ||
255 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 432 | if (dev_priv->sarea_priv) |
433 | dev_priv->sarea_priv->last_dispatch = | ||
434 | READ_BREADCRUMB(dev_priv); | ||
256 | 435 | ||
257 | if (temp & USER_INT_FLAG) | 436 | if (iir & I915_USER_INTERRUPT) { |
437 | dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); | ||
258 | DRM_WAKEUP(&dev_priv->irq_queue); | 438 | DRM_WAKEUP(&dev_priv->irq_queue); |
439 | } | ||
259 | 440 | ||
260 | if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { | 441 | if (iir & I915_ASLE_INTERRUPT) |
261 | int vblank_pipe = dev_priv->vblank_pipe; | 442 | opregion_asle_intr(dev); |
262 | 443 | ||
263 | if ((vblank_pipe & | 444 | if (vblank && dev_priv->swaps_pending > 0) { |
264 | (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) | 445 | if (dev_priv->ring.ring_obj == NULL) |
265 | == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { | ||
266 | if (temp & VSYNC_PIPEA_FLAG) | ||
267 | atomic_inc(&dev->vbl_received); | ||
268 | if (temp & VSYNC_PIPEB_FLAG) | ||
269 | atomic_inc(&dev->vbl_received2); | ||
270 | } else if (((temp & VSYNC_PIPEA_FLAG) && | ||
271 | (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || | ||
272 | ((temp & VSYNC_PIPEB_FLAG) && | ||
273 | (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) | ||
274 | atomic_inc(&dev->vbl_received); | ||
275 | |||
276 | DRM_WAKEUP(&dev->vbl_queue); | ||
277 | drm_vbl_send_signals(dev); | ||
278 | |||
279 | if (dev_priv->swaps_pending > 0) | ||
280 | drm_locked_tasklet(dev, i915_vblank_tasklet); | 446 | drm_locked_tasklet(dev, i915_vblank_tasklet); |
281 | I915_WRITE(I915REG_PIPEASTAT, | 447 | else |
282 | pipea_stats|I915_VBLANK_INTERRUPT_ENABLE| | 448 | schedule_work(&dev_priv->mm.vblank_work); |
283 | I915_VBLANK_CLEAR); | ||
284 | I915_WRITE(I915REG_PIPEBSTAT, | ||
285 | pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE| | ||
286 | I915_VBLANK_CLEAR); | ||
287 | } | 449 | } |
288 | 450 | ||
289 | return IRQ_HANDLED; | 451 | return IRQ_HANDLED; |
@@ -298,23 +460,45 @@ static int i915_emit_irq(struct drm_device * dev) | |||
298 | 460 | ||
299 | DRM_DEBUG("\n"); | 461 | DRM_DEBUG("\n"); |
300 | 462 | ||
301 | dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; | 463 | dev_priv->counter++; |
302 | |||
303 | if (dev_priv->counter > 0x7FFFFFFFUL) | 464 | if (dev_priv->counter > 0x7FFFFFFFUL) |
304 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; | 465 | dev_priv->counter = 1; |
466 | if (dev_priv->sarea_priv) | ||
467 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter; | ||
305 | 468 | ||
306 | BEGIN_LP_RING(6); | 469 | BEGIN_LP_RING(6); |
307 | OUT_RING(CMD_STORE_DWORD_IDX); | 470 | OUT_RING(MI_STORE_DWORD_INDEX); |
308 | OUT_RING(20); | 471 | OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT); |
309 | OUT_RING(dev_priv->counter); | 472 | OUT_RING(dev_priv->counter); |
310 | OUT_RING(0); | 473 | OUT_RING(0); |
311 | OUT_RING(0); | 474 | OUT_RING(0); |
312 | OUT_RING(GFX_OP_USER_INTERRUPT); | 475 | OUT_RING(MI_USER_INTERRUPT); |
313 | ADVANCE_LP_RING(); | 476 | ADVANCE_LP_RING(); |
314 | 477 | ||
315 | return dev_priv->counter; | 478 | return dev_priv->counter; |
316 | } | 479 | } |
317 | 480 | ||
481 | void i915_user_irq_get(struct drm_device *dev) | ||
482 | { | ||
483 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
484 | |||
485 | spin_lock(&dev_priv->user_irq_lock); | ||
486 | if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) | ||
487 | i915_enable_irq(dev_priv, I915_USER_INTERRUPT); | ||
488 | spin_unlock(&dev_priv->user_irq_lock); | ||
489 | } | ||
490 | |||
491 | void i915_user_irq_put(struct drm_device *dev) | ||
492 | { | ||
493 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
494 | |||
495 | spin_lock(&dev_priv->user_irq_lock); | ||
496 | BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); | ||
497 | if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) | ||
498 | i915_disable_irq(dev_priv, I915_USER_INTERRUPT); | ||
499 | spin_unlock(&dev_priv->user_irq_lock); | ||
500 | } | ||
501 | |||
318 | static int i915_wait_irq(struct drm_device * dev, int irq_nr) | 502 | static int i915_wait_irq(struct drm_device * dev, int irq_nr) |
319 | { | 503 | { |
320 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 504 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
@@ -323,55 +507,34 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) | |||
323 | DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, | 507 | DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, |
324 | READ_BREADCRUMB(dev_priv)); | 508 | READ_BREADCRUMB(dev_priv)); |
325 | 509 | ||
326 | if (READ_BREADCRUMB(dev_priv) >= irq_nr) | 510 | if (READ_BREADCRUMB(dev_priv) >= irq_nr) { |
511 | if (dev_priv->sarea_priv) { | ||
512 | dev_priv->sarea_priv->last_dispatch = | ||
513 | READ_BREADCRUMB(dev_priv); | ||
514 | } | ||
327 | return 0; | 515 | return 0; |
516 | } | ||
328 | 517 | ||
329 | dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; | 518 | if (dev_priv->sarea_priv) |
519 | dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; | ||
330 | 520 | ||
521 | i915_user_irq_get(dev); | ||
331 | DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, | 522 | DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, |
332 | READ_BREADCRUMB(dev_priv) >= irq_nr); | 523 | READ_BREADCRUMB(dev_priv) >= irq_nr); |
524 | i915_user_irq_put(dev); | ||
333 | 525 | ||
334 | if (ret == -EBUSY) { | 526 | if (ret == -EBUSY) { |
335 | DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", | 527 | DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", |
336 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); | 528 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); |
337 | } | 529 | } |
338 | 530 | ||
339 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 531 | if (dev_priv->sarea_priv) |
340 | return ret; | 532 | dev_priv->sarea_priv->last_dispatch = |
341 | } | 533 | READ_BREADCRUMB(dev_priv); |
342 | |||
343 | static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence, | ||
344 | atomic_t *counter) | ||
345 | { | ||
346 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
347 | unsigned int cur_vblank; | ||
348 | int ret = 0; | ||
349 | |||
350 | if (!dev_priv) { | ||
351 | DRM_ERROR("called with no initialization\n"); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
356 | (((cur_vblank = atomic_read(counter)) | ||
357 | - *sequence) <= (1<<23))); | ||
358 | |||
359 | *sequence = cur_vblank; | ||
360 | 534 | ||
361 | return ret; | 535 | return ret; |
362 | } | 536 | } |
363 | 537 | ||
364 | |||
365 | int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) | ||
366 | { | ||
367 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); | ||
368 | } | ||
369 | |||
370 | int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) | ||
371 | { | ||
372 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); | ||
373 | } | ||
374 | |||
375 | /* Needs the lock as it touches the ring. | 538 | /* Needs the lock as it touches the ring. |
376 | */ | 539 | */ |
377 | int i915_irq_emit(struct drm_device *dev, void *data, | 540 | int i915_irq_emit(struct drm_device *dev, void *data, |
@@ -381,14 +544,15 @@ int i915_irq_emit(struct drm_device *dev, void *data, | |||
381 | drm_i915_irq_emit_t *emit = data; | 544 | drm_i915_irq_emit_t *emit = data; |
382 | int result; | 545 | int result; |
383 | 546 | ||
384 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 547 | RING_LOCK_TEST_WITH_RETURN(dev, file_priv); |
385 | 548 | ||
386 | if (!dev_priv) { | 549 | if (!dev_priv) { |
387 | DRM_ERROR("called with no initialization\n"); | 550 | DRM_ERROR("called with no initialization\n"); |
388 | return -EINVAL; | 551 | return -EINVAL; |
389 | } | 552 | } |
390 | 553 | mutex_lock(&dev->struct_mutex); | |
391 | result = i915_emit_irq(dev); | 554 | result = i915_emit_irq(dev); |
555 | mutex_unlock(&dev->struct_mutex); | ||
392 | 556 | ||
393 | if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { | 557 | if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { |
394 | DRM_ERROR("copy_to_user\n"); | 558 | DRM_ERROR("copy_to_user\n"); |
@@ -414,18 +578,74 @@ int i915_irq_wait(struct drm_device *dev, void *data, | |||
414 | return i915_wait_irq(dev, irqwait->irq_seq); | 578 | return i915_wait_irq(dev, irqwait->irq_seq); |
415 | } | 579 | } |
416 | 580 | ||
417 | static void i915_enable_interrupt (struct drm_device *dev) | 581 | int i915_enable_vblank(struct drm_device *dev, int plane) |
418 | { | 582 | { |
419 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 583 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
420 | u16 flag; | 584 | int pipe = i915_get_pipe(dev, plane); |
585 | u32 pipestat_reg = 0; | ||
586 | u32 pipestat; | ||
587 | |||
588 | switch (pipe) { | ||
589 | case 0: | ||
590 | pipestat_reg = PIPEASTAT; | ||
591 | i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT); | ||
592 | break; | ||
593 | case 1: | ||
594 | pipestat_reg = PIPEBSTAT; | ||
595 | i915_enable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); | ||
596 | break; | ||
597 | default: | ||
598 | DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", | ||
599 | pipe); | ||
600 | break; | ||
601 | } | ||
602 | |||
603 | if (pipestat_reg) { | ||
604 | pipestat = I915_READ(pipestat_reg); | ||
605 | if (IS_I965G(dev)) | ||
606 | pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE; | ||
607 | else | ||
608 | pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE; | ||
609 | /* Clear any stale interrupt status */ | ||
610 | pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | | ||
611 | PIPE_VBLANK_INTERRUPT_STATUS); | ||
612 | I915_WRITE(pipestat_reg, pipestat); | ||
613 | } | ||
614 | |||
615 | return 0; | ||
616 | } | ||
421 | 617 | ||
422 | flag = 0; | 618 | void i915_disable_vblank(struct drm_device *dev, int plane) |
423 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) | 619 | { |
424 | flag |= VSYNC_PIPEA_FLAG; | 620 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
425 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) | 621 | int pipe = i915_get_pipe(dev, plane); |
426 | flag |= VSYNC_PIPEB_FLAG; | 622 | u32 pipestat_reg = 0; |
623 | u32 pipestat; | ||
624 | |||
625 | switch (pipe) { | ||
626 | case 0: | ||
627 | pipestat_reg = PIPEASTAT; | ||
628 | i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_A_EVENT_INTERRUPT); | ||
629 | break; | ||
630 | case 1: | ||
631 | pipestat_reg = PIPEBSTAT; | ||
632 | i915_disable_irq(dev_priv, I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); | ||
633 | break; | ||
634 | default: | ||
635 | DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", | ||
636 | pipe); | ||
637 | break; | ||
638 | } | ||
427 | 639 | ||
428 | I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); | 640 | if (pipestat_reg) { |
641 | pipestat = I915_READ(pipestat_reg); | ||
642 | pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | | ||
643 | PIPE_VBLANK_INTERRUPT_ENABLE); | ||
644 | /* Clear any stale interrupt status */ | ||
645 | pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | | ||
646 | PIPE_VBLANK_INTERRUPT_STATUS); | ||
647 | I915_WRITE(pipestat_reg, pipestat); | ||
648 | } | ||
429 | } | 649 | } |
430 | 650 | ||
431 | /* Set the vblank monitor pipe | 651 | /* Set the vblank monitor pipe |
@@ -434,22 +654,12 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data, | |||
434 | struct drm_file *file_priv) | 654 | struct drm_file *file_priv) |
435 | { | 655 | { |
436 | drm_i915_private_t *dev_priv = dev->dev_private; | 656 | drm_i915_private_t *dev_priv = dev->dev_private; |
437 | drm_i915_vblank_pipe_t *pipe = data; | ||
438 | 657 | ||
439 | if (!dev_priv) { | 658 | if (!dev_priv) { |
440 | DRM_ERROR("called with no initialization\n"); | 659 | DRM_ERROR("called with no initialization\n"); |
441 | return -EINVAL; | 660 | return -EINVAL; |
442 | } | 661 | } |
443 | 662 | ||
444 | if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { | ||
445 | DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe); | ||
446 | return -EINVAL; | ||
447 | } | ||
448 | |||
449 | dev_priv->vblank_pipe = pipe->pipe; | ||
450 | |||
451 | i915_enable_interrupt (dev); | ||
452 | |||
453 | return 0; | 663 | return 0; |
454 | } | 664 | } |
455 | 665 | ||
@@ -458,19 +668,13 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, | |||
458 | { | 668 | { |
459 | drm_i915_private_t *dev_priv = dev->dev_private; | 669 | drm_i915_private_t *dev_priv = dev->dev_private; |
460 | drm_i915_vblank_pipe_t *pipe = data; | 670 | drm_i915_vblank_pipe_t *pipe = data; |
461 | u16 flag; | ||
462 | 671 | ||
463 | if (!dev_priv) { | 672 | if (!dev_priv) { |
464 | DRM_ERROR("called with no initialization\n"); | 673 | DRM_ERROR("called with no initialization\n"); |
465 | return -EINVAL; | 674 | return -EINVAL; |
466 | } | 675 | } |
467 | 676 | ||
468 | flag = I915_READ(I915REG_INT_ENABLE_R); | 677 | pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; |
469 | pipe->pipe = 0; | ||
470 | if (flag & VSYNC_PIPEA_FLAG) | ||
471 | pipe->pipe |= DRM_I915_VBLANK_PIPE_A; | ||
472 | if (flag & VSYNC_PIPEB_FLAG) | ||
473 | pipe->pipe |= DRM_I915_VBLANK_PIPE_B; | ||
474 | 678 | ||
475 | return 0; | 679 | return 0; |
476 | } | 680 | } |
@@ -484,11 +688,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
484 | drm_i915_private_t *dev_priv = dev->dev_private; | 688 | drm_i915_private_t *dev_priv = dev->dev_private; |
485 | drm_i915_vblank_swap_t *swap = data; | 689 | drm_i915_vblank_swap_t *swap = data; |
486 | drm_i915_vbl_swap_t *vbl_swap; | 690 | drm_i915_vbl_swap_t *vbl_swap; |
487 | unsigned int pipe, seqtype, curseq; | 691 | unsigned int pipe, seqtype, curseq, plane; |
488 | unsigned long irqflags; | 692 | unsigned long irqflags; |
489 | struct list_head *list; | 693 | struct list_head *list; |
694 | int ret; | ||
490 | 695 | ||
491 | if (!dev_priv) { | 696 | if (!dev_priv || !dev_priv->sarea_priv) { |
492 | DRM_ERROR("%s called with no initialization\n", __func__); | 697 | DRM_ERROR("%s called with no initialization\n", __func__); |
493 | return -EINVAL; | 698 | return -EINVAL; |
494 | } | 699 | } |
@@ -504,7 +709,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
504 | return -EINVAL; | 709 | return -EINVAL; |
505 | } | 710 | } |
506 | 711 | ||
507 | pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; | 712 | plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; |
713 | pipe = i915_get_pipe(dev, plane); | ||
508 | 714 | ||
509 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); | 715 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); |
510 | 716 | ||
@@ -523,7 +729,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
523 | 729 | ||
524 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 730 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
525 | 731 | ||
526 | curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); | 732 | /* |
733 | * We take the ref here and put it when the swap actually completes | ||
734 | * in the tasklet. | ||
735 | */ | ||
736 | ret = drm_vblank_get(dev, pipe); | ||
737 | if (ret) | ||
738 | return ret; | ||
739 | curseq = drm_vblank_count(dev, pipe); | ||
527 | 740 | ||
528 | if (seqtype == _DRM_VBLANK_RELATIVE) | 741 | if (seqtype == _DRM_VBLANK_RELATIVE) |
529 | swap->sequence += curseq; | 742 | swap->sequence += curseq; |
@@ -533,6 +746,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
533 | swap->sequence = curseq + 1; | 746 | swap->sequence = curseq + 1; |
534 | } else { | 747 | } else { |
535 | DRM_DEBUG("Missed target sequence\n"); | 748 | DRM_DEBUG("Missed target sequence\n"); |
749 | drm_vblank_put(dev, pipe); | ||
536 | return -EINVAL; | 750 | return -EINVAL; |
537 | } | 751 | } |
538 | } | 752 | } |
@@ -543,7 +757,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
543 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); | 757 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); |
544 | 758 | ||
545 | if (vbl_swap->drw_id == swap->drawable && | 759 | if (vbl_swap->drw_id == swap->drawable && |
546 | vbl_swap->pipe == pipe && | 760 | vbl_swap->plane == plane && |
547 | vbl_swap->sequence == swap->sequence) { | 761 | vbl_swap->sequence == swap->sequence) { |
548 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); | 762 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); |
549 | DRM_DEBUG("Already scheduled\n"); | 763 | DRM_DEBUG("Already scheduled\n"); |
@@ -555,6 +769,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
555 | 769 | ||
556 | if (dev_priv->swaps_pending >= 100) { | 770 | if (dev_priv->swaps_pending >= 100) { |
557 | DRM_DEBUG("Too many swaps queued\n"); | 771 | DRM_DEBUG("Too many swaps queued\n"); |
772 | drm_vblank_put(dev, pipe); | ||
558 | return -EBUSY; | 773 | return -EBUSY; |
559 | } | 774 | } |
560 | 775 | ||
@@ -562,13 +777,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
562 | 777 | ||
563 | if (!vbl_swap) { | 778 | if (!vbl_swap) { |
564 | DRM_ERROR("Failed to allocate memory to queue swap\n"); | 779 | DRM_ERROR("Failed to allocate memory to queue swap\n"); |
780 | drm_vblank_put(dev, pipe); | ||
565 | return -ENOMEM; | 781 | return -ENOMEM; |
566 | } | 782 | } |
567 | 783 | ||
568 | DRM_DEBUG("\n"); | 784 | DRM_DEBUG("\n"); |
569 | 785 | ||
570 | vbl_swap->drw_id = swap->drawable; | 786 | vbl_swap->drw_id = swap->drawable; |
571 | vbl_swap->pipe = pipe; | 787 | vbl_swap->plane = plane; |
572 | vbl_swap->sequence = swap->sequence; | 788 | vbl_swap->sequence = swap->sequence; |
573 | 789 | ||
574 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 790 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
@@ -587,37 +803,63 @@ void i915_driver_irq_preinstall(struct drm_device * dev) | |||
587 | { | 803 | { |
588 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 804 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
589 | 805 | ||
590 | I915_WRITE16(I915REG_HWSTAM, 0xfffe); | 806 | I915_WRITE(HWSTAM, 0xeffe); |
591 | I915_WRITE16(I915REG_INT_MASK_R, 0x0); | 807 | I915_WRITE(IMR, 0xffffffff); |
592 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); | 808 | I915_WRITE(IER, 0x0); |
593 | } | 809 | } |
594 | 810 | ||
595 | void i915_driver_irq_postinstall(struct drm_device * dev) | 811 | int i915_driver_irq_postinstall(struct drm_device *dev) |
596 | { | 812 | { |
597 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 813 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
814 | int ret, num_pipes = 2; | ||
598 | 815 | ||
599 | spin_lock_init(&dev_priv->swaps_lock); | 816 | spin_lock_init(&dev_priv->swaps_lock); |
600 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); | 817 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); |
601 | dev_priv->swaps_pending = 0; | 818 | dev_priv->swaps_pending = 0; |
602 | 819 | ||
603 | if (!dev_priv->vblank_pipe) | 820 | /* Set initial unmasked IRQs to just the selected vblank pipes. */ |
604 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; | 821 | dev_priv->irq_mask_reg = ~0; |
605 | i915_enable_interrupt(dev); | 822 | |
823 | ret = drm_vblank_init(dev, num_pipes); | ||
824 | if (ret) | ||
825 | return ret; | ||
826 | |||
827 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; | ||
828 | dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; | ||
829 | dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; | ||
830 | |||
831 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ | ||
832 | |||
833 | dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK; | ||
834 | |||
835 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | ||
836 | I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK); | ||
837 | (void) I915_READ(IER); | ||
838 | |||
839 | opregion_enable_asle(dev); | ||
606 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); | 840 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); |
841 | |||
842 | return 0; | ||
607 | } | 843 | } |
608 | 844 | ||
609 | void i915_driver_irq_uninstall(struct drm_device * dev) | 845 | void i915_driver_irq_uninstall(struct drm_device * dev) |
610 | { | 846 | { |
611 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 847 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
612 | u16 temp; | 848 | u32 temp; |
613 | 849 | ||
614 | if (!dev_priv) | 850 | if (!dev_priv) |
615 | return; | 851 | return; |
616 | 852 | ||
617 | I915_WRITE16(I915REG_HWSTAM, 0xffff); | 853 | dev_priv->vblank_pipe = 0; |
618 | I915_WRITE16(I915REG_INT_MASK_R, 0xffff); | 854 | |
619 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); | 855 | I915_WRITE(HWSTAM, 0xffffffff); |
856 | I915_WRITE(IMR, 0xffffffff); | ||
857 | I915_WRITE(IER, 0x0); | ||
620 | 858 | ||
621 | temp = I915_READ16(I915REG_INT_IDENTITY_R); | 859 | temp = I915_READ(PIPEASTAT); |
622 | I915_WRITE16(I915REG_INT_IDENTITY_R, temp); | 860 | I915_WRITE(PIPEASTAT, temp); |
861 | temp = I915_READ(PIPEBSTAT); | ||
862 | I915_WRITE(PIPEBSTAT, temp); | ||
863 | temp = I915_READ(IIR); | ||
864 | I915_WRITE(IIR, temp); | ||
623 | } | 865 | } |