diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-09-30 04:56:46 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-10-24 10:33:53 -0400 |
commit | 47339cd9ff07376df1639260ecc088adf1856bfe (patch) | |
tree | 998ddfe277a2380209eed2e7d9a17d77f2162422 /drivers | |
parent | cacc6c837b799b058d59d2af02c11140640cc1d2 (diff) |
drm/i915: Extract intel_fifo_underrun.c
Prep work for some nice documentation. Requires that we export the
display irq enable/disable functions on ilk/ibx. But we already export
them for vlv/i915. So not more inconsistency.
v2: Rebase on top of skl stage 1.
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 297 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_fifo_underrun.c | 311 |
5 files changed, 334 insertions, 294 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 3a6bce047f6f..75fd7de9bf4b 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile | |||
@@ -45,6 +45,7 @@ i915-y += intel_renderstate_gen6.o \ | |||
45 | # modesetting core code | 45 | # modesetting core code |
46 | i915-y += intel_bios.o \ | 46 | i915-y += intel_bios.o \ |
47 | intel_display.o \ | 47 | intel_display.o \ |
48 | intel_fifo_underrun.o \ | ||
48 | intel_frontbuffer.o \ | 49 | intel_frontbuffer.o \ |
49 | intel_modes.o \ | 50 | intel_modes.o \ |
50 | intel_overlay.o \ | 51 | intel_overlay.o \ |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9962da202456..26724c54bd80 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -2312,6 +2312,17 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, | |||
2312 | 2312 | ||
2313 | void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv); | 2313 | void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv); |
2314 | void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv); | 2314 | void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv); |
2315 | void | ||
2316 | ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask); | ||
2317 | void | ||
2318 | ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask); | ||
2319 | void ibx_display_interrupt_update(struct drm_i915_private *dev_priv, | ||
2320 | uint32_t interrupt_mask, | ||
2321 | uint32_t enabled_irq_mask); | ||
2322 | #define ibx_enable_display_interrupt(dev_priv, bits) \ | ||
2323 | ibx_display_interrupt_update((dev_priv), (bits), (bits)) | ||
2324 | #define ibx_disable_display_interrupt(dev_priv, bits) \ | ||
2325 | ibx_display_interrupt_update((dev_priv), (bits), 0) | ||
2315 | 2326 | ||
2316 | /* i915_gem.c */ | 2327 | /* i915_gem.c */ |
2317 | int i915_gem_init_ioctl(struct drm_device *dev, void *data, | 2328 | int i915_gem_init_ioctl(struct drm_device *dev, void *data, |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f17bbf3ac136..536efa277b01 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -139,7 +139,7 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ | |||
139 | } while (0) | 139 | } while (0) |
140 | 140 | ||
141 | /* For display hotplug interrupt */ | 141 | /* For display hotplug interrupt */ |
142 | static void | 142 | void |
143 | ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask) | 143 | ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask) |
144 | { | 144 | { |
145 | assert_spin_locked(&dev_priv->irq_lock); | 145 | assert_spin_locked(&dev_priv->irq_lock); |
@@ -154,7 +154,7 @@ ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask) | |||
154 | } | 154 | } |
155 | } | 155 | } |
156 | 156 | ||
157 | static void | 157 | void |
158 | ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask) | 158 | ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask) |
159 | { | 159 | { |
160 | assert_spin_locked(&dev_priv->irq_lock); | 160 | assert_spin_locked(&dev_priv->irq_lock); |
@@ -238,24 +238,6 @@ void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) | |||
238 | snb_update_pm_irq(dev_priv, mask, 0); | 238 | snb_update_pm_irq(dev_priv, mask, 0); |
239 | } | 239 | } |
240 | 240 | ||
241 | static bool ivb_can_enable_err_int(struct drm_device *dev) | ||
242 | { | ||
243 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
244 | struct intel_crtc *crtc; | ||
245 | enum pipe pipe; | ||
246 | |||
247 | assert_spin_locked(&dev_priv->irq_lock); | ||
248 | |||
249 | for_each_pipe(dev_priv, pipe) { | ||
250 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); | ||
251 | |||
252 | if (crtc->cpu_fifo_underrun_disabled) | ||
253 | return false; | ||
254 | } | ||
255 | |||
256 | return true; | ||
257 | } | ||
258 | |||
259 | /** | 241 | /** |
260 | * bdw_update_pm_irq - update GT interrupt 2 | 242 | * bdw_update_pm_irq - update GT interrupt 2 |
261 | * @dev_priv: driver private | 243 | * @dev_priv: driver private |
@@ -296,130 +278,15 @@ void gen8_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) | |||
296 | bdw_update_pm_irq(dev_priv, mask, 0); | 278 | bdw_update_pm_irq(dev_priv, mask, 0); |
297 | } | 279 | } |
298 | 280 | ||
299 | static bool cpt_can_enable_serr_int(struct drm_device *dev) | ||
300 | { | ||
301 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
302 | enum pipe pipe; | ||
303 | struct intel_crtc *crtc; | ||
304 | |||
305 | assert_spin_locked(&dev_priv->irq_lock); | ||
306 | |||
307 | for_each_pipe(dev_priv, pipe) { | ||
308 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); | ||
309 | |||
310 | if (crtc->pch_fifo_underrun_disabled) | ||
311 | return false; | ||
312 | } | ||
313 | |||
314 | return true; | ||
315 | } | ||
316 | |||
317 | void i9xx_check_fifo_underruns(struct drm_device *dev) | ||
318 | { | ||
319 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
320 | struct intel_crtc *crtc; | ||
321 | |||
322 | spin_lock_irq(&dev_priv->irq_lock); | ||
323 | |||
324 | for_each_intel_crtc(dev, crtc) { | ||
325 | u32 reg = PIPESTAT(crtc->pipe); | ||
326 | u32 pipestat; | ||
327 | |||
328 | if (crtc->cpu_fifo_underrun_disabled) | ||
329 | continue; | ||
330 | |||
331 | pipestat = I915_READ(reg) & 0xffff0000; | ||
332 | if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0) | ||
333 | continue; | ||
334 | |||
335 | I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); | ||
336 | POSTING_READ(reg); | ||
337 | |||
338 | DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe)); | ||
339 | } | ||
340 | |||
341 | spin_unlock_irq(&dev_priv->irq_lock); | ||
342 | } | ||
343 | |||
344 | static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev, | ||
345 | enum pipe pipe, | ||
346 | bool enable, bool old) | ||
347 | { | ||
348 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
349 | u32 reg = PIPESTAT(pipe); | ||
350 | u32 pipestat = I915_READ(reg) & 0xffff0000; | ||
351 | |||
352 | assert_spin_locked(&dev_priv->irq_lock); | ||
353 | |||
354 | if (enable) { | ||
355 | I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); | ||
356 | POSTING_READ(reg); | ||
357 | } else { | ||
358 | if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS) | ||
359 | DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, | ||
364 | enum pipe pipe, bool enable) | ||
365 | { | ||
366 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
367 | uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN : | ||
368 | DE_PIPEB_FIFO_UNDERRUN; | ||
369 | |||
370 | if (enable) | ||
371 | ironlake_enable_display_irq(dev_priv, bit); | ||
372 | else | ||
373 | ironlake_disable_display_irq(dev_priv, bit); | ||
374 | } | ||
375 | |||
376 | static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, | ||
377 | enum pipe pipe, | ||
378 | bool enable, bool old) | ||
379 | { | ||
380 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
381 | if (enable) { | ||
382 | I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe)); | ||
383 | |||
384 | if (!ivb_can_enable_err_int(dev)) | ||
385 | return; | ||
386 | |||
387 | ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); | ||
388 | } else { | ||
389 | ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); | ||
390 | |||
391 | if (old && | ||
392 | I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) { | ||
393 | DRM_ERROR("uncleared fifo underrun on pipe %c\n", | ||
394 | pipe_name(pipe)); | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | |||
399 | static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev, | ||
400 | enum pipe pipe, bool enable) | ||
401 | { | ||
402 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
403 | |||
404 | assert_spin_locked(&dev_priv->irq_lock); | ||
405 | |||
406 | if (enable) | ||
407 | dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN; | ||
408 | else | ||
409 | dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN; | ||
410 | I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); | ||
411 | POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); | ||
412 | } | ||
413 | |||
414 | /** | 281 | /** |
415 | * ibx_display_interrupt_update - update SDEIMR | 282 | * ibx_display_interrupt_update - update SDEIMR |
416 | * @dev_priv: driver private | 283 | * @dev_priv: driver private |
417 | * @interrupt_mask: mask of interrupt bits to update | 284 | * @interrupt_mask: mask of interrupt bits to update |
418 | * @enabled_irq_mask: mask of interrupt bits to enable | 285 | * @enabled_irq_mask: mask of interrupt bits to enable |
419 | */ | 286 | */ |
420 | static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv, | 287 | void ibx_display_interrupt_update(struct drm_i915_private *dev_priv, |
421 | uint32_t interrupt_mask, | 288 | uint32_t interrupt_mask, |
422 | uint32_t enabled_irq_mask) | 289 | uint32_t enabled_irq_mask) |
423 | { | 290 | { |
424 | uint32_t sdeimr = I915_READ(SDEIMR); | 291 | uint32_t sdeimr = I915_READ(SDEIMR); |
425 | sdeimr &= ~interrupt_mask; | 292 | sdeimr &= ~interrupt_mask; |
@@ -433,160 +300,6 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv, | |||
433 | I915_WRITE(SDEIMR, sdeimr); | 300 | I915_WRITE(SDEIMR, sdeimr); |
434 | POSTING_READ(SDEIMR); | 301 | POSTING_READ(SDEIMR); |
435 | } | 302 | } |
436 | #define ibx_enable_display_interrupt(dev_priv, bits) \ | ||
437 | ibx_display_interrupt_update((dev_priv), (bits), (bits)) | ||
438 | #define ibx_disable_display_interrupt(dev_priv, bits) \ | ||
439 | ibx_display_interrupt_update((dev_priv), (bits), 0) | ||
440 | |||
441 | static void ibx_set_fifo_underrun_reporting(struct drm_device *dev, | ||
442 | enum transcoder pch_transcoder, | ||
443 | bool enable) | ||
444 | { | ||
445 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
446 | uint32_t bit = (pch_transcoder == TRANSCODER_A) ? | ||
447 | SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER; | ||
448 | |||
449 | if (enable) | ||
450 | ibx_enable_display_interrupt(dev_priv, bit); | ||
451 | else | ||
452 | ibx_disable_display_interrupt(dev_priv, bit); | ||
453 | } | ||
454 | |||
455 | static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, | ||
456 | enum transcoder pch_transcoder, | ||
457 | bool enable, bool old) | ||
458 | { | ||
459 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
460 | |||
461 | if (enable) { | ||
462 | I915_WRITE(SERR_INT, | ||
463 | SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)); | ||
464 | |||
465 | if (!cpt_can_enable_serr_int(dev)) | ||
466 | return; | ||
467 | |||
468 | ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT); | ||
469 | } else { | ||
470 | ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT); | ||
471 | |||
472 | if (old && I915_READ(SERR_INT) & | ||
473 | SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) { | ||
474 | DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n", | ||
475 | transcoder_name(pch_transcoder)); | ||
476 | } | ||
477 | } | ||
478 | } | ||
479 | |||
480 | /** | ||
481 | * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages | ||
482 | * @dev: drm device | ||
483 | * @pipe: pipe | ||
484 | * @enable: true if we want to report FIFO underrun errors, false otherwise | ||
485 | * | ||
486 | * This function makes us disable or enable CPU fifo underruns for a specific | ||
487 | * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun | ||
488 | * reporting for one pipe may also disable all the other CPU error interruts for | ||
489 | * the other pipes, due to the fact that there's just one interrupt mask/enable | ||
490 | * bit for all the pipes. | ||
491 | * | ||
492 | * Returns the previous state of underrun reporting. | ||
493 | */ | ||
494 | static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, | ||
495 | enum pipe pipe, bool enable) | ||
496 | { | ||
497 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
498 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; | ||
499 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
500 | bool old; | ||
501 | |||
502 | assert_spin_locked(&dev_priv->irq_lock); | ||
503 | |||
504 | old = !intel_crtc->cpu_fifo_underrun_disabled; | ||
505 | intel_crtc->cpu_fifo_underrun_disabled = !enable; | ||
506 | |||
507 | if (HAS_GMCH_DISPLAY(dev)) | ||
508 | i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old); | ||
509 | else if (IS_GEN5(dev) || IS_GEN6(dev)) | ||
510 | ironlake_set_fifo_underrun_reporting(dev, pipe, enable); | ||
511 | else if (IS_GEN7(dev)) | ||
512 | ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old); | ||
513 | else if (IS_GEN8(dev) || IS_GEN9(dev)) | ||
514 | broadwell_set_fifo_underrun_reporting(dev, pipe, enable); | ||
515 | |||
516 | return old; | ||
517 | } | ||
518 | |||
519 | bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, | ||
520 | enum pipe pipe, bool enable) | ||
521 | { | ||
522 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
523 | unsigned long flags; | ||
524 | bool ret; | ||
525 | |||
526 | spin_lock_irqsave(&dev_priv->irq_lock, flags); | ||
527 | ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable); | ||
528 | spin_unlock_irqrestore(&dev_priv->irq_lock, flags); | ||
529 | |||
530 | return ret; | ||
531 | } | ||
532 | |||
533 | static bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev, | ||
534 | enum pipe pipe) | ||
535 | { | ||
536 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
537 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; | ||
538 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
539 | |||
540 | return !intel_crtc->cpu_fifo_underrun_disabled; | ||
541 | } | ||
542 | |||
543 | /** | ||
544 | * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages | ||
545 | * @dev: drm device | ||
546 | * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older) | ||
547 | * @enable: true if we want to report FIFO underrun errors, false otherwise | ||
548 | * | ||
549 | * This function makes us disable or enable PCH fifo underruns for a specific | ||
550 | * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO | ||
551 | * underrun reporting for one transcoder may also disable all the other PCH | ||
552 | * error interruts for the other transcoders, due to the fact that there's just | ||
553 | * one interrupt mask/enable bit for all the transcoders. | ||
554 | * | ||
555 | * Returns the previous state of underrun reporting. | ||
556 | */ | ||
557 | bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, | ||
558 | enum transcoder pch_transcoder, | ||
559 | bool enable) | ||
560 | { | ||
561 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
562 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder]; | ||
563 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
564 | unsigned long flags; | ||
565 | bool old; | ||
566 | |||
567 | /* | ||
568 | * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT | ||
569 | * has only one pch transcoder A that all pipes can use. To avoid racy | ||
570 | * pch transcoder -> pipe lookups from interrupt code simply store the | ||
571 | * underrun statistics in crtc A. Since we never expose this anywhere | ||
572 | * nor use it outside of the fifo underrun code here using the "wrong" | ||
573 | * crtc on LPT won't cause issues. | ||
574 | */ | ||
575 | |||
576 | spin_lock_irqsave(&dev_priv->irq_lock, flags); | ||
577 | |||
578 | old = !intel_crtc->pch_fifo_underrun_disabled; | ||
579 | intel_crtc->pch_fifo_underrun_disabled = !enable; | ||
580 | |||
581 | if (HAS_PCH_IBX(dev)) | ||
582 | ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable); | ||
583 | else | ||
584 | cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old); | ||
585 | |||
586 | spin_unlock_irqrestore(&dev_priv->irq_lock, flags); | ||
587 | return old; | ||
588 | } | ||
589 | |||
590 | 303 | ||
591 | static void | 304 | static void |
592 | __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, | 305 | __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 94993d23e547..321701da12ec 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -755,12 +755,17 @@ static inline unsigned int intel_num_planes(struct intel_crtc *crtc) | |||
755 | return INTEL_INFO(crtc->base.dev)->num_sprites[crtc->pipe] + 1; | 755 | return INTEL_INFO(crtc->base.dev)->num_sprites[crtc->pipe] + 1; |
756 | } | 756 | } |
757 | 757 | ||
758 | /* i915_irq.c */ | 758 | /* intel_fifo_underrun.c */ |
759 | bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, | 759 | bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, |
760 | enum pipe pipe, bool enable); | 760 | enum pipe pipe, bool enable); |
761 | bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, | 761 | bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, |
762 | enum transcoder pch_transcoder, | 762 | enum transcoder pch_transcoder, |
763 | bool enable); | 763 | bool enable); |
764 | void i9xx_check_fifo_underruns(struct drm_device *dev); | ||
765 | bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev, | ||
766 | enum pipe pipe); | ||
767 | |||
768 | /* i915_irq.c */ | ||
764 | void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); | 769 | void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); |
765 | void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); | 770 | void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); |
766 | void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); | 771 | void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); |
@@ -779,7 +784,6 @@ static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv) | |||
779 | } | 784 | } |
780 | 785 | ||
781 | int intel_get_crtc_scanline(struct intel_crtc *crtc); | 786 | int intel_get_crtc_scanline(struct intel_crtc *crtc); |
782 | void i9xx_check_fifo_underruns(struct drm_device *dev); | ||
783 | void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv); | 787 | void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv); |
784 | 788 | ||
785 | /* intel_crt.c */ | 789 | /* intel_crt.c */ |
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c new file mode 100644 index 000000000000..8e79d2ba787d --- /dev/null +++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c | |||
@@ -0,0 +1,311 @@ | |||
1 | /* | ||
2 | * Copyright © 2014 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Daniel Vetter <daniel.vetter@ffwll.ch> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include "i915_drv.h" | ||
29 | #include "intel_drv.h" | ||
30 | |||
31 | static bool ivb_can_enable_err_int(struct drm_device *dev) | ||
32 | { | ||
33 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
34 | struct intel_crtc *crtc; | ||
35 | enum pipe pipe; | ||
36 | |||
37 | assert_spin_locked(&dev_priv->irq_lock); | ||
38 | |||
39 | for_each_pipe(dev_priv, pipe) { | ||
40 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); | ||
41 | |||
42 | if (crtc->cpu_fifo_underrun_disabled) | ||
43 | return false; | ||
44 | } | ||
45 | |||
46 | return true; | ||
47 | } | ||
48 | |||
49 | static bool cpt_can_enable_serr_int(struct drm_device *dev) | ||
50 | { | ||
51 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
52 | enum pipe pipe; | ||
53 | struct intel_crtc *crtc; | ||
54 | |||
55 | assert_spin_locked(&dev_priv->irq_lock); | ||
56 | |||
57 | for_each_pipe(dev_priv, pipe) { | ||
58 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); | ||
59 | |||
60 | if (crtc->pch_fifo_underrun_disabled) | ||
61 | return false; | ||
62 | } | ||
63 | |||
64 | return true; | ||
65 | } | ||
66 | |||
67 | void i9xx_check_fifo_underruns(struct drm_device *dev) | ||
68 | { | ||
69 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
70 | struct intel_crtc *crtc; | ||
71 | |||
72 | spin_lock_irq(&dev_priv->irq_lock); | ||
73 | |||
74 | for_each_intel_crtc(dev, crtc) { | ||
75 | u32 reg = PIPESTAT(crtc->pipe); | ||
76 | u32 pipestat; | ||
77 | |||
78 | if (crtc->cpu_fifo_underrun_disabled) | ||
79 | continue; | ||
80 | |||
81 | pipestat = I915_READ(reg) & 0xffff0000; | ||
82 | if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0) | ||
83 | continue; | ||
84 | |||
85 | I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); | ||
86 | POSTING_READ(reg); | ||
87 | |||
88 | DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe)); | ||
89 | } | ||
90 | |||
91 | spin_unlock_irq(&dev_priv->irq_lock); | ||
92 | } | ||
93 | |||
94 | static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev, | ||
95 | enum pipe pipe, | ||
96 | bool enable, bool old) | ||
97 | { | ||
98 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
99 | u32 reg = PIPESTAT(pipe); | ||
100 | u32 pipestat = I915_READ(reg) & 0xffff0000; | ||
101 | |||
102 | assert_spin_locked(&dev_priv->irq_lock); | ||
103 | |||
104 | if (enable) { | ||
105 | I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); | ||
106 | POSTING_READ(reg); | ||
107 | } else { | ||
108 | if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS) | ||
109 | DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, | ||
114 | enum pipe pipe, bool enable) | ||
115 | { | ||
116 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
117 | uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN : | ||
118 | DE_PIPEB_FIFO_UNDERRUN; | ||
119 | |||
120 | if (enable) | ||
121 | ironlake_enable_display_irq(dev_priv, bit); | ||
122 | else | ||
123 | ironlake_disable_display_irq(dev_priv, bit); | ||
124 | } | ||
125 | |||
126 | static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, | ||
127 | enum pipe pipe, | ||
128 | bool enable, bool old) | ||
129 | { | ||
130 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
131 | if (enable) { | ||
132 | I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe)); | ||
133 | |||
134 | if (!ivb_can_enable_err_int(dev)) | ||
135 | return; | ||
136 | |||
137 | ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); | ||
138 | } else { | ||
139 | ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); | ||
140 | |||
141 | if (old && | ||
142 | I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) { | ||
143 | DRM_ERROR("uncleared fifo underrun on pipe %c\n", | ||
144 | pipe_name(pipe)); | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev, | ||
150 | enum pipe pipe, bool enable) | ||
151 | { | ||
152 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
153 | |||
154 | assert_spin_locked(&dev_priv->irq_lock); | ||
155 | |||
156 | if (enable) | ||
157 | dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN; | ||
158 | else | ||
159 | dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN; | ||
160 | I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); | ||
161 | POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); | ||
162 | } | ||
163 | |||
164 | static void ibx_set_fifo_underrun_reporting(struct drm_device *dev, | ||
165 | enum transcoder pch_transcoder, | ||
166 | bool enable) | ||
167 | { | ||
168 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
169 | uint32_t bit = (pch_transcoder == TRANSCODER_A) ? | ||
170 | SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER; | ||
171 | |||
172 | if (enable) | ||
173 | ibx_enable_display_interrupt(dev_priv, bit); | ||
174 | else | ||
175 | ibx_disable_display_interrupt(dev_priv, bit); | ||
176 | } | ||
177 | |||
178 | static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, | ||
179 | enum transcoder pch_transcoder, | ||
180 | bool enable, bool old) | ||
181 | { | ||
182 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
183 | |||
184 | if (enable) { | ||
185 | I915_WRITE(SERR_INT, | ||
186 | SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)); | ||
187 | |||
188 | if (!cpt_can_enable_serr_int(dev)) | ||
189 | return; | ||
190 | |||
191 | ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT); | ||
192 | } else { | ||
193 | ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT); | ||
194 | |||
195 | if (old && I915_READ(SERR_INT) & | ||
196 | SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) { | ||
197 | DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n", | ||
198 | transcoder_name(pch_transcoder)); | ||
199 | } | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages | ||
205 | * @dev: drm device | ||
206 | * @pipe: pipe | ||
207 | * @enable: true if we want to report FIFO underrun errors, false otherwise | ||
208 | * | ||
209 | * This function makes us disable or enable CPU fifo underruns for a specific | ||
210 | * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun | ||
211 | * reporting for one pipe may also disable all the other CPU error interruts for | ||
212 | * the other pipes, due to the fact that there's just one interrupt mask/enable | ||
213 | * bit for all the pipes. | ||
214 | * | ||
215 | * Returns the previous state of underrun reporting. | ||
216 | */ | ||
217 | static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, | ||
218 | enum pipe pipe, bool enable) | ||
219 | { | ||
220 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
221 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; | ||
222 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
223 | bool old; | ||
224 | |||
225 | assert_spin_locked(&dev_priv->irq_lock); | ||
226 | |||
227 | old = !intel_crtc->cpu_fifo_underrun_disabled; | ||
228 | intel_crtc->cpu_fifo_underrun_disabled = !enable; | ||
229 | |||
230 | if (HAS_GMCH_DISPLAY(dev)) | ||
231 | i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old); | ||
232 | else if (IS_GEN5(dev) || IS_GEN6(dev)) | ||
233 | ironlake_set_fifo_underrun_reporting(dev, pipe, enable); | ||
234 | else if (IS_GEN7(dev)) | ||
235 | ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old); | ||
236 | else if (IS_GEN8(dev) || IS_GEN9(dev)) | ||
237 | broadwell_set_fifo_underrun_reporting(dev, pipe, enable); | ||
238 | |||
239 | return old; | ||
240 | } | ||
241 | |||
242 | bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, | ||
243 | enum pipe pipe, bool enable) | ||
244 | { | ||
245 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
246 | unsigned long flags; | ||
247 | bool ret; | ||
248 | |||
249 | spin_lock_irqsave(&dev_priv->irq_lock, flags); | ||
250 | ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable); | ||
251 | spin_unlock_irqrestore(&dev_priv->irq_lock, flags); | ||
252 | |||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev, | ||
257 | enum pipe pipe) | ||
258 | { | ||
259 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
260 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; | ||
261 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
262 | |||
263 | return !intel_crtc->cpu_fifo_underrun_disabled; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages | ||
268 | * @dev: drm device | ||
269 | * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older) | ||
270 | * @enable: true if we want to report FIFO underrun errors, false otherwise | ||
271 | * | ||
272 | * This function makes us disable or enable PCH fifo underruns for a specific | ||
273 | * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO | ||
274 | * underrun reporting for one transcoder may also disable all the other PCH | ||
275 | * error interruts for the other transcoders, due to the fact that there's just | ||
276 | * one interrupt mask/enable bit for all the transcoders. | ||
277 | * | ||
278 | * Returns the previous state of underrun reporting. | ||
279 | */ | ||
280 | bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, | ||
281 | enum transcoder pch_transcoder, | ||
282 | bool enable) | ||
283 | { | ||
284 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
285 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder]; | ||
286 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
287 | unsigned long flags; | ||
288 | bool old; | ||
289 | |||
290 | /* | ||
291 | * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT | ||
292 | * has only one pch transcoder A that all pipes can use. To avoid racy | ||
293 | * pch transcoder -> pipe lookups from interrupt code simply store the | ||
294 | * underrun statistics in crtc A. Since we never expose this anywhere | ||
295 | * nor use it outside of the fifo underrun code here using the "wrong" | ||
296 | * crtc on LPT won't cause issues. | ||
297 | */ | ||
298 | |||
299 | spin_lock_irqsave(&dev_priv->irq_lock, flags); | ||
300 | |||
301 | old = !intel_crtc->pch_fifo_underrun_disabled; | ||
302 | intel_crtc->pch_fifo_underrun_disabled = !enable; | ||
303 | |||
304 | if (HAS_PCH_IBX(dev)) | ||
305 | ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable); | ||
306 | else | ||
307 | cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old); | ||
308 | |||
309 | spin_unlock_irqrestore(&dev_priv->irq_lock, flags); | ||
310 | return old; | ||
311 | } | ||