mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
drm/nouveau/therm: better transitions and debug logging
Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Martin Peres <martin.peres@labri.fr>
This commit is contained in:
parent
041d62469f
commit
1a22274b28
@ -4,11 +4,10 @@
|
|||||||
#include <core/device.h>
|
#include <core/device.h>
|
||||||
#include <core/subdev.h>
|
#include <core/subdev.h>
|
||||||
|
|
||||||
enum nouveau_therm_fan_mode {
|
enum nouveau_therm_mode {
|
||||||
FAN_CONTROL_NONE = 0,
|
NOUVEAU_THERM_CTRL_NONE = 0,
|
||||||
FAN_CONTROL_MANUAL = 1,
|
NOUVEAU_THERM_CTRL_MANUAL = 1,
|
||||||
FAN_CONTROL_AUTO = 2,
|
NOUVEAU_THERM_CTRL_AUTO = 2,
|
||||||
FAN_CONTROL_NR,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum nouveau_therm_attr_type {
|
enum nouveau_therm_attr_type {
|
||||||
|
@ -93,24 +93,27 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
|
|||||||
priv->mode = mode;
|
priv->mode = mode;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case FAN_CONTROL_MANUAL:
|
case NOUVEAU_THERM_CTRL_MANUAL:
|
||||||
duty = priv->fan->percent;
|
duty = nouveau_therm_fan_get(therm);
|
||||||
|
if (duty < 0)
|
||||||
|
duty = 100;
|
||||||
break;
|
break;
|
||||||
case FAN_CONTROL_AUTO:
|
case NOUVEAU_THERM_CTRL_AUTO:
|
||||||
if (priv->fan->bios.nr_fan_trip)
|
if (priv->fan->bios.nr_fan_trip)
|
||||||
duty = nouveau_therm_update_trip(therm);
|
duty = nouveau_therm_update_trip(therm);
|
||||||
else
|
else
|
||||||
duty = nouveau_therm_update_linear(therm);
|
duty = nouveau_therm_update_linear(therm);
|
||||||
break;
|
break;
|
||||||
case FAN_CONTROL_NONE:
|
case NOUVEAU_THERM_CTRL_NONE:
|
||||||
default:
|
default:
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
nouveau_therm_fan_set(therm, (mode != FAN_CONTROL_AUTO), duty);
|
nv_debug(therm, "FAN target request: %d%%\n", duty);
|
||||||
|
nouveau_therm_fan_set(therm, (mode != NOUVEAU_THERM_CTRL_AUTO), duty);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (list_empty(&priv->alarm.head) && (mode == FAN_CONTROL_AUTO))
|
if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO))
|
||||||
ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm);
|
ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm);
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
}
|
}
|
||||||
@ -127,28 +130,22 @@ int
|
|||||||
nouveau_therm_mode(struct nouveau_therm *therm, int mode)
|
nouveau_therm_mode(struct nouveau_therm *therm, int mode)
|
||||||
{
|
{
|
||||||
struct nouveau_therm_priv *priv = (void *)therm;
|
struct nouveau_therm_priv *priv = (void *)therm;
|
||||||
|
struct nouveau_device *device = nv_device(therm);
|
||||||
|
static const char *name[] = {
|
||||||
|
"disabled",
|
||||||
|
"manual",
|
||||||
|
"automatic"
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The default PDAEMON ucode interferes with fan management */
|
||||||
|
if ((mode >= ARRAY_SIZE(name)) ||
|
||||||
|
(mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (priv->mode == mode)
|
if (priv->mode == mode)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* The default PDAEMON ucode interferes with fan management */
|
nv_info(therm, "Thermal management: %s\n", name[mode]);
|
||||||
if (nv_device(therm)->card_type >= NV_C0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case FAN_CONTROL_NONE:
|
|
||||||
nv_info(therm, "switch to no-control mode\n");
|
|
||||||
break;
|
|
||||||
case FAN_CONTROL_MANUAL:
|
|
||||||
nv_info(therm, "switch to manual mode\n");
|
|
||||||
break;
|
|
||||||
case FAN_CONTROL_AUTO:
|
|
||||||
nv_info(therm, "switch to automatic mode\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nouveau_therm_update(therm, mode);
|
nouveau_therm_update(therm, mode);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -258,9 +255,8 @@ _nouveau_therm_init(struct nouveau_object *object)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (priv->fan->percent >= 0)
|
if (priv->suspend >= 0)
|
||||||
therm->fan_set(therm, priv->fan->percent);
|
nouveau_therm_mode(therm, priv->mode);
|
||||||
|
|
||||||
priv->sensor.program_alarms(therm);
|
priv->sensor.program_alarms(therm);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -271,7 +267,10 @@ _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;
|
||||||
|
|
||||||
priv->fan->percent = therm->fan_get(therm);
|
if (suspend) {
|
||||||
|
priv->suspend = priv->mode;
|
||||||
|
priv->mode = NOUVEAU_THERM_CTRL_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
return nouveau_subdev_fini(&therm->base, suspend);
|
return nouveau_subdev_fini(&therm->base, suspend);
|
||||||
}
|
}
|
||||||
@ -299,6 +298,7 @@ nouveau_therm_create_(struct nouveau_object *parent,
|
|||||||
priv->base.fan_sense = nouveau_therm_fan_sense;
|
priv->base.fan_sense = nouveau_therm_fan_sense;
|
||||||
priv->base.attr_get = nouveau_therm_attr_get;
|
priv->base.attr_get = nouveau_therm_attr_get;
|
||||||
priv->base.attr_set = nouveau_therm_attr_set;
|
priv->base.attr_set = nouveau_therm_attr_set;
|
||||||
|
priv->mode = priv->suspend = -1; /* undefined */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,6 +308,8 @@ nouveau_therm_preinit(struct nouveau_therm *therm)
|
|||||||
nouveau_therm_ic_ctor(therm);
|
nouveau_therm_ic_ctor(therm);
|
||||||
nouveau_therm_sensor_ctor(therm);
|
nouveau_therm_sensor_ctor(therm);
|
||||||
nouveau_therm_fan_ctor(therm);
|
nouveau_therm_fan_ctor(therm);
|
||||||
|
|
||||||
|
nouveau_therm_mode(therm, NOUVEAU_THERM_CTRL_NONE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,10 +47,17 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
|
|||||||
target = fan->percent;
|
target = fan->percent;
|
||||||
target = max_t(u8, target, fan->bios.min_duty);
|
target = max_t(u8, target, fan->bios.min_duty);
|
||||||
target = min_t(u8, target, fan->bios.max_duty);
|
target = min_t(u8, target, fan->bios.max_duty);
|
||||||
|
if (fan->percent != target) {
|
||||||
|
nv_debug(therm, "FAN target: %d\n", target);
|
||||||
fan->percent = target;
|
fan->percent = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check that we're not already at the target duty cycle */
|
||||||
|
duty = fan->get(therm);
|
||||||
|
if (duty == target)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* smooth out the fanspeed increase/decrease */
|
/* smooth out the fanspeed increase/decrease */
|
||||||
duty = fan->get(therm);
|
|
||||||
if (!immediate && duty >= 0) {
|
if (!immediate && duty >= 0) {
|
||||||
/* the constant "3" is a rough approximation taken from
|
/* the constant "3" is a rough approximation taken from
|
||||||
* nvidia's behaviour.
|
* nvidia's behaviour.
|
||||||
@ -64,6 +71,7 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
|
|||||||
duty = target;
|
duty = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nv_debug(therm, "FAN update: %d\n", duty);
|
||||||
ret = fan->set(therm, duty);
|
ret = fan->set(therm, duty);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto done;
|
goto done;
|
||||||
@ -161,7 +169,7 @@ nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent)
|
|||||||
{
|
{
|
||||||
struct nouveau_therm_priv *priv = (void *)therm;
|
struct nouveau_therm_priv *priv = (void *)therm;
|
||||||
|
|
||||||
if (priv->mode != FAN_CONTROL_MANUAL)
|
if (priv->mode != NOUVEAU_THERM_CTRL_MANUAL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return nouveau_therm_fan_set(therm, true, percent);
|
return nouveau_therm_fan_set(therm, true, percent);
|
||||||
|
@ -76,6 +76,7 @@ struct nouveau_therm_priv {
|
|||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct nouveau_therm_trip_point *last_trip;
|
struct nouveau_therm_trip_point *last_trip;
|
||||||
int mode;
|
int mode;
|
||||||
|
int suspend;
|
||||||
|
|
||||||
/* bios */
|
/* bios */
|
||||||
struct nvbios_therm_sensor bios_sensor;
|
struct nvbios_therm_sensor bios_sensor;
|
||||||
|
@ -108,7 +108,7 @@ void nouveau_therm_sensor_event(struct nouveau_therm *therm,
|
|||||||
switch (thrs) {
|
switch (thrs) {
|
||||||
case NOUVEAU_THERM_THRS_FANBOOST:
|
case NOUVEAU_THERM_THRS_FANBOOST:
|
||||||
nouveau_therm_fan_set(therm, true, 100);
|
nouveau_therm_fan_set(therm, true, 100);
|
||||||
nouveau_therm_mode(therm, FAN_CONTROL_AUTO);
|
nouveau_therm_mode(therm, NOUVEAU_THERM_CTRL_AUTO);
|
||||||
break;
|
break;
|
||||||
case NOUVEAU_THERM_THRS_DOWNCLOCK:
|
case NOUVEAU_THERM_THRS_DOWNCLOCK:
|
||||||
if (priv->emergency.downclock)
|
if (priv->emergency.downclock)
|
||||||
|
Loading…
Reference in New Issue
Block a user