Skip to content

Commit e33df1d

Browse files
Javi MerinoEduardo Valentin
authored andcommitted
thermal: let governors have private data for each thermal zone
A governor may need to store its current state between calls to throttle(). That state depends on the thermal zone, so store it as private data in struct thermal_zone_device. The governors may have two new ops: bind_to_tz() and unbind_from_tz(). When provided, these functions let governors do some initialization and teardown when they are bound/unbound to a tz and possibly store that information in the governor_data field of the struct thermal_zone_device. Cc: Zhang Rui <rui.zhang@intel.com> Cc: Eduardo Valentin <edubezval@gmail.com> Signed-off-by: Javi Merino <javi.merino@arm.com> Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
1 parent c610afa commit e33df1d

File tree

2 files changed

+84
-8
lines changed

2 files changed

+84
-8
lines changed

drivers/thermal/thermal_core.c

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,58 @@ static struct thermal_governor *__find_governor(const char *name)
7575
return NULL;
7676
}
7777

78+
/**
79+
* bind_previous_governor() - bind the previous governor of the thermal zone
80+
* @tz: a valid pointer to a struct thermal_zone_device
81+
* @failed_gov_name: the name of the governor that failed to register
82+
*
83+
* Register the previous governor of the thermal zone after a new
84+
* governor has failed to be bound.
85+
*/
86+
static void bind_previous_governor(struct thermal_zone_device *tz,
87+
const char *failed_gov_name)
88+
{
89+
if (tz->governor && tz->governor->bind_to_tz) {
90+
if (tz->governor->bind_to_tz(tz)) {
91+
dev_err(&tz->device,
92+
"governor %s failed to bind and the previous one (%s) failed to bind again, thermal zone %s has no governor\n",
93+
failed_gov_name, tz->governor->name, tz->type);
94+
tz->governor = NULL;
95+
}
96+
}
97+
}
98+
99+
/**
100+
* thermal_set_governor() - Switch to another governor
101+
* @tz: a valid pointer to a struct thermal_zone_device
102+
* @new_gov: pointer to the new governor
103+
*
104+
* Change the governor of thermal zone @tz.
105+
*
106+
* Return: 0 on success, an error if the new governor's bind_to_tz() failed.
107+
*/
108+
static int thermal_set_governor(struct thermal_zone_device *tz,
109+
struct thermal_governor *new_gov)
110+
{
111+
int ret = 0;
112+
113+
if (tz->governor && tz->governor->unbind_from_tz)
114+
tz->governor->unbind_from_tz(tz);
115+
116+
if (new_gov && new_gov->bind_to_tz) {
117+
ret = new_gov->bind_to_tz(tz);
118+
if (ret) {
119+
bind_previous_governor(tz, new_gov->name);
120+
121+
return ret;
122+
}
123+
}
124+
125+
tz->governor = new_gov;
126+
127+
return ret;
128+
}
129+
78130
int thermal_register_governor(struct thermal_governor *governor)
79131
{
80132
int err;
@@ -107,8 +159,15 @@ int thermal_register_governor(struct thermal_governor *governor)
107159

108160
name = pos->tzp->governor_name;
109161

110-
if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH))
111-
pos->governor = governor;
162+
if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH)) {
163+
int ret;
164+
165+
ret = thermal_set_governor(pos, governor);
166+
if (ret)
167+
dev_err(&pos->device,
168+
"Failed to set governor %s for thermal zone %s: %d\n",
169+
governor->name, pos->type, ret);
170+
}
112171
}
113172

114173
mutex_unlock(&thermal_list_lock);
@@ -134,7 +193,7 @@ void thermal_unregister_governor(struct thermal_governor *governor)
134193
list_for_each_entry(pos, &thermal_tz_list, node) {
135194
if (!strncasecmp(pos->governor->name, governor->name,
136195
THERMAL_NAME_LENGTH))
137-
pos->governor = NULL;
196+
thermal_set_governor(pos, NULL);
138197
}
139198

140199
mutex_unlock(&thermal_list_lock);
@@ -770,8 +829,9 @@ policy_store(struct device *dev, struct device_attribute *attr,
770829
if (!gov)
771830
goto exit;
772831

773-
tz->governor = gov;
774-
ret = count;
832+
ret = thermal_set_governor(tz, gov);
833+
if (!ret)
834+
ret = count;
775835

776836
exit:
777837
mutex_unlock(&tz->lock);
@@ -1512,6 +1572,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
15121572
int result;
15131573
int count;
15141574
int passive = 0;
1575+
struct thermal_governor *governor;
15151576

15161577
if (type && strlen(type) >= THERMAL_NAME_LENGTH)
15171578
return ERR_PTR(-EINVAL);
@@ -1602,9 +1663,15 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
16021663
mutex_lock(&thermal_governor_lock);
16031664

16041665
if (tz->tzp)
1605-
tz->governor = __find_governor(tz->tzp->governor_name);
1666+
governor = __find_governor(tz->tzp->governor_name);
16061667
else
1607-
tz->governor = def_governor;
1668+
governor = def_governor;
1669+
1670+
result = thermal_set_governor(tz, governor);
1671+
if (result) {
1672+
mutex_unlock(&thermal_governor_lock);
1673+
goto unregister;
1674+
}
16081675

16091676
mutex_unlock(&thermal_governor_lock);
16101677

@@ -1693,7 +1760,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
16931760
device_remove_file(&tz->device, &dev_attr_mode);
16941761
device_remove_file(&tz->device, &dev_attr_policy);
16951762
remove_trip_attrs(tz);
1696-
tz->governor = NULL;
1763+
thermal_set_governor(tz, NULL);
16971764

16981765
thermal_remove_hwmon_sysfs(tz);
16991766
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);

include/linux/thermal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ struct thermal_attr {
165165
* @ops: operations this &thermal_zone_device supports
166166
* @tzp: thermal zone parameters
167167
* @governor: pointer to the governor for this thermal zone
168+
* @governor_data: private pointer for governor data
168169
* @thermal_instances: list of &struct thermal_instance of this thermal zone
169170
* @idr: &struct idr to generate unique id for this zone's cooling
170171
* devices
@@ -191,6 +192,7 @@ struct thermal_zone_device {
191192
struct thermal_zone_device_ops *ops;
192193
const struct thermal_zone_params *tzp;
193194
struct thermal_governor *governor;
195+
void *governor_data;
194196
struct list_head thermal_instances;
195197
struct idr idr;
196198
struct mutex lock;
@@ -201,12 +203,19 @@ struct thermal_zone_device {
201203
/**
202204
* struct thermal_governor - structure that holds thermal governor information
203205
* @name: name of the governor
206+
* @bind_to_tz: callback called when binding to a thermal zone. If it
207+
* returns 0, the governor is bound to the thermal zone,
208+
* otherwise it fails.
209+
* @unbind_from_tz: callback called when a governor is unbound from a
210+
* thermal zone.
204211
* @throttle: callback called for every trip point even if temperature is
205212
* below the trip point temperature
206213
* @governor_list: node in thermal_governor_list (in thermal_core.c)
207214
*/
208215
struct thermal_governor {
209216
char name[THERMAL_NAME_LENGTH];
217+
int (*bind_to_tz)(struct thermal_zone_device *tz);
218+
void (*unbind_from_tz)(struct thermal_zone_device *tz);
210219
int (*throttle)(struct thermal_zone_device *tz, int trip);
211220
struct list_head governor_list;
212221
};

0 commit comments

Comments
 (0)