]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
drm/nouveau/therm: survive to suspend/resume cycles
authorMartin Peres <martin.peres@labri.fr>
Mon, 12 Aug 2013 02:48:52 +0000 (22:48 -0400)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 4 Sep 2013 03:46:52 +0000 (13:46 +1000)
Therm uses 3 ptimer alarms. Two to drive the fan and one for polling the
temperature. When suspending/resuming, alarms will never be fired.
As we are checking if there isn't an alarm pending before rescheduling
another one, we end up never checking temperature or updating the
fan speed.

This commit also adds debug messages to be able to spot more easily
if this case happens again in the future. Sorry for the spam if you
activate the debug level though.

Tested-by: Dash Four <mr.dash.four@googlemail.com>
v2:
- fix temperature polling too

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>
drivers/gpu/drm/nouveau/core/subdev/therm/base.c
drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
drivers/gpu/drm/nouveau/core/subdev/therm/temp.c

index 2ada3d71312f9512198e6dc6a0a2be6088c78d4c..f1de7a9c572be624d607d450081499a447d919ca 100644 (file)
@@ -95,12 +95,14 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
        int duty;
 
        spin_lock_irqsave(&priv->lock, flags);
+       nv_debug(therm, "FAN speed check\n");
        if (mode < 0)
                mode = priv->mode;
        priv->mode = mode;
 
        switch (mode) {
        case NOUVEAU_THERM_CTRL_MANUAL:
+               ptimer->alarm_cancel(ptimer, &priv->alarm);
                duty = nouveau_therm_fan_get(therm);
                if (duty < 0)
                        duty = 100;
@@ -113,6 +115,7 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
                break;
        case NOUVEAU_THERM_CTRL_NONE:
        default:
+               ptimer->alarm_cancel(ptimer, &priv->alarm);
                goto done;
        }
 
@@ -122,6 +125,8 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
 done:
        if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO))
                ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm);
+       else if (!list_empty(&priv->alarm.head))
+               nv_debug(therm, "therm fan alarm list is not empty\n");
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
@@ -274,7 +279,8 @@ _nouveau_therm_init(struct nouveau_object *object)
 
                nouveau_therm_fan_mode(therm, priv->suspend);
        }
-       priv->sensor.program_alarms(therm);
+       nouveau_therm_sensor_init(therm);
+       nouveau_therm_fan_init(therm);
        return 0;
 }
 
@@ -284,6 +290,8 @@ _nouveau_therm_fini(struct nouveau_object *object, bool suspend)
        struct nouveau_therm *therm = (void *)object;
        struct nouveau_therm_priv *priv = (void *)therm;
 
+       nouveau_therm_fan_fini(therm, suspend);
+       nouveau_therm_sensor_fini(therm, suspend);
        if (suspend) {
                priv->suspend = priv->mode;
                priv->mode = NOUVEAU_THERM_CTRL_NONE;
index 4d8450fcf0a0392dcb06cdde9681b30135229915..39f47b950ad1bd79a1315fb9a4a9bd725624ed8e 100644 (file)
@@ -203,6 +203,23 @@ nouveau_therm_fan_safety_checks(struct nouveau_therm *therm)
                priv->fan->bios.min_duty = priv->fan->bios.max_duty;
 }
 
+int
+nouveau_therm_fan_init(struct nouveau_therm *therm)
+{
+       return 0;
+}
+
+int
+nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend)
+{
+       struct nouveau_therm_priv *priv = (void *)therm;
+       struct nouveau_timer *ptimer = nouveau_timer(therm);
+
+       if (suspend)
+               ptimer->alarm_cancel(ptimer, &priv->fan->alarm);
+       return 0;
+}
+
 int
 nouveau_therm_fan_ctor(struct nouveau_therm *therm)
 {
index 15ca64e481f1c8aa88521ae960eab695b6c3ed7b..dd38529262fb7622dccf9d825d84bce7489b8d8a 100644 (file)
@@ -113,6 +113,8 @@ void nouveau_therm_ic_ctor(struct nouveau_therm *therm);
 int nouveau_therm_sensor_ctor(struct nouveau_therm *therm);
 
 int nouveau_therm_fan_ctor(struct nouveau_therm *therm);
+int nouveau_therm_fan_init(struct nouveau_therm *therm);
+int nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend);
 int nouveau_therm_fan_get(struct nouveau_therm *therm);
 int nouveau_therm_fan_set(struct nouveau_therm *therm, bool now, int percent);
 int nouveau_therm_fan_user_get(struct nouveau_therm *therm);
@@ -122,6 +124,8 @@ int nouveau_therm_fan_sense(struct nouveau_therm *therm);
 
 int nouveau_therm_preinit(struct nouveau_therm *);
 
+int nouveau_therm_sensor_init(struct nouveau_therm *therm);
+int nouveau_therm_sensor_fini(struct nouveau_therm *therm, bool suspend);
 void nouveau_therm_sensor_preinit(struct nouveau_therm *);
 void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm,
                                             enum nouveau_therm_thrs thrs,
index dde746c78c8a3c1e26d8c68e3cefef31531f7617..b80a33011b9313f8ac4e771cb93aaaf7e163d889 100644 (file)
@@ -180,6 +180,8 @@ alarm_timer_callback(struct nouveau_alarm *alarm)
 
        spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
 
+       nv_debug(therm, "polling the internal temperature\n");
+
        nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost,
                                             NOUVEAU_THERM_THRS_FANBOOST);
 
@@ -216,6 +218,25 @@ nouveau_therm_program_alarms_polling(struct nouveau_therm *therm)
        alarm_timer_callback(&priv->sensor.therm_poll_alarm);
 }
 
+int
+nouveau_therm_sensor_init(struct nouveau_therm *therm)
+{
+       struct nouveau_therm_priv *priv = (void *)therm;
+       priv->sensor.program_alarms(therm);
+       return 0;
+}
+
+int
+nouveau_therm_sensor_fini(struct nouveau_therm *therm, bool suspend)
+{
+       struct nouveau_therm_priv *priv = (void *)therm;
+       struct nouveau_timer *ptimer = nouveau_timer(therm);
+
+       if (suspend)
+               ptimer->alarm_cancel(ptimer, &priv->sensor.therm_poll_alarm);
+       return 0;
+}
+
 void
 nouveau_therm_sensor_preinit(struct nouveau_therm *therm)
 {