Thermal: Allow first cooling device update
[linux-2.6.git] / drivers / thermal / fair_share.c
1 /*
2  *  fair_share.c - A simple weight based Thermal governor
3  *
4  *  Copyright (C) 2012 Intel Corp
5  *  Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
6  *
7  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; version 2 of the License.
12  *
13  *  This program is distributed in the hope that it will be useful, but
14  *  WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License along
19  *  with this program; if not, write to the Free Software Foundation, Inc.,
20  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21  *
22  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23  */
24
25 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27 #include <linux/module.h>
28 #include <linux/thermal.h>
29
30 #include "thermal_core.h"
31
32 /**
33  * get_trip_level: - obtains the current trip level for a zone
34  * @tz:         thermal zone device
35  */
36 static int get_trip_level(struct thermal_zone_device *tz)
37 {
38         int count = 0;
39         unsigned long trip_temp;
40
41         if (tz->trips == 0 || !tz->ops->get_trip_temp)
42                 return 0;
43
44         for (count = 0; count < tz->trips; count++) {
45                 tz->ops->get_trip_temp(tz, count, &trip_temp);
46                 if (tz->temperature < trip_temp)
47                         break;
48         }
49         return count;
50 }
51
52 static long get_target_state(struct thermal_zone_device *tz,
53                 struct thermal_cooling_device *cdev, int weight, int level)
54 {
55         unsigned long max_state;
56
57         cdev->ops->get_max_state(cdev, &max_state);
58
59         return (long)(weight * level * max_state) / (100 * tz->trips);
60 }
61
62 /**
63  * fair_share_throttle - throttles devices asscciated with the given zone
64  * @tz - thermal_zone_device
65  *
66  * Throttling Logic: This uses three parameters to calculate the new
67  * throttle state of the cooling devices associated with the given zone.
68  *
69  * Parameters used for Throttling:
70  * P1. max_state: Maximum throttle state exposed by the cooling device.
71  * P2. weight[i]/100:
72  *      How 'effective' the 'i'th device is, in cooling the given zone.
73  * P3. cur_trip_level/max_no_of_trips:
74  *      This describes the extent to which the devices should be throttled.
75  *      We do not want to throttle too much when we trip a lower temperature,
76  *      whereas the throttling is at full swing if we trip critical levels.
77  *      (Heavily assumes the trip points are in ascending order)
78  * new_state of cooling device = P3 * P2 * P1
79  */
80 static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
81 {
82         const struct thermal_zone_params *tzp;
83         struct thermal_cooling_device *cdev;
84         struct thermal_instance *instance;
85         int i;
86         int cur_trip_level = get_trip_level(tz);
87
88         if (!tz->tzp || !tz->tzp->tbp)
89                 return -EINVAL;
90
91         tzp = tz->tzp;
92
93         for (i = 0; i < tzp->num_tbps; i++) {
94                 if (!tzp->tbp[i].cdev)
95                         continue;
96
97                 cdev = tzp->tbp[i].cdev;
98                 instance = get_thermal_instance(tz, cdev, trip);
99                 if (!instance)
100                         continue;
101
102                 instance->target = get_target_state(tz, cdev,
103                                         tzp->tbp[i].weight, cur_trip_level);
104
105                 instance->cdev->updated = false;
106                 thermal_cdev_update(cdev);
107         }
108         return 0;
109 }
110
111 static struct thermal_governor thermal_gov_fair_share = {
112         .name           = "fair_share",
113         .throttle       = fair_share_throttle,
114         .owner          = THIS_MODULE,
115 };
116
117 static int __init thermal_gov_fair_share_init(void)
118 {
119         return thermal_register_governor(&thermal_gov_fair_share);
120 }
121
122 static void __exit thermal_gov_fair_share_exit(void)
123 {
124         thermal_unregister_governor(&thermal_gov_fair_share);
125 }
126
127 /* This should load after thermal framework */
128 fs_initcall(thermal_gov_fair_share_init);
129 module_exit(thermal_gov_fair_share_exit);
130
131 MODULE_AUTHOR("Durgadoss R");
132 MODULE_DESCRIPTION("A simple weight based thermal throttling governor");
133 MODULE_LICENSE("GPL");