aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq
diff options
context:
space:
mode:
authorSaravana Kannan <skannan@codeaurora.org>2014-02-27 22:38:57 -0500
committerMyungJoo Ham <myungjoo.ham@samsung.com>2014-03-20 22:16:30 -0400
commite35d35a1c0b3a7317d77e03e686a4a205cdd4eed (patch)
tree13bfac6f86fcc9fb5e40315d7e4a115f05e88bc5 /drivers/devfreq
parentdcb99fd9b08cfe1afe426af4d8d3cbc429190f15 (diff)
PM / devfreq: Rewrite devfreq_update_status() to fix multiple bugs
The current devfreq_update_status() has the following bugs: - If previous frequency doesn't have a valid level, it does an out of bounds access into the trans_table and causes memory corruption. - When the new frequency doesn't have a valid level, the time spent in the new frequency is counted towards the next valid frequency switch instead of being ignored. - The time spent on the previous frequency is added to the new frequency's stats instead of the previous frequency's stats. This patch fixes all of this. Signed-off-by: Saravana Kannan <skannan@codeaurora.org> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers/devfreq')
-rw-r--r--drivers/devfreq/devfreq.c31
1 files changed, 20 insertions, 11 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index a0b2f7e0eedb..2042ec3656ba 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -91,26 +91,35 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
91 */ 91 */
92static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) 92static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
93{ 93{
94 int lev, prev_lev; 94 int lev, prev_lev, ret = 0;
95 unsigned long cur_time; 95 unsigned long cur_time;
96 96
97 lev = devfreq_get_freq_level(devfreq, freq);
98 if (lev < 0)
99 return lev;
100
101 cur_time = jiffies; 97 cur_time = jiffies;
102 devfreq->time_in_state[lev] += 98
99 prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq);
100 if (prev_lev < 0) {
101 ret = prev_lev;
102 goto out;
103 }
104
105 devfreq->time_in_state[prev_lev] +=
103 cur_time - devfreq->last_stat_updated; 106 cur_time - devfreq->last_stat_updated;
104 if (freq != devfreq->previous_freq) { 107
105 prev_lev = devfreq_get_freq_level(devfreq, 108 lev = devfreq_get_freq_level(devfreq, freq);
106 devfreq->previous_freq); 109 if (lev < 0) {
110 ret = lev;
111 goto out;
112 }
113
114 if (lev != prev_lev) {
107 devfreq->trans_table[(prev_lev * 115 devfreq->trans_table[(prev_lev *
108 devfreq->profile->max_state) + lev]++; 116 devfreq->profile->max_state) + lev]++;
109 devfreq->total_trans++; 117 devfreq->total_trans++;
110 } 118 }
111 devfreq->last_stat_updated = cur_time;
112 119
113 return 0; 120out:
121 devfreq->last_stat_updated = cur_time;
122 return ret;
114} 123}
115 124
116/** 125/**