Commit 1a22274b authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/therm: better transitions and debug logging

parent 041d6246
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -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 {
+29 −27
Original line number Diff line number Diff line
@@ -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;
}

+11 −3
Original line number Diff line number Diff line
@@ -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);
	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);
+1 −0
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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)