diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d7efdfe0c12c..08ca8c9f41cd 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -352,6 +352,33 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition); /********************************************************************* * SYSFS INTERFACE * *********************************************************************/ +ssize_t show_boost(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled); +} + +static ssize_t store_boost(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + int ret, enable; + + ret = sscanf(buf, "%d", &enable); + if (ret != 1 || enable < 0 || enable > 1) + return -EINVAL; + + if (cpufreq_boost_trigger_state(enable)) { + pr_err("%s: Cannot %s BOOST!\n", __func__, + enable ? "enable" : "disable"); + return -EINVAL; + } + + pr_debug("%s: cpufreq BOOST %s\n", __func__, + enable ? "enabled" : "disabled"); + + return count; +} +define_one_global_rw(boost); static struct cpufreq_governor *__find_governor(const char *str_governor) { @@ -2183,6 +2210,73 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = { .notifier_call = cpufreq_cpu_callback, }; +/********************************************************************* + * BOOST * + *********************************************************************/ +static int cpufreq_boost_set_sw(int state) +{ + struct cpufreq_frequency_table *freq_table; + struct cpufreq_policy *policy; + int ret = -EINVAL; + + list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { + freq_table = cpufreq_frequency_get_table(policy->cpu); + if (freq_table) { + ret = cpufreq_frequency_table_cpuinfo(policy, + freq_table); + if (ret) { + pr_err("%s: Policy frequency update failed\n", + __func__); + break; + } + policy->user_policy.max = policy->max; + __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); + } + } + + return ret; +} + +int cpufreq_boost_trigger_state(int state) +{ + unsigned long flags; + int ret = 0; + + if (cpufreq_driver->boost_enabled == state) + return 0; + + write_lock_irqsave(&cpufreq_driver_lock, flags); + cpufreq_driver->boost_enabled = state; + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + + ret = cpufreq_driver->set_boost(state); + if (ret) { + write_lock_irqsave(&cpufreq_driver_lock, flags); + cpufreq_driver->boost_enabled = !state; + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + + pr_err("%s: Cannot %s BOOST\n", __func__, + state ? "enable" : "disable"); + } + + return ret; +} + +int cpufreq_boost_supported(void) +{ + if (likely(cpufreq_driver)) + return cpufreq_driver->boost_supported; + + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_boost_supported); + +int cpufreq_boost_enabled(void) +{ + return cpufreq_driver->boost_enabled; +} +EXPORT_SYMBOL_GPL(cpufreq_boost_enabled); + /********************************************************************* * REGISTER / UNREGISTER CPUFREQ DRIVER * *********************************************************************/ @@ -2223,9 +2317,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) cpufreq_driver = driver_data; write_unlock_irqrestore(&cpufreq_driver_lock, flags); + if (cpufreq_boost_supported()) { + /* + * Check if driver provides function to enable boost - + * if not, use cpufreq_boost_set_sw as default + */ + if (!cpufreq_driver->set_boost) + cpufreq_driver->set_boost = cpufreq_boost_set_sw; + + ret = cpufreq_sysfs_create_file(&boost.attr); + if (ret) { + pr_err("%s: cannot register global BOOST sysfs file\n", + __func__); + goto err_null_driver; + } + } + ret = subsys_interface_register(&cpufreq_interface); if (ret) - goto err_null_driver; + goto err_boost_unreg; if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) { int i; @@ -2252,6 +2362,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) return 0; err_if_unreg: subsys_interface_unregister(&cpufreq_interface); +err_boost_unreg: + if (cpufreq_boost_supported()) + cpufreq_sysfs_remove_file(&boost.attr); err_null_driver: write_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_driver = NULL; @@ -2278,6 +2391,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) pr_debug("unregistering driver %s\n", driver->name); subsys_interface_unregister(&cpufreq_interface); + if (cpufreq_boost_supported()) + cpufreq_sysfs_remove_file(&boost.attr); + unregister_hotcpu_notifier(&cpufreq_cpu_notifier); down_write(&cpufreq_rwsem); diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index a8ac0427fbfe..8e54f97899ba 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -32,6 +32,10 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, continue; } + if (!cpufreq_boost_enabled() + && table[i].driver_data == CPUFREQ_BOOST_FREQ) + continue; + pr_debug("table entry %u: %u kHz, %u driver_data\n", i, freq, table[i].driver_data); if (freq < min_freq) @@ -204,7 +208,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); /** * show_available_freqs - show available frequencies for the specified CPU */ -static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) +static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf, + bool show_boost) { unsigned int i = 0; unsigned int cpu = policy->cpu; @@ -219,6 +224,20 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { if (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue; + /* + * show_boost = true and driver_data = BOOST freq + * display BOOST freqs + * + * show_boost = false and driver_data = BOOST freq + * show_boost = true and driver_data != BOOST freq + * continue - do not display anything + * + * show_boost = false and driver_data != BOOST freq + * display NON BOOST freqs + */ + if (show_boost ^ (table[i].driver_data == CPUFREQ_BOOST_FREQ)) + continue; + count += sprintf(&buf[count], "%d ", table[i].frequency); } count += sprintf(&buf[count], "\n"); @@ -227,16 +246,39 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) } -struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { - .attr = { .name = "scaling_available_frequencies", - .mode = 0444, - }, - .show = show_available_freqs, -}; +#define cpufreq_attr_available_freq(_name) \ +struct freq_attr cpufreq_freq_attr_##_name##_freqs = \ +__ATTR_RO(_name##_frequencies) + +/** + * show_scaling_available_frequencies - show available normal frequencies for + * the specified CPU + */ +static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy, + char *buf) +{ + return show_available_freqs(policy, buf, false); +} +cpufreq_attr_available_freq(scaling_available); EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); +/** + * show_available_boost_freqs - show available boost frequencies for + * the specified CPU + */ +static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy, + char *buf) +{ + return show_available_freqs(policy, buf, true); +} +cpufreq_attr_available_freq(scaling_boost); +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs); + struct freq_attr *cpufreq_generic_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, +#ifdef CONFIG_CPU_FREQ_BOOST_SW + &cpufreq_freq_attr_scaling_boost_freqs, +#endif NULL, }; EXPORT_SYMBOL_GPL(cpufreq_generic_attr); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 422f10561e0b..4d89e0e6f9cc 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -227,6 +227,11 @@ struct cpufreq_driver { int (*suspend) (struct cpufreq_policy *policy); int (*resume) (struct cpufreq_policy *policy); struct freq_attr **attr; + + /* platform specific boost support code */ + bool boost_supported; + bool boost_enabled; + int (*set_boost) (int state); }; /* flags */ @@ -435,6 +440,7 @@ extern struct cpufreq_governor cpufreq_gov_conservative; #define CPUFREQ_ENTRY_INVALID ~0 #define CPUFREQ_TABLE_END ~1 +#define CPUFREQ_BOOST_FREQ ~2 struct cpufreq_frequency_table { unsigned int driver_data; /* driver specific data, not used by core */ @@ -460,6 +466,24 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy); ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf); +#ifdef CONFIG_CPU_FREQ +int cpufreq_boost_trigger_state(int state); +int cpufreq_boost_supported(void); +int cpufreq_boost_enabled(void); +#else +static inline int cpufreq_boost_trigger_state(int state) +{ + return 0; +} +static inline int cpufreq_boost_supported(void) +{ + return 0; +} +static inline int cpufreq_boost_enabled(void) +{ + return 0; +} +#endif /* the following funtion is for cpufreq core use only */ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);