Commit 2f951a5d authored by Martin Peres's avatar Martin Peres Committed by Ben Skeggs

drm/nouveau/therm: add support for fan-control modes

For now, only 2 control modes are available:
- NONE: The fan is never touched (default)
- MANUAL: The fan is set to the user-defined fan speed (pwm1)

This patch introduces a distinction between ptherm internal fan management
and external fan management. The latter is bound to respect the fan mode
while the first can still select the speed it wants unless the NONE mode
is selected. This is important for automatic fan management.
Signed-off-by: default avatarMartin Peres <martin.peres@labri.fr>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent c9cbf135
...@@ -40,6 +40,8 @@ nouveau_therm_attr_get(struct nouveau_therm *therm, ...@@ -40,6 +40,8 @@ nouveau_therm_attr_get(struct nouveau_therm *therm,
return priv->bios_fan.min_duty; return priv->bios_fan.min_duty;
case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY: case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY:
return priv->bios_fan.max_duty; return priv->bios_fan.max_duty;
case NOUVEAU_THERM_ATTR_FAN_MODE:
return priv->fan.mode;
case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
return priv->bios_sensor.thrs_fan_boost.temp; return priv->bios_sensor.thrs_fan_boost.temp;
case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST: case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST:
...@@ -82,6 +84,8 @@ nouveau_therm_attr_set(struct nouveau_therm *therm, ...@@ -82,6 +84,8 @@ nouveau_therm_attr_set(struct nouveau_therm *therm,
value = priv->bios_fan.min_duty; value = priv->bios_fan.min_duty;
priv->bios_fan.max_duty = value; priv->bios_fan.max_duty = value;
return 0; return 0;
case NOUVEAU_THERM_ATTR_FAN_MODE:
return nouveau_therm_fan_set_mode(therm, value);
case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST: case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
priv->bios_sensor.thrs_fan_boost.temp = value; priv->bios_sensor.thrs_fan_boost.temp = value;
return 0; return 0;
......
...@@ -69,6 +69,9 @@ nouveau_therm_fan_set(struct nouveau_therm *therm, int percent) ...@@ -69,6 +69,9 @@ nouveau_therm_fan_set(struct nouveau_therm *therm, int percent)
u32 divs, duty; u32 divs, duty;
int ret; int ret;
if (priv->fan.mode == FAN_CONTROL_NONE)
return -EINVAL;
if (!priv->fan.pwm_set) if (!priv->fan.pwm_set)
return -ENODEV; return -ENODEV;
...@@ -138,7 +141,52 @@ nouveau_therm_fan_sense(struct nouveau_therm *therm) ...@@ -138,7 +141,52 @@ nouveau_therm_fan_sense(struct nouveau_therm *therm)
return 0; return 0;
} }
static void int
nouveau_therm_fan_set_mode(struct nouveau_therm *therm,
enum nouveau_therm_fan_mode mode)
{
struct nouveau_therm_priv *priv = (void *)therm;
if (priv->fan.mode == mode)
return 0;
if (mode < FAN_CONTROL_NONE || mode >= FAN_CONTROL_NR)
return -EINVAL;
switch (mode)
{
case FAN_CONTROL_NONE:
nv_info(therm, "switch fan to no-control mode\n");
break;
case FAN_CONTROL_MANUAL:
nv_info(therm, "switch fan to manual mode\n");
break;
case FAN_CONTROL_NR:
break;
}
priv->fan.mode = mode;
return 0;
}
int
nouveau_therm_fan_user_get(struct nouveau_therm *therm)
{
return nouveau_therm_fan_get(therm);
}
int
nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent)
{
struct nouveau_therm_priv *priv = (void *)therm;
if (priv->fan.mode != FAN_CONTROL_MANUAL)
return -EINVAL;
return nouveau_therm_fan_set(therm, percent);
}
void
nouveau_therm_fan_set_defaults(struct nouveau_therm *therm) nouveau_therm_fan_set_defaults(struct nouveau_therm *therm)
{ {
struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_therm_priv *priv = (void *)therm;
...@@ -180,5 +228,7 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm) ...@@ -180,5 +228,7 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm)
nv_error(therm, "parsing the thermal table failed\n"); nv_error(therm, "parsing the thermal table failed\n");
nouveau_therm_fan_safety_checks(therm); nouveau_therm_fan_safety_checks(therm);
nouveau_therm_fan_set_mode(therm, FAN_CONTROL_NONE);
return 0; return 0;
} }
...@@ -142,8 +142,8 @@ nv40_therm_ctor(struct nouveau_object *parent, ...@@ -142,8 +142,8 @@ nv40_therm_ctor(struct nouveau_object *parent,
priv->fan.pwm_set = nv40_fan_pwm_set; priv->fan.pwm_set = nv40_fan_pwm_set;
therm->temp_get = nv40_temp_get; therm->temp_get = nv40_temp_get;
therm->fan_get = nouveau_therm_fan_get; therm->fan_get = nouveau_therm_fan_user_get;
therm->fan_set = nouveau_therm_fan_set; therm->fan_set = nouveau_therm_fan_user_set;
therm->fan_sense = nouveau_therm_fan_sense; therm->fan_sense = nouveau_therm_fan_sense;
therm->attr_get = nouveau_therm_attr_get; therm->attr_get = nouveau_therm_attr_get;
therm->attr_set = nouveau_therm_attr_set; therm->attr_set = nouveau_therm_attr_set;
......
...@@ -136,8 +136,8 @@ nv50_therm_ctor(struct nouveau_object *parent, ...@@ -136,8 +136,8 @@ nv50_therm_ctor(struct nouveau_object *parent,
priv->fan.pwm_clock = nv50_fan_pwm_clock; priv->fan.pwm_clock = nv50_fan_pwm_clock;
therm->temp_get = nv50_temp_get; therm->temp_get = nv50_temp_get;
therm->fan_get = nouveau_therm_fan_get; therm->fan_get = nouveau_therm_fan_user_get;
therm->fan_set = nouveau_therm_fan_set; therm->fan_set = nouveau_therm_fan_user_set;
therm->fan_sense = nouveau_therm_fan_sense; therm->fan_sense = nouveau_therm_fan_sense;
therm->attr_get = nouveau_therm_attr_get; therm->attr_get = nouveau_therm_attr_get;
therm->attr_set = nouveau_therm_attr_set; therm->attr_set = nouveau_therm_attr_set;
......
...@@ -38,6 +38,7 @@ struct nouveau_therm_priv { ...@@ -38,6 +38,7 @@ struct nouveau_therm_priv {
/* fan priv */ /* fan priv */
struct { struct {
enum nouveau_therm_fan_mode mode;
int percent; int percent;
int (*pwm_get)(struct nouveau_therm *, int line, u32*, u32*); int (*pwm_get)(struct nouveau_therm *, int line, u32*, u32*);
...@@ -63,5 +64,10 @@ int nouveau_therm_sensor_ctor(struct nouveau_therm *therm); ...@@ -63,5 +64,10 @@ 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_get(struct nouveau_therm *therm); int nouveau_therm_fan_get(struct nouveau_therm *therm);
int nouveau_therm_fan_set(struct nouveau_therm *therm, int percent); int nouveau_therm_fan_set(struct nouveau_therm *therm, int percent);
int nouveau_therm_fan_user_get(struct nouveau_therm *therm);
int nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent);
int nouveau_therm_fan_set_mode(struct nouveau_therm *therm,
enum nouveau_therm_fan_mode mode);
int nouveau_therm_fan_sense(struct nouveau_therm *therm); int nouveau_therm_fan_sense(struct nouveau_therm *therm);
...@@ -503,6 +503,45 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, ...@@ -503,6 +503,45 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr,
static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input, static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input,
NULL, 0); NULL, 0);
static ssize_t
nouveau_hwmon_get_pwm1_enable(struct device *d,
struct device_attribute *a, char *buf)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
int ret;
ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MODE);
if (ret < 0)
return ret;
return sprintf(buf, "%i\n", ret);
}
static ssize_t
nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a,
const char *buf, size_t count)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
long value;
int ret;
if (strict_strtol(buf, 10, &value) == -EINVAL)
return -EINVAL;
ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value);
if (ret)
return ret;
else
return count;
}
static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
nouveau_hwmon_get_pwm1_enable,
nouveau_hwmon_set_pwm1_enable, 0);
static ssize_t static ssize_t
nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf) nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf)
{ {
...@@ -638,6 +677,7 @@ static struct attribute *hwmon_fan_rpm_attributes[] = { ...@@ -638,6 +677,7 @@ static struct attribute *hwmon_fan_rpm_attributes[] = {
NULL NULL
}; };
static struct attribute *hwmon_pwm_fan_attributes[] = { static struct attribute *hwmon_pwm_fan_attributes[] = {
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm1_min.dev_attr.attr, &sensor_dev_attr_pwm1_min.dev_attr.attr,
&sensor_dev_attr_pwm1_max.dev_attr.attr, &sensor_dev_attr_pwm1_max.dev_attr.attr,
......
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