diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c')
-rw-r--r-- | kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c | 158 |
1 files changed, 108 insertions, 50 deletions
diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c index d894061ce..d4dae1f12 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c @@ -21,73 +21,131 @@ * * Authors: Ben Skeggs */ -#include <subdev/timer.h> +#include "priv.h" -bool -nvkm_timer_wait_eq(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) +u64 +nvkm_timer_read(struct nvkm_timer *tmr) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - u64 time0; - - time0 = ptimer->read(ptimer); - do { - if (nv_iclass(obj, NV_SUBDEV_CLASS)) { - if ((nv_rd32(obj, addr) & mask) == data) - return true; - } else { - if ((nv_ro32(obj, addr) & mask) == data) - return true; - } - } while (ptimer->read(ptimer) - time0 < nsec); + 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); + } - return false; + /* 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); + } } -bool -nvkm_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) +void +nvkm_timer_alarm(struct nvkm_timer *tmr, u32 nsec, struct nvkm_alarm *alarm) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - u64 time0; - - time0 = ptimer->read(ptimer); - do { - if (nv_iclass(obj, NV_SUBDEV_CLASS)) { - if ((nv_rd32(obj, addr) & mask) != data) - return true; - } else { - if ((nv_ro32(obj, addr) & mask) != data) - return true; + 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; } - } while (ptimer->read(ptimer) - time0 < nsec); + list_add_tail(&alarm->head, &list->head); + } + spin_unlock_irqrestore(&tmr->lock, flags); - return false; + /* process pending alarms */ + nvkm_timer_alarm_trigger(tmr); } -bool -nvkm_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data) +void +nvkm_timer_alarm_cancel(struct nvkm_timer *tmr, struct nvkm_alarm *alarm) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - u64 time0; + unsigned long flags; + spin_lock_irqsave(&tmr->lock, flags); + list_del_init(&alarm->head); + spin_unlock_irqrestore(&tmr->lock, flags); +} - time0 = ptimer->read(ptimer); - do { - if (func(data) == true) - return true; - } while (ptimer->read(ptimer) - time0 < nsec); +static void +nvkm_timer_intr(struct nvkm_subdev *subdev) +{ + struct nvkm_timer *tmr = nvkm_timer(subdev); + tmr->func->intr(tmr); +} - return false; +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; } -void -nvkm_timer_alarm(void *obj, u32 nsec, struct nvkm_alarm *alarm) +static int +nvkm_timer_init(struct nvkm_subdev *subdev) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - ptimer->alarm(ptimer, nsec, alarm); + 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; } -void -nvkm_timer_alarm_cancel(void *obj, struct nvkm_alarm *alarm) +static void * +nvkm_timer_dtor(struct nvkm_subdev *subdev) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - ptimer->alarm_cancel(ptimer, alarm); + 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; } |