diff options
author | MyungJoo Ham <myungjoo.ham@samsung.com> | 2011-12-09 02:42:19 -0500 |
---|---|---|
committer | MyungJoo Ham <myungjoo.ham@samsung.com> | 2012-01-19 20:12:38 -0500 |
commit | 6530b9dea1b7f33eaf79ba625e3a99f2455f3eb1 (patch) | |
tree | 70beddf04779d5941ba6ef851b30e02c7fa0c86c /drivers/devfreq | |
parent | a95e1f5dbca385908aa4087bb98470b0e0ac58d8 (diff) |
PM / devfreq: add min/max_freq limit requested by users.
The frequency requested to devfreq device driver from devfreq governors
is restricted by min_freq and max_freq input.
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Diffstat (limited to 'drivers/devfreq')
-rw-r--r-- | drivers/devfreq/devfreq.c | 70 | ||||
-rw-r--r-- | drivers/devfreq/governor_performance.c | 5 | ||||
-rw-r--r-- | drivers/devfreq/governor_powersave.c | 2 | ||||
-rw-r--r-- | drivers/devfreq/governor_simpleondemand.c | 12 | ||||
-rw-r--r-- | drivers/devfreq/governor_userspace.c | 15 |
5 files changed, 96 insertions, 8 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index c189b82f5ece..a129a7b6bfd1 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c | |||
@@ -501,12 +501,82 @@ static ssize_t show_central_polling(struct device *dev, | |||
501 | !to_devfreq(dev)->governor->no_central_polling); | 501 | !to_devfreq(dev)->governor->no_central_polling); |
502 | } | 502 | } |
503 | 503 | ||
504 | static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr, | ||
505 | const char *buf, size_t count) | ||
506 | { | ||
507 | struct devfreq *df = to_devfreq(dev); | ||
508 | unsigned long value; | ||
509 | int ret; | ||
510 | unsigned long max; | ||
511 | |||
512 | ret = sscanf(buf, "%lu", &value); | ||
513 | if (ret != 1) | ||
514 | goto out; | ||
515 | |||
516 | mutex_lock(&df->lock); | ||
517 | max = df->max_freq; | ||
518 | if (value && max && value > max) { | ||
519 | ret = -EINVAL; | ||
520 | goto unlock; | ||
521 | } | ||
522 | |||
523 | df->min_freq = value; | ||
524 | update_devfreq(df); | ||
525 | ret = count; | ||
526 | unlock: | ||
527 | mutex_unlock(&df->lock); | ||
528 | out: | ||
529 | return ret; | ||
530 | } | ||
531 | |||
532 | static ssize_t show_min_freq(struct device *dev, struct device_attribute *attr, | ||
533 | char *buf) | ||
534 | { | ||
535 | return sprintf(buf, "%lu\n", to_devfreq(dev)->min_freq); | ||
536 | } | ||
537 | |||
538 | static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr, | ||
539 | const char *buf, size_t count) | ||
540 | { | ||
541 | struct devfreq *df = to_devfreq(dev); | ||
542 | unsigned long value; | ||
543 | int ret; | ||
544 | unsigned long min; | ||
545 | |||
546 | ret = sscanf(buf, "%lu", &value); | ||
547 | if (ret != 1) | ||
548 | goto out; | ||
549 | |||
550 | mutex_lock(&df->lock); | ||
551 | min = df->min_freq; | ||
552 | if (value && min && value < min) { | ||
553 | ret = -EINVAL; | ||
554 | goto unlock; | ||
555 | } | ||
556 | |||
557 | df->max_freq = value; | ||
558 | update_devfreq(df); | ||
559 | ret = count; | ||
560 | unlock: | ||
561 | mutex_unlock(&df->lock); | ||
562 | out: | ||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr, | ||
567 | char *buf) | ||
568 | { | ||
569 | return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq); | ||
570 | } | ||
571 | |||
504 | static struct device_attribute devfreq_attrs[] = { | 572 | static struct device_attribute devfreq_attrs[] = { |
505 | __ATTR(governor, S_IRUGO, show_governor, NULL), | 573 | __ATTR(governor, S_IRUGO, show_governor, NULL), |
506 | __ATTR(cur_freq, S_IRUGO, show_freq, NULL), | 574 | __ATTR(cur_freq, S_IRUGO, show_freq, NULL), |
507 | __ATTR(central_polling, S_IRUGO, show_central_polling, NULL), | 575 | __ATTR(central_polling, S_IRUGO, show_central_polling, NULL), |
508 | __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval, | 576 | __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval, |
509 | store_polling_interval), | 577 | store_polling_interval), |
578 | __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq), | ||
579 | __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq), | ||
510 | { }, | 580 | { }, |
511 | }; | 581 | }; |
512 | 582 | ||
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index c0596b291761..574a06b1b1de 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c | |||
@@ -18,7 +18,10 @@ static int devfreq_performance_func(struct devfreq *df, | |||
18 | * target callback should be able to get floor value as | 18 | * target callback should be able to get floor value as |
19 | * said in devfreq.h | 19 | * said in devfreq.h |
20 | */ | 20 | */ |
21 | *freq = UINT_MAX; | 21 | if (!df->max_freq) |
22 | *freq = UINT_MAX; | ||
23 | else | ||
24 | *freq = df->max_freq; | ||
22 | return 0; | 25 | return 0; |
23 | } | 26 | } |
24 | 27 | ||
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index 2483a85a266f..d742d4a82d6a 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c | |||
@@ -18,7 +18,7 @@ static int devfreq_powersave_func(struct devfreq *df, | |||
18 | * target callback should be able to get ceiling value as | 18 | * target callback should be able to get ceiling value as |
19 | * said in devfreq.h | 19 | * said in devfreq.h |
20 | */ | 20 | */ |
21 | *freq = 0; | 21 | *freq = df->min_freq; |
22 | return 0; | 22 | return 0; |
23 | } | 23 | } |
24 | 24 | ||
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index efad8dcf9028..a2e3eae79011 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c | |||
@@ -25,6 +25,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, | |||
25 | unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; | 25 | unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; |
26 | unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; | 26 | unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; |
27 | struct devfreq_simple_ondemand_data *data = df->data; | 27 | struct devfreq_simple_ondemand_data *data = df->data; |
28 | unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; | ||
28 | 29 | ||
29 | if (err) | 30 | if (err) |
30 | return err; | 31 | return err; |
@@ -41,7 +42,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, | |||
41 | 42 | ||
42 | /* Assume MAX if it is going to be divided by zero */ | 43 | /* Assume MAX if it is going to be divided by zero */ |
43 | if (stat.total_time == 0) { | 44 | if (stat.total_time == 0) { |
44 | *freq = UINT_MAX; | 45 | *freq = max; |
45 | return 0; | 46 | return 0; |
46 | } | 47 | } |
47 | 48 | ||
@@ -54,13 +55,13 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, | |||
54 | /* Set MAX if it's busy enough */ | 55 | /* Set MAX if it's busy enough */ |
55 | if (stat.busy_time * 100 > | 56 | if (stat.busy_time * 100 > |
56 | stat.total_time * dfso_upthreshold) { | 57 | stat.total_time * dfso_upthreshold) { |
57 | *freq = UINT_MAX; | 58 | *freq = max; |
58 | return 0; | 59 | return 0; |
59 | } | 60 | } |
60 | 61 | ||
61 | /* Set MAX if we do not know the initial frequency */ | 62 | /* Set MAX if we do not know the initial frequency */ |
62 | if (stat.current_frequency == 0) { | 63 | if (stat.current_frequency == 0) { |
63 | *freq = UINT_MAX; | 64 | *freq = max; |
64 | return 0; | 65 | return 0; |
65 | } | 66 | } |
66 | 67 | ||
@@ -79,6 +80,11 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, | |||
79 | b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); | 80 | b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); |
80 | *freq = (unsigned long) b; | 81 | *freq = (unsigned long) b; |
81 | 82 | ||
83 | if (df->min_freq && *freq < df->min_freq) | ||
84 | *freq = df->min_freq; | ||
85 | if (df->max_freq && *freq > df->max_freq) | ||
86 | *freq = df->max_freq; | ||
87 | |||
82 | return 0; | 88 | return 0; |
83 | } | 89 | } |
84 | 90 | ||
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 4f8b563da782..0681246fc89d 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c | |||
@@ -25,10 +25,19 @@ static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq) | |||
25 | { | 25 | { |
26 | struct userspace_data *data = df->data; | 26 | struct userspace_data *data = df->data; |
27 | 27 | ||
28 | if (!data->valid) | 28 | if (data->valid) { |
29 | unsigned long adjusted_freq = data->user_frequency; | ||
30 | |||
31 | if (df->max_freq && adjusted_freq > df->max_freq) | ||
32 | adjusted_freq = df->max_freq; | ||
33 | |||
34 | if (df->min_freq && adjusted_freq < df->min_freq) | ||
35 | adjusted_freq = df->min_freq; | ||
36 | |||
37 | *freq = adjusted_freq; | ||
38 | } else { | ||
29 | *freq = df->previous_freq; /* No user freq specified yet */ | 39 | *freq = df->previous_freq; /* No user freq specified yet */ |
30 | else | 40 | } |
31 | *freq = data->user_frequency; | ||
32 | return 0; | 41 | return 0; |
33 | } | 42 | } |
34 | 43 | ||