Lines Matching +full:irq +full:- +full:can +full:- +full:wake

1 // SPDX-License-Identifier: MIT
15 * Many DRM drivers need to program hardware in a time-sensitive manner, many
18 * simply do said time-sensitive programming in the driver's IRQ handler,
21 * time-critical programming independently of the CPU.
24 * doesn't need to be concerned with extremely time-sensitive programming,
25 * there's a few situations where it can't be helped. Some unforgiving
26 * hardware may require that certain time-sensitive programming be handled
28 * handle in an IRQ handler. Another such situation would be where the driver
30 * period, but might possibly block and thus cannot be handled in an IRQ
31 * context. Both of these situations can't be solved perfectly in Linux since
34 * enough if we can lower our chance of being preempted to an absolute
41 * time-sensitive hardware programming on time, even when the system is under
43 * re-arming work items can be easily implemented.
49 u64 count = atomic64_read(&vblank->count); in drm_handle_vblank_works()
50 bool wake = false; in drm_handle_vblank_works() local
52 assert_spin_locked(&vblank->dev->event_lock); in drm_handle_vblank_works()
54 list_for_each_entry_safe(work, next, &vblank->pending_work, node) { in drm_handle_vblank_works()
55 if (!drm_vblank_passed(count, work->count)) in drm_handle_vblank_works()
58 list_del_init(&work->node); in drm_handle_vblank_works()
59 drm_vblank_put(vblank->dev, vblank->pipe); in drm_handle_vblank_works()
60 kthread_queue_work(vblank->worker, &work->base); in drm_handle_vblank_works()
61 wake = true; in drm_handle_vblank_works()
63 if (wake) in drm_handle_vblank_works()
64 wake_up_all(&vblank->work_wait_queue); in drm_handle_vblank_works()
74 assert_spin_locked(&vblank->dev->event_lock); in drm_vblank_cancel_pending_works()
76 drm_WARN_ONCE(vblank->dev, !list_empty(&vblank->pending_work), in drm_vblank_cancel_pending_works()
79 list_for_each_entry_safe(work, next, &vblank->pending_work, node) { in drm_vblank_cancel_pending_works()
80 list_del_init(&work->node); in drm_vblank_cancel_pending_works()
81 drm_vblank_put(vblank->dev, vblank->pipe); in drm_vblank_cancel_pending_works()
84 wake_up_all(&vblank->work_wait_queue); in drm_vblank_cancel_pending_works()
88 * drm_vblank_work_schedule - schedule a vblank work
103 * using the new @count. This can be used for self-rearming work items.
112 struct drm_vblank_crtc *vblank = work->vblank; in drm_vblank_work_schedule()
113 struct drm_device *dev = vblank->dev; in drm_vblank_work_schedule()
116 bool passed, inmodeset, rescheduling = false, wake = false; in drm_vblank_work_schedule() local
119 spin_lock_irqsave(&dev->event_lock, irqflags); in drm_vblank_work_schedule()
120 if (work->cancelling) in drm_vblank_work_schedule()
123 spin_lock(&dev->vbl_lock); in drm_vblank_work_schedule()
124 inmodeset = vblank->inmodeset; in drm_vblank_work_schedule()
125 spin_unlock(&dev->vbl_lock); in drm_vblank_work_schedule()
129 if (list_empty(&work->node)) { in drm_vblank_work_schedule()
130 ret = drm_vblank_get(dev, vblank->pipe); in drm_vblank_work_schedule()
133 } else if (work->count == count) { in drm_vblank_work_schedule()
140 work->count = count; in drm_vblank_work_schedule()
141 cur_vbl = drm_vblank_count(dev, vblank->pipe); in drm_vblank_work_schedule()
146 vblank->pipe, count, cur_vbl); in drm_vblank_work_schedule()
149 drm_vblank_put(dev, vblank->pipe); in drm_vblank_work_schedule()
150 ret = kthread_queue_work(vblank->worker, &work->base); in drm_vblank_work_schedule()
153 list_del_init(&work->node); in drm_vblank_work_schedule()
154 wake = true; in drm_vblank_work_schedule()
158 list_add_tail(&work->node, &vblank->pending_work); in drm_vblank_work_schedule()
163 spin_unlock_irqrestore(&dev->event_lock, irqflags); in drm_vblank_work_schedule()
164 if (wake) in drm_vblank_work_schedule()
165 wake_up_all(&vblank->work_wait_queue); in drm_vblank_work_schedule()
171 * drm_vblank_work_cancel_sync - cancel a vblank work and wait for it to
179 * if it's self-arming.
187 struct drm_vblank_crtc *vblank = work->vblank; in drm_vblank_work_cancel_sync()
188 struct drm_device *dev = vblank->dev; in drm_vblank_work_cancel_sync()
191 spin_lock_irq(&dev->event_lock); in drm_vblank_work_cancel_sync()
192 if (!list_empty(&work->node)) { in drm_vblank_work_cancel_sync()
193 list_del_init(&work->node); in drm_vblank_work_cancel_sync()
194 drm_vblank_put(vblank->dev, vblank->pipe); in drm_vblank_work_cancel_sync()
198 work->cancelling++; in drm_vblank_work_cancel_sync()
199 spin_unlock_irq(&dev->event_lock); in drm_vblank_work_cancel_sync()
201 wake_up_all(&vblank->work_wait_queue); in drm_vblank_work_cancel_sync()
203 if (kthread_cancel_work_sync(&work->base)) in drm_vblank_work_cancel_sync()
206 spin_lock_irq(&dev->event_lock); in drm_vblank_work_cancel_sync()
207 work->cancelling--; in drm_vblank_work_cancel_sync()
208 spin_unlock_irq(&dev->event_lock); in drm_vblank_work_cancel_sync()
215 * drm_vblank_work_flush - wait for a scheduled vblank work to finish
223 struct drm_vblank_crtc *vblank = work->vblank; in drm_vblank_work_flush()
224 struct drm_device *dev = vblank->dev; in drm_vblank_work_flush()
226 spin_lock_irq(&dev->event_lock); in drm_vblank_work_flush()
227 wait_event_lock_irq(vblank->work_wait_queue, list_empty(&work->node), in drm_vblank_work_flush()
228 dev->event_lock); in drm_vblank_work_flush()
229 spin_unlock_irq(&dev->event_lock); in drm_vblank_work_flush()
231 kthread_flush_work(&work->base); in drm_vblank_work_flush()
236 * drm_vblank_work_flush_all - flush all currently pending vblank work on crtc.
244 struct drm_device *dev = crtc->dev; in drm_vblank_work_flush_all()
245 struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(crtc)]; in drm_vblank_work_flush_all()
247 spin_lock_irq(&dev->event_lock); in drm_vblank_work_flush_all()
248 wait_event_lock_irq(vblank->work_wait_queue, in drm_vblank_work_flush_all()
249 list_empty(&vblank->pending_work), in drm_vblank_work_flush_all()
250 dev->event_lock); in drm_vblank_work_flush_all()
251 spin_unlock_irq(&dev->event_lock); in drm_vblank_work_flush_all()
253 kthread_flush_worker(vblank->worker); in drm_vblank_work_flush_all()
258 * drm_vblank_work_init - initialize a vblank work item
268 kthread_init_work(&work->base, func); in drm_vblank_work_init()
269 INIT_LIST_HEAD(&work->node); in drm_vblank_work_init()
270 work->vblank = drm_crtc_vblank_crtc(crtc); in drm_vblank_work_init()
278 INIT_LIST_HEAD(&vblank->pending_work); in drm_vblank_worker_init()
279 init_waitqueue_head(&vblank->work_wait_queue); in drm_vblank_worker_init()
280 worker = kthread_create_worker(0, "card%d-crtc%d", in drm_vblank_worker_init()
281 vblank->dev->primary->index, in drm_vblank_worker_init()
282 vblank->pipe); in drm_vblank_worker_init()
286 vblank->worker = worker; in drm_vblank_worker_init()
288 sched_set_fifo(worker->task); in drm_vblank_worker_init()