drm/nouveau/timer: add a way to cancel alarms

Since alarms don't play well with suspend, it is important every alarm
user cancels his tasks before suspending.

The task should be rescheduled on resume.

Signed-off-by: Martin Peres <martin.peres@labri.fr>
Tested-by: Martin Peres <martin.peres@labri.fr>
Tested-by: Dash Four <mr.dash.four@googlemail.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Martin Peres 2013-08-11 22:48:51 -04:00 committed by Ben Skeggs
parent 7fabd25393
commit b925a75d67
3 changed files with 29 additions and 0 deletions

View file

@ -22,6 +22,7 @@ bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data);
bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data);
bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data);
void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *);
void nouveau_timer_alarm_cancel(void *, struct nouveau_alarm *);
#define NV_WAIT_DEFAULT 2000000000ULL
#define nv_wait(o,a,m,v) \
@ -35,6 +36,7 @@ struct nouveau_timer {
struct nouveau_subdev base;
u64 (*read)(struct nouveau_timer *);
void (*alarm)(struct nouveau_timer *, u64 time, struct nouveau_alarm *);
void (*alarm_cancel)(struct nouveau_timer *, struct nouveau_alarm *);
};
static inline struct nouveau_timer *

View file

@ -85,3 +85,10 @@ nouveau_timer_alarm(void *obj, u32 nsec, struct nouveau_alarm *alarm)
struct nouveau_timer *ptimer = nouveau_timer(obj);
ptimer->alarm(ptimer, nsec, alarm);
}
void
nouveau_timer_alarm_cancel(void *obj, struct nouveau_alarm *alarm)
{
struct nouveau_timer *ptimer = nouveau_timer(obj);
ptimer->alarm_cancel(ptimer, alarm);
}

View file

@ -113,6 +113,25 @@ nv04_timer_alarm(struct nouveau_timer *ptimer, u64 time,
nv04_timer_alarm_trigger(ptimer);
}
static void
nv04_timer_alarm_cancel(struct nouveau_timer *ptimer,
struct nouveau_alarm *alarm)
{
struct nv04_timer_priv *priv = (void *)ptimer;
unsigned long flags;
/* avoid deleting an entry while the alarm intr is running */
spin_lock_irqsave(&priv->lock, flags);
/* delete the alarm from the list */
list_del(&alarm->head);
/* reset the head so as list_empty returns 1 */
INIT_LIST_HEAD(&alarm->head);
spin_unlock_irqrestore(&priv->lock, flags);
}
static void
nv04_timer_intr(struct nouveau_subdev *subdev)
{
@ -147,6 +166,7 @@ nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->base.base.intr = nv04_timer_intr;
priv->base.read = nv04_timer_read;
priv->base.alarm = nv04_timer_alarm;
priv->base.alarm_cancel = nv04_timer_alarm_cancel;
priv->suspend_time = 0;
INIT_LIST_HEAD(&priv->alarms);