summaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorLukasz Majewski <l.majewski@samsung.com>2013-12-20 09:24:49 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-01-16 20:00:44 -0500
commit6f19efc0a1ca08bc61841b971d8b85ab505d95c8 (patch)
treef522350ff98997a14b3cb86d1d17814965ac098c /drivers/cpufreq
parentb69880f9ccf7e13b2e2cb38f49a2451d7aa548b3 (diff)
cpufreq: Add boost frequency support in core
This commit adds boost frequency support in cpufreq core (Hardware & Software). Some SoCs (like Exynos4 - e.g. 4x12) allow setting frequency above its normal operation limits. Such mode shall be only used for a short time. Overclocking (boost) support is essentially provided by platform dependent cpufreq driver. This commit unifies support for SW and HW (Intel) overclocking solutions in the core cpufreq driver. Previously the "boost" sysfs attribute was defined in the ACPI processor driver code. By default boost is disabled. One global attribute is available at: /sys/devices/system/cpu/cpufreq/boost. It only shows up when cpufreq driver supports overclocking. Under the hood frequencies dedicated for boosting are marked with a special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table. It is the user's concern to enable/disable overclocking with a proper call to sysfs. The cpufreq_boost_trigger_state() function is defined non static on purpose. It is used later with thermal subsystem to provide automatic enable/disable of the BOOST feature. Signed-off-by: Lukasz Majewski <l.majewski@samsung.com> Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq.c118
-rw-r--r--drivers/cpufreq/freq_table.c56
2 files changed, 166 insertions, 8 deletions
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);
352/********************************************************************* 352/*********************************************************************
353 * SYSFS INTERFACE * 353 * SYSFS INTERFACE *
354 *********************************************************************/ 354 *********************************************************************/
355ssize_t show_boost(struct kobject *kobj,
356 struct attribute *attr, char *buf)
357{
358 return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
359}
360
361static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
362 const char *buf, size_t count)
363{
364 int ret, enable;
365
366 ret = sscanf(buf, "%d", &enable);
367 if (ret != 1 || enable < 0 || enable > 1)
368 return -EINVAL;
369
370 if (cpufreq_boost_trigger_state(enable)) {
371 pr_err("%s: Cannot %s BOOST!\n", __func__,
372 enable ? "enable" : "disable");
373 return -EINVAL;
374 }
375
376 pr_debug("%s: cpufreq BOOST %s\n", __func__,
377 enable ? "enabled" : "disabled");
378
379 return count;
380}
381define_one_global_rw(boost);
355 382
356static struct cpufreq_governor *__find_governor(const char *str_governor) 383static struct cpufreq_governor *__find_governor(const char *str_governor)
357{ 384{
@@ -2184,6 +2211,73 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
2184}; 2211};
2185 2212
2186/********************************************************************* 2213/*********************************************************************
2214 * BOOST *
2215 *********************************************************************/
2216static int cpufreq_boost_set_sw(int state)
2217{
2218 struct cpufreq_frequency_table *freq_table;
2219 struct cpufreq_policy *policy;
2220 int ret = -EINVAL;
2221
2222 list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
2223 freq_table = cpufreq_frequency_get_table(policy->cpu);
2224 if (freq_table) {
2225 ret = cpufreq_frequency_table_cpuinfo(policy,
2226 freq_table);
2227 if (ret) {
2228 pr_err("%s: Policy frequency update failed\n",
2229 __func__);
2230 break;
2231 }
2232 policy->user_policy.max = policy->max;
2233 __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
2234 }
2235 }
2236
2237 return ret;
2238}
2239
2240int cpufreq_boost_trigger_state(int state)
2241{
2242 unsigned long flags;
2243 int ret = 0;
2244
2245 if (cpufreq_driver->boost_enabled == state)
2246 return 0;
2247
2248 write_lock_irqsave(&cpufreq_driver_lock, flags);
2249 cpufreq_driver->boost_enabled = state;
2250 write_unlock_irqrestore(&cpufreq_driver_lock, flags);
2251
2252 ret = cpufreq_driver->set_boost(state);
2253 if (ret) {
2254 write_lock_irqsave(&cpufreq_driver_lock, flags);
2255 cpufreq_driver->boost_enabled = !state;
2256 write_unlock_irqrestore(&cpufreq_driver_lock, flags);
2257
2258 pr_err("%s: Cannot %s BOOST\n", __func__,
2259 state ? "enable" : "disable");
2260 }
2261
2262 return ret;
2263}
2264
2265int cpufreq_boost_supported(void)
2266{
2267 if (likely(cpufreq_driver))
2268 return cpufreq_driver->boost_supported;
2269
2270 return 0;
2271}
2272EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
2273
2274int cpufreq_boost_enabled(void)
2275{
2276 return cpufreq_driver->boost_enabled;
2277}
2278EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
2279
2280/*********************************************************************
2187 * REGISTER / UNREGISTER CPUFREQ DRIVER * 2281 * REGISTER / UNREGISTER CPUFREQ DRIVER *
2188 *********************************************************************/ 2282 *********************************************************************/
2189 2283
@@ -2223,9 +2317,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
2223 cpufreq_driver = driver_data; 2317 cpufreq_driver = driver_data;
2224 write_unlock_irqrestore(&cpufreq_driver_lock, flags); 2318 write_unlock_irqrestore(&cpufreq_driver_lock, flags);
2225 2319
2320 if (cpufreq_boost_supported()) {
2321 /*
2322 * Check if driver provides function to enable boost -
2323 * if not, use cpufreq_boost_set_sw as default
2324 */
2325 if (!cpufreq_driver->set_boost)
2326 cpufreq_driver->set_boost = cpufreq_boost_set_sw;
2327
2328 ret = cpufreq_sysfs_create_file(&boost.attr);
2329 if (ret) {
2330 pr_err("%s: cannot register global BOOST sysfs file\n",
2331 __func__);
2332 goto err_null_driver;
2333 }
2334 }
2335
2226 ret = subsys_interface_register(&cpufreq_interface); 2336 ret = subsys_interface_register(&cpufreq_interface);
2227 if (ret) 2337 if (ret)
2228 goto err_null_driver; 2338 goto err_boost_unreg;
2229 2339
2230 if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) { 2340 if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
2231 int i; 2341 int i;
@@ -2252,6 +2362,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
2252 return 0; 2362 return 0;
2253err_if_unreg: 2363err_if_unreg:
2254 subsys_interface_unregister(&cpufreq_interface); 2364 subsys_interface_unregister(&cpufreq_interface);
2365err_boost_unreg:
2366 if (cpufreq_boost_supported())
2367 cpufreq_sysfs_remove_file(&boost.attr);
2255err_null_driver: 2368err_null_driver:
2256 write_lock_irqsave(&cpufreq_driver_lock, flags); 2369 write_lock_irqsave(&cpufreq_driver_lock, flags);
2257 cpufreq_driver = NULL; 2370 cpufreq_driver = NULL;
@@ -2278,6 +2391,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
2278 pr_debug("unregistering driver %s\n", driver->name); 2391 pr_debug("unregistering driver %s\n", driver->name);
2279 2392
2280 subsys_interface_unregister(&cpufreq_interface); 2393 subsys_interface_unregister(&cpufreq_interface);
2394 if (cpufreq_boost_supported())
2395 cpufreq_sysfs_remove_file(&boost.attr);
2396
2281 unregister_hotcpu_notifier(&cpufreq_cpu_notifier); 2397 unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
2282 2398
2283 down_write(&cpufreq_rwsem); 2399 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,
32 32
33 continue; 33 continue;
34 } 34 }
35 if (!cpufreq_boost_enabled()
36 && table[i].driver_data == CPUFREQ_BOOST_FREQ)
37 continue;
38
35 pr_debug("table entry %u: %u kHz, %u driver_data\n", 39 pr_debug("table entry %u: %u kHz, %u driver_data\n",
36 i, freq, table[i].driver_data); 40 i, freq, table[i].driver_data);
37 if (freq < min_freq) 41 if (freq < min_freq)
@@ -204,7 +208,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
204/** 208/**
205 * show_available_freqs - show available frequencies for the specified CPU 209 * show_available_freqs - show available frequencies for the specified CPU
206 */ 210 */
207static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) 211static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
212 bool show_boost)
208{ 213{
209 unsigned int i = 0; 214 unsigned int i = 0;
210 unsigned int cpu = policy->cpu; 215 unsigned int cpu = policy->cpu;
@@ -219,6 +224,20 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
219 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 224 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
220 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 225 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
221 continue; 226 continue;
227 /*
228 * show_boost = true and driver_data = BOOST freq
229 * display BOOST freqs
230 *
231 * show_boost = false and driver_data = BOOST freq
232 * show_boost = true and driver_data != BOOST freq
233 * continue - do not display anything
234 *
235 * show_boost = false and driver_data != BOOST freq
236 * display NON BOOST freqs
237 */
238 if (show_boost ^ (table[i].driver_data == CPUFREQ_BOOST_FREQ))
239 continue;
240
222 count += sprintf(&buf[count], "%d ", table[i].frequency); 241 count += sprintf(&buf[count], "%d ", table[i].frequency);
223 } 242 }
224 count += sprintf(&buf[count], "\n"); 243 count += sprintf(&buf[count], "\n");
@@ -227,16 +246,39 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
227 246
228} 247}
229 248
230struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { 249#define cpufreq_attr_available_freq(_name) \
231 .attr = { .name = "scaling_available_frequencies", 250struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
232 .mode = 0444, 251__ATTR_RO(_name##_frequencies)
233 }, 252
234 .show = show_available_freqs, 253/**
235}; 254 * show_scaling_available_frequencies - show available normal frequencies for
255 * the specified CPU
256 */
257static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
258 char *buf)
259{
260 return show_available_freqs(policy, buf, false);
261}
262cpufreq_attr_available_freq(scaling_available);
236EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); 263EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
237 264
265/**
266 * show_available_boost_freqs - show available boost frequencies for
267 * the specified CPU
268 */
269static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
270 char *buf)
271{
272 return show_available_freqs(policy, buf, true);
273}
274cpufreq_attr_available_freq(scaling_boost);
275EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
276
238struct freq_attr *cpufreq_generic_attr[] = { 277struct freq_attr *cpufreq_generic_attr[] = {
239 &cpufreq_freq_attr_scaling_available_freqs, 278 &cpufreq_freq_attr_scaling_available_freqs,
279#ifdef CONFIG_CPU_FREQ_BOOST_SW
280 &cpufreq_freq_attr_scaling_boost_freqs,
281#endif
240 NULL, 282 NULL,
241}; 283};
242EXPORT_SYMBOL_GPL(cpufreq_generic_attr); 284EXPORT_SYMBOL_GPL(cpufreq_generic_attr);