7912f188b46e5c9748b4b89745be14b049efa14f
[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         /* max derivative output, percentage of max error */
55         unsigned long max_dout;
56
57         unsigned long compensation_rate;
58 };
59
60 #define tz_to_gov(t)            \
61         (t->governor_data)
62
63 #define kobj_to_gov(k)          \
64         container_of(k, struct pid_thermal_governor, kobj)
65
66 #define attr_to_gov_attr(a)     \
67         container_of(a, struct pid_thermal_gov_attribute, attr)
68
69 static ssize_t max_err_temp_show(struct kobject *kobj, struct attribute *attr,
70                                  char *buf)
71 {
72         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
73
74         if (!gov)
75                 return -ENODEV;
76
77         return sprintf(buf, "%d\n", gov->max_err_temp);
78 }
79
80 static ssize_t max_err_temp_store(struct kobject *kobj, struct attribute *attr,
81                                   const char *buf, size_t count)
82 {
83         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
84         int val;
85
86         if (!gov)
87                 return -ENODEV;
88
89         if (!sscanf(buf, "%d\n", &val))
90                 return -EINVAL;
91
92         gov->max_err_temp = val;
93         return count;
94 }
95
96 static struct pid_thermal_gov_attribute max_err_temp_attr =
97         __ATTR(max_err_temp, 0644, max_err_temp_show, max_err_temp_store);
98
99 static ssize_t max_err_gain_show(struct kobject *kobj, struct attribute *attr,
100                                  char *buf)
101 {
102         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
103
104         if (!gov)
105                 return -ENODEV;
106
107         return sprintf(buf, "%d\n", gov->max_err_gain);
108 }
109
110 static ssize_t max_err_gain_store(struct kobject *kobj, struct attribute *attr,
111                                   const char *buf, size_t count)
112 {
113         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
114         int val;
115
116         if (!gov)
117                 return -ENODEV;
118
119         if (!sscanf(buf, "%d\n", &val))
120                 return -EINVAL;
121
122         gov->max_err_gain = val;
123         return count;
124 }
125
126 static struct pid_thermal_gov_attribute max_err_gain_attr =
127         __ATTR(max_err_gain, 0644, max_err_gain_show, max_err_gain_store);
128
129 static ssize_t max_dout_show(struct kobject *kobj,
130                              struct attribute *attr, char *buf)
131 {
132         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
133
134         if (!gov)
135                 return -ENODEV;
136
137         return sprintf(buf, "%lu\n", gov->max_dout);
138 }
139
140 static ssize_t max_dout_store(struct kobject *kobj, struct attribute *attr,
141                               const char *buf, size_t count)
142 {
143         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
144         unsigned long val;
145
146         if (!gov)
147                 return -ENODEV;
148
149         if (!sscanf(buf, "%lu\n", &val))
150                 return -EINVAL;
151
152         gov->max_dout = val;
153         return count;
154 }
155
156 static struct pid_thermal_gov_attribute max_dout_attr =
157         __ATTR(max_dout, 0644, max_dout_show, max_dout_store);
158
159 static ssize_t gain_p_show(struct kobject *kobj, struct attribute *attr,
160                            char *buf)
161 {
162         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
163
164         if (!gov)
165                 return -ENODEV;
166
167         return sprintf(buf, "%d\n", gov->gain_p);
168 }
169
170 static ssize_t gain_p_store(struct kobject *kobj, struct attribute *attr,
171                             const char *buf, size_t count)
172 {
173         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
174         int val;
175
176         if (!gov)
177                 return -ENODEV;
178
179         if (!sscanf(buf, "%d\n", &val))
180                 return -EINVAL;
181
182         gov->gain_p = val;
183         return count;
184 }
185
186 static struct pid_thermal_gov_attribute gain_p_attr =
187         __ATTR(gain_p, 0644, gain_p_show, gain_p_store);
188
189 static ssize_t gain_d_show(struct kobject *kobj, struct attribute *attr,
190                            char *buf)
191 {
192         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
193
194         if (!gov)
195                 return -ENODEV;
196
197         return sprintf(buf, "%d\n", gov->gain_d);
198 }
199
200 static ssize_t gain_d_store(struct kobject *kobj, struct attribute *attr,
201                             const char *buf, size_t count)
202 {
203         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
204         int val;
205
206         if (!gov)
207                 return -ENODEV;
208
209         if (!sscanf(buf, "%d\n", &val))
210                 return -EINVAL;
211
212         gov->gain_d = val;
213         return count;
214 }
215
216 static struct pid_thermal_gov_attribute gain_d_attr =
217         __ATTR(gain_d, 0644, gain_d_show, gain_d_store);
218
219 static ssize_t compensation_rate_show(struct kobject *kobj,
220                                       struct attribute *attr, char *buf)
221 {
222         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
223
224         if (!gov)
225                 return -ENODEV;
226
227         return sprintf(buf, "%lu\n", gov->compensation_rate);
228 }
229
230 static ssize_t compensation_rate_store(struct kobject *kobj,
231                                        struct attribute *attr, const char *buf,
232                                        size_t count)
233 {
234         struct pid_thermal_governor *gov = kobj_to_gov(kobj);
235         unsigned long val;
236
237         if (!gov)
238                 return -ENODEV;
239
240         if (!sscanf(buf, "%lu\n", &val))
241                 return -EINVAL;
242
243         gov->compensation_rate = val;
244         return count;
245 }
246
247 static struct pid_thermal_gov_attribute compensation_rate_attr =
248         __ATTR(compensation_rate, 0644,
249                compensation_rate_show, compensation_rate_store);
250
251 static struct attribute *pid_thermal_gov_default_attrs[] = {
252         &max_err_temp_attr.attr,
253         &max_err_gain_attr.attr,
254         &gain_p_attr.attr,
255         &gain_d_attr.attr,
256         &max_dout_attr.attr,
257         &compensation_rate_attr.attr,
258         NULL,
259 };
260
261 static ssize_t pid_thermal_gov_show(struct kobject *kobj,
262                                     struct attribute *attr, char *buf)
263 {
264         struct pid_thermal_gov_attribute *gov_attr = attr_to_gov_attr(attr);
265
266         if (!gov_attr->show)
267                 return -EIO;
268
269         return gov_attr->show(kobj, attr, buf);
270 }
271
272 static ssize_t pid_thermal_gov_store(struct kobject *kobj,
273                                      struct attribute *attr, const char *buf,
274                                      size_t len)
275 {
276         struct pid_thermal_gov_attribute *gov_attr = attr_to_gov_attr(attr);
277
278         if (!gov_attr->store)
279                 return -EIO;
280
281         return gov_attr->store(kobj, attr, buf, len);
282 }
283
284 static const struct sysfs_ops pid_thermal_gov_sysfs_ops = {
285         .show   = pid_thermal_gov_show,
286         .store  = pid_thermal_gov_store,
287 };
288
289 static struct kobj_type pid_thermal_gov_ktype = {
290         .default_attrs  = pid_thermal_gov_default_attrs,
291         .sysfs_ops      = &pid_thermal_gov_sysfs_ops,
292 };
293
294 static int pid_thermal_gov_start(struct thermal_zone_device *tz)
295 {
296         struct pid_thermal_governor *gov;
297         int ret;
298
299         gov = kzalloc(sizeof(struct pid_thermal_governor), GFP_KERNEL);
300         if (!gov) {
301                 dev_err(&tz->device, "%s: Can't alloc governor data\n",
302                         DRV_NAME);
303                 return -ENOMEM;
304         }
305
306         ret = kobject_init_and_add(&gov->kobj, &pid_thermal_gov_ktype,
307                                    &tz->device.kobj, DRV_NAME);
308         if (ret) {
309                 dev_err(&tz->device, "%s: Can't init kobject\n", DRV_NAME);
310                 kobject_put(&gov->kobj);
311                 kfree(gov);
312                 return ret;
313         }
314
315         gov->max_err_temp = MAX_ERR_TEMP_DEFAULT;
316         gov->max_err_gain = MAX_ERR_GAIN_DEFAULT;
317         gov->gain_p = GAIN_P_DEFAULT;
318         gov->gain_d = GAIN_D_DEFAULT;
319         gov->compensation_rate = COMPENSATION_RATE_DEFAULT;
320         tz->governor_data = gov;
321
322         return 0;
323 }
324
325 static void pid_thermal_gov_stop(struct thermal_zone_device *tz)
326 {
327         struct pid_thermal_governor *gov = tz_to_gov(tz);
328
329         if (!gov)
330                 return;
331
332         kobject_put(&gov->kobj);
333         kfree(gov);
334 }
335
336 static void pid_thermal_gov_update_passive(struct thermal_zone_device *tz,
337                                            enum thermal_trip_type trip_type,
338                                            unsigned long old,
339                                            unsigned long new)
340 {
341         if ((trip_type != THERMAL_TRIP_PASSIVE) &&
342                         (trip_type != THERMAL_TRIPS_NONE))
343                 return;
344
345         if ((old == THERMAL_NO_TARGET) && (new != THERMAL_NO_TARGET))
346                 tz->passive++;
347         else if ((old != THERMAL_NO_TARGET) && (new == THERMAL_NO_TARGET))
348                 tz->passive--;
349 }
350
351 static unsigned long
352 pid_thermal_gov_get_target(struct thermal_zone_device *tz,
353                            struct thermal_cooling_device *cdev,
354                            enum thermal_trip_type trip_type,
355                            unsigned long trip_temp)
356 {
357         struct pid_thermal_governor *gov = tz_to_gov(tz);
358         int last_temperature = tz->passive ? tz->last_temperature : trip_temp;
359         int passive_delay = tz->passive ? tz->passive_delay : MSEC_PER_SEC;
360         s64 proportional, derivative, sum_err, max_err;
361         unsigned long max_state, cur_state, target, compensation;
362
363         if (cdev->ops->get_max_state(cdev, &max_state) < 0)
364                 return 0;
365
366         if (cdev->ops->get_cur_state(cdev, &cur_state) < 0)
367                 return 0;
368
369         max_err = (s64)gov->max_err_temp * (s64)gov->max_err_gain;
370
371         /* Calculate proportional term */
372         proportional = (s64)tz->temperature - (s64)trip_temp;
373         proportional *= gov->gain_p;
374
375         /* Calculate derivative term */
376         derivative = (s64)tz->temperature - (s64)last_temperature;
377         derivative *= gov->gain_d;
378         derivative *= MSEC_PER_SEC;
379         derivative = div64_s64(derivative, passive_delay);
380         if (gov->max_dout) {
381                 s64 max_dout = div64_s64(max_err * gov->max_dout, 100);
382                 if (derivative < 0)
383                         derivative = -min_t(s64, abs64(derivative), max_dout);
384                 else
385                         derivative = min_t(s64, derivative, max_dout);
386         }
387
388         sum_err = max_t(s64, proportional + derivative, 0);
389         sum_err = min_t(s64, sum_err, max_err);
390         sum_err = sum_err * max_state + max_err - 1;
391         target = (unsigned long)div64_s64(sum_err, max_err);
392
393         /* Apply compensation */
394         if (target == cur_state)
395                 return target;
396
397         if (target > cur_state) {
398                 compensation = DIV_ROUND_UP(gov->compensation_rate *
399                                             (target - cur_state), 100);
400                 target = min(cur_state + compensation, max_state);
401         } else if (target < cur_state) {
402                 compensation = DIV_ROUND_UP(gov->compensation_rate *
403                                             (cur_state - target), 100);
404                 target = (cur_state > compensation) ?
405                          (cur_state - compensation) : 0;
406         }
407
408         return target;
409 }
410
411 static int pid_thermal_gov_throttle(struct thermal_zone_device *tz, int trip)
412 {
413         struct thermal_instance *instance;
414         enum thermal_trip_type trip_type;
415         long trip_temp;
416         unsigned long target;
417
418         tz->ops->get_trip_type(tz, trip, &trip_type);
419         tz->ops->get_trip_temp(tz, trip, &trip_temp);
420
421         mutex_lock(&tz->lock);
422
423         list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
424                 if ((instance->trip != trip) ||
425                                 ((tz->temperature < trip_temp) &&
426                                  (instance->target == THERMAL_NO_TARGET)))
427                         continue;
428
429                 target = pid_thermal_gov_get_target(tz, instance->cdev,
430                                                     trip_type, trip_temp);
431                 if (target >= instance->upper)
432                         target = instance->upper;
433                 else if (target < instance->lower)
434                         target = instance->lower;
435
436                 if ((tz->temperature < trip_temp) &&
437                                 (instance->target == instance->lower) &&
438                                 (target == instance->lower))
439                         target = THERMAL_NO_TARGET;
440
441                 if (instance->target == target)
442                         continue;
443
444                 pid_thermal_gov_update_passive(tz, trip_type, instance->target,
445                                                target);
446                 instance->target = target;
447                 instance->cdev->updated = false;
448         }
449
450         list_for_each_entry(instance, &tz->thermal_instances, tz_node)
451                 thermal_cdev_update(instance->cdev);
452
453         mutex_unlock(&tz->lock);
454
455         return 0;
456 }
457
458 static struct thermal_governor pid_thermal_gov = {
459         .name           = DRV_NAME,
460         .start          = pid_thermal_gov_start,
461         .stop           = pid_thermal_gov_stop,
462         .throttle       = pid_thermal_gov_throttle,
463         .owner          = THIS_MODULE,
464 };
465
466 static int __init pid_thermal_gov_init(void)
467 {
468         return thermal_register_governor(&pid_thermal_gov);
469 }
470 fs_initcall(pid_thermal_gov_init);
471
472 static void __exit pid_thermal_gov_exit(void)
473 {
474         thermal_unregister_governor(&pid_thermal_gov);
475 }
476 module_exit(pid_thermal_gov_exit);
477
478 MODULE_AUTHOR("Jinyoung Park <jinyoungp@nvidia.com>");
479 MODULE_DESCRIPTION("PID thermal governor");
480 MODULE_LICENSE("GPL");