diff options
author | Martin Peres <martin.peres@labri.fr> | 2013-08-11 22:48:51 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-09-03 23:46:46 -0400 |
commit | b925a75d6729cec8debd0c378b354d8c228b36aa (patch) | |
tree | 8a0050246254e8c07aca6658a6abae4453c32cf8 | |
parent | 7fabd25393c7b5cb749d358772ccea2a570f4b49 (diff) |
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>
-rw-r--r-- | drivers/gpu/drm/nouveau/core/include/subdev/timer.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/timer/base.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c | 20 |
3 files changed, 29 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h index e465d158d352..9ab70dfe5b02 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h | |||
@@ -22,6 +22,7 @@ bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data); | |||
22 | bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data); | 22 | bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data); |
23 | bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data); | 23 | bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data); |
24 | void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *); | 24 | void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *); |
25 | void nouveau_timer_alarm_cancel(void *, struct nouveau_alarm *); | ||
25 | 26 | ||
26 | #define NV_WAIT_DEFAULT 2000000000ULL | 27 | #define NV_WAIT_DEFAULT 2000000000ULL |
27 | #define nv_wait(o,a,m,v) \ | 28 | #define nv_wait(o,a,m,v) \ |
@@ -35,6 +36,7 @@ struct nouveau_timer { | |||
35 | struct nouveau_subdev base; | 36 | struct nouveau_subdev base; |
36 | u64 (*read)(struct nouveau_timer *); | 37 | u64 (*read)(struct nouveau_timer *); |
37 | void (*alarm)(struct nouveau_timer *, u64 time, struct nouveau_alarm *); | 38 | void (*alarm)(struct nouveau_timer *, u64 time, struct nouveau_alarm *); |
39 | void (*alarm_cancel)(struct nouveau_timer *, struct nouveau_alarm *); | ||
38 | }; | 40 | }; |
39 | 41 | ||
40 | static inline struct nouveau_timer * | 42 | static inline struct nouveau_timer * |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/base.c b/drivers/gpu/drm/nouveau/core/subdev/timer/base.c index 5d417cc9949b..cf8a0e0f8ee3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/timer/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/base.c | |||
@@ -85,3 +85,10 @@ nouveau_timer_alarm(void *obj, u32 nsec, struct nouveau_alarm *alarm) | |||
85 | struct nouveau_timer *ptimer = nouveau_timer(obj); | 85 | struct nouveau_timer *ptimer = nouveau_timer(obj); |
86 | ptimer->alarm(ptimer, nsec, alarm); | 86 | ptimer->alarm(ptimer, nsec, alarm); |
87 | } | 87 | } |
88 | |||
89 | void | ||
90 | nouveau_timer_alarm_cancel(void *obj, struct nouveau_alarm *alarm) | ||
91 | { | ||
92 | struct nouveau_timer *ptimer = nouveau_timer(obj); | ||
93 | ptimer->alarm_cancel(ptimer, alarm); | ||
94 | } | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c index 49350eaf4df5..57711ecb566c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c | |||
@@ -114,6 +114,25 @@ nv04_timer_alarm(struct nouveau_timer *ptimer, u64 time, | |||
114 | } | 114 | } |
115 | 115 | ||
116 | static void | 116 | static void |
117 | nv04_timer_alarm_cancel(struct nouveau_timer *ptimer, | ||
118 | struct nouveau_alarm *alarm) | ||
119 | { | ||
120 | struct nv04_timer_priv *priv = (void *)ptimer; | ||
121 | unsigned long flags; | ||
122 | |||
123 | /* avoid deleting an entry while the alarm intr is running */ | ||
124 | spin_lock_irqsave(&priv->lock, flags); | ||
125 | |||
126 | /* delete the alarm from the list */ | ||
127 | list_del(&alarm->head); | ||
128 | |||
129 | /* reset the head so as list_empty returns 1 */ | ||
130 | INIT_LIST_HEAD(&alarm->head); | ||
131 | |||
132 | spin_unlock_irqrestore(&priv->lock, flags); | ||
133 | } | ||
134 | |||
135 | static void | ||
117 | nv04_timer_intr(struct nouveau_subdev *subdev) | 136 | nv04_timer_intr(struct nouveau_subdev *subdev) |
118 | { | 137 | { |
119 | struct nv04_timer_priv *priv = (void *)subdev; | 138 | struct nv04_timer_priv *priv = (void *)subdev; |
@@ -147,6 +166,7 @@ nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
147 | priv->base.base.intr = nv04_timer_intr; | 166 | priv->base.base.intr = nv04_timer_intr; |
148 | priv->base.read = nv04_timer_read; | 167 | priv->base.read = nv04_timer_read; |
149 | priv->base.alarm = nv04_timer_alarm; | 168 | priv->base.alarm = nv04_timer_alarm; |
169 | priv->base.alarm_cancel = nv04_timer_alarm_cancel; | ||
150 | priv->suspend_time = 0; | 170 | priv->suspend_time = 0; |
151 | 171 | ||
152 | INIT_LIST_HEAD(&priv->alarms); | 172 | INIT_LIST_HEAD(&priv->alarms); |