aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/devfreq')
-rw-r--r--drivers/devfreq/devfreq.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index c44e562bdfe0..bf6de38190cf 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -66,6 +66,51 @@ static struct devfreq *find_device_devfreq(struct device *dev)
66 return ERR_PTR(-ENODEV); 66 return ERR_PTR(-ENODEV);
67} 67}
68 68
69/**
70 * devfreq_get_freq_level() - Lookup freq_table for the frequency
71 * @devfreq: the devfreq instance
72 * @freq: the target frequency
73 */
74static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
75{
76 int lev;
77
78 for (lev = 0; lev < devfreq->profile->max_state; lev++)
79 if (freq == devfreq->profile->freq_table[lev])
80 return lev;
81
82 return -EINVAL;
83}
84
85/**
86 * devfreq_update_status() - Update statistics of devfreq behavior
87 * @devfreq: the devfreq instance
88 * @freq: the update target frequency
89 */
90static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
91{
92 int lev, prev_lev;
93 unsigned long cur_time;
94
95 lev = devfreq_get_freq_level(devfreq, freq);
96 if (lev < 0)
97 return lev;
98
99 cur_time = jiffies;
100 devfreq->time_in_state[lev] +=
101 cur_time - devfreq->last_stat_updated;
102 if (freq != devfreq->previous_freq) {
103 prev_lev = devfreq_get_freq_level(devfreq,
104 devfreq->previous_freq);
105 devfreq->trans_table[(prev_lev *
106 devfreq->profile->max_state) + lev]++;
107 devfreq->total_trans++;
108 }
109 devfreq->last_stat_updated = cur_time;
110
111 return 0;
112}
113
69/* Load monitoring helper functions for governors use */ 114/* Load monitoring helper functions for governors use */
70 115
71/** 116/**
@@ -112,6 +157,11 @@ int update_devfreq(struct devfreq *devfreq)
112 if (err) 157 if (err)
113 return err; 158 return err;
114 159
160 if (devfreq->profile->freq_table)
161 if (devfreq_update_status(devfreq, freq))
162 dev_err(&devfreq->dev,
163 "Couldn't update frequency transition information.\n");
164
115 devfreq->previous_freq = freq; 165 devfreq->previous_freq = freq;
116 return err; 166 return err;
117} 167}
@@ -378,6 +428,15 @@ struct devfreq *devfreq_add_device(struct device *dev,
378 devfreq->data = data; 428 devfreq->data = data;
379 devfreq->nb.notifier_call = devfreq_notifier_call; 429 devfreq->nb.notifier_call = devfreq_notifier_call;
380 430
431 devfreq->trans_table = devm_kzalloc(dev, sizeof(unsigned int) *
432 devfreq->profile->max_state *
433 devfreq->profile->max_state,
434 GFP_KERNEL);
435 devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned int) *
436 devfreq->profile->max_state,
437 GFP_KERNEL);
438 devfreq->last_stat_updated = jiffies;
439
381 dev_set_name(&devfreq->dev, dev_name(dev)); 440 dev_set_name(&devfreq->dev, dev_name(dev));
382 err = device_register(&devfreq->dev); 441 err = device_register(&devfreq->dev);
383 if (err) { 442 if (err) {
@@ -601,6 +660,47 @@ static ssize_t show_available_freqs(struct device *d,
601 return count; 660 return count;
602} 661}
603 662
663static ssize_t show_trans_table(struct device *dev, struct device_attribute *attr,
664 char *buf)
665{
666 struct devfreq *devfreq = to_devfreq(dev);
667 ssize_t len;
668 int i, j, err;
669 unsigned int max_state = devfreq->profile->max_state;
670
671 err = devfreq_update_status(devfreq, devfreq->previous_freq);
672 if (err)
673 return 0;
674
675 len = sprintf(buf, " From : To\n");
676 len += sprintf(buf + len, " :");
677 for (i = 0; i < max_state; i++)
678 len += sprintf(buf + len, "%8u",
679 devfreq->profile->freq_table[i]);
680
681 len += sprintf(buf + len, " time(ms)\n");
682
683 for (i = 0; i < max_state; i++) {
684 if (devfreq->profile->freq_table[i]
685 == devfreq->previous_freq) {
686 len += sprintf(buf + len, "*");
687 } else {
688 len += sprintf(buf + len, " ");
689 }
690 len += sprintf(buf + len, "%8u:",
691 devfreq->profile->freq_table[i]);
692 for (j = 0; j < max_state; j++)
693 len += sprintf(buf + len, "%8u",
694 devfreq->trans_table[(i * max_state) + j]);
695 len += sprintf(buf + len, "%10u\n",
696 jiffies_to_msecs(devfreq->time_in_state[i]));
697 }
698
699 len += sprintf(buf + len, "Total transition : %u\n",
700 devfreq->total_trans);
701 return len;
702}
703
604static struct device_attribute devfreq_attrs[] = { 704static struct device_attribute devfreq_attrs[] = {
605 __ATTR(governor, S_IRUGO, show_governor, NULL), 705 __ATTR(governor, S_IRUGO, show_governor, NULL),
606 __ATTR(cur_freq, S_IRUGO, show_freq, NULL), 706 __ATTR(cur_freq, S_IRUGO, show_freq, NULL),
@@ -610,6 +710,7 @@ static struct device_attribute devfreq_attrs[] = {
610 store_polling_interval), 710 store_polling_interval),
611 __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq), 711 __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq),
612 __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq), 712 __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq),
713 __ATTR(trans_stat, S_IRUGO, show_trans_table, NULL),
613 { }, 714 { },
614}; 715};
615 716