Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf9a625f authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'drm-nouveau-fixes-3.9' of...

Merge branch 'drm-nouveau-fixes-3.9' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next

Lots of thermal fixes and fix a lockdep warning we've been seeing.

* 'drm-nouveau-fixes-3.9' of git://anongit.freedesktop.org/git/nouveau/linux-2.6:
  drm/nv50/kms: prevent lockdep false-positive in page flipping path
  drm/nouveau/core: fix return value of nouveau_object_del()
  drm/nouveau/hwmon: do not expose a buggy temperature if it is unavailable
  drm/nouveau/therm: display the availability of the internal sensor
  drm/nouveau/therm: disable temperature management if the sensor isn't readable
  drm/nouveau/therm: disable auto fan management if temperature is not available
  drm/nv40/therm: reserve negative temperatures for errors
  drm/nv40/therm: disable temperature reading if the bios misses some parameters
  drm/nouveau/therm-ic: the temperature is off by sensor_constant, warn the user
  drm/nouveau/therm: remove some confusion introduced by therm_mode
  drm/nouveau/therm: do not make assumptions on temperature
  drm/nv40/therm: increase the sensor's settling delay to 20ms
  drm/nv40/therm: improve selection between the old and the new style
parents 10b38669 f60b6e7a
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -278,7 +278,6 @@ nouveau_object_del(struct nouveau_object *client, u32 _parent, u32 _handle)
	struct nouveau_object *parent = NULL;
	struct nouveau_object *namedb = NULL;
	struct nouveau_handle *handle = NULL;
	int ret = -EINVAL;

	parent = nouveau_handle_ref(client, _parent);
	if (!parent)
@@ -295,7 +294,7 @@ nouveau_object_del(struct nouveau_object *client, u32 _parent, u32 _handle)
	}

	nouveau_object_ref(NULL, &parent);
	return ret;
	return handle ? 0 : -EINVAL;
}

int
+1 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
#include <core/device.h>
#include <core/subdev.h>

enum nouveau_therm_mode {
enum nouveau_therm_fan_mode {
	NOUVEAU_THERM_CTRL_NONE = 0,
	NOUVEAU_THERM_CTRL_MANUAL = 1,
	NOUVEAU_THERM_CTRL_AUTO = 2,
+12 −6
Original line number Diff line number Diff line
@@ -134,7 +134,7 @@ nouveau_therm_alarm(struct nouveau_alarm *alarm)
}

int
nouveau_therm_mode(struct nouveau_therm *therm, int mode)
nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode)
{
	struct nouveau_therm_priv *priv = (void *)therm;
	struct nouveau_device *device = nv_device(therm);
@@ -149,10 +149,15 @@ nouveau_therm_mode(struct nouveau_therm *therm, int mode)
	    (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0))
		return -EINVAL;

	/* do not allow automatic fan management if the thermal sensor is
	 * not available */
	if (priv->mode == 2 && therm->temp_get(therm) < 0)
		return -EINVAL;

	if (priv->mode == mode)
		return 0;

	nv_info(therm, "Thermal management: %s\n", name[mode]);
	nv_info(therm, "fan management: %s\n", name[mode]);
	nouveau_therm_update(therm, mode);
	return 0;
}
@@ -213,7 +218,7 @@ nouveau_therm_attr_set(struct nouveau_therm *therm,
		priv->fan->bios.max_duty = value;
		return 0;
	case NOUVEAU_THERM_ATTR_FAN_MODE:
		return nouveau_therm_mode(therm, value);
		return nouveau_therm_fan_mode(therm, value);
	case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
		priv->bios_sensor.thrs_fan_boost.temp = value;
		priv->sensor.program_alarms(therm);
@@ -263,7 +268,7 @@ _nouveau_therm_init(struct nouveau_object *object)
		return ret;

	if (priv->suspend >= 0)
		nouveau_therm_mode(therm, priv->mode);
		nouveau_therm_fan_mode(therm, priv->mode);
	priv->sensor.program_alarms(therm);
	return 0;
}
@@ -313,11 +318,12 @@ nouveau_therm_create_(struct nouveau_object *parent,
int
nouveau_therm_preinit(struct nouveau_therm *therm)
{
	nouveau_therm_ic_ctor(therm);
	nouveau_therm_sensor_ctor(therm);
	nouveau_therm_ic_ctor(therm);
	nouveau_therm_fan_ctor(therm);

	nouveau_therm_mode(therm, NOUVEAU_THERM_CTRL_NONE);
	nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_NONE);
	nouveau_therm_sensor_preinit(therm);
	return 0;
}

