aadb82d26587542e64d4fded2409533286defc9c
[linux-2.6.git] / drivers / thermal / pid_thermal_gov.c
1 /*
2  * drivers/thermal/pid_thermal_gov.c
3  *
4  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
5
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21 #include <linux/module.h>
22 #include <linux/kobject.h>
23 #include <linux/slab.h>
24 #include <linux/thermal.h>
25
26 #include "thermal_core.h"
27
28 #define DRV_NAME        "pid_thermal_gov"
29
30 #define MAX_ERR_TEMP_DEFAULT            9000    /* in mC */
31 #define MAX_ERR_GAIN_DEFAULT            1000
32 #define GAIN_P_DEFAULT                  1000
33 #define GAIN_D_DEFAULT                  0
34 #define COMPENSATION_RATE_DEFAULT       20
35
36 struct pid_thermal_gov_attribute {
37         struct attribute attr;
38         ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
39                         char *buf);
40         ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
41                          const char *buf, size_t count);
42 };
43
44 struct pid_thermal_governor {
45         struct kobject kobj;
46
47         int max_err_temp; /* max error temperature in mC */
48         int max_err_gain; /* max error gain */
49
50         int gain_p; /* proportional gain */
51         int gain_i; /* integral gain */
52         int gain_d; /* derivative gain */
53
54         unsigned long compensation_rate;
55 };
56
57 #define tz_to_gov(t)            \
58         (t->governor_data)
59
60 #define kobj_to_gov(k)          \
61         container_of(k, struct pid_thermal_governor, kobj)
62
63 #define attr_to_gov_attr(a)     \
64         container_of(a, struct pid_thermal_gov_attribute, attr)
65
66 static ssize_t max_err_temp_show(struct kobject *kobj, struct attribute *attr,
67                                  char *buf)
68 {
69         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
70
71         if (!gov)
72                 return -ENODEV;
73
74         return sprintf(buf, "%d\n", gov->max_err_temp);
75 }
76
77 static ssize_t max_err_temp_store(struct kobject *kobj, struct attribute *attr,
78                                   const char *buf, size_t count)
79 {
80         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
81         int val;
82
83         if (!gov)
84                 return -ENODEV;
85
86         if (!sscanf(buf, "%d\n", &val))
87                 return -EINVAL;
88
89         gov->max_err_temp = val;
90         return count;
91 }
92
93 static struct pid_thermal_gov_attribute max_err_temp_attr =
94         __ATTR(max_err_temp, 0644, max_err_temp_show, max_err_temp_store);
95
96 static ssize_t max_err_gain_show(struct kobject *kobj, struct attribute *attr,
97                                  char *buf)
98 {
99         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
100
101         if (!gov)
102                 return -ENODEV;
103
104         return sprintf(buf, "%d\n", gov->max_err_gain);
105 }
106
107 static ssize_t max_err_gain_store(struct kobject *kobj, struct attribute *attr,
108                                   const char *buf, size_t count)
109 {
110         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
111         int val;
112
113         if (!gov)
114                 return -ENODEV;
115
116         if (!sscanf(buf, "%d\n", &val))
117                 return -EINVAL;
118
119         gov->max_err_gain = val;
120         return count;
121 }
122
123 static struct pid_thermal_gov_attribute max_err_gain_attr =
124         __ATTR(max_err_gain, 0644, max_err_gain_show, max_err_gain_store);
125
126 static ssize_t gain_p_show(struct kobject *kobj, struct attribute *attr,
127                            char *buf)
128 {
129         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
130
131         if (!gov)
132                 return -ENODEV;
133
134         return sprintf(buf, "%d\n", gov->gain_p);
135 }
136
137 static ssize_t gain_p_store(struct kobject *kobj, struct attribute *attr,
138                             const char *buf, size_t count)
139 {
140         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
141         int val;
142
143         if (!gov)
144                 return -ENODEV;
145
146         if (!sscanf(buf, "%d\n", &val))
147                 return -EINVAL;
148
149         gov->gain_p = val;
150         return count;
151 }
152
153 static struct pid_thermal_gov_attribute gain_p_attr =
154         __ATTR(gain_p, 0644, gain_p_show, gain_p_store);
155
156 static ssize_t gain_d_show(struct kobject *kobj, struct attribute *attr,
157                            char *buf)
158 {
159         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
160
161         if (!gov)
162                 return -ENODEV;
163
164         return sprintf(buf, "%d\n", gov->gain_d);
165 }
166
167 static ssize_t gain_d_store(struct kobject *kobj, struct attribute *attr,
168                             const char *buf, size_t count)
169 {
170         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
171         int val;
172
173         if (!gov)
174                 return -ENODEV;
175
176         if (!sscanf(buf, "%d\n", &val))
177                 return -EINVAL;
178
179         gov->gain_d = val;
180         return count;
181 }
182
183 static struct pid_thermal_gov_attribute gain_d_attr =
184         __ATTR(gain_d, 0644, gain_d_show, gain_d_store);
185
186 static ssize_t compensation_rate_show(struct kobject *kobj,
187                                       struct attribute *attr, char *buf)
188 {
189         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
190
191         if (!gov)
192                 return -ENODEV;
193
194         return sprintf(buf, "%lu\n", gov->compensation_rate);
195 }
196
197 static ssize_t compensation_rate_store(struct kobject *kobj,
198                                        struct attribute *attr, const char *buf,
199                                        size_t count)
200 {
201         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
202         unsigned long val;
203
204         if (!gov)
205                 return -ENODEV;
206
207         if (!sscanf(buf, "%lu\n", &val))
208                 return -EINVAL;
209
210         gov->compensation_rate = val;
211         return count;
212 }
213
214 static struct pid_thermal_gov_attribute compensation_rate_attr =
215         __ATTR(compensation_rate, 0644,
216                compensation_rate_show, compensation_rate_store);
217
218 static struct attribute *pid_thermal_gov_default_attrs[] = {
219         &max_err_temp_attr.attr,
220         &max_err_gain_attr.attr,
221         &gain_p_attr.attr,
222         &gain_d_attr.attr,
223         &compensation_rate_attr.attr,
224         NULL,
225 };
226
227 static ssize_t pid_thermal_gov_show(struct kobject *kobj,
228                                     struct attribute *attr, char *buf)
229 {
230         struct pid_thermal_gov_attribute *gov_attr = attr_to_gov_attr(attr);
231
232         if (!gov_attr->show)
233                 return -EIO;
234
235         return gov_attr->show(kobj, attr, buf);
236 }
237
238 static ssize_t pid_thermal_gov_store(struct kobject *kobj,
239                                      struct attribute *attr, const char *buf,
240                                      size_t len)
241 {
242         struct pid_thermal_gov_attribute *gov_attr = attr_to_gov_attr(attr);
243
244         if (!gov_attr->store)
245                 return -EIO;
246
247         return gov_attr->store(kobj, attr, buf, len);
248 }
249
250 static const struct sysfs_ops pid_thermal_gov_sysfs_ops = {
251         .show   = pid_thermal_gov_show,
252         .store  = pid_thermal_gov_store,
253 };
254
255 static struct kobj_type pid_thermal_gov_ktype = {
256         .default_attrs  = pid_thermal_gov_default_attrs,
257         .sysfs_ops      = &pid_thermal_gov_sysfs_ops,
258 };
259
260 static int pid_thermal_gov_start(struct thermal_zone_device *tz)
261 {
262         struct pid_thermal_governor *gov;
263         int ret;
264
265         gov = kzalloc(sizeof(struct pid_thermal_governor), GFP_KERNEL);
266         if (!gov) {
267                 dev_err(&tz->device, "%s: Can't alloc governor data\n",
268                         DRV_NAME);
269                 return -ENOMEM;
270         }
271
272         ret = kobject_init_and_add(&gov->kobj, &pid_thermal_gov_ktype,
273                                    &tz->device.kobj, DRV_NAME);
274         if (ret) {
275                 dev_err(&tz->device, "%s: Can't init kobject\n", DRV_NAME);
276                 kobject_put(&gov->kobj);
277                 kfree(gov);
278                 return ret;
279         }
280
281         gov->max_err_temp = MAX_ERR_TEMP_DEFAULT;
282         gov->max_err_gain = MAX_ERR_GAIN_DEFAULT;
283         gov->gain_p = GAIN_P_DEFAULT;
284         gov->gain_d = GAIN_D_DEFAULT;
285         gov->compensation_rate = COMPENSATION_RATE_DEFAULT;
286         tz->governor_data = gov;
287
288         return 0;
289 }
290
291 static void pid_thermal_gov_stop(struct thermal_zone_device *tz)
292 {
293         struct pid_thermal_governor *gov = tz_to_gov(tz);
294
295         if (!gov)
296                 return;
297
298         kobject_put(&gov->kobj);
299         kfree(gov);
300 }
301
302 static void pid_thermal_gov_update_passive(struct thermal_zone_device *tz,
303                                            enum thermal_trip_type trip_type,
304                                            unsigned long old_target,
305                                            unsigned long target)
306 {
307         if ((trip_type != THERMAL_TRIP_PASSIVE) &&
308                         (trip_type != THERMAL_TRIPS_NONE))
309                 return;
310
311         if ((!old_target || old_target == THERMAL_NO_TARGET) &&
312                         (target && target != THERMAL_NO_TARGET))
313                 tz->passive++;
314         else if ((old_target && old_target != THERMAL_NO_TARGET) &&
315                         (!target || target == THERMAL_NO_TARGET))
316                 tz->passive--;
317 }
318
319 static unsigned long
320 pid_thermal_gov_get_target(struct thermal_zone_device *tz,
321                            struct thermal_cooling_device *cdev,
322                            enum thermal_trip_type trip_type,
323                            unsigned long trip_temp)
324 {
325         struct pid_thermal_governor *gov = tz_to_gov(tz);
326         int last_temperature = tz->passive ? tz->last_temperature : trip_temp;
327         int passive_delay = tz->passive ? tz->passive_delay : MSEC_PER_SEC;
328         s64 proportional, derivative, sum_err, max_err;
329         unsigned long max_state, cur_state, target, compensation;
330
331         if (cdev->ops->get_max_state(cdev, &max_state) < 0)
332                 return 0;
333
334         if (cdev->ops->get_cur_state(cdev, &cur_state) < 0)
335                 return 0;
336
337         /* Calculate proportional term */
338         proportional = (s64)tz->temperature - (s64)trip_temp;
339         proportional *= gov->gain_p;
340
341         /* Calculate derivative term */
342         derivative = (s64)tz->temperature - (s64)last_temperature;
343         derivative *= gov->gain_d;
344         derivative *= MSEC_PER_SEC;
345         derivative = div64_s64(derivative, passive_delay);
346
347         max_err = (s64)gov->max_err_temp * (s64)gov->max_err_gain;
348         sum_err = proportional + derivative;
349         sum_err = max_t(s64, sum_err, 0);
350         if (sum_err == 0)
351                 return 0;
352
353         sum_err = min_t(s64, sum_err, max_err);
354         if (sum_err == max_err)
355                 return max_state;
356
357         sum_err = sum_err * max_state + max_err - 1;
358         target = (unsigned long)div64_s64(sum_err, max_err);
359
360         /* Apply compensation */
361         if (target == cur_state)
362                 return target;
363
364         if (target > cur_state) {
365                 compensation = DIV_ROUND_UP(gov->compensation_rate *
366                                             (target - cur_state), 100);
367                 target = min(cur_state + compensation, max_state);
368         } else if (target < cur_state) {
369                 compensation = DIV_ROUND_UP(gov->compensation_rate *
370                                             (cur_state - target), 100);
371                 target = (cur_state > compensation) ?
372                          (cur_state - compensation) : 0;
373         }
374
375         return target;
376 }
377
378 static int pid_thermal_gov_throttle(struct thermal_zone_device *tz, int trip)
379 {
380         struct thermal_instance *instance;
381         enum thermal_trip_type trip_type;
382         unsigned long trip_temp, target;
383
384         tz->ops->get_trip_type(tz, trip, &trip_type);
385         tz->ops->get_trip_temp(tz, trip, &trip_temp);
386
387         mutex_lock(&tz->lock);
388
389         list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
390                 if (instance->trip != trip)
391                         continue;
392
393                 target = pid_thermal_gov_get_target(tz, instance->cdev,
394                                                     trip_type, trip_temp);
395                 if (target >= instance->upper)
396                         target = instance->upper;
397                 else if (target < instance->lower)
398                         target = instance->lower;
399
400                 if (tz->temperature < trip_temp) {
401                         if ((target == instance->lower) &&
402                                         (instance->target == instance->lower ||
403                                         instance->target == THERMAL_NO_TARGET))
404                                 target = THERMAL_NO_TARGET;
405                 }
406
407                 if (instance->target == target)
408                         continue;
409
410                 pid_thermal_gov_update_passive(tz, trip_type, instance->target,
411                                                target);
412                 instance->target = target;
413                 instance->cdev->updated = false;
414         }
415
416         list_for_each_entry(instance, &tz->thermal_instances, tz_node)
417                 thermal_cdev_update(instance->cdev);
418
419         mutex_unlock(&tz->lock);
420
421         return 0;
422 }
423
424 static struct thermal_governor pid_thermal_gov = {
425         .name           = DRV_NAME,
426         .start          = pid_thermal_gov_start,
427         .stop           = pid_thermal_gov_stop,
428         .throttle       = pid_thermal_gov_throttle,
429         .owner          = THIS_MODULE,
430 };
431
432 static int __init pid_thermal_gov_init(void)
433 {
434         return thermal_register_governor(&pid_thermal_gov);
435 }
436 fs_initcall(pid_thermal_gov_init);
437
438 static void __exit pid_thermal_gov_exit(void)
439 {
440         thermal_unregister_governor(&pid_thermal_gov);
441 }
442 module_exit(pid_thermal_gov_exit);
443
444 MODULE_AUTHOR("Jinyoung Park <jinyoungp@nvidia.com>");
445 MODULE_DESCRIPTION("PID thermal governor");
446 MODULE_LICENSE("GPL");