aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Peres <martin.peres@labri.fr>2013-08-11 22:48:50 -0400
committerBen Skeggs <bskeggs@redhat.com>2013-09-03 23:46:42 -0400
commit7fabd25393c7b5cb749d358772ccea2a570f4b49 (patch)
tree77ef02640979f17f8375e7886889f6f4f8bf0761
parent4cc00ad1373674cdd1bce387bd1d4e3f5c42a99c (diff)
drm/nouveau/timer: restore the time on resume
This can be useful if some parts of Nouveau try to calculate the time between two events. Without this patch, the time difference would be negative in the case where the computer is suspended/resumed between two events. This patch should fix fan speed probing when done while suspending/resuming. Solve this by saving the current time before suspending and by restoring it on resume. Signed-off-by: Martin Peres <martin.peres@labri.fr> Tested-by: Martin Peres <martin.peres@labri.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
index 9469b8275675..49350eaf4df5 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
@@ -36,6 +36,7 @@ struct nv04_timer_priv {
36 struct nouveau_timer base; 36 struct nouveau_timer base;
37 struct list_head alarms; 37 struct list_head alarms;
38 spinlock_t lock; 38 spinlock_t lock;
39 u64 suspend_time;
39}; 40};
40 41
41static u64 42static u64
@@ -146,6 +147,7 @@ nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
146 priv->base.base.intr = nv04_timer_intr; 147 priv->base.base.intr = nv04_timer_intr;
147 priv->base.read = nv04_timer_read; 148 priv->base.read = nv04_timer_read;
148 priv->base.alarm = nv04_timer_alarm; 149 priv->base.alarm = nv04_timer_alarm;
150 priv->suspend_time = 0;
149 151
150 INIT_LIST_HEAD(&priv->alarms); 152 INIT_LIST_HEAD(&priv->alarms);
151 spin_lock_init(&priv->lock); 153 spin_lock_init(&priv->lock);
@@ -164,7 +166,7 @@ nv04_timer_init(struct nouveau_object *object)
164{ 166{
165 struct nouveau_device *device = nv_device(object); 167 struct nouveau_device *device = nv_device(object);
166 struct nv04_timer_priv *priv = (void *)object; 168 struct nv04_timer_priv *priv = (void *)object;
167 u32 m = 1, f, n, d; 169 u32 m = 1, f, n, d, lo, hi;
168 int ret; 170 int ret;
169 171
170 ret = nouveau_timer_init(&priv->base); 172 ret = nouveau_timer_init(&priv->base);
@@ -221,16 +223,25 @@ nv04_timer_init(struct nouveau_object *object)
221 d >>= 1; 223 d >>= 1;
222 } 224 }
223 225
226 /* restore the time before suspend */
227 lo = priv->suspend_time;
228 hi = (priv->suspend_time >> 32);
229
224 nv_debug(priv, "input frequency : %dHz\n", f); 230 nv_debug(priv, "input frequency : %dHz\n", f);
225 nv_debug(priv, "input multiplier: %d\n", m); 231 nv_debug(priv, "input multiplier: %d\n", m);
226 nv_debug(priv, "numerator : 0x%08x\n", n); 232 nv_debug(priv, "numerator : 0x%08x\n", n);
227 nv_debug(priv, "denominator : 0x%08x\n", d); 233 nv_debug(priv, "denominator : 0x%08x\n", d);
228 nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n); 234 nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n);
235 nv_debug(priv, "time low : 0x%08x\n", lo);
236 nv_debug(priv, "time high : 0x%08x\n", hi);
229 237
230 nv_wr32(priv, NV04_PTIMER_NUMERATOR, n); 238 nv_wr32(priv, NV04_PTIMER_NUMERATOR, n);
231 nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d); 239 nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d);
232 nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff); 240 nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff);
233 nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); 241 nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
242 nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
243 nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
244
234 return 0; 245 return 0;
235} 246}
236 247
@@ -238,6 +249,8 @@ static int
238nv04_timer_fini(struct nouveau_object *object, bool suspend) 249nv04_timer_fini(struct nouveau_object *object, bool suspend)
239{ 250{
240 struct nv04_timer_priv *priv = (void *)object; 251 struct nv04_timer_priv *priv = (void *)object;
252 if (suspend)
253 priv->suspend_time = nv04_timer_read(&priv->base);
241 nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); 254 nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
242 return nouveau_timer_fini(&priv->base, suspend); 255 return nouveau_timer_fini(&priv->base, suspend);
243} 256}