+4 −2
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c,
			struct i2c_board_info *info)
{
	struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c);
	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
	struct i2c_client *client;

	request_module("%s%s", I2C_MODULE_PREFIX, info->type);
@@ -46,8 +47,9 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c,
	}

	nv_info(priv,
		"Found an %s at address 0x%x (controlled by lm_sensors)\n",
		info->type, info->addr);
		"Found an %s at address 0x%x (controlled by lm_sensors, "
		"temp offset %+i C)\n",
		info->type, info->addr, sensor->offset_constant);
	priv->ic = client;

	return true;
+48 −19
Original line number Diff line number Diff line
@@ -29,54 +29,83 @@ struct nv40_therm_priv {
	struct nouveau_therm_priv base;
};

enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 };

static enum nv40_sensor_style
nv40_sensor_style(struct nouveau_therm *therm)
{
	struct nouveau_device *device = nv_device(therm);

	switch (device->chipset) {
	case 0x43:
	case 0x44:
	case 0x4a:
	case 0x47:
		return OLD_STYLE;

	case 0x46:
	case 0x49:
	case 0x4b:
	case 0x4e:
	case 0x4c:
	case 0x67:
	case 0x68:
	case 0x63:
		return NEW_STYLE;
	default:
		return INVALID_STYLE;
	}
}

static int
nv40_sensor_setup(struct nouveau_therm *therm)
{
	struct nouveau_device *device = nv_device(therm);
	enum nv40_sensor_style style = nv40_sensor_style(therm);

	/* enable ADC readout and disable the ALARM threshold */
	if (device->chipset >= 0x46) {
	if (style == NEW_STYLE) {
		nv_mask(therm, 0x15b8, 0x80000000, 0);
		nv_wr32(therm, 0x15b0, 0x80003fff);
		mdelay(10); /* wait for the temperature to stabilize */
		mdelay(20); /* wait for the temperature to stabilize */
		return nv_rd32(therm, 0x15b4) & 0x3fff;
	} else {
	} else if (style == OLD_STYLE) {
		nv_wr32(therm, 0x15b0, 0xff);
		mdelay(20); /* wait for the temperature to stabilize */
		return nv_rd32(therm, 0x15b4) & 0xff;
	}
	} else
		return -ENODEV;
}

static int
nv40_temp_get(struct nouveau_therm *therm)
{
	struct nouveau_therm_priv *priv = (void *)therm;
	struct nouveau_device *device = nv_device(therm);
	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
	enum nv40_sensor_style style = nv40_sensor_style(therm);
	int core_temp;

	if (device->chipset >= 0x46) {
	if (style == NEW_STYLE) {
		nv_wr32(therm, 0x15b0, 0x80003fff);
		core_temp = nv_rd32(therm, 0x15b4) & 0x3fff;
	} else {
	} else if (style == OLD_STYLE) {
		nv_wr32(therm, 0x15b0, 0xff);
		core_temp = nv_rd32(therm, 0x15b4) & 0xff;
	}

	/* Setup the sensor if the temperature is 0 */
	if (core_temp == 0)
		core_temp = nv40_sensor_setup(therm);
	} else
		return -ENODEV;

	if (sensor->slope_div == 0)
		sensor->slope_div = 1;
	if (sensor->offset_den == 0)
		sensor->offset_den = 1;
	if (sensor->slope_mult < 1)
		sensor->slope_mult = 1;
	/* if the slope or the offset is unset, do no use the sensor */
	if (!sensor->slope_div || !sensor->slope_mult ||
	    !sensor->offset_num || !sensor->offset_den)
	    return -ENODEV;

	core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
	core_temp = core_temp + sensor->offset_num / sensor->offset_den;
	core_temp = core_temp + sensor->offset_constant - 8;

	/* reserve negative temperatures for errors */
	if (core_temp < 0)
		core_temp = 0;

	return core_temp;
}

Loading