drm/nouveau/therm: better transitions and debug logging
authorBen Skeggs <bskeggs@redhat.com>
Thu, 6 Dec 2012 00:28:34 +0000 (10:28 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 20 Feb 2013 06:00:25 +0000 (16:00 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Signed-off-by: Martin Peres <martin.peres@labri.fr>
drivers/gpu/drm/nouveau/core/include/subdev/therm.h
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 7c83ecc..6b17b61 100644 (file)
@@ -4,11 +4,10 @@
 #include <core/device.h>
 #include <core/subdev.h>
 
-enum nouveau_therm_fan_mode {
-       FAN_CONTROL_NONE = 0,
-       FAN_CONTROL_MANUAL = 1,
-       FAN_CONTROL_AUTO = 2,
-       FAN_CONTROL_NR,
+enum nouveau_therm_mode {
+       NOUVEAU_THERM_CTRL_NONE = 0,
+       NOUVEAU_THERM_CTRL_MANUAL = 1,
+       NOUVEAU_THERM_CTRL_AUTO = 2,
 };
 
 enum nouveau_therm_attr_type {
index f54495a..b35b4a2 100644 (file)
@@ -93,24 +93,27 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
        priv->mode = mode;
 
        switch (mode) {
-       case FAN_CONTROL_MANUAL:
-               duty = priv->fan->percent;
+       case NOUVEAU_THERM_CTRL_MANUAL:
+               duty = nouveau_therm_fan_get(therm);
+               if (duty < 0)
+                       duty = 100;
                break;
-       case FAN_CONTROL_AUTO:
+       case NOUVEAU_THERM_CTRL_AUTO:
                if (priv->fan->bios.nr_fan_trip)
                        duty = nouveau_therm_update_trip(therm);
                else
                        duty = nouveau_therm_update_linear(therm);
                break;
-       case FAN_CONTROL_NONE:
+       case NOUVEAU_THERM_CTRL_NONE:
        default:
                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:
-       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);
        spin_unlock_irqrestore(&priv->lock, flags);
 }
@@ -127,28 +130,22 @@ int
 nouveau_therm_mode(struct nouveau_therm *therm, int mode)
 {
        struct nouveau_therm_priv *priv = (void *)therm;
-
-       if (priv->mode == mode)
-               return 0;
+       struct nouveau_device *device = nv_device(therm);
+       static const char *name[] = {
+               "disabled",
+               "manual",
+               "automatic"
+       };
 
        /* The default PDAEMON ucode interferes with fan management */
-       if (nv_device(therm)->card_type >= NV_C0)
+       if ((mode >= ARRAY_SIZE(name)) ||
+           (mode != NOUVEAU_THERM_CTRL_NONE && device->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;
-       }
+       if (priv->mode == mode)
+               return 0;
 
+       nv_info(therm, "Thermal management: %s\n", name[mode]);
        nouveau_therm_update(therm, mode);
        return 0;
 }
@@ -258,9 +255,8 @@ _nouveau_therm_init(struct nouveau_object *object)
        if (ret)
                return ret;
 
-       if (priv->fan->percent >= 0)
-               therm->fan_set(therm, priv->fan->percent);
-
+       if (priv->suspend >= 0)
+               nouveau_therm_mode(therm, priv->mode);
        priv->sensor.program_alarms(therm);
        return 0;
 }
@@ -271,7 +267,10 @@ _nouveau_therm_fini(struct nouveau_object *object, bool suspend)
        struct nouveau_therm *therm = (void *)object;
        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);
 }
@@ -299,6 +298,7 @@ nouveau_therm_create_(struct nouveau_object *parent,
        priv->base.fan_sense = nouveau_therm_fan_sense;
        priv->base.attr_get = nouveau_therm_attr_get;
        priv->base.attr_set = nouveau_therm_attr_set;
+       priv->mode = priv->suspend = -1; /* undefined */
        return 0;
 }
 
@@ -308,6 +308,8 @@ nouveau_therm_preinit(struct nouveau_therm *therm)
        nouveau_therm_ic_ctor(therm);
        nouveau_therm_sensor_ctor(therm);
        nouveau_therm_fan_ctor(therm);
+
+       nouveau_therm_mode(therm, NOUVEAU_THERM_CTRL_NONE);
        return 0;
 }
 
index 0f210f0..f7d32f4 100644 (file)
@@ -47,10 +47,17 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
                target = fan->percent;
        target = max_t(u8, target, fan->bios.min_duty);
        target = min_t(u8, target, fan->bios.max_duty);
-       fan->percent = target;
+       if (fan->percent != target) {
+               nv_debug(therm, "FAN target: %d\n", target);
+               fan->percent = target;
+       }
 
-       /* smooth out the fanspeed increase/decrease */
+       /* 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 */
        if (!immediate && duty >= 0) {
                /* the constant "3" is a rough approximation taken from
                 * nvidia's behaviour.
@@ -64,6 +71,7 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
                duty = target;
        }
 
+       nv_debug(therm, "FAN update: %d\n", duty);
        ret = fan->set(therm, duty);
        if (ret)
                goto done;
@@ -161,7 +169,7 @@ nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent)
 {
        struct nouveau_therm_priv *priv = (void *)therm;
 
-       if (priv->mode != FAN_CONTROL_MANUAL)
+       if (priv->mode != NOUVEAU_THERM_CTRL_MANUAL)
                return -EINVAL;
 
        return nouveau_therm_fan_set(therm, true, percent);
index c2413e6..06b9870 100644 (file)
@@ -76,6 +76,7 @@ struct nouveau_therm_priv {
        spinlock_t lock;
        struct nouveau_therm_trip_point *last_trip;
        int mode;
+       int suspend;
 
        /* bios */
        struct nvbios_therm_sensor bios_sensor;
index d80c572..820e097 100644 (file)
@@ -108,7 +108,7 @@ void nouveau_therm_sensor_event(struct nouveau_therm *therm,
        switch (thrs) {
        case NOUVEAU_THERM_THRS_FANBOOST:
                nouveau_therm_fan_set(therm, true, 100);
-               nouveau_therm_mode(therm, FAN_CONTROL_AUTO);
+               nouveau_therm_mode(therm, NOUVEAU_THERM_CTRL_AUTO);
                break;
        case NOUVEAU_THERM_THRS_DOWNCLOCK:
                if (priv->emergency.downclock)