]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blobdiff - drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
drm/nouveau/tmr: convert to new-style nvkm_subdev
[mirror_ubuntu-eoan-kernel.git] / drivers / gpu / drm / nouveau / nvkm / subdev / timer / base.c
index 4c34e2bd0487db63d0ba2cad83ad1c4f689eccad..d4dae1f12d622b03cb2af61d2dcb966fed28f7fb 100644 (file)
  *
  * Authors: Ben Skeggs
  */
-#include <subdev/timer.h>
+#include "priv.h"
+
+u64
+nvkm_timer_read(struct nvkm_timer *tmr)
+{
+       return tmr->func->read(tmr);
+}
+
+void
+nvkm_timer_alarm_trigger(struct nvkm_timer *tmr)
+{
+       struct nvkm_alarm *alarm, *atemp;
+       unsigned long flags;
+       LIST_HEAD(exec);
+
+       /* move any due alarms off the pending list */
+       spin_lock_irqsave(&tmr->lock, flags);
+       list_for_each_entry_safe(alarm, atemp, &tmr->alarms, head) {
+               if (alarm->timestamp <= nvkm_timer_read(tmr))
+                       list_move_tail(&alarm->head, &exec);
+       }
+
+       /* reschedule interrupt for next alarm time */
+       if (!list_empty(&tmr->alarms)) {
+               alarm = list_first_entry(&tmr->alarms, typeof(*alarm), head);
+               tmr->func->alarm_init(tmr, alarm->timestamp);
+       } else {
+               tmr->func->alarm_fini(tmr);
+       }
+       spin_unlock_irqrestore(&tmr->lock, flags);
+
+       /* execute any pending alarm handlers */
+       list_for_each_entry_safe(alarm, atemp, &exec, head) {
+               list_del_init(&alarm->head);
+               alarm->func(alarm);
+       }
+}
 
 void
-nvkm_timer_alarm(void *obj, u32 nsec, struct nvkm_alarm *alarm)
+nvkm_timer_alarm(struct nvkm_timer *tmr, u32 nsec, struct nvkm_alarm *alarm)
 {
-       struct nvkm_timer *tmr = nvkm_timer(obj);
-       tmr->alarm(tmr, nsec, alarm);
+       struct nvkm_alarm *list;
+       unsigned long flags;
+
+       alarm->timestamp = nvkm_timer_read(tmr) + nsec;
+
+       /* append new alarm to list, in soonest-alarm-first order */
+       spin_lock_irqsave(&tmr->lock, flags);
+       if (!nsec) {
+               if (!list_empty(&alarm->head))
+                       list_del(&alarm->head);
+       } else {
+               list_for_each_entry(list, &tmr->alarms, head) {
+                       if (list->timestamp > alarm->timestamp)
+                               break;
+               }
+               list_add_tail(&alarm->head, &list->head);
+       }
+       spin_unlock_irqrestore(&tmr->lock, flags);
+
+       /* process pending alarms */
+       nvkm_timer_alarm_trigger(tmr);
 }
 
 void
-nvkm_timer_alarm_cancel(void *obj, struct nvkm_alarm *alarm)
+nvkm_timer_alarm_cancel(struct nvkm_timer *tmr, struct nvkm_alarm *alarm)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tmr->lock, flags);
+       list_del_init(&alarm->head);
+       spin_unlock_irqrestore(&tmr->lock, flags);
+}
+
+static void
+nvkm_timer_intr(struct nvkm_subdev *subdev)
 {
-       struct nvkm_timer *tmr = nvkm_timer(obj);
-       tmr->alarm_cancel(tmr, alarm);
+       struct nvkm_timer *tmr = nvkm_timer(subdev);
+       tmr->func->intr(tmr);
+}
+
+static int
+nvkm_timer_fini(struct nvkm_subdev *subdev, bool suspend)
+{
+       struct nvkm_timer *tmr = nvkm_timer(subdev);
+       tmr->func->alarm_fini(tmr);
+       return 0;
+}
+
+static int
+nvkm_timer_init(struct nvkm_subdev *subdev)
+{
+       struct nvkm_timer *tmr = nvkm_timer(subdev);
+       if (tmr->func->init)
+               tmr->func->init(tmr);
+       tmr->func->time(tmr, ktime_to_ns(ktime_get()));
+       nvkm_timer_alarm_trigger(tmr);
+       return 0;
+}
+
+static void *
+nvkm_timer_dtor(struct nvkm_subdev *subdev)
+{
+       return nvkm_timer(subdev);
+}
+
+static const struct nvkm_subdev_func
+nvkm_timer = {
+       .dtor = nvkm_timer_dtor,
+       .init = nvkm_timer_init,
+       .fini = nvkm_timer_fini,
+       .intr = nvkm_timer_intr,
+};
+
+int
+nvkm_timer_new_(const struct nvkm_timer_func *func, struct nvkm_device *device,
+               int index, struct nvkm_timer **ptmr)
+{
+       struct nvkm_timer *tmr;
+
+       if (!(tmr = *ptmr = kzalloc(sizeof(*tmr), GFP_KERNEL)))
+               return -ENOMEM;
+
+       nvkm_subdev_ctor(&nvkm_timer, device, index, 0, &tmr->subdev);
+       tmr->func = func;
+       INIT_LIST_HEAD(&tmr->alarms);
+       spin_lock_init(&tmr->lock);
+       return 0;
 }