aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-class-devfreq11
-rw-r--r--drivers/devfreq/devfreq.c101
-rw-r--r--include/linux/devfreq.h15
3 files changed, 127 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq
index e672ccb02e7f..40f98a9428dc 100644
--- a/Documentation/ABI/testing/sysfs-class-devfreq
+++ b/Documentation/ABI/testing/sysfs-class-devfreq
@@ -44,6 +44,17 @@ Description:
44 (/sys/class/devfreq/.../central_polling is 0), this value 44 (/sys/class/devfreq/.../central_polling is 0), this value
45 may be useless. 45 may be useless.
46 46
47What: /sys/class/devfreq/.../trans_stat
48Date: October 2012
49Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
50Descrtiption:
51 This ABI shows the statistics of devfreq behavior on a
52 specific device. It shows the time spent in each state and
53 the number of transitions between states.
54 In order to activate this ABI, the devfreq target device
55 driver should provide the list of available frequencies
56 with its profile.
57
47What: /sys/class/devfreq/.../userspace/set_freq 58What: /sys/class/devfreq/.../userspace/set_freq
48Date: September 2011 59Date: September 2011
49Contact: MyungJoo Ham <myungjoo.ham@samsung.com> 60Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
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
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 1461fb2355ad..bc35c4aee6a3 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -73,6 +73,8 @@ struct devfreq_dev_status {
73 * from devfreq_remove_device() call. If the user 73 * from devfreq_remove_device() call. If the user
74 * has registered devfreq->nb at a notifier-head, 74 * has registered devfreq->nb at a notifier-head,
75 * this is the time to unregister it. 75 * this is the time to unregister it.
76 * @freq_table: Optional list of frequencies to support statistics.
77 * @max_state: The size of freq_table.
76 */ 78 */
77struct devfreq_dev_profile { 79struct devfreq_dev_profile {
78 unsigned long initial_freq; 80 unsigned long initial_freq;
@@ -83,6 +85,9 @@ struct devfreq_dev_profile {
83 struct devfreq_dev_status *stat); 85 struct devfreq_dev_status *stat);
84 int (*get_cur_freq)(struct device *dev, unsigned long *freq); 86 int (*get_cur_freq)(struct device *dev, unsigned long *freq);
85 void (*exit)(struct device *dev); 87 void (*exit)(struct device *dev);
88
89 unsigned int *freq_table;
90 unsigned int max_state;
86}; 91};
87 92
88/** 93/**
@@ -127,6 +132,10 @@ struct devfreq_governor {
127 * @min_freq: Limit minimum frequency requested by user (0: none) 132 * @min_freq: Limit minimum frequency requested by user (0: none)
128 * @max_freq: Limit maximum frequency requested by user (0: none) 133 * @max_freq: Limit maximum frequency requested by user (0: none)
129 * @stop_polling: devfreq polling status of a device. 134 * @stop_polling: devfreq polling status of a device.
135 * @total_trans: Number of devfreq transitions
136 * @trans_table: Statistics of devfreq transitions
137 * @time_in_state: Statistics of devfreq states
138 * @last_stat_updated: The last time stat updated
130 * 139 *
131 * This structure stores the devfreq information for a give device. 140 * This structure stores the devfreq information for a give device.
132 * 141 *
@@ -153,6 +162,12 @@ struct devfreq {
153 unsigned long min_freq; 162 unsigned long min_freq;
154 unsigned long max_freq; 163 unsigned long max_freq;
155 bool stop_polling; 164 bool stop_polling;
165
166 /* information for device freqeuncy transition */
167 unsigned int total_trans;
168 unsigned int *trans_table;
169 unsigned long *time_in_state;
170 unsigned long last_stat_updated;
156}; 171};
157 172
158#if defined(CONFIG_PM_DEVFREQ) 173#if defined(CONFIG_PM_DEVFREQ)