summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Peres <martin.peres@labri.fr>2013-08-11 22:48:50 -0400
committerBen Skeggs <bskeggs@redhat.com>2013-08-21 11:34:46 +1000
commitb7cf45132801d39e2bc6760ba1015054869dc335 (patch)
treeebce308402e4182ba0e443fbeeb00ca55f0f166a
parent7af9a560a7e51ce46489f1eac8f4975d7d9e3626 (diff)
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--nvkm/subdev/timer/nv04.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/nvkm/subdev/timer/nv04.c b/nvkm/subdev/timer/nv04.c
index 9469b827..49350eaf 100644
--- a/nvkm/subdev/timer/nv04.c
+++ b/nvkm/subdev/timer/nv04.c
@@ -36,6 +36,7 @@ struct nv04_timer_priv {
struct nouveau_timer base;
struct list_head alarms;
spinlock_t lock;
+ u64 suspend_time;
};
static u64
@@ -146,6 +147,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->suspend_time = 0;
INIT_LIST_HEAD(&priv->alarms);
spin_lock_init(&priv->lock);
@@ -164,7 +166,7 @@ nv04_timer_init(struct nouveau_object *object)
{
struct nouveau_device *device = nv_device(object);
struct nv04_timer_priv *priv = (void *)object;
- u32 m = 1, f, n, d;
+ u32 m = 1, f, n, d, lo, hi;
int ret;
ret = nouveau_timer_init(&priv->base);
@@ -221,16 +223,25 @@ nv04_timer_init(struct nouveau_object *object)
d >>= 1;
}
+ /* restore the time before suspend */
+ lo = priv->suspend_time;
+ hi = (priv->suspend_time >> 32);
+
nv_debug(priv, "input frequency : %dHz\n", f);
nv_debug(priv, "input multiplier: %d\n", m);
nv_debug(priv, "numerator : 0x%08x\n", n);
nv_debug(priv, "denominator : 0x%08x\n", d);
nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n);
+ nv_debug(priv, "time low : 0x%08x\n", lo);
+ nv_debug(priv, "time high : 0x%08x\n", hi);
nv_wr32(priv, NV04_PTIMER_NUMERATOR, n);
nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d);
nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff);
nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
+ nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
+ nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
+
return 0;
}
@@ -238,6 +249,8 @@ static int
nv04_timer_fini(struct nouveau_object *object, bool suspend)
{
struct nv04_timer_priv *priv = (void *)object;
+ if (suspend)
+ priv->suspend_time = nv04_timer_read(&priv->base);
nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
return nouveau_timer_fini(&priv->base, suspend);
}