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:
parent
7fabd25393
commit
b925a75d67
|
@ -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 *
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue