|
@@ -75,6 +75,58 @@ static struct thermal_governor *__find_governor(const char *name)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * bind_previous_governor() - bind the previous governor of the thermal zone
|
|
|
+ * @tz: a valid pointer to a struct thermal_zone_device
|
|
|
+ * @failed_gov_name: the name of the governor that failed to register
|
|
|
+ *
|
|
|
+ * Register the previous governor of the thermal zone after a new
|
|
|
+ * governor has failed to be bound.
|
|
|
+ */
|
|
|
+static void bind_previous_governor(struct thermal_zone_device *tz,
|
|
|
+ const char *failed_gov_name)
|
|
|
+{
|
|
|
+ if (tz->governor && tz->governor->bind_to_tz) {
|
|
|
+ if (tz->governor->bind_to_tz(tz)) {
|
|
|
+ dev_err(&tz->device,
|
|
|
+ "governor %s failed to bind and the previous one (%s) failed to bind again, thermal zone %s has no governor\n",
|
|
|
+ failed_gov_name, tz->governor->name, tz->type);
|
|
|
+ tz->governor = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * thermal_set_governor() - Switch to another governor
|
|
|
+ * @tz: a valid pointer to a struct thermal_zone_device
|
|
|
+ * @new_gov: pointer to the new governor
|
|
|
+ *
|
|
|
+ * Change the governor of thermal zone @tz.
|
|
|
+ *
|
|
|
+ * Return: 0 on success, an error if the new governor's bind_to_tz() failed.
|
|
|
+ */
|
|
|
+static int thermal_set_governor(struct thermal_zone_device *tz,
|
|
|
+ struct thermal_governor *new_gov)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (tz->governor && tz->governor->unbind_from_tz)
|
|
|
+ tz->governor->unbind_from_tz(tz);
|
|
|
+
|
|
|
+ if (new_gov && new_gov->bind_to_tz) {
|
|
|
+ ret = new_gov->bind_to_tz(tz);
|
|
|
+ if (ret) {
|
|
|
+ bind_previous_governor(tz, new_gov->name);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ tz->governor = new_gov;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
int thermal_register_governor(struct thermal_governor *governor)
|
|
|
{
|
|
|
int err;
|
|
@@ -107,8 +159,15 @@ int thermal_register_governor(struct thermal_governor *governor)
|
|
|
|
|
|
name = pos->tzp->governor_name;
|
|
|
|
|
|
- if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH))
|
|
|
- pos->governor = governor;
|
|
|
+ if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH)) {
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = thermal_set_governor(pos, governor);
|
|
|
+ if (ret)
|
|
|
+ dev_err(&pos->device,
|
|
|
+ "Failed to set governor %s for thermal zone %s: %d\n",
|
|
|
+ governor->name, pos->type, ret);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
mutex_unlock(&thermal_list_lock);
|
|
@@ -134,7 +193,7 @@ void thermal_unregister_governor(struct thermal_governor *governor)
|
|
|
list_for_each_entry(pos, &thermal_tz_list, node) {
|
|
|
if (!strncasecmp(pos->governor->name, governor->name,
|
|
|
THERMAL_NAME_LENGTH))
|
|
|
- pos->governor = NULL;
|
|
|
+ thermal_set_governor(pos, NULL);
|
|
|
}
|
|
|
|
|
|
mutex_unlock(&thermal_list_lock);
|
|
@@ -770,8 +829,9 @@ policy_store(struct device *dev, struct device_attribute *attr,
|
|
|
if (!gov)
|
|
|
goto exit;
|
|
|
|
|
|
- tz->governor = gov;
|
|
|
- ret = count;
|
|
|
+ ret = thermal_set_governor(tz, gov);
|
|
|
+ if (!ret)
|
|
|
+ ret = count;
|
|
|
|
|
|
exit:
|
|
|
mutex_unlock(&tz->lock);
|
|
@@ -1512,6 +1572,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
|
|
|
int result;
|
|
|
int count;
|
|
|
int passive = 0;
|
|
|
+ struct thermal_governor *governor;
|
|
|
|
|
|
if (type && strlen(type) >= THERMAL_NAME_LENGTH)
|
|
|
return ERR_PTR(-EINVAL);
|
|
@@ -1602,9 +1663,15 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
|
|
|
mutex_lock(&thermal_governor_lock);
|
|
|
|
|
|
if (tz->tzp)
|
|
|
- tz->governor = __find_governor(tz->tzp->governor_name);
|
|
|
+ governor = __find_governor(tz->tzp->governor_name);
|
|
|
else
|
|
|
- tz->governor = def_governor;
|
|
|
+ governor = def_governor;
|
|
|
+
|
|
|
+ result = thermal_set_governor(tz, governor);
|
|
|
+ if (result) {
|
|
|
+ mutex_unlock(&thermal_governor_lock);
|
|
|
+ goto unregister;
|
|
|
+ }
|
|
|
|
|
|
mutex_unlock(&thermal_governor_lock);
|
|
|
|
|
@@ -1693,7 +1760,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
|
|
|
device_remove_file(&tz->device, &dev_attr_mode);
|
|
|
device_remove_file(&tz->device, &dev_attr_policy);
|
|
|
remove_trip_attrs(tz);
|
|
|
- tz->governor = NULL;
|
|
|
+ thermal_set_governor(tz, NULL);
|
|
|
|
|
|
thermal_remove_hwmon_sysfs(tz);
|
|
|
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
|