Commit c4a62a76 authored by Martin Peres's avatar Martin Peres Committed by Ben Skeggs

drm/nouveau/therm: survive to suspend/resume cycles

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: default avatarDash Four <mr.dash.four@googlemail.com>

v2:
- fix temperature polling too
Signed-off-by: default avatarMartin Peres <martin.peres@labri.fr>
Tested-by: default avatarMartin Peres <martin.peres@labri.fr>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent b925a75d
...@@ -95,12 +95,14 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode) ...@@ -95,12 +95,14 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
int duty; int duty;
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
nv_debug(therm, "FAN speed check\n");
if (mode < 0) if (mode < 0)
mode = priv->mode; mode = priv->mode;
priv->mode = mode; priv->mode = mode;
switch (mode) { switch (mode) {
case NOUVEAU_THERM_CTRL_MANUAL: case NOUVEAU_THERM_CTRL_MANUAL:
ptimer->alarm_cancel(ptimer, &priv->alarm);
duty = nouveau_therm_fan_get(therm); duty = nouveau_therm_fan_get(therm);
if (duty < 0) if (duty < 0)
duty = 100; duty = 100;
...@@ -113,6 +115,7 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode) ...@@ -113,6 +115,7 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
break; break;
case NOUVEAU_THERM_CTRL_NONE: case NOUVEAU_THERM_CTRL_NONE:
default: default:
ptimer->alarm_cancel(ptimer, &priv->alarm);
goto done; goto done;
} }
...@@ -122,6 +125,8 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode) ...@@ -122,6 +125,8 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
done: done:
if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO)) if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO))
ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm); 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); spin_unlock_irqrestore(&priv->lock, flags);
} }
...@@ -274,7 +279,8 @@ _nouveau_therm_init(struct nouveau_object *object) ...@@ -274,7 +279,8 @@ _nouveau_therm_init(struct nouveau_object *object)
nouveau_therm_fan_mode(therm, priv->suspend); nouveau_therm_fan_mode(therm, priv->suspend);
} }
priv->sensor.program_alarms(therm); nouveau_therm_sensor_init(therm);
nouveau_therm_fan_init(therm);
return 0; return 0;
} }
...@@ -284,6 +290,8 @@ _nouveau_therm_fini(struct nouveau_object *object, bool suspend) ...@@ -284,6 +290,8 @@ _nouveau_therm_fini(struct nouveau_object *object, bool suspend)
struct nouveau_therm *therm = (void *)object; struct nouveau_therm *therm = (void *)object;
struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_therm_priv *priv = (void *)therm;
nouveau_therm_fan_fini(therm, suspend);
nouveau_therm_sensor_fini(therm, suspend);
if (suspend) { if (suspend) {
priv->suspend = priv->mode; priv->suspend = priv->mode;
priv->mode = NOUVEAU_THERM_CTRL_NONE; priv->mode = NOUVEAU_THERM_CTRL_NONE;
......
...@@ -203,6 +203,23 @@ nouveau_therm_fan_safety_checks(struct nouveau_therm *therm) ...@@ -203,6 +203,23 @@ nouveau_therm_fan_safety_checks(struct nouveau_therm *therm)
priv->fan->bios.min_duty = priv->fan->bios.max_duty; 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 int
nouveau_therm_fan_ctor(struct nouveau_therm *therm) nouveau_therm_fan_ctor(struct nouveau_therm *therm)
{ {
......
...@@ -113,6 +113,8 @@ void nouveau_therm_ic_ctor(struct nouveau_therm *therm); ...@@ -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_sensor_ctor(struct nouveau_therm *therm);
int nouveau_therm_fan_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_get(struct nouveau_therm *therm);
int nouveau_therm_fan_set(struct nouveau_therm *therm, bool now, int percent); int nouveau_therm_fan_set(struct nouveau_therm *therm, bool now, int percent);
int nouveau_therm_fan_user_get(struct nouveau_therm *therm); int nouveau_therm_fan_user_get(struct nouveau_therm *therm);
...@@ -122,6 +124,8 @@ int nouveau_therm_fan_sense(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_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_preinit(struct nouveau_therm *);
void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm, void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm,
enum nouveau_therm_thrs thrs, enum nouveau_therm_thrs thrs,
......
...@@ -180,6 +180,8 @@ alarm_timer_callback(struct nouveau_alarm *alarm) ...@@ -180,6 +180,8 @@ alarm_timer_callback(struct nouveau_alarm *alarm)
spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); 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_threshold_hyst_polling(therm, &sensor->thrs_fan_boost,
NOUVEAU_THERM_THRS_FANBOOST); NOUVEAU_THERM_THRS_FANBOOST);
...@@ -216,6 +218,25 @@ nouveau_therm_program_alarms_polling(struct nouveau_therm *therm) ...@@ -216,6 +218,25 @@ nouveau_therm_program_alarms_polling(struct nouveau_therm *therm)
alarm_timer_callback(&priv->sensor.therm_poll_alarm); 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 void
nouveau_therm_sensor_preinit(struct nouveau_therm *therm) nouveau_therm_sensor_preinit(struct nouveau_therm *therm)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment