Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 336776
b: refs/heads/master
c: e552bba
h: refs/heads/master
v: v3
  • Loading branch information
Jonghwa Lee authored and MyungJoo Ham committed Nov 20, 2012
1 parent 0f59d9a commit 5027a23
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d287de855f97c56ca7146ff627e652bd7cd64f3f
refs/heads/master: e552bbaf5b987f57c43e6981a452b8a3c700b1ae
11 changes: 11 additions & 0 deletions trunk/Documentation/ABI/testing/sysfs-class-devfreq
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ Description:
(/sys/class/devfreq/.../central_polling is 0), this value
may be useless.

What: /sys/class/devfreq/.../trans_stat
Date: October 2012
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
Descrtiption:
This ABI shows the statistics of devfreq behavior on a
specific device. It shows the time spent in each state and
the number of transitions between states.
In order to activate this ABI, the devfreq target device
driver should provide the list of available frequencies
with its profile.

What: /sys/class/devfreq/.../userspace/set_freq
Date: September 2011
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
Expand Down
101 changes: 101 additions & 0 deletions trunk/drivers/devfreq/devfreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,51 @@ static struct devfreq *find_device_devfreq(struct device *dev)
return ERR_PTR(-ENODEV);
}

/**
* devfreq_get_freq_level() - Lookup freq_table for the frequency
* @devfreq: the devfreq instance
* @freq: the target frequency
*/
static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
{
int lev;

for (lev = 0; lev < devfreq->profile->max_state; lev++)
if (freq == devfreq->profile->freq_table[lev])
return lev;

return -EINVAL;
}

/**
* devfreq_update_status() - Update statistics of devfreq behavior
* @devfreq: the devfreq instance
* @freq: the update target frequency
*/
static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
{
int lev, prev_lev;
unsigned long cur_time;

lev = devfreq_get_freq_level(devfreq, freq);
if (lev < 0)
return lev;

cur_time = jiffies;
devfreq->time_in_state[lev] +=
cur_time - devfreq->last_stat_updated;
if (freq != devfreq->previous_freq) {
prev_lev = devfreq_get_freq_level(devfreq,
devfreq->previous_freq);
devfreq->trans_table[(prev_lev *
devfreq->profile->max_state) + lev]++;
devfreq->total_trans++;
}
devfreq->last_stat_updated = cur_time;

return 0;
}

/* Load monitoring helper functions for governors use */

/**
Expand Down Expand Up @@ -112,6 +157,11 @@ int update_devfreq(struct devfreq *devfreq)
if (err)
return err;

if (devfreq->profile->freq_table)
if (devfreq_update_status(devfreq, freq))
dev_err(&devfreq->dev,
"Couldn't update frequency transition information.\n");

devfreq->previous_freq = freq;
return err;
}
Expand Down Expand Up @@ -378,6 +428,15 @@ struct devfreq *devfreq_add_device(struct device *dev,
devfreq->data = data;
devfreq->nb.notifier_call = devfreq_notifier_call;

devfreq->trans_table = devm_kzalloc(dev, sizeof(unsigned int) *
devfreq->profile->max_state *
devfreq->profile->max_state,
GFP_KERNEL);
devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned int) *
devfreq->profile->max_state,
GFP_KERNEL);
devfreq->last_stat_updated = jiffies;

dev_set_name(&devfreq->dev, dev_name(dev));
err = device_register(&devfreq->dev);
if (err) {
Expand Down Expand Up @@ -601,6 +660,47 @@ static ssize_t show_available_freqs(struct device *d,
return count;
}

static ssize_t show_trans_table(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct devfreq *devfreq = to_devfreq(dev);
ssize_t len;
int i, j, err;
unsigned int max_state = devfreq->profile->max_state;

err = devfreq_update_status(devfreq, devfreq->previous_freq);
if (err)
return 0;

len = sprintf(buf, " From : To\n");
len += sprintf(buf + len, " :");
for (i = 0; i < max_state; i++)
len += sprintf(buf + len, "%8u",
devfreq->profile->freq_table[i]);

len += sprintf(buf + len, " time(ms)\n");

for (i = 0; i < max_state; i++) {
if (devfreq->profile->freq_table[i]
== devfreq->previous_freq) {
len += sprintf(buf + len, "*");
} else {
len += sprintf(buf + len, " ");
}
len += sprintf(buf + len, "%8u:",
devfreq->profile->freq_table[i]);
for (j = 0; j < max_state; j++)
len += sprintf(buf + len, "%8u",
devfreq->trans_table[(i * max_state) + j]);
len += sprintf(buf + len, "%10u\n",
jiffies_to_msecs(devfreq->time_in_state[i]));
}

len += sprintf(buf + len, "Total transition : %u\n",
devfreq->total_trans);
return len;
}

static struct device_attribute devfreq_attrs[] = {
__ATTR(governor, S_IRUGO, show_governor, NULL),
__ATTR(cur_freq, S_IRUGO, show_freq, NULL),
Expand All @@ -610,6 +710,7 @@ static struct device_attribute devfreq_attrs[] = {
store_polling_interval),
__ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq),
__ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq),
__ATTR(trans_stat, S_IRUGO, show_trans_table, NULL),
{ },
};

Expand Down
15 changes: 15 additions & 0 deletions trunk/include/linux/devfreq.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ struct devfreq_dev_status {
* from devfreq_remove_device() call. If the user
* has registered devfreq->nb at a notifier-head,
* this is the time to unregister it.
* @freq_table: Optional list of frequencies to support statistics.
* @max_state: The size of freq_table.
*/
struct devfreq_dev_profile {
unsigned long initial_freq;
Expand All @@ -83,6 +85,9 @@ struct devfreq_dev_profile {
struct devfreq_dev_status *stat);
int (*get_cur_freq)(struct device *dev, unsigned long *freq);
void (*exit)(struct device *dev);

unsigned int *freq_table;
unsigned int max_state;
};

/**
Expand Down Expand Up @@ -127,6 +132,10 @@ struct devfreq_governor {
* @min_freq: Limit minimum frequency requested by user (0: none)
* @max_freq: Limit maximum frequency requested by user (0: none)
* @stop_polling: devfreq polling status of a device.
* @total_trans: Number of devfreq transitions
* @trans_table: Statistics of devfreq transitions
* @time_in_state: Statistics of devfreq states
* @last_stat_updated: The last time stat updated
*
* This structure stores the devfreq information for a give device.
*
Expand All @@ -153,6 +162,12 @@ struct devfreq {
unsigned long min_freq;
unsigned long max_freq;
bool stop_polling;

/* information for device freqeuncy transition */
unsigned int total_trans;
unsigned int *trans_table;
unsigned long *time_in_state;
unsigned long last_stat_updated;
};

#if defined(CONFIG_PM_DEVFREQ)
Expand Down

0 comments on commit 5027a23

Please sign in to comment.