0451-drm-vc4-Make-pageflip-completion-handling-more-robus.patch 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. From 83b8a95e047475cd43016426288f5072067ea369 Mon Sep 17 00:00:00 2001
  2. From: Mario Kleiner <mario.kleiner.de@gmail.com>
  3. Date: Wed, 18 May 2016 14:02:46 +0200
  4. Subject: [PATCH] drm/vc4: Make pageflip completion handling more robust.
  5. Protect both the setup of the pageflip event and the
  6. latching of the new requested displaylist head pointer
  7. by the event lock, so we can't get into a situation
  8. where vc4_atomic_flush latches the new display list via
  9. HVS_WRITE, then immediately gets preempted before queueing
  10. the pageflip event, then the page-flip completes in hw and
  11. the vc4_crtc_handle_page_flip() runs and no-ops due to
  12. lack of a pending pageflip event, then vc4_atomic_flush
  13. continues and only then queues the pageflip event - after
  14. the page flip handling already no-oped. This would cause
  15. flip completion handling only at the next vblank - one
  16. frame too late.
  17. In vc4_crtc_handle_page_flip() check the actual DL head
  18. pointer in SCALER_DISPLACTX against the requested pointer
  19. for page flip to make sure that the flip actually really
  20. completed in the current vblank and doesn't get deferred
  21. to the next one because the DL head pointer was written
  22. a bit too late into SCALER_DISPLISTX, after start of
  23. vblank, and missed the boat. This avoids handling a
  24. pageflip completion too early - one frame too early.
  25. According to Eric, DL head pointer updates which were
  26. written into the HVS DISPLISTX reg get committed to hardware
  27. at the last pixel of active scanout. Our vblank interrupt
  28. handler, as triggered by PV_INT_VFP_START irq, gets to run
  29. earliest at the first pixel of HBLANK at the end of the
  30. last scanline of active scanout, ie. vblank irq handling
  31. runs at least 1 pixel duration after a potential pageflip
  32. completion happened in hardware.
  33. This ordering of events in the hardware, together with the
  34. lock protection and SCALER_DISPLACTX sampling of this patch,
  35. guarantees that pageflip completion handling only runs at
  36. exactly the vblank irq of actual pageflip completion in all
  37. cases.
  38. Background info from Eric about the relative timing of
  39. HVS, PV's and trigger points for interrupts, DL updates:
  40. https://lists.freedesktop.org/archives/dri-devel/2016-May/107510.html
  41. Tested on RPi 2B with hardware timing measurement equipment
  42. and shown to no longer complete flips too early or too late.
  43. Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
  44. Reviewed-by: Eric Anholt <eric@anholt.net>
  45. (cherry picked from commit 56d1fe0979dc9b73c1c12ee07722ac380d42a0c4)
  46. ---
  47. drivers/gpu/drm/vc4/vc4_crtc.c | 28 ++++++++++++++++++----------
  48. drivers/gpu/drm/vc4/vc4_regs.h | 4 ++++
  49. 2 files changed, 22 insertions(+), 10 deletions(-)
  50. --- a/drivers/gpu/drm/vc4/vc4_crtc.c
  51. +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
  52. @@ -465,14 +465,6 @@ static void vc4_crtc_atomic_flush(struct
  53. WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size);
  54. - HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
  55. - vc4_state->mm.start);
  56. -
  57. - if (debug_dump_regs) {
  58. - DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc));
  59. - vc4_hvs_dump_state(dev);
  60. - }
  61. -
  62. if (crtc->state->event) {
  63. unsigned long flags;
  64. @@ -482,8 +474,20 @@ static void vc4_crtc_atomic_flush(struct
  65. spin_lock_irqsave(&dev->event_lock, flags);
  66. vc4_crtc->event = crtc->state->event;
  67. - spin_unlock_irqrestore(&dev->event_lock, flags);
  68. crtc->state->event = NULL;
  69. +
  70. + HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
  71. + vc4_state->mm.start);
  72. +
  73. + spin_unlock_irqrestore(&dev->event_lock, flags);
  74. + } else {
  75. + HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
  76. + vc4_state->mm.start);
  77. + }
  78. +
  79. + if (debug_dump_regs) {
  80. + DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc));
  81. + vc4_hvs_dump_state(dev);
  82. }
  83. }
  84. @@ -509,10 +513,14 @@ static void vc4_crtc_handle_page_flip(st
  85. {
  86. struct drm_crtc *crtc = &vc4_crtc->base;
  87. struct drm_device *dev = crtc->dev;
  88. + struct vc4_dev *vc4 = to_vc4_dev(dev);
  89. + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
  90. + u32 chan = vc4_crtc->channel;
  91. unsigned long flags;
  92. spin_lock_irqsave(&dev->event_lock, flags);
  93. - if (vc4_crtc->event) {
  94. + if (vc4_crtc->event &&
  95. + (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)))) {
  96. drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
  97. vc4_crtc->event = NULL;
  98. drm_crtc_vblank_put(crtc);
  99. --- a/drivers/gpu/drm/vc4/vc4_regs.h
  100. +++ b/drivers/gpu/drm/vc4/vc4_regs.h
  101. @@ -343,6 +343,10 @@
  102. #define SCALER_DISPLACT0 0x00000030
  103. #define SCALER_DISPLACT1 0x00000034
  104. #define SCALER_DISPLACT2 0x00000038
  105. +#define SCALER_DISPLACTX(x) (SCALER_DISPLACT0 + \
  106. + (x) * (SCALER_DISPLACT1 - \
  107. + SCALER_DISPLACT0))
  108. +
  109. #define SCALER_DISPCTRL0 0x00000040
  110. # define SCALER_DISPCTRLX_ENABLE BIT(31)
  111. # define SCALER_DISPCTRLX_RESET BIT(30)