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 c189b82f5ec..a129a7b6bfd 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 c0596b29176..574a06b1b1d 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 2483a85a266..d742d4a82d6 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 efad8dcf902..a2e3eae7901 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 4f8b563da78..0681246fc89 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 */ | ||
