drm_vblank_work.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // SPDX-License-Identifier: MIT
  2. #include <uapi/linux/sched/types.h>
  3. #include <linux/export.h>
  4. #include <drm/drm_print.h>
  5. #include <drm/drm_vblank.h>
  6. #include <drm/drm_vblank_work.h>
  7. #include <drm/drm_crtc.h>
  8. #include "drm_internal.h"
  9. /**
  10. * DOC: vblank works
  11. *
  12. * Many DRM drivers need to program hardware in a time-sensitive manner, many
  13. * times with a deadline of starting and finishing within a certain region of
  14. * the scanout. Most of the time the safest way to accomplish this is to
  15. * simply do said time-sensitive programming in the driver's IRQ handler,
  16. * which allows drivers to avoid being preempted during these critical
  17. * regions. Or even better, the hardware may even handle applying such
  18. * time-critical programming independently of the CPU.
  19. *
  20. * While there's a decent amount of hardware that's designed so that the CPU
  21. * doesn't need to be concerned with extremely time-sensitive programming,
  22. * there's a few situations where it can't be helped. Some unforgiving
  23. * hardware may require that certain time-sensitive programming be handled
  24. * completely by the CPU, and said programming may even take too long to
  25. * handle in an IRQ handler. Another such situation would be where the driver
  26. * needs to perform a task that needs to complete within a specific scanout
  27. * period, but might possibly block and thus cannot be handled in an IRQ
  28. * context. Both of these situations can't be solved perfectly in Linux since
  29. * we're not a realtime kernel, and thus the scheduler may cause us to miss
  30. * our deadline if it decides to preempt us. But for some drivers, it's good
  31. * enough if we can lower our chance of being preempted to an absolute
  32. * minimum.
  33. *
  34. * This is where &drm_vblank_work comes in. &drm_vblank_work provides a simple
  35. * generic delayed work implementation which delays work execution until a
  36. * particular vblank has passed, and then executes the work at realtime
  37. * priority. This provides the best possible chance at performing
  38. * time-sensitive hardware programming on time, even when the system is under
  39. * heavy load. &drm_vblank_work also supports rescheduling, so that self
  40. * re-arming work items can be easily implemented.
  41. */
  42. void drm_handle_vblank_works(struct drm_vblank_crtc *vblank)
  43. {
  44. struct drm_vblank_work *work, *next;
  45. u64 count = atomic64_read(&vblank->count);
  46. bool wake = false;
  47. assert_spin_locked(&vblank->dev->event_lock);
  48. list_for_each_entry_safe(work, next, &vblank->pending_work, node) {
  49. if (!drm_vblank_passed(count, work->count))
  50. continue;
  51. list_del_init(&work->node);
  52. drm_vblank_put(vblank->dev, vblank->pipe);
  53. kthread_queue_work(vblank->worker, &work->base);
  54. wake = true;
  55. }
  56. if (wake)
  57. wake_up_all(&vblank->work_wait_queue);
  58. }
  59. /* Handle cancelling any pending vblank work items and drop respective vblank
  60. * references in response to vblank interrupts being disabled.
  61. */
  62. void drm_vblank_cancel_pending_works(struct drm_vblank_crtc *vblank)
  63. {
  64. struct drm_vblank_work *work, *next;
  65. assert_spin_locked(&vblank->dev->event_lock);
  66. drm_WARN_ONCE(vblank->dev, !list_empty(&vblank->pending_work),
  67. "Cancelling pending vblank works!\n");
  68. list_for_each_entry_safe(work, next, &vblank->pending_work, node) {
  69. list_del_init(&work->node);
  70. drm_vblank_put(vblank->dev, vblank->pipe);
  71. }
  72. wake_up_all(&vblank->work_wait_queue);
  73. }
  74. /**
  75. * drm_vblank_work_schedule - schedule a vblank work
  76. * @work: vblank work to schedule
  77. * @count: target vblank count
  78. * @nextonmiss: defer until the next vblank if target vblank was missed
  79. *
  80. * Schedule @work for execution once the crtc vblank count reaches @count.
  81. *
  82. * If the crtc vblank count has already reached @count and @nextonmiss is
  83. * %false the work starts to execute immediately.
  84. *
  85. * If the crtc vblank count has already reached @count and @nextonmiss is
  86. * %true the work is deferred until the next vblank (as if @count has been
  87. * specified as crtc vblank count + 1).
  88. *
  89. * If @work is already scheduled, this function will reschedule said work
  90. * using the new @count. This can be used for self-rearming work items.
  91. *
  92. * Returns:
  93. * %1 if @work was successfully (re)scheduled, %0 if it was either already
  94. * scheduled or cancelled, or a negative error code on failure.
  95. */
  96. int drm_vblank_work_schedule(struct drm_vblank_work *work,
  97. u64 count, bool nextonmiss)
  98. {
  99. struct drm_vblank_crtc *vblank = work->vblank;
  100. struct drm_device *dev = vblank->dev;
  101. u64 cur_vbl;
  102. unsigned long irqflags;
  103. bool passed, inmodeset, rescheduling = false, wake = false;
  104. int ret = 0;
  105. spin_lock_irqsave(&dev->event_lock, irqflags);
  106. if (work->cancelling)
  107. goto out;
  108. spin_lock(&dev->vbl_lock);
  109. inmodeset = vblank->inmodeset;
  110. spin_unlock(&dev->vbl_lock);
  111. if (inmodeset)
  112. goto out;
  113. if (list_empty(&work->node)) {
  114. ret = drm_vblank_get(dev, vblank->pipe);
  115. if (ret < 0)
  116. goto out;
  117. } else if (work->count == count) {
  118. /* Already scheduled w/ same vbl count */
  119. goto out;
  120. } else {
  121. rescheduling = true;
  122. }
  123. work->count = count;
  124. cur_vbl = drm_vblank_count(dev, vblank->pipe);
  125. passed = drm_vblank_passed(cur_vbl, count);
  126. if (passed)
  127. drm_dbg_core(dev,
  128. "crtc %d vblank %llu already passed (current %llu)\n",
  129. vblank->pipe, count, cur_vbl);
  130. if (!nextonmiss && passed) {
  131. drm_vblank_put(dev, vblank->pipe);
  132. ret = kthread_queue_work(vblank->worker, &work->base);
  133. if (rescheduling) {
  134. list_del_init(&work->node);
  135. wake = true;
  136. }
  137. } else {
  138. if (!rescheduling)
  139. list_add_tail(&work->node, &vblank->pending_work);
  140. ret = true;
  141. }
  142. out:
  143. spin_unlock_irqrestore(&dev->event_lock, irqflags);
  144. if (wake)
  145. wake_up_all(&vblank->work_wait_queue);
  146. return ret;
  147. }
  148. EXPORT_SYMBOL(drm_vblank_work_schedule);
  149. /**
  150. * drm_vblank_work_cancel_sync - cancel a vblank work and wait for it to
  151. * finish executing
  152. * @work: vblank work to cancel
  153. *
  154. * Cancel an already scheduled vblank work and wait for its
  155. * execution to finish.
  156. *
  157. * On return, @work is guaranteed to no longer be scheduled or running, even
  158. * if it's self-arming.
  159. *
  160. * Returns:
  161. * %True if the work was cancelled before it started to execute, %false
  162. * otherwise.
  163. */
  164. bool drm_vblank_work_cancel_sync(struct drm_vblank_work *work)
  165. {
  166. struct drm_vblank_crtc *vblank = work->vblank;
  167. struct drm_device *dev = vblank->dev;
  168. bool ret = false;
  169. spin_lock_irq(&dev->event_lock);
  170. if (!list_empty(&work->node)) {
  171. list_del_init(&work->node);
  172. drm_vblank_put(vblank->dev, vblank->pipe);
  173. ret = true;
  174. }
  175. work->cancelling++;
  176. spin_unlock_irq(&dev->event_lock);
  177. wake_up_all(&vblank->work_wait_queue);
  178. if (kthread_cancel_work_sync(&work->base))
  179. ret = true;
  180. spin_lock_irq(&dev->event_lock);
  181. work->cancelling--;
  182. spin_unlock_irq(&dev->event_lock);
  183. return ret;
  184. }
  185. EXPORT_SYMBOL(drm_vblank_work_cancel_sync);
  186. /**
  187. * drm_vblank_work_flush - wait for a scheduled vblank work to finish
  188. * executing
  189. * @work: vblank work to flush
  190. *
  191. * Wait until @work has finished executing once.
  192. */
  193. void drm_vblank_work_flush(struct drm_vblank_work *work)
  194. {
  195. struct drm_vblank_crtc *vblank = work->vblank;
  196. struct drm_device *dev = vblank->dev;
  197. spin_lock_irq(&dev->event_lock);
  198. wait_event_lock_irq(vblank->work_wait_queue, list_empty(&work->node),
  199. dev->event_lock);
  200. spin_unlock_irq(&dev->event_lock);
  201. kthread_flush_work(&work->base);
  202. }
  203. EXPORT_SYMBOL(drm_vblank_work_flush);
  204. /**
  205. * drm_vblank_work_flush_all - flush all currently pending vblank work on crtc.
  206. * @crtc: crtc for which vblank work to flush
  207. *
  208. * Wait until all currently queued vblank work on @crtc
  209. * has finished executing once.
  210. */
  211. void drm_vblank_work_flush_all(struct drm_crtc *crtc)
  212. {
  213. struct drm_device *dev = crtc->dev;
  214. struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
  215. spin_lock_irq(&dev->event_lock);
  216. wait_event_lock_irq(vblank->work_wait_queue,
  217. list_empty(&vblank->pending_work),
  218. dev->event_lock);
  219. spin_unlock_irq(&dev->event_lock);
  220. kthread_flush_worker(vblank->worker);
  221. }
  222. EXPORT_SYMBOL(drm_vblank_work_flush_all);
  223. /**
  224. * drm_vblank_work_init - initialize a vblank work item
  225. * @work: vblank work item
  226. * @crtc: CRTC whose vblank will trigger the work execution
  227. * @func: work function to be executed
  228. *
  229. * Initialize a vblank work item for a specific crtc.
  230. */
  231. void drm_vblank_work_init(struct drm_vblank_work *work, struct drm_crtc *crtc,
  232. void (*func)(struct kthread_work *work))
  233. {
  234. kthread_init_work(&work->base, func);
  235. INIT_LIST_HEAD(&work->node);
  236. work->vblank = drm_crtc_vblank_crtc(crtc);
  237. }
  238. EXPORT_SYMBOL(drm_vblank_work_init);
  239. int drm_vblank_worker_init(struct drm_vblank_crtc *vblank)
  240. {
  241. struct kthread_worker *worker;
  242. INIT_LIST_HEAD(&vblank->pending_work);
  243. init_waitqueue_head(&vblank->work_wait_queue);
  244. worker = kthread_run_worker(0, "card%d-crtc%d",
  245. vblank->dev->primary->index,
  246. vblank->pipe);
  247. if (IS_ERR(worker))
  248. return PTR_ERR(worker);
  249. vblank->worker = worker;
  250. sched_set_fifo(worker->task);
  251. return 0;
  252. }