11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/drivers/cpufreq/cpufreq.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001 Russell King 51da177e4SLinus Torvalds * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de> 6bb176f7dSViresh Kumar * (C) 2013 Viresh Kumar <viresh.kumar@linaro.org> 71da177e4SLinus Torvalds * 8c32b6b8eSAshok Raj * Oct 2005 - Ashok Raj <ashok.raj@intel.com> 9c32b6b8eSAshok Raj * Added handling for CPU hotplug 108ff69732SDave Jones * Feb 2006 - Jacob Shin <jacob.shin@amd.com> 118ff69732SDave Jones * Fix handling for CPU hotplug -- affected CPUs 12c32b6b8eSAshok Raj * 131da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 141da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 151da177e4SLinus Torvalds * published by the Free Software Foundation. 161da177e4SLinus Torvalds */ 171da177e4SLinus Torvalds 18db701151SViresh Kumar #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19db701151SViresh Kumar 205ff0a268SViresh Kumar #include <linux/cpu.h> 211da177e4SLinus Torvalds #include <linux/cpufreq.h> 221da177e4SLinus Torvalds #include <linux/delay.h> 231da177e4SLinus Torvalds #include <linux/device.h> 245ff0a268SViresh Kumar #include <linux/init.h> 255ff0a268SViresh Kumar #include <linux/kernel_stat.h> 265ff0a268SViresh Kumar #include <linux/module.h> 273fc54d37Sakpm@osdl.org #include <linux/mutex.h> 285ff0a268SViresh Kumar #include <linux/slab.h> 29e00e56dfSRafael J. Wysocki #include <linux/syscore_ops.h> 305ff0a268SViresh Kumar #include <linux/tick.h> 316f4f2723SThomas Renninger #include <trace/events/power.h> 326f4f2723SThomas Renninger 331da177e4SLinus Torvalds /** 34cd878479SDave Jones * The "cpufreq driver" - the arch- or hardware-dependent low 351da177e4SLinus Torvalds * level driver of CPUFreq support, and its spinlock. This lock 361da177e4SLinus Torvalds * also protects the cpufreq_cpu_data array. 371da177e4SLinus Torvalds */ 381c3d85ddSRafael J. Wysocki static struct cpufreq_driver *cpufreq_driver; 397a6aedfaSMike Travis static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); 408414809cSSrivatsa S. Bhat static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback); 41bb176f7dSViresh Kumar static DEFINE_RWLOCK(cpufreq_driver_lock); 426f1e4efdSJane Li DEFINE_MUTEX(cpufreq_governor_lock); 43c88a1f8bSLukasz Majewski static LIST_HEAD(cpufreq_policy_list); 44bb176f7dSViresh Kumar 45084f3493SThomas Renninger #ifdef CONFIG_HOTPLUG_CPU 46084f3493SThomas Renninger /* This one keeps track of the previously set governor of a removed CPU */ 47e77b89f1SDmitry Monakhov static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); 48084f3493SThomas Renninger #endif 491da177e4SLinus Torvalds 509c0ebcf7SViresh Kumar static inline bool has_target(void) 519c0ebcf7SViresh Kumar { 529c0ebcf7SViresh Kumar return cpufreq_driver->target_index || cpufreq_driver->target; 539c0ebcf7SViresh Kumar } 549c0ebcf7SViresh Kumar 555a01f2e8SVenkatesh Pallipadi /* 566eed9404SViresh Kumar * rwsem to guarantee that cpufreq driver module doesn't unload during critical 576eed9404SViresh Kumar * sections 586eed9404SViresh Kumar */ 596eed9404SViresh Kumar static DECLARE_RWSEM(cpufreq_rwsem); 606eed9404SViresh Kumar 611da177e4SLinus Torvalds /* internal prototypes */ 6229464f28SDave Jones static int __cpufreq_governor(struct cpufreq_policy *policy, 6329464f28SDave Jones unsigned int event); 645a01f2e8SVenkatesh Pallipadi static unsigned int __cpufreq_get(unsigned int cpu); 6565f27f38SDavid Howells static void handle_update(struct work_struct *work); 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /** 681da177e4SLinus Torvalds * Two notifier lists: the "policy" list is involved in the 691da177e4SLinus Torvalds * validation process for a new CPU frequency policy; the 701da177e4SLinus Torvalds * "transition" list for kernel code that needs to handle 711da177e4SLinus Torvalds * changes to devices when the CPU clock speed changes. 721da177e4SLinus Torvalds * The mutex locks both lists. 731da177e4SLinus Torvalds */ 74e041c683SAlan Stern static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); 75b4dfdbb3SAlan Stern static struct srcu_notifier_head cpufreq_transition_notifier_list; 761da177e4SLinus Torvalds 7774212ca4SCesar Eduardo Barros static bool init_cpufreq_transition_notifier_list_called; 78b4dfdbb3SAlan Stern static int __init init_cpufreq_transition_notifier_list(void) 79b4dfdbb3SAlan Stern { 80b4dfdbb3SAlan Stern srcu_init_notifier_head(&cpufreq_transition_notifier_list); 8174212ca4SCesar Eduardo Barros init_cpufreq_transition_notifier_list_called = true; 82b4dfdbb3SAlan Stern return 0; 83b4dfdbb3SAlan Stern } 84b3438f82SLinus Torvalds pure_initcall(init_cpufreq_transition_notifier_list); 851da177e4SLinus Torvalds 86a7b422cdSKonrad Rzeszutek Wilk static int off __read_mostly; 87da584455SViresh Kumar static int cpufreq_disabled(void) 88a7b422cdSKonrad Rzeszutek Wilk { 89a7b422cdSKonrad Rzeszutek Wilk return off; 90a7b422cdSKonrad Rzeszutek Wilk } 91a7b422cdSKonrad Rzeszutek Wilk void disable_cpufreq(void) 92a7b422cdSKonrad Rzeszutek Wilk { 93a7b422cdSKonrad Rzeszutek Wilk off = 1; 94a7b422cdSKonrad Rzeszutek Wilk } 951da177e4SLinus Torvalds static LIST_HEAD(cpufreq_governor_list); 963fc54d37Sakpm@osdl.org static DEFINE_MUTEX(cpufreq_governor_mutex); 971da177e4SLinus Torvalds 984d5dcc42SViresh Kumar bool have_governor_per_policy(void) 994d5dcc42SViresh Kumar { 1000b981e70SViresh Kumar return !!(cpufreq_driver->flags & CPUFREQ_HAVE_GOVERNOR_PER_POLICY); 1014d5dcc42SViresh Kumar } 1023f869d6dSViresh Kumar EXPORT_SYMBOL_GPL(have_governor_per_policy); 1034d5dcc42SViresh Kumar 104944e9a03SViresh Kumar struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy) 105944e9a03SViresh Kumar { 106944e9a03SViresh Kumar if (have_governor_per_policy()) 107944e9a03SViresh Kumar return &policy->kobj; 108944e9a03SViresh Kumar else 109944e9a03SViresh Kumar return cpufreq_global_kobject; 110944e9a03SViresh Kumar } 111944e9a03SViresh Kumar EXPORT_SYMBOL_GPL(get_governor_parent_kobj); 112944e9a03SViresh Kumar 11372a4ce34SViresh Kumar static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) 11472a4ce34SViresh Kumar { 11572a4ce34SViresh Kumar u64 idle_time; 11672a4ce34SViresh Kumar u64 cur_wall_time; 11772a4ce34SViresh Kumar u64 busy_time; 11872a4ce34SViresh Kumar 11972a4ce34SViresh Kumar cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); 12072a4ce34SViresh Kumar 12172a4ce34SViresh Kumar busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; 12272a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; 12372a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; 12472a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; 12572a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; 12672a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; 12772a4ce34SViresh Kumar 12872a4ce34SViresh Kumar idle_time = cur_wall_time - busy_time; 12972a4ce34SViresh Kumar if (wall) 13072a4ce34SViresh Kumar *wall = cputime_to_usecs(cur_wall_time); 13172a4ce34SViresh Kumar 13272a4ce34SViresh Kumar return cputime_to_usecs(idle_time); 13372a4ce34SViresh Kumar } 13472a4ce34SViresh Kumar 13572a4ce34SViresh Kumar u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy) 13672a4ce34SViresh Kumar { 13772a4ce34SViresh Kumar u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL); 13872a4ce34SViresh Kumar 13972a4ce34SViresh Kumar if (idle_time == -1ULL) 14072a4ce34SViresh Kumar return get_cpu_idle_time_jiffy(cpu, wall); 14172a4ce34SViresh Kumar else if (!io_busy) 14272a4ce34SViresh Kumar idle_time += get_cpu_iowait_time_us(cpu, wall); 14372a4ce34SViresh Kumar 14472a4ce34SViresh Kumar return idle_time; 14572a4ce34SViresh Kumar } 14672a4ce34SViresh Kumar EXPORT_SYMBOL_GPL(get_cpu_idle_time); 14772a4ce34SViresh Kumar 14870e9e778SViresh Kumar /* 14970e9e778SViresh Kumar * This is a generic cpufreq init() routine which can be used by cpufreq 15070e9e778SViresh Kumar * drivers of SMP systems. It will do following: 15170e9e778SViresh Kumar * - validate & show freq table passed 15270e9e778SViresh Kumar * - set policies transition latency 15370e9e778SViresh Kumar * - policy->cpus with all possible CPUs 15470e9e778SViresh Kumar */ 15570e9e778SViresh Kumar int cpufreq_generic_init(struct cpufreq_policy *policy, 15670e9e778SViresh Kumar struct cpufreq_frequency_table *table, 15770e9e778SViresh Kumar unsigned int transition_latency) 15870e9e778SViresh Kumar { 15970e9e778SViresh Kumar int ret; 16070e9e778SViresh Kumar 16170e9e778SViresh Kumar ret = cpufreq_table_validate_and_show(policy, table); 16270e9e778SViresh Kumar if (ret) { 16370e9e778SViresh Kumar pr_err("%s: invalid frequency table: %d\n", __func__, ret); 16470e9e778SViresh Kumar return ret; 16570e9e778SViresh Kumar } 16670e9e778SViresh Kumar 16770e9e778SViresh Kumar policy->cpuinfo.transition_latency = transition_latency; 16870e9e778SViresh Kumar 16970e9e778SViresh Kumar /* 17070e9e778SViresh Kumar * The driver only supports the SMP configuartion where all processors 17170e9e778SViresh Kumar * share the clock and voltage and clock. 17270e9e778SViresh Kumar */ 17370e9e778SViresh Kumar cpumask_setall(policy->cpus); 17470e9e778SViresh Kumar 17570e9e778SViresh Kumar return 0; 17670e9e778SViresh Kumar } 17770e9e778SViresh Kumar EXPORT_SYMBOL_GPL(cpufreq_generic_init); 17870e9e778SViresh Kumar 1796eed9404SViresh Kumar struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) 1801da177e4SLinus Torvalds { 1816eed9404SViresh Kumar struct cpufreq_policy *policy = NULL; 1821da177e4SLinus Torvalds unsigned long flags; 1831da177e4SLinus Torvalds 1846eed9404SViresh Kumar if (cpufreq_disabled() || (cpu >= nr_cpu_ids)) 1856eed9404SViresh Kumar return NULL; 1866eed9404SViresh Kumar 1876eed9404SViresh Kumar if (!down_read_trylock(&cpufreq_rwsem)) 1886eed9404SViresh Kumar return NULL; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds /* get the cpufreq driver */ 1910d1857a1SNathan Zimmer read_lock_irqsave(&cpufreq_driver_lock, flags); 1921da177e4SLinus Torvalds 1936eed9404SViresh Kumar if (cpufreq_driver) { 1941da177e4SLinus Torvalds /* get the CPU */ 1953a3e9e06SViresh Kumar policy = per_cpu(cpufreq_cpu_data, cpu); 1966eed9404SViresh Kumar if (policy) 1976eed9404SViresh Kumar kobject_get(&policy->kobj); 1986eed9404SViresh Kumar } 1996eed9404SViresh Kumar 2006eed9404SViresh Kumar read_unlock_irqrestore(&cpufreq_driver_lock, flags); 2011da177e4SLinus Torvalds 2023a3e9e06SViresh Kumar if (!policy) 2036eed9404SViresh Kumar up_read(&cpufreq_rwsem); 2041da177e4SLinus Torvalds 2053a3e9e06SViresh Kumar return policy; 206a9144436SStephen Boyd } 2071da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_cpu_get); 2081da177e4SLinus Torvalds 2093a3e9e06SViresh Kumar void cpufreq_cpu_put(struct cpufreq_policy *policy) 210a9144436SStephen Boyd { 211d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 212d5aaffa9SDirk Brandewie return; 213d5aaffa9SDirk Brandewie 2146eed9404SViresh Kumar kobject_put(&policy->kobj); 2156eed9404SViresh Kumar up_read(&cpufreq_rwsem); 216a9144436SStephen Boyd } 2171da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_cpu_put); 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds /********************************************************************* 2201da177e4SLinus Torvalds * EXTERNALLY AFFECTING FREQUENCY CHANGES * 2211da177e4SLinus Torvalds *********************************************************************/ 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds /** 2241da177e4SLinus Torvalds * adjust_jiffies - adjust the system "loops_per_jiffy" 2251da177e4SLinus Torvalds * 2261da177e4SLinus Torvalds * This function alters the system "loops_per_jiffy" for the clock 2271da177e4SLinus Torvalds * speed change. Note that loops_per_jiffy cannot be updated on SMP 2281da177e4SLinus Torvalds * systems as each CPU might be scaled differently. So, use the arch 2291da177e4SLinus Torvalds * per-CPU loops_per_jiffy value wherever possible. 2301da177e4SLinus Torvalds */ 2311da177e4SLinus Torvalds #ifndef CONFIG_SMP 2321da177e4SLinus Torvalds static unsigned long l_p_j_ref; 2331da177e4SLinus Torvalds static unsigned int l_p_j_ref_freq; 2341da177e4SLinus Torvalds 235858119e1SArjan van de Ven static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) 2361da177e4SLinus Torvalds { 2371da177e4SLinus Torvalds if (ci->flags & CPUFREQ_CONST_LOOPS) 2381da177e4SLinus Torvalds return; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds if (!l_p_j_ref_freq) { 2411da177e4SLinus Torvalds l_p_j_ref = loops_per_jiffy; 2421da177e4SLinus Torvalds l_p_j_ref_freq = ci->old; 2432d06d8c4SDominik Brodowski pr_debug("saving %lu as reference value for loops_per_jiffy; " 244e08f5f5bSGautham R Shenoy "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq); 2451da177e4SLinus Torvalds } 246d08de0c1SAfzal Mohammed if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) || 24742d4dc3fSBenjamin Herrenschmidt (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { 248e08f5f5bSGautham R Shenoy loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, 249e08f5f5bSGautham R Shenoy ci->new); 2502d06d8c4SDominik Brodowski pr_debug("scaling loops_per_jiffy to %lu " 251e08f5f5bSGautham R Shenoy "for frequency %u kHz\n", loops_per_jiffy, ci->new); 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds #else 255e08f5f5bSGautham R Shenoy static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) 256e08f5f5bSGautham R Shenoy { 257e08f5f5bSGautham R Shenoy return; 258e08f5f5bSGautham R Shenoy } 2591da177e4SLinus Torvalds #endif 2601da177e4SLinus Torvalds 2610956df9cSViresh Kumar static void __cpufreq_notify_transition(struct cpufreq_policy *policy, 262b43a7ffbSViresh Kumar struct cpufreq_freqs *freqs, unsigned int state) 2631da177e4SLinus Torvalds { 2641da177e4SLinus Torvalds BUG_ON(irqs_disabled()); 2651da177e4SLinus Torvalds 266d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 267d5aaffa9SDirk Brandewie return; 268d5aaffa9SDirk Brandewie 2691c3d85ddSRafael J. Wysocki freqs->flags = cpufreq_driver->flags; 2702d06d8c4SDominik Brodowski pr_debug("notification %u of frequency transition to %u kHz\n", 271e4472cb3SDave Jones state, freqs->new); 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds switch (state) { 274e4472cb3SDave Jones 2751da177e4SLinus Torvalds case CPUFREQ_PRECHANGE: 276e4472cb3SDave Jones /* detect if the driver reported a value as "old frequency" 277e4472cb3SDave Jones * which is not equal to what the cpufreq core thinks is 278e4472cb3SDave Jones * "old frequency". 2791da177e4SLinus Torvalds */ 2801c3d85ddSRafael J. Wysocki if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { 281e4472cb3SDave Jones if ((policy) && (policy->cpu == freqs->cpu) && 282e4472cb3SDave Jones (policy->cur) && (policy->cur != freqs->old)) { 2832d06d8c4SDominik Brodowski pr_debug("Warning: CPU frequency is" 284e4472cb3SDave Jones " %u, cpufreq assumed %u kHz.\n", 285e4472cb3SDave Jones freqs->old, policy->cur); 286e4472cb3SDave Jones freqs->old = policy->cur; 2871da177e4SLinus Torvalds } 2881da177e4SLinus Torvalds } 289b4dfdbb3SAlan Stern srcu_notifier_call_chain(&cpufreq_transition_notifier_list, 290e4472cb3SDave Jones CPUFREQ_PRECHANGE, freqs); 2911da177e4SLinus Torvalds adjust_jiffies(CPUFREQ_PRECHANGE, freqs); 2921da177e4SLinus Torvalds break; 293e4472cb3SDave Jones 2941da177e4SLinus Torvalds case CPUFREQ_POSTCHANGE: 2951da177e4SLinus Torvalds adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); 2962d06d8c4SDominik Brodowski pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, 2976f4f2723SThomas Renninger (unsigned long)freqs->cpu); 29825e41933SThomas Renninger trace_cpu_frequency(freqs->new, freqs->cpu); 299b4dfdbb3SAlan Stern srcu_notifier_call_chain(&cpufreq_transition_notifier_list, 300e4472cb3SDave Jones CPUFREQ_POSTCHANGE, freqs); 301e4472cb3SDave Jones if (likely(policy) && likely(policy->cpu == freqs->cpu)) 302e4472cb3SDave Jones policy->cur = freqs->new; 3031da177e4SLinus Torvalds break; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds } 306bb176f7dSViresh Kumar 307b43a7ffbSViresh Kumar /** 308b43a7ffbSViresh Kumar * cpufreq_notify_transition - call notifier chain and adjust_jiffies 309b43a7ffbSViresh Kumar * on frequency transition. 310b43a7ffbSViresh Kumar * 311b43a7ffbSViresh Kumar * This function calls the transition notifiers and the "adjust_jiffies" 312b43a7ffbSViresh Kumar * function. It is called twice on all CPU frequency changes that have 313b43a7ffbSViresh Kumar * external effects. 314b43a7ffbSViresh Kumar */ 315b43a7ffbSViresh Kumar void cpufreq_notify_transition(struct cpufreq_policy *policy, 316b43a7ffbSViresh Kumar struct cpufreq_freqs *freqs, unsigned int state) 317b43a7ffbSViresh Kumar { 318b43a7ffbSViresh Kumar for_each_cpu(freqs->cpu, policy->cpus) 319b43a7ffbSViresh Kumar __cpufreq_notify_transition(policy, freqs, state); 320b43a7ffbSViresh Kumar } 3211da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_notify_transition); 3221da177e4SLinus Torvalds 323f7ba3b41SViresh Kumar /* Do post notifications when there are chances that transition has failed */ 324f7ba3b41SViresh Kumar void cpufreq_notify_post_transition(struct cpufreq_policy *policy, 325f7ba3b41SViresh Kumar struct cpufreq_freqs *freqs, int transition_failed) 326f7ba3b41SViresh Kumar { 327f7ba3b41SViresh Kumar cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE); 328f7ba3b41SViresh Kumar if (!transition_failed) 329f7ba3b41SViresh Kumar return; 330f7ba3b41SViresh Kumar 331f7ba3b41SViresh Kumar swap(freqs->old, freqs->new); 332f7ba3b41SViresh Kumar cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE); 333f7ba3b41SViresh Kumar cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE); 334f7ba3b41SViresh Kumar } 335f7ba3b41SViresh Kumar EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition); 336f7ba3b41SViresh Kumar 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds /********************************************************************* 3391da177e4SLinus Torvalds * SYSFS INTERFACE * 3401da177e4SLinus Torvalds *********************************************************************/ 3411da177e4SLinus Torvalds 3423bcb09a3SJeremy Fitzhardinge static struct cpufreq_governor *__find_governor(const char *str_governor) 3433bcb09a3SJeremy Fitzhardinge { 3443bcb09a3SJeremy Fitzhardinge struct cpufreq_governor *t; 3453bcb09a3SJeremy Fitzhardinge 3463bcb09a3SJeremy Fitzhardinge list_for_each_entry(t, &cpufreq_governor_list, governor_list) 3473bcb09a3SJeremy Fitzhardinge if (!strnicmp(str_governor, t->name, CPUFREQ_NAME_LEN)) 3483bcb09a3SJeremy Fitzhardinge return t; 3493bcb09a3SJeremy Fitzhardinge 3503bcb09a3SJeremy Fitzhardinge return NULL; 3513bcb09a3SJeremy Fitzhardinge } 3523bcb09a3SJeremy Fitzhardinge 3531da177e4SLinus Torvalds /** 3541da177e4SLinus Torvalds * cpufreq_parse_governor - parse a governor string 3551da177e4SLinus Torvalds */ 3561da177e4SLinus Torvalds static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, 3571da177e4SLinus Torvalds struct cpufreq_governor **governor) 3581da177e4SLinus Torvalds { 3593bcb09a3SJeremy Fitzhardinge int err = -EINVAL; 3603bcb09a3SJeremy Fitzhardinge 3611c3d85ddSRafael J. Wysocki if (!cpufreq_driver) 3623bcb09a3SJeremy Fitzhardinge goto out; 3633bcb09a3SJeremy Fitzhardinge 3641c3d85ddSRafael J. Wysocki if (cpufreq_driver->setpolicy) { 3651da177e4SLinus Torvalds if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { 3661da177e4SLinus Torvalds *policy = CPUFREQ_POLICY_PERFORMANCE; 3673bcb09a3SJeremy Fitzhardinge err = 0; 368e08f5f5bSGautham R Shenoy } else if (!strnicmp(str_governor, "powersave", 369e08f5f5bSGautham R Shenoy CPUFREQ_NAME_LEN)) { 3701da177e4SLinus Torvalds *policy = CPUFREQ_POLICY_POWERSAVE; 3713bcb09a3SJeremy Fitzhardinge err = 0; 3721da177e4SLinus Torvalds } 3739c0ebcf7SViresh Kumar } else if (has_target()) { 3741da177e4SLinus Torvalds struct cpufreq_governor *t; 3753bcb09a3SJeremy Fitzhardinge 3763fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 3773bcb09a3SJeremy Fitzhardinge 3783bcb09a3SJeremy Fitzhardinge t = __find_governor(str_governor); 3793bcb09a3SJeremy Fitzhardinge 380ea714970SJeremy Fitzhardinge if (t == NULL) { 381ea714970SJeremy Fitzhardinge int ret; 382ea714970SJeremy Fitzhardinge 383ea714970SJeremy Fitzhardinge mutex_unlock(&cpufreq_governor_mutex); 3841a8e1463SKees Cook ret = request_module("cpufreq_%s", str_governor); 385ea714970SJeremy Fitzhardinge mutex_lock(&cpufreq_governor_mutex); 386ea714970SJeremy Fitzhardinge 387ea714970SJeremy Fitzhardinge if (ret == 0) 388ea714970SJeremy Fitzhardinge t = __find_governor(str_governor); 389ea714970SJeremy Fitzhardinge } 390ea714970SJeremy Fitzhardinge 3913bcb09a3SJeremy Fitzhardinge if (t != NULL) { 3921da177e4SLinus Torvalds *governor = t; 3933bcb09a3SJeremy Fitzhardinge err = 0; 3941da177e4SLinus Torvalds } 3953bcb09a3SJeremy Fitzhardinge 3963bcb09a3SJeremy Fitzhardinge mutex_unlock(&cpufreq_governor_mutex); 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds out: 3993bcb09a3SJeremy Fitzhardinge return err; 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds /** 403e08f5f5bSGautham R Shenoy * cpufreq_per_cpu_attr_read() / show_##file_name() - 404e08f5f5bSGautham R Shenoy * print out cpufreq information 4051da177e4SLinus Torvalds * 4061da177e4SLinus Torvalds * Write out information from cpufreq_driver->policy[cpu]; object must be 4071da177e4SLinus Torvalds * "unsigned int". 4081da177e4SLinus Torvalds */ 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds #define show_one(file_name, object) \ 4111da177e4SLinus Torvalds static ssize_t show_##file_name \ 4121da177e4SLinus Torvalds (struct cpufreq_policy *policy, char *buf) \ 4131da177e4SLinus Torvalds { \ 4141da177e4SLinus Torvalds return sprintf(buf, "%u\n", policy->object); \ 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds show_one(cpuinfo_min_freq, cpuinfo.min_freq); 4181da177e4SLinus Torvalds show_one(cpuinfo_max_freq, cpuinfo.max_freq); 419ed129784SThomas Renninger show_one(cpuinfo_transition_latency, cpuinfo.transition_latency); 4201da177e4SLinus Torvalds show_one(scaling_min_freq, min); 4211da177e4SLinus Torvalds show_one(scaling_max_freq, max); 4221da177e4SLinus Torvalds show_one(scaling_cur_freq, cur); 4231da177e4SLinus Torvalds 424037ce839SViresh Kumar static int cpufreq_set_policy(struct cpufreq_policy *policy, 4253a3e9e06SViresh Kumar struct cpufreq_policy *new_policy); 4267970e08bSThomas Renninger 4271da177e4SLinus Torvalds /** 4281da177e4SLinus Torvalds * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access 4291da177e4SLinus Torvalds */ 4301da177e4SLinus Torvalds #define store_one(file_name, object) \ 4311da177e4SLinus Torvalds static ssize_t store_##file_name \ 4321da177e4SLinus Torvalds (struct cpufreq_policy *policy, const char *buf, size_t count) \ 4331da177e4SLinus Torvalds { \ 4345136fa56SSrivatsa S. Bhat int ret; \ 4351da177e4SLinus Torvalds struct cpufreq_policy new_policy; \ 4361da177e4SLinus Torvalds \ 4371da177e4SLinus Torvalds ret = cpufreq_get_policy(&new_policy, policy->cpu); \ 4381da177e4SLinus Torvalds if (ret) \ 4391da177e4SLinus Torvalds return -EINVAL; \ 4401da177e4SLinus Torvalds \ 4411da177e4SLinus Torvalds ret = sscanf(buf, "%u", &new_policy.object); \ 4421da177e4SLinus Torvalds if (ret != 1) \ 4431da177e4SLinus Torvalds return -EINVAL; \ 4441da177e4SLinus Torvalds \ 445037ce839SViresh Kumar ret = cpufreq_set_policy(policy, &new_policy); \ 4467970e08bSThomas Renninger policy->user_policy.object = policy->object; \ 4471da177e4SLinus Torvalds \ 4481da177e4SLinus Torvalds return ret ? ret : count; \ 4491da177e4SLinus Torvalds } 4501da177e4SLinus Torvalds 4511da177e4SLinus Torvalds store_one(scaling_min_freq, min); 4521da177e4SLinus Torvalds store_one(scaling_max_freq, max); 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds /** 4551da177e4SLinus Torvalds * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware 4561da177e4SLinus Torvalds */ 457e08f5f5bSGautham R Shenoy static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy, 458e08f5f5bSGautham R Shenoy char *buf) 4591da177e4SLinus Torvalds { 4605a01f2e8SVenkatesh Pallipadi unsigned int cur_freq = __cpufreq_get(policy->cpu); 4611da177e4SLinus Torvalds if (!cur_freq) 4621da177e4SLinus Torvalds return sprintf(buf, "<unknown>"); 4631da177e4SLinus Torvalds return sprintf(buf, "%u\n", cur_freq); 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds /** 4671da177e4SLinus Torvalds * show_scaling_governor - show the current policy for the specified CPU 4681da177e4SLinus Torvalds */ 469905d77cdSDave Jones static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) 4701da177e4SLinus Torvalds { 4711da177e4SLinus Torvalds if (policy->policy == CPUFREQ_POLICY_POWERSAVE) 4721da177e4SLinus Torvalds return sprintf(buf, "powersave\n"); 4731da177e4SLinus Torvalds else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) 4741da177e4SLinus Torvalds return sprintf(buf, "performance\n"); 4751da177e4SLinus Torvalds else if (policy->governor) 4764b972f0bSviresh kumar return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", 47729464f28SDave Jones policy->governor->name); 4781da177e4SLinus Torvalds return -EINVAL; 4791da177e4SLinus Torvalds } 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds /** 4821da177e4SLinus Torvalds * store_scaling_governor - store policy for the specified CPU 4831da177e4SLinus Torvalds */ 4841da177e4SLinus Torvalds static ssize_t store_scaling_governor(struct cpufreq_policy *policy, 4851da177e4SLinus Torvalds const char *buf, size_t count) 4861da177e4SLinus Torvalds { 4875136fa56SSrivatsa S. Bhat int ret; 4881da177e4SLinus Torvalds char str_governor[16]; 4891da177e4SLinus Torvalds struct cpufreq_policy new_policy; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds ret = cpufreq_get_policy(&new_policy, policy->cpu); 4921da177e4SLinus Torvalds if (ret) 4931da177e4SLinus Torvalds return ret; 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds ret = sscanf(buf, "%15s", str_governor); 4961da177e4SLinus Torvalds if (ret != 1) 4971da177e4SLinus Torvalds return -EINVAL; 4981da177e4SLinus Torvalds 499e08f5f5bSGautham R Shenoy if (cpufreq_parse_governor(str_governor, &new_policy.policy, 500e08f5f5bSGautham R Shenoy &new_policy.governor)) 5011da177e4SLinus Torvalds return -EINVAL; 5021da177e4SLinus Torvalds 503037ce839SViresh Kumar ret = cpufreq_set_policy(policy, &new_policy); 5047970e08bSThomas Renninger 5057970e08bSThomas Renninger policy->user_policy.policy = policy->policy; 5067970e08bSThomas Renninger policy->user_policy.governor = policy->governor; 5077970e08bSThomas Renninger 508e08f5f5bSGautham R Shenoy if (ret) 509e08f5f5bSGautham R Shenoy return ret; 510e08f5f5bSGautham R Shenoy else 511e08f5f5bSGautham R Shenoy return count; 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds /** 5151da177e4SLinus Torvalds * show_scaling_driver - show the cpufreq driver currently loaded 5161da177e4SLinus Torvalds */ 5171da177e4SLinus Torvalds static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) 5181da177e4SLinus Torvalds { 5191c3d85ddSRafael J. Wysocki return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", cpufreq_driver->name); 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds /** 5231da177e4SLinus Torvalds * show_scaling_available_governors - show the available CPUfreq governors 5241da177e4SLinus Torvalds */ 5251da177e4SLinus Torvalds static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, 5261da177e4SLinus Torvalds char *buf) 5271da177e4SLinus Torvalds { 5281da177e4SLinus Torvalds ssize_t i = 0; 5291da177e4SLinus Torvalds struct cpufreq_governor *t; 5301da177e4SLinus Torvalds 5319c0ebcf7SViresh Kumar if (!has_target()) { 5321da177e4SLinus Torvalds i += sprintf(buf, "performance powersave"); 5331da177e4SLinus Torvalds goto out; 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds list_for_each_entry(t, &cpufreq_governor_list, governor_list) { 53729464f28SDave Jones if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) 53829464f28SDave Jones - (CPUFREQ_NAME_LEN + 2))) 5391da177e4SLinus Torvalds goto out; 5404b972f0bSviresh kumar i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name); 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds out: 5431da177e4SLinus Torvalds i += sprintf(&buf[i], "\n"); 5441da177e4SLinus Torvalds return i; 5451da177e4SLinus Torvalds } 546e8628dd0SDarrick J. Wong 547f4fd3797SLan Tianyu ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf) 5481da177e4SLinus Torvalds { 5491da177e4SLinus Torvalds ssize_t i = 0; 5501da177e4SLinus Torvalds unsigned int cpu; 5511da177e4SLinus Torvalds 552835481d9SRusty Russell for_each_cpu(cpu, mask) { 5531da177e4SLinus Torvalds if (i) 5541da177e4SLinus Torvalds i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " "); 5551da177e4SLinus Torvalds i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu); 5561da177e4SLinus Torvalds if (i >= (PAGE_SIZE - 5)) 5571da177e4SLinus Torvalds break; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds i += sprintf(&buf[i], "\n"); 5601da177e4SLinus Torvalds return i; 5611da177e4SLinus Torvalds } 562f4fd3797SLan Tianyu EXPORT_SYMBOL_GPL(cpufreq_show_cpus); 5631da177e4SLinus Torvalds 564e8628dd0SDarrick J. Wong /** 565e8628dd0SDarrick J. Wong * show_related_cpus - show the CPUs affected by each transition even if 566e8628dd0SDarrick J. Wong * hw coordination is in use 567e8628dd0SDarrick J. Wong */ 568e8628dd0SDarrick J. Wong static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf) 569e8628dd0SDarrick J. Wong { 570f4fd3797SLan Tianyu return cpufreq_show_cpus(policy->related_cpus, buf); 571e8628dd0SDarrick J. Wong } 572e8628dd0SDarrick J. Wong 573e8628dd0SDarrick J. Wong /** 574e8628dd0SDarrick J. Wong * show_affected_cpus - show the CPUs affected by each transition 575e8628dd0SDarrick J. Wong */ 576e8628dd0SDarrick J. Wong static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) 577e8628dd0SDarrick J. Wong { 578f4fd3797SLan Tianyu return cpufreq_show_cpus(policy->cpus, buf); 579e8628dd0SDarrick J. Wong } 580e8628dd0SDarrick J. Wong 5819e76988eSVenki Pallipadi static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy, 5829e76988eSVenki Pallipadi const char *buf, size_t count) 5839e76988eSVenki Pallipadi { 5849e76988eSVenki Pallipadi unsigned int freq = 0; 5859e76988eSVenki Pallipadi unsigned int ret; 5869e76988eSVenki Pallipadi 587879000f9SCHIKAMA masaki if (!policy->governor || !policy->governor->store_setspeed) 5889e76988eSVenki Pallipadi return -EINVAL; 5899e76988eSVenki Pallipadi 5909e76988eSVenki Pallipadi ret = sscanf(buf, "%u", &freq); 5919e76988eSVenki Pallipadi if (ret != 1) 5929e76988eSVenki Pallipadi return -EINVAL; 5939e76988eSVenki Pallipadi 5949e76988eSVenki Pallipadi policy->governor->store_setspeed(policy, freq); 5959e76988eSVenki Pallipadi 5969e76988eSVenki Pallipadi return count; 5979e76988eSVenki Pallipadi } 5989e76988eSVenki Pallipadi 5999e76988eSVenki Pallipadi static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf) 6009e76988eSVenki Pallipadi { 601879000f9SCHIKAMA masaki if (!policy->governor || !policy->governor->show_setspeed) 6029e76988eSVenki Pallipadi return sprintf(buf, "<unsupported>\n"); 6039e76988eSVenki Pallipadi 6049e76988eSVenki Pallipadi return policy->governor->show_setspeed(policy, buf); 6059e76988eSVenki Pallipadi } 6061da177e4SLinus Torvalds 607e2f74f35SThomas Renninger /** 6088bf1ac72Sviresh kumar * show_bios_limit - show the current cpufreq HW/BIOS limitation 609e2f74f35SThomas Renninger */ 610e2f74f35SThomas Renninger static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) 611e2f74f35SThomas Renninger { 612e2f74f35SThomas Renninger unsigned int limit; 613e2f74f35SThomas Renninger int ret; 6141c3d85ddSRafael J. Wysocki if (cpufreq_driver->bios_limit) { 6151c3d85ddSRafael J. Wysocki ret = cpufreq_driver->bios_limit(policy->cpu, &limit); 616e2f74f35SThomas Renninger if (!ret) 617e2f74f35SThomas Renninger return sprintf(buf, "%u\n", limit); 618e2f74f35SThomas Renninger } 619e2f74f35SThomas Renninger return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); 620e2f74f35SThomas Renninger } 621e2f74f35SThomas Renninger 6226dad2a29SBorislav Petkov cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400); 6236dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_min_freq); 6246dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_max_freq); 6256dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_transition_latency); 6266dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_available_governors); 6276dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_driver); 6286dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_cur_freq); 6296dad2a29SBorislav Petkov cpufreq_freq_attr_ro(bios_limit); 6306dad2a29SBorislav Petkov cpufreq_freq_attr_ro(related_cpus); 6316dad2a29SBorislav Petkov cpufreq_freq_attr_ro(affected_cpus); 6326dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_min_freq); 6336dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_max_freq); 6346dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_governor); 6356dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_setspeed); 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds static struct attribute *default_attrs[] = { 6381da177e4SLinus Torvalds &cpuinfo_min_freq.attr, 6391da177e4SLinus Torvalds &cpuinfo_max_freq.attr, 640ed129784SThomas Renninger &cpuinfo_transition_latency.attr, 6411da177e4SLinus Torvalds &scaling_min_freq.attr, 6421da177e4SLinus Torvalds &scaling_max_freq.attr, 6431da177e4SLinus Torvalds &affected_cpus.attr, 644e8628dd0SDarrick J. Wong &related_cpus.attr, 6451da177e4SLinus Torvalds &scaling_governor.attr, 6461da177e4SLinus Torvalds &scaling_driver.attr, 6471da177e4SLinus Torvalds &scaling_available_governors.attr, 6489e76988eSVenki Pallipadi &scaling_setspeed.attr, 6491da177e4SLinus Torvalds NULL 6501da177e4SLinus Torvalds }; 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds #define to_policy(k) container_of(k, struct cpufreq_policy, kobj) 6531da177e4SLinus Torvalds #define to_attr(a) container_of(a, struct freq_attr, attr) 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) 6561da177e4SLinus Torvalds { 6571da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 6581da177e4SLinus Torvalds struct freq_attr *fattr = to_attr(attr); 6591b750e3bSViresh Kumar ssize_t ret; 6606eed9404SViresh Kumar 6616eed9404SViresh Kumar if (!down_read_trylock(&cpufreq_rwsem)) 6621b750e3bSViresh Kumar return -EINVAL; 6635a01f2e8SVenkatesh Pallipadi 664ad7722daSviresh kumar down_read(&policy->rwsem); 6655a01f2e8SVenkatesh Pallipadi 666e08f5f5bSGautham R Shenoy if (fattr->show) 667e08f5f5bSGautham R Shenoy ret = fattr->show(policy, buf); 668e08f5f5bSGautham R Shenoy else 669e08f5f5bSGautham R Shenoy ret = -EIO; 670e08f5f5bSGautham R Shenoy 671ad7722daSviresh kumar up_read(&policy->rwsem); 6726eed9404SViresh Kumar up_read(&cpufreq_rwsem); 6731b750e3bSViresh Kumar 6741da177e4SLinus Torvalds return ret; 6751da177e4SLinus Torvalds } 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds static ssize_t store(struct kobject *kobj, struct attribute *attr, 6781da177e4SLinus Torvalds const char *buf, size_t count) 6791da177e4SLinus Torvalds { 6801da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 6811da177e4SLinus Torvalds struct freq_attr *fattr = to_attr(attr); 682a07530b4SDave Jones ssize_t ret = -EINVAL; 6836eed9404SViresh Kumar 6844f750c93SSrivatsa S. Bhat get_online_cpus(); 6854f750c93SSrivatsa S. Bhat 6864f750c93SSrivatsa S. Bhat if (!cpu_online(policy->cpu)) 6874f750c93SSrivatsa S. Bhat goto unlock; 6884f750c93SSrivatsa S. Bhat 6896eed9404SViresh Kumar if (!down_read_trylock(&cpufreq_rwsem)) 6904f750c93SSrivatsa S. Bhat goto unlock; 6915a01f2e8SVenkatesh Pallipadi 692ad7722daSviresh kumar down_write(&policy->rwsem); 6935a01f2e8SVenkatesh Pallipadi 694e08f5f5bSGautham R Shenoy if (fattr->store) 695e08f5f5bSGautham R Shenoy ret = fattr->store(policy, buf, count); 696e08f5f5bSGautham R Shenoy else 697e08f5f5bSGautham R Shenoy ret = -EIO; 698e08f5f5bSGautham R Shenoy 699ad7722daSviresh kumar up_write(&policy->rwsem); 7006eed9404SViresh Kumar 7016eed9404SViresh Kumar up_read(&cpufreq_rwsem); 7024f750c93SSrivatsa S. Bhat unlock: 7034f750c93SSrivatsa S. Bhat put_online_cpus(); 7044f750c93SSrivatsa S. Bhat 7051da177e4SLinus Torvalds return ret; 7061da177e4SLinus Torvalds } 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds static void cpufreq_sysfs_release(struct kobject *kobj) 7091da177e4SLinus Torvalds { 7101da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 7112d06d8c4SDominik Brodowski pr_debug("last reference is dropped\n"); 7121da177e4SLinus Torvalds complete(&policy->kobj_unregister); 7131da177e4SLinus Torvalds } 7141da177e4SLinus Torvalds 71552cf25d0SEmese Revfy static const struct sysfs_ops sysfs_ops = { 7161da177e4SLinus Torvalds .show = show, 7171da177e4SLinus Torvalds .store = store, 7181da177e4SLinus Torvalds }; 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds static struct kobj_type ktype_cpufreq = { 7211da177e4SLinus Torvalds .sysfs_ops = &sysfs_ops, 7221da177e4SLinus Torvalds .default_attrs = default_attrs, 7231da177e4SLinus Torvalds .release = cpufreq_sysfs_release, 7241da177e4SLinus Torvalds }; 7251da177e4SLinus Torvalds 7262361be23SViresh Kumar struct kobject *cpufreq_global_kobject; 7272361be23SViresh Kumar EXPORT_SYMBOL(cpufreq_global_kobject); 7282361be23SViresh Kumar 7292361be23SViresh Kumar static int cpufreq_global_kobject_usage; 7302361be23SViresh Kumar 7312361be23SViresh Kumar int cpufreq_get_global_kobject(void) 7322361be23SViresh Kumar { 7332361be23SViresh Kumar if (!cpufreq_global_kobject_usage++) 7342361be23SViresh Kumar return kobject_add(cpufreq_global_kobject, 7352361be23SViresh Kumar &cpu_subsys.dev_root->kobj, "%s", "cpufreq"); 7362361be23SViresh Kumar 7372361be23SViresh Kumar return 0; 7382361be23SViresh Kumar } 7392361be23SViresh Kumar EXPORT_SYMBOL(cpufreq_get_global_kobject); 7402361be23SViresh Kumar 7412361be23SViresh Kumar void cpufreq_put_global_kobject(void) 7422361be23SViresh Kumar { 7432361be23SViresh Kumar if (!--cpufreq_global_kobject_usage) 7442361be23SViresh Kumar kobject_del(cpufreq_global_kobject); 7452361be23SViresh Kumar } 7462361be23SViresh Kumar EXPORT_SYMBOL(cpufreq_put_global_kobject); 7472361be23SViresh Kumar 7482361be23SViresh Kumar int cpufreq_sysfs_create_file(const struct attribute *attr) 7492361be23SViresh Kumar { 7502361be23SViresh Kumar int ret = cpufreq_get_global_kobject(); 7512361be23SViresh Kumar 7522361be23SViresh Kumar if (!ret) { 7532361be23SViresh Kumar ret = sysfs_create_file(cpufreq_global_kobject, attr); 7542361be23SViresh Kumar if (ret) 7552361be23SViresh Kumar cpufreq_put_global_kobject(); 7562361be23SViresh Kumar } 7572361be23SViresh Kumar 7582361be23SViresh Kumar return ret; 7592361be23SViresh Kumar } 7602361be23SViresh Kumar EXPORT_SYMBOL(cpufreq_sysfs_create_file); 7612361be23SViresh Kumar 7622361be23SViresh Kumar void cpufreq_sysfs_remove_file(const struct attribute *attr) 7632361be23SViresh Kumar { 7642361be23SViresh Kumar sysfs_remove_file(cpufreq_global_kobject, attr); 7652361be23SViresh Kumar cpufreq_put_global_kobject(); 7662361be23SViresh Kumar } 7672361be23SViresh Kumar EXPORT_SYMBOL(cpufreq_sysfs_remove_file); 7682361be23SViresh Kumar 76919d6f7ecSDave Jones /* symlink affected CPUs */ 770308b60e7SViresh Kumar static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy) 77119d6f7ecSDave Jones { 77219d6f7ecSDave Jones unsigned int j; 77319d6f7ecSDave Jones int ret = 0; 77419d6f7ecSDave Jones 77519d6f7ecSDave Jones for_each_cpu(j, policy->cpus) { 7768a25a2fdSKay Sievers struct device *cpu_dev; 77719d6f7ecSDave Jones 778308b60e7SViresh Kumar if (j == policy->cpu) 77919d6f7ecSDave Jones continue; 78019d6f7ecSDave Jones 781e8fdde10SViresh Kumar pr_debug("Adding link for CPU: %u\n", j); 7828a25a2fdSKay Sievers cpu_dev = get_cpu_device(j); 7838a25a2fdSKay Sievers ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, 78419d6f7ecSDave Jones "cpufreq"); 78571c3461eSRafael J. Wysocki if (ret) 78671c3461eSRafael J. Wysocki break; 78719d6f7ecSDave Jones } 78819d6f7ecSDave Jones return ret; 78919d6f7ecSDave Jones } 79019d6f7ecSDave Jones 791308b60e7SViresh Kumar static int cpufreq_add_dev_interface(struct cpufreq_policy *policy, 7928a25a2fdSKay Sievers struct device *dev) 793909a694eSDave Jones { 794909a694eSDave Jones struct freq_attr **drv_attr; 795909a694eSDave Jones int ret = 0; 796909a694eSDave Jones 797909a694eSDave Jones /* prepare interface data */ 798909a694eSDave Jones ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, 7998a25a2fdSKay Sievers &dev->kobj, "cpufreq"); 800909a694eSDave Jones if (ret) 801909a694eSDave Jones return ret; 802909a694eSDave Jones 803909a694eSDave Jones /* set up files for this cpu device */ 8041c3d85ddSRafael J. Wysocki drv_attr = cpufreq_driver->attr; 805909a694eSDave Jones while ((drv_attr) && (*drv_attr)) { 806909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); 807909a694eSDave Jones if (ret) 8081c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 809909a694eSDave Jones drv_attr++; 810909a694eSDave Jones } 8111c3d85ddSRafael J. Wysocki if (cpufreq_driver->get) { 812909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); 813909a694eSDave Jones if (ret) 8141c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 815909a694eSDave Jones } 8169c0ebcf7SViresh Kumar if (has_target()) { 817909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); 818909a694eSDave Jones if (ret) 8191c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 820909a694eSDave Jones } 8211c3d85ddSRafael J. Wysocki if (cpufreq_driver->bios_limit) { 822e2f74f35SThomas Renninger ret = sysfs_create_file(&policy->kobj, &bios_limit.attr); 823e2f74f35SThomas Renninger if (ret) 8241c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 825e2f74f35SThomas Renninger } 826909a694eSDave Jones 827308b60e7SViresh Kumar ret = cpufreq_add_dev_symlink(policy); 828ecf7e461SDave Jones if (ret) 829ecf7e461SDave Jones goto err_out_kobj_put; 830ecf7e461SDave Jones 831e18f1682SSrivatsa S. Bhat return ret; 832e18f1682SSrivatsa S. Bhat 833e18f1682SSrivatsa S. Bhat err_out_kobj_put: 834e18f1682SSrivatsa S. Bhat kobject_put(&policy->kobj); 835e18f1682SSrivatsa S. Bhat wait_for_completion(&policy->kobj_unregister); 836e18f1682SSrivatsa S. Bhat return ret; 837e18f1682SSrivatsa S. Bhat } 838e18f1682SSrivatsa S. Bhat 839e18f1682SSrivatsa S. Bhat static void cpufreq_init_policy(struct cpufreq_policy *policy) 840e18f1682SSrivatsa S. Bhat { 841e18f1682SSrivatsa S. Bhat struct cpufreq_policy new_policy; 842e18f1682SSrivatsa S. Bhat int ret = 0; 843e18f1682SSrivatsa S. Bhat 844d5b73cd8SViresh Kumar memcpy(&new_policy, policy, sizeof(*policy)); 845a27a9ab7SJason Baron 846a27a9ab7SJason Baron /* Use the default policy if its valid. */ 847a27a9ab7SJason Baron if (cpufreq_driver->setpolicy) 848a27a9ab7SJason Baron cpufreq_parse_governor(policy->governor->name, 849a27a9ab7SJason Baron &new_policy.policy, NULL); 850a27a9ab7SJason Baron 851037ce839SViresh Kumar /* assure that the starting sequence is run in cpufreq_set_policy */ 852ecf7e461SDave Jones policy->governor = NULL; 853ecf7e461SDave Jones 854ecf7e461SDave Jones /* set default policy */ 855037ce839SViresh Kumar ret = cpufreq_set_policy(policy, &new_policy); 856ecf7e461SDave Jones if (ret) { 8572d06d8c4SDominik Brodowski pr_debug("setting policy failed\n"); 8581c3d85ddSRafael J. Wysocki if (cpufreq_driver->exit) 8591c3d85ddSRafael J. Wysocki cpufreq_driver->exit(policy); 860ecf7e461SDave Jones } 861909a694eSDave Jones } 862909a694eSDave Jones 863fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 864d8d3b471SViresh Kumar static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, 86542f921a6SViresh Kumar unsigned int cpu, struct device *dev) 866fcf80582SViresh Kumar { 8679c0ebcf7SViresh Kumar int ret = 0; 868fcf80582SViresh Kumar unsigned long flags; 869fcf80582SViresh Kumar 8709c0ebcf7SViresh Kumar if (has_target()) { 8713de9bdebSViresh Kumar ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); 8723de9bdebSViresh Kumar if (ret) { 8733de9bdebSViresh Kumar pr_err("%s: Failed to stop governor\n", __func__); 8743de9bdebSViresh Kumar return ret; 8753de9bdebSViresh Kumar } 8763de9bdebSViresh Kumar } 877fcf80582SViresh Kumar 878ad7722daSviresh kumar down_write(&policy->rwsem); 8792eaa3e2dSViresh Kumar 8800d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 8812eaa3e2dSViresh Kumar 882fcf80582SViresh Kumar cpumask_set_cpu(cpu, policy->cpus); 883fcf80582SViresh Kumar per_cpu(cpufreq_cpu_data, cpu) = policy; 8840d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 885fcf80582SViresh Kumar 886ad7722daSviresh kumar up_write(&policy->rwsem); 8872eaa3e2dSViresh Kumar 8889c0ebcf7SViresh Kumar if (has_target()) { 8893de9bdebSViresh Kumar if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) || 8903de9bdebSViresh Kumar (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) { 8913de9bdebSViresh Kumar pr_err("%s: Failed to start governor\n", __func__); 8923de9bdebSViresh Kumar return ret; 8933de9bdebSViresh Kumar } 894820c6ca2SViresh Kumar } 895fcf80582SViresh Kumar 89642f921a6SViresh Kumar return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); 897fcf80582SViresh Kumar } 898fcf80582SViresh Kumar #endif 8991da177e4SLinus Torvalds 9008414809cSSrivatsa S. Bhat static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu) 9018414809cSSrivatsa S. Bhat { 9028414809cSSrivatsa S. Bhat struct cpufreq_policy *policy; 9038414809cSSrivatsa S. Bhat unsigned long flags; 9048414809cSSrivatsa S. Bhat 90544871c9cSLan Tianyu read_lock_irqsave(&cpufreq_driver_lock, flags); 9068414809cSSrivatsa S. Bhat 9078414809cSSrivatsa S. Bhat policy = per_cpu(cpufreq_cpu_data_fallback, cpu); 9088414809cSSrivatsa S. Bhat 90944871c9cSLan Tianyu read_unlock_irqrestore(&cpufreq_driver_lock, flags); 9108414809cSSrivatsa S. Bhat 9118414809cSSrivatsa S. Bhat return policy; 9128414809cSSrivatsa S. Bhat } 9138414809cSSrivatsa S. Bhat 914e9698cc5SSrivatsa S. Bhat static struct cpufreq_policy *cpufreq_policy_alloc(void) 915e9698cc5SSrivatsa S. Bhat { 916e9698cc5SSrivatsa S. Bhat struct cpufreq_policy *policy; 917e9698cc5SSrivatsa S. Bhat 918e9698cc5SSrivatsa S. Bhat policy = kzalloc(sizeof(*policy), GFP_KERNEL); 919e9698cc5SSrivatsa S. Bhat if (!policy) 920e9698cc5SSrivatsa S. Bhat return NULL; 921e9698cc5SSrivatsa S. Bhat 922e9698cc5SSrivatsa S. Bhat if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) 923e9698cc5SSrivatsa S. Bhat goto err_free_policy; 924e9698cc5SSrivatsa S. Bhat 925e9698cc5SSrivatsa S. Bhat if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) 926e9698cc5SSrivatsa S. Bhat goto err_free_cpumask; 927e9698cc5SSrivatsa S. Bhat 928c88a1f8bSLukasz Majewski INIT_LIST_HEAD(&policy->policy_list); 929ad7722daSviresh kumar init_rwsem(&policy->rwsem); 930ad7722daSviresh kumar 931e9698cc5SSrivatsa S. Bhat return policy; 932e9698cc5SSrivatsa S. Bhat 933e9698cc5SSrivatsa S. Bhat err_free_cpumask: 934e9698cc5SSrivatsa S. Bhat free_cpumask_var(policy->cpus); 935e9698cc5SSrivatsa S. Bhat err_free_policy: 936e9698cc5SSrivatsa S. Bhat kfree(policy); 937e9698cc5SSrivatsa S. Bhat 938e9698cc5SSrivatsa S. Bhat return NULL; 939e9698cc5SSrivatsa S. Bhat } 940e9698cc5SSrivatsa S. Bhat 94142f921a6SViresh Kumar static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy) 94242f921a6SViresh Kumar { 94342f921a6SViresh Kumar struct kobject *kobj; 94442f921a6SViresh Kumar struct completion *cmp; 94542f921a6SViresh Kumar 946*fcd7af91SViresh Kumar blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 947*fcd7af91SViresh Kumar CPUFREQ_REMOVE_POLICY, policy); 948*fcd7af91SViresh Kumar 94942f921a6SViresh Kumar down_read(&policy->rwsem); 95042f921a6SViresh Kumar kobj = &policy->kobj; 95142f921a6SViresh Kumar cmp = &policy->kobj_unregister; 95242f921a6SViresh Kumar up_read(&policy->rwsem); 95342f921a6SViresh Kumar kobject_put(kobj); 95442f921a6SViresh Kumar 95542f921a6SViresh Kumar /* 95642f921a6SViresh Kumar * We need to make sure that the underlying kobj is 95742f921a6SViresh Kumar * actually not referenced anymore by anybody before we 95842f921a6SViresh Kumar * proceed with unloading. 95942f921a6SViresh Kumar */ 96042f921a6SViresh Kumar pr_debug("waiting for dropping of refcount\n"); 96142f921a6SViresh Kumar wait_for_completion(cmp); 96242f921a6SViresh Kumar pr_debug("wait complete\n"); 96342f921a6SViresh Kumar } 96442f921a6SViresh Kumar 965e9698cc5SSrivatsa S. Bhat static void cpufreq_policy_free(struct cpufreq_policy *policy) 966e9698cc5SSrivatsa S. Bhat { 967e9698cc5SSrivatsa S. Bhat free_cpumask_var(policy->related_cpus); 968e9698cc5SSrivatsa S. Bhat free_cpumask_var(policy->cpus); 969e9698cc5SSrivatsa S. Bhat kfree(policy); 970e9698cc5SSrivatsa S. Bhat } 971e9698cc5SSrivatsa S. Bhat 9720d66b91eSSrivatsa S. Bhat static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) 9730d66b91eSSrivatsa S. Bhat { 97499ec899eSSrivatsa S. Bhat if (WARN_ON(cpu == policy->cpu)) 975cb38ed5cSSrivatsa S. Bhat return; 976cb38ed5cSSrivatsa S. Bhat 977ad7722daSviresh kumar down_write(&policy->rwsem); 9788efd5765SViresh Kumar 9790d66b91eSSrivatsa S. Bhat policy->last_cpu = policy->cpu; 9800d66b91eSSrivatsa S. Bhat policy->cpu = cpu; 9810d66b91eSSrivatsa S. Bhat 982ad7722daSviresh kumar up_write(&policy->rwsem); 9838efd5765SViresh Kumar 9840d66b91eSSrivatsa S. Bhat cpufreq_frequency_table_update_policy_cpu(policy); 9850d66b91eSSrivatsa S. Bhat blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 9860d66b91eSSrivatsa S. Bhat CPUFREQ_UPDATE_POLICY_CPU, policy); 9870d66b91eSSrivatsa S. Bhat } 9880d66b91eSSrivatsa S. Bhat 989a82fab29SSrivatsa S. Bhat static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, 990a82fab29SSrivatsa S. Bhat bool frozen) 9911da177e4SLinus Torvalds { 992fcf80582SViresh Kumar unsigned int j, cpu = dev->id; 99365922465SViresh Kumar int ret = -ENOMEM; 9941da177e4SLinus Torvalds struct cpufreq_policy *policy; 9951da177e4SLinus Torvalds unsigned long flags; 99690e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 9971b274294SViresh Kumar struct cpufreq_policy *tpolicy; 998fcf80582SViresh Kumar struct cpufreq_governor *gov; 99990e41bacSPrarit Bhargava #endif 10001da177e4SLinus Torvalds 1001c32b6b8eSAshok Raj if (cpu_is_offline(cpu)) 1002c32b6b8eSAshok Raj return 0; 1003c32b6b8eSAshok Raj 10042d06d8c4SDominik Brodowski pr_debug("adding CPU %u\n", cpu); 10051da177e4SLinus Torvalds 10061da177e4SLinus Torvalds #ifdef CONFIG_SMP 10071da177e4SLinus Torvalds /* check whether a different CPU already registered this 10081da177e4SLinus Torvalds * CPU because it is in the same boat. */ 10091da177e4SLinus Torvalds policy = cpufreq_cpu_get(cpu); 10101da177e4SLinus Torvalds if (unlikely(policy)) { 10118ff69732SDave Jones cpufreq_cpu_put(policy); 10121da177e4SLinus Torvalds return 0; 10131da177e4SLinus Torvalds } 10145025d628SLi Zhong #endif 1015fcf80582SViresh Kumar 10166eed9404SViresh Kumar if (!down_read_trylock(&cpufreq_rwsem)) 10176eed9404SViresh Kumar return 0; 10186eed9404SViresh Kumar 1019fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 1020fcf80582SViresh Kumar /* Check if this cpu was hot-unplugged earlier and has siblings */ 10210d1857a1SNathan Zimmer read_lock_irqsave(&cpufreq_driver_lock, flags); 10221b274294SViresh Kumar list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { 10231b274294SViresh Kumar if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) { 10240d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 102542f921a6SViresh Kumar ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev); 10266eed9404SViresh Kumar up_read(&cpufreq_rwsem); 10276eed9404SViresh Kumar return ret; 1028fcf80582SViresh Kumar } 10292eaa3e2dSViresh Kumar } 10300d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1031fcf80582SViresh Kumar #endif 10321da177e4SLinus Torvalds 103372368d12SRafael J. Wysocki /* 103472368d12SRafael J. Wysocki * Restore the saved policy when doing light-weight init and fall back 103572368d12SRafael J. Wysocki * to the full init if that fails. 103672368d12SRafael J. Wysocki */ 103772368d12SRafael J. Wysocki policy = frozen ? cpufreq_policy_restore(cpu) : NULL; 103872368d12SRafael J. Wysocki if (!policy) { 103972368d12SRafael J. Wysocki frozen = false; 1040e9698cc5SSrivatsa S. Bhat policy = cpufreq_policy_alloc(); 1041059019a3SDave Jones if (!policy) 10421da177e4SLinus Torvalds goto nomem_out; 104372368d12SRafael J. Wysocki } 10440d66b91eSSrivatsa S. Bhat 10450d66b91eSSrivatsa S. Bhat /* 10460d66b91eSSrivatsa S. Bhat * In the resume path, since we restore a saved policy, the assignment 10470d66b91eSSrivatsa S. Bhat * to policy->cpu is like an update of the existing policy, rather than 10480d66b91eSSrivatsa S. Bhat * the creation of a brand new one. So we need to perform this update 10490d66b91eSSrivatsa S. Bhat * by invoking update_policy_cpu(). 10500d66b91eSSrivatsa S. Bhat */ 10510d66b91eSSrivatsa S. Bhat if (frozen && cpu != policy->cpu) 10520d66b91eSSrivatsa S. Bhat update_policy_cpu(policy, cpu); 10530d66b91eSSrivatsa S. Bhat else 10541da177e4SLinus Torvalds policy->cpu = cpu; 10550d66b91eSSrivatsa S. Bhat 105665922465SViresh Kumar policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 1057835481d9SRusty Russell cpumask_copy(policy->cpus, cpumask_of(cpu)); 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds init_completion(&policy->kobj_unregister); 106065f27f38SDavid Howells INIT_WORK(&policy->update, handle_update); 10611da177e4SLinus Torvalds 10621da177e4SLinus Torvalds /* call driver. From then on the cpufreq must be able 10631da177e4SLinus Torvalds * to accept all calls to ->verify and ->setpolicy for this CPU 10641da177e4SLinus Torvalds */ 10651c3d85ddSRafael J. Wysocki ret = cpufreq_driver->init(policy); 10661da177e4SLinus Torvalds if (ret) { 10672d06d8c4SDominik Brodowski pr_debug("initialization failed\n"); 10682eaa3e2dSViresh Kumar goto err_set_policy_cpu; 10691da177e4SLinus Torvalds } 1070643ae6e8SViresh Kumar 1071da60ce9fSViresh Kumar if (cpufreq_driver->get) { 1072da60ce9fSViresh Kumar policy->cur = cpufreq_driver->get(policy->cpu); 1073da60ce9fSViresh Kumar if (!policy->cur) { 1074da60ce9fSViresh Kumar pr_err("%s: ->get() failed\n", __func__); 1075da60ce9fSViresh Kumar goto err_get_freq; 1076da60ce9fSViresh Kumar } 1077da60ce9fSViresh Kumar } 1078da60ce9fSViresh Kumar 1079d3916691SViresh Kumar /* 1080d3916691SViresh Kumar * Sometimes boot loaders set CPU frequency to a value outside of 1081d3916691SViresh Kumar * frequency table present with cpufreq core. In such cases CPU might be 1082d3916691SViresh Kumar * unstable if it has to run on that frequency for long duration of time 1083d3916691SViresh Kumar * and so its better to set it to a frequency which is specified in 1084d3916691SViresh Kumar * freq-table. This also makes cpufreq stats inconsistent as 1085d3916691SViresh Kumar * cpufreq-stats would fail to register because current frequency of CPU 1086d3916691SViresh Kumar * isn't found in freq-table. 1087d3916691SViresh Kumar * 1088d3916691SViresh Kumar * Because we don't want this change to effect boot process badly, we go 1089d3916691SViresh Kumar * for the next freq which is >= policy->cur ('cur' must be set by now, 1090d3916691SViresh Kumar * otherwise we will end up setting freq to lowest of the table as 'cur' 1091d3916691SViresh Kumar * is initialized to zero). 1092d3916691SViresh Kumar * 1093d3916691SViresh Kumar * We are passing target-freq as "policy->cur - 1" otherwise 1094d3916691SViresh Kumar * __cpufreq_driver_target() would simply fail, as policy->cur will be 1095d3916691SViresh Kumar * equal to target-freq. 1096d3916691SViresh Kumar */ 1097d3916691SViresh Kumar if ((cpufreq_driver->flags & CPUFREQ_NEED_INITIAL_FREQ_CHECK) 1098d3916691SViresh Kumar && has_target()) { 1099d3916691SViresh Kumar /* Are we running at unknown frequency ? */ 1100d3916691SViresh Kumar ret = cpufreq_frequency_table_get_index(policy, policy->cur); 1101d3916691SViresh Kumar if (ret == -EINVAL) { 1102d3916691SViresh Kumar /* Warn user and fix it */ 1103d3916691SViresh Kumar pr_warn("%s: CPU%d: Running at unlisted freq: %u KHz\n", 1104d3916691SViresh Kumar __func__, policy->cpu, policy->cur); 1105d3916691SViresh Kumar ret = __cpufreq_driver_target(policy, policy->cur - 1, 1106d3916691SViresh Kumar CPUFREQ_RELATION_L); 1107d3916691SViresh Kumar 1108d3916691SViresh Kumar /* 1109d3916691SViresh Kumar * Reaching here after boot in a few seconds may not 1110d3916691SViresh Kumar * mean that system will remain stable at "unknown" 1111d3916691SViresh Kumar * frequency for longer duration. Hence, a BUG_ON(). 1112d3916691SViresh Kumar */ 1113d3916691SViresh Kumar BUG_ON(ret); 1114d3916691SViresh Kumar pr_warn("%s: CPU%d: Unlisted initial frequency changed to: %u KHz\n", 1115d3916691SViresh Kumar __func__, policy->cpu, policy->cur); 1116d3916691SViresh Kumar } 1117d3916691SViresh Kumar } 1118d3916691SViresh Kumar 1119fcf80582SViresh Kumar /* related cpus should atleast have policy->cpus */ 1120fcf80582SViresh Kumar cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); 1121fcf80582SViresh Kumar 1122643ae6e8SViresh Kumar /* 1123643ae6e8SViresh Kumar * affected cpus must always be the one, which are online. We aren't 1124643ae6e8SViresh Kumar * managing offline cpus here. 1125643ae6e8SViresh Kumar */ 1126643ae6e8SViresh Kumar cpumask_and(policy->cpus, policy->cpus, cpu_online_mask); 1127643ae6e8SViresh Kumar 112808fd8c1cSViresh Kumar if (!frozen) { 1129187d9f4eSMike Chan policy->user_policy.min = policy->min; 1130187d9f4eSMike Chan policy->user_policy.max = policy->max; 113108fd8c1cSViresh Kumar } 11321da177e4SLinus Torvalds 1133a1531acdSThomas Renninger blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1134a1531acdSThomas Renninger CPUFREQ_START, policy); 1135a1531acdSThomas Renninger 1136fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 1137fcf80582SViresh Kumar gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu)); 1138fcf80582SViresh Kumar if (gov) { 1139fcf80582SViresh Kumar policy->governor = gov; 1140fcf80582SViresh Kumar pr_debug("Restoring governor %s for cpu %d\n", 1141fcf80582SViresh Kumar policy->governor->name, cpu); 11424bfa042cSThomas Renninger } 1143fcf80582SViresh Kumar #endif 11441da177e4SLinus Torvalds 1145e18f1682SSrivatsa S. Bhat write_lock_irqsave(&cpufreq_driver_lock, flags); 1146474deff7SViresh Kumar for_each_cpu(j, policy->cpus) 1147e18f1682SSrivatsa S. Bhat per_cpu(cpufreq_cpu_data, j) = policy; 1148e18f1682SSrivatsa S. Bhat write_unlock_irqrestore(&cpufreq_driver_lock, flags); 1149e18f1682SSrivatsa S. Bhat 1150a82fab29SSrivatsa S. Bhat if (!frozen) { 1151308b60e7SViresh Kumar ret = cpufreq_add_dev_interface(policy, dev); 115219d6f7ecSDave Jones if (ret) 11530142f9dcSAhmed S. Darwish goto err_out_unregister; 1154*fcd7af91SViresh Kumar blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1155*fcd7af91SViresh Kumar CPUFREQ_CREATE_POLICY, policy); 11569515f4d6SViresh Kumar } 1157c88a1f8bSLukasz Majewski 1158c88a1f8bSLukasz Majewski write_lock_irqsave(&cpufreq_driver_lock, flags); 1159c88a1f8bSLukasz Majewski list_add(&policy->policy_list, &cpufreq_policy_list); 1160c88a1f8bSLukasz Majewski write_unlock_irqrestore(&cpufreq_driver_lock, flags); 11618ff69732SDave Jones 1162e18f1682SSrivatsa S. Bhat cpufreq_init_policy(policy); 1163e18f1682SSrivatsa S. Bhat 116408fd8c1cSViresh Kumar if (!frozen) { 116508fd8c1cSViresh Kumar policy->user_policy.policy = policy->policy; 116608fd8c1cSViresh Kumar policy->user_policy.governor = policy->governor; 116708fd8c1cSViresh Kumar } 116808fd8c1cSViresh Kumar 1169038c5b3eSGreg Kroah-Hartman kobject_uevent(&policy->kobj, KOBJ_ADD); 11706eed9404SViresh Kumar up_read(&cpufreq_rwsem); 11716eed9404SViresh Kumar 11722d06d8c4SDominik Brodowski pr_debug("initialization complete\n"); 11731da177e4SLinus Torvalds 11741da177e4SLinus Torvalds return 0; 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds err_out_unregister: 11770d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 1178474deff7SViresh Kumar for_each_cpu(j, policy->cpus) 11797a6aedfaSMike Travis per_cpu(cpufreq_cpu_data, j) = NULL; 11800d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 11811da177e4SLinus Torvalds 1182da60ce9fSViresh Kumar err_get_freq: 1183da60ce9fSViresh Kumar if (cpufreq_driver->exit) 1184da60ce9fSViresh Kumar cpufreq_driver->exit(policy); 11852eaa3e2dSViresh Kumar err_set_policy_cpu: 118672368d12SRafael J. Wysocki if (frozen) { 118772368d12SRafael J. Wysocki /* Do not leave stale fallback data behind. */ 118872368d12SRafael J. Wysocki per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL; 118942f921a6SViresh Kumar cpufreq_policy_put_kobj(policy); 119072368d12SRafael J. Wysocki } 1191e9698cc5SSrivatsa S. Bhat cpufreq_policy_free(policy); 119242f921a6SViresh Kumar 11931da177e4SLinus Torvalds nomem_out: 11946eed9404SViresh Kumar up_read(&cpufreq_rwsem); 11956eed9404SViresh Kumar 11961da177e4SLinus Torvalds return ret; 11971da177e4SLinus Torvalds } 11981da177e4SLinus Torvalds 1199a82fab29SSrivatsa S. Bhat /** 1200a82fab29SSrivatsa S. Bhat * cpufreq_add_dev - add a CPU device 1201a82fab29SSrivatsa S. Bhat * 1202a82fab29SSrivatsa S. Bhat * Adds the cpufreq interface for a CPU device. 1203a82fab29SSrivatsa S. Bhat * 1204a82fab29SSrivatsa S. Bhat * The Oracle says: try running cpufreq registration/unregistration concurrently 1205a82fab29SSrivatsa S. Bhat * with with cpu hotplugging and all hell will break loose. Tried to clean this 1206a82fab29SSrivatsa S. Bhat * mess up, but more thorough testing is needed. - Mathieu 1207a82fab29SSrivatsa S. Bhat */ 1208a82fab29SSrivatsa S. Bhat static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) 1209a82fab29SSrivatsa S. Bhat { 1210a82fab29SSrivatsa S. Bhat return __cpufreq_add_dev(dev, sif, false); 1211a82fab29SSrivatsa S. Bhat } 1212a82fab29SSrivatsa S. Bhat 12133a3e9e06SViresh Kumar static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, 121442f921a6SViresh Kumar unsigned int old_cpu) 1215f9ba680dSSrivatsa S. Bhat { 1216f9ba680dSSrivatsa S. Bhat struct device *cpu_dev; 1217f9ba680dSSrivatsa S. Bhat int ret; 1218f9ba680dSSrivatsa S. Bhat 1219f9ba680dSSrivatsa S. Bhat /* first sibling now owns the new sysfs dir */ 12209c8f1ee4SViresh Kumar cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu)); 1221a82fab29SSrivatsa S. Bhat 1222f9ba680dSSrivatsa S. Bhat sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); 12233a3e9e06SViresh Kumar ret = kobject_move(&policy->kobj, &cpu_dev->kobj); 1224f9ba680dSSrivatsa S. Bhat if (ret) { 1225f9ba680dSSrivatsa S. Bhat pr_err("%s: Failed to move kobj: %d", __func__, ret); 1226f9ba680dSSrivatsa S. Bhat 1227ad7722daSviresh kumar down_write(&policy->rwsem); 12283a3e9e06SViresh Kumar cpumask_set_cpu(old_cpu, policy->cpus); 1229ad7722daSviresh kumar up_write(&policy->rwsem); 1230f9ba680dSSrivatsa S. Bhat 12313a3e9e06SViresh Kumar ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, 1232f9ba680dSSrivatsa S. Bhat "cpufreq"); 1233f9ba680dSSrivatsa S. Bhat 1234f9ba680dSSrivatsa S. Bhat return -EINVAL; 1235f9ba680dSSrivatsa S. Bhat } 1236f9ba680dSSrivatsa S. Bhat 1237f9ba680dSSrivatsa S. Bhat return cpu_dev->id; 1238f9ba680dSSrivatsa S. Bhat } 1239f9ba680dSSrivatsa S. Bhat 1240cedb70afSSrivatsa S. Bhat static int __cpufreq_remove_dev_prepare(struct device *dev, 1241cedb70afSSrivatsa S. Bhat struct subsys_interface *sif, 1242cedb70afSSrivatsa S. Bhat bool frozen) 12431da177e4SLinus Torvalds { 1244f9ba680dSSrivatsa S. Bhat unsigned int cpu = dev->id, cpus; 12453de9bdebSViresh Kumar int new_cpu, ret; 12461da177e4SLinus Torvalds unsigned long flags; 12473a3e9e06SViresh Kumar struct cpufreq_policy *policy; 12481da177e4SLinus Torvalds 1249b8eed8afSViresh Kumar pr_debug("%s: unregistering CPU %u\n", __func__, cpu); 12501da177e4SLinus Torvalds 12510d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 12521da177e4SLinus Torvalds 12533a3e9e06SViresh Kumar policy = per_cpu(cpufreq_cpu_data, cpu); 12541da177e4SLinus Torvalds 12558414809cSSrivatsa S. Bhat /* Save the policy somewhere when doing a light-weight tear-down */ 12568414809cSSrivatsa S. Bhat if (frozen) 12573a3e9e06SViresh Kumar per_cpu(cpufreq_cpu_data_fallback, cpu) = policy; 12588414809cSSrivatsa S. Bhat 12590d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 12601da177e4SLinus Torvalds 12613a3e9e06SViresh Kumar if (!policy) { 1262b8eed8afSViresh Kumar pr_debug("%s: No cpu_data found\n", __func__); 12631da177e4SLinus Torvalds return -EINVAL; 12641da177e4SLinus Torvalds } 12651da177e4SLinus Torvalds 12669c0ebcf7SViresh Kumar if (has_target()) { 12673de9bdebSViresh Kumar ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); 12683de9bdebSViresh Kumar if (ret) { 12693de9bdebSViresh Kumar pr_err("%s: Failed to stop governor\n", __func__); 12703de9bdebSViresh Kumar return ret; 12713de9bdebSViresh Kumar } 12723de9bdebSViresh Kumar } 12735a01f2e8SVenkatesh Pallipadi 12741da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG_CPU 12751c3d85ddSRafael J. Wysocki if (!cpufreq_driver->setpolicy) 1276fa69e33fSDirk Brandewie strncpy(per_cpu(cpufreq_cpu_governor, cpu), 12773a3e9e06SViresh Kumar policy->governor->name, CPUFREQ_NAME_LEN); 12781da177e4SLinus Torvalds #endif 12791da177e4SLinus Torvalds 1280ad7722daSviresh kumar down_read(&policy->rwsem); 12813a3e9e06SViresh Kumar cpus = cpumask_weight(policy->cpus); 1282ad7722daSviresh kumar up_read(&policy->rwsem); 12831da177e4SLinus Torvalds 128461173f25SSrivatsa S. Bhat if (cpu != policy->cpu) { 128561173f25SSrivatsa S. Bhat if (!frozen) 128673bf0fc2SViresh Kumar sysfs_remove_link(&dev->kobj, "cpufreq"); 128773bf0fc2SViresh Kumar } else if (cpus > 1) { 128842f921a6SViresh Kumar new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu); 1289f9ba680dSSrivatsa S. Bhat if (new_cpu >= 0) { 12903a3e9e06SViresh Kumar update_policy_cpu(policy, new_cpu); 1291a82fab29SSrivatsa S. Bhat 1292a82fab29SSrivatsa S. Bhat if (!frozen) { 129375949c9aSViresh Kumar pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", 129475949c9aSViresh Kumar __func__, new_cpu, cpu); 12951da177e4SLinus Torvalds } 12961da177e4SLinus Torvalds } 1297a82fab29SSrivatsa S. Bhat } 1298b8eed8afSViresh Kumar 1299cedb70afSSrivatsa S. Bhat return 0; 1300cedb70afSSrivatsa S. Bhat } 1301cedb70afSSrivatsa S. Bhat 1302cedb70afSSrivatsa S. Bhat static int __cpufreq_remove_dev_finish(struct device *dev, 1303cedb70afSSrivatsa S. Bhat struct subsys_interface *sif, 1304cedb70afSSrivatsa S. Bhat bool frozen) 1305cedb70afSSrivatsa S. Bhat { 1306cedb70afSSrivatsa S. Bhat unsigned int cpu = dev->id, cpus; 1307cedb70afSSrivatsa S. Bhat int ret; 1308cedb70afSSrivatsa S. Bhat unsigned long flags; 1309cedb70afSSrivatsa S. Bhat struct cpufreq_policy *policy; 1310cedb70afSSrivatsa S. Bhat 1311cedb70afSSrivatsa S. Bhat read_lock_irqsave(&cpufreq_driver_lock, flags); 1312cedb70afSSrivatsa S. Bhat policy = per_cpu(cpufreq_cpu_data, cpu); 1313cedb70afSSrivatsa S. Bhat read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1314cedb70afSSrivatsa S. Bhat 1315cedb70afSSrivatsa S. Bhat if (!policy) { 1316cedb70afSSrivatsa S. Bhat pr_debug("%s: No cpu_data found\n", __func__); 1317cedb70afSSrivatsa S. Bhat return -EINVAL; 1318cedb70afSSrivatsa S. Bhat } 1319cedb70afSSrivatsa S. Bhat 1320ad7722daSviresh kumar down_write(&policy->rwsem); 1321cedb70afSSrivatsa S. Bhat cpus = cpumask_weight(policy->cpus); 13229c8f1ee4SViresh Kumar 13239c8f1ee4SViresh Kumar if (cpus > 1) 13249c8f1ee4SViresh Kumar cpumask_clear_cpu(cpu, policy->cpus); 1325ad7722daSviresh kumar up_write(&policy->rwsem); 1326cedb70afSSrivatsa S. Bhat 1327b8eed8afSViresh Kumar /* If cpu is last user of policy, free policy */ 1328b8eed8afSViresh Kumar if (cpus == 1) { 13299c0ebcf7SViresh Kumar if (has_target()) { 13303de9bdebSViresh Kumar ret = __cpufreq_governor(policy, 13313de9bdebSViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 13323de9bdebSViresh Kumar if (ret) { 13333de9bdebSViresh Kumar pr_err("%s: Failed to exit governor\n", 13343de9bdebSViresh Kumar __func__); 13353de9bdebSViresh Kumar return ret; 13363de9bdebSViresh Kumar } 13373de9bdebSViresh Kumar } 13382a998599SRafael J. Wysocki 133942f921a6SViresh Kumar if (!frozen) 134042f921a6SViresh Kumar cpufreq_policy_put_kobj(policy); 13411da177e4SLinus Torvalds 13428414809cSSrivatsa S. Bhat /* 13438414809cSSrivatsa S. Bhat * Perform the ->exit() even during light-weight tear-down, 13448414809cSSrivatsa S. Bhat * since this is a core component, and is essential for the 13458414809cSSrivatsa S. Bhat * subsequent light-weight ->init() to succeed. 13468414809cSSrivatsa S. Bhat */ 13471c3d85ddSRafael J. Wysocki if (cpufreq_driver->exit) 13483a3e9e06SViresh Kumar cpufreq_driver->exit(policy); 134927ecddc2SJacob Shin 13509515f4d6SViresh Kumar /* Remove policy from list of active policies */ 13519515f4d6SViresh Kumar write_lock_irqsave(&cpufreq_driver_lock, flags); 13529515f4d6SViresh Kumar list_del(&policy->policy_list); 13539515f4d6SViresh Kumar write_unlock_irqrestore(&cpufreq_driver_lock, flags); 13549515f4d6SViresh Kumar 13558414809cSSrivatsa S. Bhat if (!frozen) 13563a3e9e06SViresh Kumar cpufreq_policy_free(policy); 13572a998599SRafael J. Wysocki } else { 13589c0ebcf7SViresh Kumar if (has_target()) { 13593de9bdebSViresh Kumar if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) || 13603de9bdebSViresh Kumar (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) { 13613de9bdebSViresh Kumar pr_err("%s: Failed to start governor\n", 13623de9bdebSViresh Kumar __func__); 13633de9bdebSViresh Kumar return ret; 13643de9bdebSViresh Kumar } 1365b8eed8afSViresh Kumar } 13662a998599SRafael J. Wysocki } 13671da177e4SLinus Torvalds 1368474deff7SViresh Kumar per_cpu(cpufreq_cpu_data, cpu) = NULL; 13691da177e4SLinus Torvalds return 0; 13701da177e4SLinus Torvalds } 13711da177e4SLinus Torvalds 1372cedb70afSSrivatsa S. Bhat /** 137327a862e9SViresh Kumar * cpufreq_remove_dev - remove a CPU device 1374cedb70afSSrivatsa S. Bhat * 1375cedb70afSSrivatsa S. Bhat * Removes the cpufreq interface for a CPU device. 1376cedb70afSSrivatsa S. Bhat */ 13778a25a2fdSKay Sievers static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) 13785a01f2e8SVenkatesh Pallipadi { 13798a25a2fdSKay Sievers unsigned int cpu = dev->id; 138027a862e9SViresh Kumar int ret; 1381ec28297aSVenki Pallipadi 1382ec28297aSVenki Pallipadi if (cpu_is_offline(cpu)) 1383ec28297aSVenki Pallipadi return 0; 1384ec28297aSVenki Pallipadi 138527a862e9SViresh Kumar ret = __cpufreq_remove_dev_prepare(dev, sif, false); 138627a862e9SViresh Kumar 138727a862e9SViresh Kumar if (!ret) 138827a862e9SViresh Kumar ret = __cpufreq_remove_dev_finish(dev, sif, false); 138927a862e9SViresh Kumar 139027a862e9SViresh Kumar return ret; 13915a01f2e8SVenkatesh Pallipadi } 13925a01f2e8SVenkatesh Pallipadi 139365f27f38SDavid Howells static void handle_update(struct work_struct *work) 13941da177e4SLinus Torvalds { 139565f27f38SDavid Howells struct cpufreq_policy *policy = 139665f27f38SDavid Howells container_of(work, struct cpufreq_policy, update); 139765f27f38SDavid Howells unsigned int cpu = policy->cpu; 13982d06d8c4SDominik Brodowski pr_debug("handle_update for cpu %u called\n", cpu); 13991da177e4SLinus Torvalds cpufreq_update_policy(cpu); 14001da177e4SLinus Torvalds } 14011da177e4SLinus Torvalds 14021da177e4SLinus Torvalds /** 1403bb176f7dSViresh Kumar * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're 1404bb176f7dSViresh Kumar * in deep trouble. 14051da177e4SLinus Torvalds * @cpu: cpu number 14061da177e4SLinus Torvalds * @old_freq: CPU frequency the kernel thinks the CPU runs at 14071da177e4SLinus Torvalds * @new_freq: CPU frequency the CPU actually runs at 14081da177e4SLinus Torvalds * 140929464f28SDave Jones * We adjust to current frequency first, and need to clean up later. 141029464f28SDave Jones * So either call to cpufreq_update_policy() or schedule handle_update()). 14111da177e4SLinus Torvalds */ 1412e08f5f5bSGautham R Shenoy static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, 1413e08f5f5bSGautham R Shenoy unsigned int new_freq) 14141da177e4SLinus Torvalds { 1415b43a7ffbSViresh Kumar struct cpufreq_policy *policy; 14161da177e4SLinus Torvalds struct cpufreq_freqs freqs; 1417b43a7ffbSViresh Kumar unsigned long flags; 1418b43a7ffbSViresh Kumar 14192d06d8c4SDominik Brodowski pr_debug("Warning: CPU frequency out of sync: cpufreq and timing " 14201da177e4SLinus Torvalds "core thinks of %u, is %u kHz.\n", old_freq, new_freq); 14211da177e4SLinus Torvalds 14221da177e4SLinus Torvalds freqs.old = old_freq; 14231da177e4SLinus Torvalds freqs.new = new_freq; 1424b43a7ffbSViresh Kumar 1425b43a7ffbSViresh Kumar read_lock_irqsave(&cpufreq_driver_lock, flags); 1426b43a7ffbSViresh Kumar policy = per_cpu(cpufreq_cpu_data, cpu); 1427b43a7ffbSViresh Kumar read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1428b43a7ffbSViresh Kumar 1429b43a7ffbSViresh Kumar cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); 1430b43a7ffbSViresh Kumar cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); 14311da177e4SLinus Torvalds } 14321da177e4SLinus Torvalds 14331da177e4SLinus Torvalds /** 14344ab70df4SDhaval Giani * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur 143595235ca2SVenkatesh Pallipadi * @cpu: CPU number 143695235ca2SVenkatesh Pallipadi * 143795235ca2SVenkatesh Pallipadi * This is the last known freq, without actually getting it from the driver. 143895235ca2SVenkatesh Pallipadi * Return value will be same as what is shown in scaling_cur_freq in sysfs. 143995235ca2SVenkatesh Pallipadi */ 144095235ca2SVenkatesh Pallipadi unsigned int cpufreq_quick_get(unsigned int cpu) 144195235ca2SVenkatesh Pallipadi { 14429e21ba8bSDirk Brandewie struct cpufreq_policy *policy; 1443e08f5f5bSGautham R Shenoy unsigned int ret_freq = 0; 144495235ca2SVenkatesh Pallipadi 14451c3d85ddSRafael J. Wysocki if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get) 14461c3d85ddSRafael J. Wysocki return cpufreq_driver->get(cpu); 14479e21ba8bSDirk Brandewie 14489e21ba8bSDirk Brandewie policy = cpufreq_cpu_get(cpu); 144995235ca2SVenkatesh Pallipadi if (policy) { 1450e08f5f5bSGautham R Shenoy ret_freq = policy->cur; 145195235ca2SVenkatesh Pallipadi cpufreq_cpu_put(policy); 145295235ca2SVenkatesh Pallipadi } 145395235ca2SVenkatesh Pallipadi 14544d34a67dSDave Jones return ret_freq; 145595235ca2SVenkatesh Pallipadi } 145695235ca2SVenkatesh Pallipadi EXPORT_SYMBOL(cpufreq_quick_get); 145795235ca2SVenkatesh Pallipadi 14583d737108SJesse Barnes /** 14593d737108SJesse Barnes * cpufreq_quick_get_max - get the max reported CPU frequency for this CPU 14603d737108SJesse Barnes * @cpu: CPU number 14613d737108SJesse Barnes * 14623d737108SJesse Barnes * Just return the max possible frequency for a given CPU. 14633d737108SJesse Barnes */ 14643d737108SJesse Barnes unsigned int cpufreq_quick_get_max(unsigned int cpu) 14653d737108SJesse Barnes { 14663d737108SJesse Barnes struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 14673d737108SJesse Barnes unsigned int ret_freq = 0; 14683d737108SJesse Barnes 14693d737108SJesse Barnes if (policy) { 14703d737108SJesse Barnes ret_freq = policy->max; 14713d737108SJesse Barnes cpufreq_cpu_put(policy); 14723d737108SJesse Barnes } 14733d737108SJesse Barnes 14743d737108SJesse Barnes return ret_freq; 14753d737108SJesse Barnes } 14763d737108SJesse Barnes EXPORT_SYMBOL(cpufreq_quick_get_max); 14773d737108SJesse Barnes 14785a01f2e8SVenkatesh Pallipadi static unsigned int __cpufreq_get(unsigned int cpu) 14791da177e4SLinus Torvalds { 14807a6aedfaSMike Travis struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); 1481e08f5f5bSGautham R Shenoy unsigned int ret_freq = 0; 14821da177e4SLinus Torvalds 14831c3d85ddSRafael J. Wysocki if (!cpufreq_driver->get) 14844d34a67dSDave Jones return ret_freq; 14851da177e4SLinus Torvalds 14861c3d85ddSRafael J. Wysocki ret_freq = cpufreq_driver->get(cpu); 14871da177e4SLinus Torvalds 1488e08f5f5bSGautham R Shenoy if (ret_freq && policy->cur && 14891c3d85ddSRafael J. Wysocki !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { 1490e08f5f5bSGautham R Shenoy /* verify no discrepancy between actual and 1491e08f5f5bSGautham R Shenoy saved value exists */ 1492e08f5f5bSGautham R Shenoy if (unlikely(ret_freq != policy->cur)) { 1493e08f5f5bSGautham R Shenoy cpufreq_out_of_sync(cpu, policy->cur, ret_freq); 14941da177e4SLinus Torvalds schedule_work(&policy->update); 14951da177e4SLinus Torvalds } 14961da177e4SLinus Torvalds } 14971da177e4SLinus Torvalds 14984d34a67dSDave Jones return ret_freq; 14995a01f2e8SVenkatesh Pallipadi } 15001da177e4SLinus Torvalds 15015a01f2e8SVenkatesh Pallipadi /** 15025a01f2e8SVenkatesh Pallipadi * cpufreq_get - get the current CPU frequency (in kHz) 15035a01f2e8SVenkatesh Pallipadi * @cpu: CPU number 15045a01f2e8SVenkatesh Pallipadi * 15055a01f2e8SVenkatesh Pallipadi * Get the CPU current (static) CPU frequency 15065a01f2e8SVenkatesh Pallipadi */ 15075a01f2e8SVenkatesh Pallipadi unsigned int cpufreq_get(unsigned int cpu) 15085a01f2e8SVenkatesh Pallipadi { 1509ad7722daSviresh kumar struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); 15105a01f2e8SVenkatesh Pallipadi unsigned int ret_freq = 0; 15115a01f2e8SVenkatesh Pallipadi 151226ca8694SViresh Kumar if (cpufreq_disabled() || !cpufreq_driver) 151326ca8694SViresh Kumar return -ENOENT; 151426ca8694SViresh Kumar 1515ad7722daSviresh kumar BUG_ON(!policy); 1516ad7722daSviresh kumar 15176eed9404SViresh Kumar if (!down_read_trylock(&cpufreq_rwsem)) 15186eed9404SViresh Kumar return 0; 15195a01f2e8SVenkatesh Pallipadi 1520ad7722daSviresh kumar down_read(&policy->rwsem); 15215a01f2e8SVenkatesh Pallipadi 15225a01f2e8SVenkatesh Pallipadi ret_freq = __cpufreq_get(cpu); 15235a01f2e8SVenkatesh Pallipadi 1524ad7722daSviresh kumar up_read(&policy->rwsem); 15256eed9404SViresh Kumar up_read(&cpufreq_rwsem); 15266eed9404SViresh Kumar 15274d34a67dSDave Jones return ret_freq; 15281da177e4SLinus Torvalds } 15291da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_get); 15301da177e4SLinus Torvalds 15318a25a2fdSKay Sievers static struct subsys_interface cpufreq_interface = { 15328a25a2fdSKay Sievers .name = "cpufreq", 15338a25a2fdSKay Sievers .subsys = &cpu_subsys, 15348a25a2fdSKay Sievers .add_dev = cpufreq_add_dev, 15358a25a2fdSKay Sievers .remove_dev = cpufreq_remove_dev, 1536e00e56dfSRafael J. Wysocki }; 1537e00e56dfSRafael J. Wysocki 15381da177e4SLinus Torvalds /** 1539e00e56dfSRafael J. Wysocki * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. 1540e00e56dfSRafael J. Wysocki * 1541e00e56dfSRafael J. Wysocki * This function is only executed for the boot processor. The other CPUs 1542e00e56dfSRafael J. Wysocki * have been put offline by means of CPU hotplug. 154342d4dc3fSBenjamin Herrenschmidt */ 1544e00e56dfSRafael J. Wysocki static int cpufreq_bp_suspend(void) 154542d4dc3fSBenjamin Herrenschmidt { 1546e08f5f5bSGautham R Shenoy int ret = 0; 15474bc5d341SDave Jones 1548e00e56dfSRafael J. Wysocki int cpu = smp_processor_id(); 15493a3e9e06SViresh Kumar struct cpufreq_policy *policy; 155042d4dc3fSBenjamin Herrenschmidt 15512d06d8c4SDominik Brodowski pr_debug("suspending cpu %u\n", cpu); 155242d4dc3fSBenjamin Herrenschmidt 1553e00e56dfSRafael J. Wysocki /* If there's no policy for the boot CPU, we have nothing to do. */ 15543a3e9e06SViresh Kumar policy = cpufreq_cpu_get(cpu); 15553a3e9e06SViresh Kumar if (!policy) 1556e00e56dfSRafael J. Wysocki return 0; 155742d4dc3fSBenjamin Herrenschmidt 15581c3d85ddSRafael J. Wysocki if (cpufreq_driver->suspend) { 15593a3e9e06SViresh Kumar ret = cpufreq_driver->suspend(policy); 1560ce6c3997SDominik Brodowski if (ret) 156142d4dc3fSBenjamin Herrenschmidt printk(KERN_ERR "cpufreq: suspend failed in ->suspend " 15623a3e9e06SViresh Kumar "step on CPU %u\n", policy->cpu); 156342d4dc3fSBenjamin Herrenschmidt } 156442d4dc3fSBenjamin Herrenschmidt 15653a3e9e06SViresh Kumar cpufreq_cpu_put(policy); 1566c9060494SDave Jones return ret; 156742d4dc3fSBenjamin Herrenschmidt } 156842d4dc3fSBenjamin Herrenschmidt 156942d4dc3fSBenjamin Herrenschmidt /** 1570e00e56dfSRafael J. Wysocki * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU. 15711da177e4SLinus Torvalds * 15721da177e4SLinus Torvalds * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) 1573ce6c3997SDominik Brodowski * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are 1574ce6c3997SDominik Brodowski * restored. It will verify that the current freq is in sync with 1575ce6c3997SDominik Brodowski * what we believe it to be. This is a bit later than when it 1576ce6c3997SDominik Brodowski * should be, but nonethteless it's better than calling 1577ce6c3997SDominik Brodowski * cpufreq_driver->get() here which might re-enable interrupts... 1578e00e56dfSRafael J. Wysocki * 1579e00e56dfSRafael J. Wysocki * This function is only executed for the boot CPU. The other CPUs have not 1580e00e56dfSRafael J. Wysocki * been turned on yet. 15811da177e4SLinus Torvalds */ 1582e00e56dfSRafael J. Wysocki static void cpufreq_bp_resume(void) 15831da177e4SLinus Torvalds { 1584e08f5f5bSGautham R Shenoy int ret = 0; 15854bc5d341SDave Jones 1586e00e56dfSRafael J. Wysocki int cpu = smp_processor_id(); 15873a3e9e06SViresh Kumar struct cpufreq_policy *policy; 15881da177e4SLinus Torvalds 15892d06d8c4SDominik Brodowski pr_debug("resuming cpu %u\n", cpu); 15901da177e4SLinus Torvalds 1591e00e56dfSRafael J. Wysocki /* If there's no policy for the boot CPU, we have nothing to do. */ 15923a3e9e06SViresh Kumar policy = cpufreq_cpu_get(cpu); 15933a3e9e06SViresh Kumar if (!policy) 1594e00e56dfSRafael J. Wysocki return; 15951da177e4SLinus Torvalds 15961c3d85ddSRafael J. Wysocki if (cpufreq_driver->resume) { 15973a3e9e06SViresh Kumar ret = cpufreq_driver->resume(policy); 15981da177e4SLinus Torvalds if (ret) { 15991da177e4SLinus Torvalds printk(KERN_ERR "cpufreq: resume failed in ->resume " 16003a3e9e06SViresh Kumar "step on CPU %u\n", policy->cpu); 1601c9060494SDave Jones goto fail; 16021da177e4SLinus Torvalds } 16031da177e4SLinus Torvalds } 16041da177e4SLinus Torvalds 16053a3e9e06SViresh Kumar schedule_work(&policy->update); 1606ce6c3997SDominik Brodowski 1607c9060494SDave Jones fail: 16083a3e9e06SViresh Kumar cpufreq_cpu_put(policy); 16091da177e4SLinus Torvalds } 16101da177e4SLinus Torvalds 1611e00e56dfSRafael J. Wysocki static struct syscore_ops cpufreq_syscore_ops = { 1612e00e56dfSRafael J. Wysocki .suspend = cpufreq_bp_suspend, 1613e00e56dfSRafael J. Wysocki .resume = cpufreq_bp_resume, 16141da177e4SLinus Torvalds }; 16151da177e4SLinus Torvalds 16169d95046eSBorislav Petkov /** 16179d95046eSBorislav Petkov * cpufreq_get_current_driver - return current driver's name 16189d95046eSBorislav Petkov * 16199d95046eSBorislav Petkov * Return the name string of the currently loaded cpufreq driver 16209d95046eSBorislav Petkov * or NULL, if none. 16219d95046eSBorislav Petkov */ 16229d95046eSBorislav Petkov const char *cpufreq_get_current_driver(void) 16239d95046eSBorislav Petkov { 16241c3d85ddSRafael J. Wysocki if (cpufreq_driver) 16251c3d85ddSRafael J. Wysocki return cpufreq_driver->name; 16261c3d85ddSRafael J. Wysocki 16271c3d85ddSRafael J. Wysocki return NULL; 16289d95046eSBorislav Petkov } 16299d95046eSBorislav Petkov EXPORT_SYMBOL_GPL(cpufreq_get_current_driver); 16301da177e4SLinus Torvalds 16311da177e4SLinus Torvalds /********************************************************************* 16321da177e4SLinus Torvalds * NOTIFIER LISTS INTERFACE * 16331da177e4SLinus Torvalds *********************************************************************/ 16341da177e4SLinus Torvalds 16351da177e4SLinus Torvalds /** 16361da177e4SLinus Torvalds * cpufreq_register_notifier - register a driver with cpufreq 16371da177e4SLinus Torvalds * @nb: notifier function to register 16381da177e4SLinus Torvalds * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER 16391da177e4SLinus Torvalds * 16401da177e4SLinus Torvalds * Add a driver to one of two lists: either a list of drivers that 16411da177e4SLinus Torvalds * are notified about clock rate changes (once before and once after 16421da177e4SLinus Torvalds * the transition), or a list of drivers that are notified about 16431da177e4SLinus Torvalds * changes in cpufreq policy. 16441da177e4SLinus Torvalds * 16451da177e4SLinus Torvalds * This function may sleep, and has the same return conditions as 1646e041c683SAlan Stern * blocking_notifier_chain_register. 16471da177e4SLinus Torvalds */ 16481da177e4SLinus Torvalds int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) 16491da177e4SLinus Torvalds { 16501da177e4SLinus Torvalds int ret; 16511da177e4SLinus Torvalds 1652d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1653d5aaffa9SDirk Brandewie return -EINVAL; 1654d5aaffa9SDirk Brandewie 165574212ca4SCesar Eduardo Barros WARN_ON(!init_cpufreq_transition_notifier_list_called); 165674212ca4SCesar Eduardo Barros 16571da177e4SLinus Torvalds switch (list) { 16581da177e4SLinus Torvalds case CPUFREQ_TRANSITION_NOTIFIER: 1659b4dfdbb3SAlan Stern ret = srcu_notifier_chain_register( 1660e041c683SAlan Stern &cpufreq_transition_notifier_list, nb); 16611da177e4SLinus Torvalds break; 16621da177e4SLinus Torvalds case CPUFREQ_POLICY_NOTIFIER: 1663e041c683SAlan Stern ret = blocking_notifier_chain_register( 1664e041c683SAlan Stern &cpufreq_policy_notifier_list, nb); 16651da177e4SLinus Torvalds break; 16661da177e4SLinus Torvalds default: 16671da177e4SLinus Torvalds ret = -EINVAL; 16681da177e4SLinus Torvalds } 16691da177e4SLinus Torvalds 16701da177e4SLinus Torvalds return ret; 16711da177e4SLinus Torvalds } 16721da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_register_notifier); 16731da177e4SLinus Torvalds 16741da177e4SLinus Torvalds /** 16751da177e4SLinus Torvalds * cpufreq_unregister_notifier - unregister a driver with cpufreq 16761da177e4SLinus Torvalds * @nb: notifier block to be unregistered 16771da177e4SLinus Torvalds * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER 16781da177e4SLinus Torvalds * 16791da177e4SLinus Torvalds * Remove a driver from the CPU frequency notifier list. 16801da177e4SLinus Torvalds * 16811da177e4SLinus Torvalds * This function may sleep, and has the same return conditions as 1682e041c683SAlan Stern * blocking_notifier_chain_unregister. 16831da177e4SLinus Torvalds */ 16841da177e4SLinus Torvalds int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) 16851da177e4SLinus Torvalds { 16861da177e4SLinus Torvalds int ret; 16871da177e4SLinus Torvalds 1688d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1689d5aaffa9SDirk Brandewie return -EINVAL; 1690d5aaffa9SDirk Brandewie 16911da177e4SLinus Torvalds switch (list) { 16921da177e4SLinus Torvalds case CPUFREQ_TRANSITION_NOTIFIER: 1693b4dfdbb3SAlan Stern ret = srcu_notifier_chain_unregister( 1694e041c683SAlan Stern &cpufreq_transition_notifier_list, nb); 16951da177e4SLinus Torvalds break; 16961da177e4SLinus Torvalds case CPUFREQ_POLICY_NOTIFIER: 1697e041c683SAlan Stern ret = blocking_notifier_chain_unregister( 1698e041c683SAlan Stern &cpufreq_policy_notifier_list, nb); 16991da177e4SLinus Torvalds break; 17001da177e4SLinus Torvalds default: 17011da177e4SLinus Torvalds ret = -EINVAL; 17021da177e4SLinus Torvalds } 17031da177e4SLinus Torvalds 17041da177e4SLinus Torvalds return ret; 17051da177e4SLinus Torvalds } 17061da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_unregister_notifier); 17071da177e4SLinus Torvalds 17081da177e4SLinus Torvalds 17091da177e4SLinus Torvalds /********************************************************************* 17101da177e4SLinus Torvalds * GOVERNORS * 17111da177e4SLinus Torvalds *********************************************************************/ 17121da177e4SLinus Torvalds 17131da177e4SLinus Torvalds int __cpufreq_driver_target(struct cpufreq_policy *policy, 17141da177e4SLinus Torvalds unsigned int target_freq, 17151da177e4SLinus Torvalds unsigned int relation) 17161da177e4SLinus Torvalds { 17171da177e4SLinus Torvalds int retval = -EINVAL; 17187249924eSViresh Kumar unsigned int old_target_freq = target_freq; 1719c32b6b8eSAshok Raj 1720a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1721a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 1722a7b422cdSKonrad Rzeszutek Wilk 17237249924eSViresh Kumar /* Make sure that target_freq is within supported range */ 17247249924eSViresh Kumar if (target_freq > policy->max) 17257249924eSViresh Kumar target_freq = policy->max; 17267249924eSViresh Kumar if (target_freq < policy->min) 17277249924eSViresh Kumar target_freq = policy->min; 17287249924eSViresh Kumar 17297249924eSViresh Kumar pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", 17307249924eSViresh Kumar policy->cpu, target_freq, relation, old_target_freq); 17315a1c0228SViresh Kumar 17329c0ebcf7SViresh Kumar /* 17339c0ebcf7SViresh Kumar * This might look like a redundant call as we are checking it again 17349c0ebcf7SViresh Kumar * after finding index. But it is left intentionally for cases where 17359c0ebcf7SViresh Kumar * exactly same freq is called again and so we can save on few function 17369c0ebcf7SViresh Kumar * calls. 17379c0ebcf7SViresh Kumar */ 17385a1c0228SViresh Kumar if (target_freq == policy->cur) 17395a1c0228SViresh Kumar return 0; 17405a1c0228SViresh Kumar 17411c3d85ddSRafael J. Wysocki if (cpufreq_driver->target) 17421c3d85ddSRafael J. Wysocki retval = cpufreq_driver->target(policy, target_freq, relation); 17439c0ebcf7SViresh Kumar else if (cpufreq_driver->target_index) { 17449c0ebcf7SViresh Kumar struct cpufreq_frequency_table *freq_table; 1745d4019f0aSViresh Kumar struct cpufreq_freqs freqs; 1746d4019f0aSViresh Kumar bool notify; 17479c0ebcf7SViresh Kumar int index; 174890d45d17SAshok Raj 17499c0ebcf7SViresh Kumar freq_table = cpufreq_frequency_get_table(policy->cpu); 17509c0ebcf7SViresh Kumar if (unlikely(!freq_table)) { 17519c0ebcf7SViresh Kumar pr_err("%s: Unable to find freq_table\n", __func__); 17529c0ebcf7SViresh Kumar goto out; 17539c0ebcf7SViresh Kumar } 17549c0ebcf7SViresh Kumar 17559c0ebcf7SViresh Kumar retval = cpufreq_frequency_table_target(policy, freq_table, 17569c0ebcf7SViresh Kumar target_freq, relation, &index); 17579c0ebcf7SViresh Kumar if (unlikely(retval)) { 17589c0ebcf7SViresh Kumar pr_err("%s: Unable to find matching freq\n", __func__); 17599c0ebcf7SViresh Kumar goto out; 17609c0ebcf7SViresh Kumar } 17619c0ebcf7SViresh Kumar 1762d4019f0aSViresh Kumar if (freq_table[index].frequency == policy->cur) { 17639c0ebcf7SViresh Kumar retval = 0; 1764d4019f0aSViresh Kumar goto out; 1765d4019f0aSViresh Kumar } 1766d4019f0aSViresh Kumar 1767d4019f0aSViresh Kumar notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION); 1768d4019f0aSViresh Kumar 1769d4019f0aSViresh Kumar if (notify) { 1770d4019f0aSViresh Kumar freqs.old = policy->cur; 1771d4019f0aSViresh Kumar freqs.new = freq_table[index].frequency; 1772d4019f0aSViresh Kumar freqs.flags = 0; 1773d4019f0aSViresh Kumar 1774d4019f0aSViresh Kumar pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n", 1775d4019f0aSViresh Kumar __func__, policy->cpu, freqs.old, 1776d4019f0aSViresh Kumar freqs.new); 1777d4019f0aSViresh Kumar 1778d4019f0aSViresh Kumar cpufreq_notify_transition(policy, &freqs, 1779d4019f0aSViresh Kumar CPUFREQ_PRECHANGE); 1780d4019f0aSViresh Kumar } 1781d4019f0aSViresh Kumar 17829c0ebcf7SViresh Kumar retval = cpufreq_driver->target_index(policy, index); 1783d4019f0aSViresh Kumar if (retval) 1784d4019f0aSViresh Kumar pr_err("%s: Failed to change cpu frequency: %d\n", 1785d4019f0aSViresh Kumar __func__, retval); 1786d4019f0aSViresh Kumar 1787ab1b1c4eSViresh Kumar if (notify) 1788ab1b1c4eSViresh Kumar cpufreq_notify_post_transition(policy, &freqs, retval); 17899c0ebcf7SViresh Kumar } 17909c0ebcf7SViresh Kumar 17919c0ebcf7SViresh Kumar out: 17921da177e4SLinus Torvalds return retval; 17931da177e4SLinus Torvalds } 17941da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(__cpufreq_driver_target); 17951da177e4SLinus Torvalds 17961da177e4SLinus Torvalds int cpufreq_driver_target(struct cpufreq_policy *policy, 17971da177e4SLinus Torvalds unsigned int target_freq, 17981da177e4SLinus Torvalds unsigned int relation) 17991da177e4SLinus Torvalds { 1800f1829e4aSJulia Lawall int ret = -EINVAL; 18011da177e4SLinus Torvalds 1802ad7722daSviresh kumar down_write(&policy->rwsem); 18031da177e4SLinus Torvalds 18041da177e4SLinus Torvalds ret = __cpufreq_driver_target(policy, target_freq, relation); 18051da177e4SLinus Torvalds 1806ad7722daSviresh kumar up_write(&policy->rwsem); 18071da177e4SLinus Torvalds 18081da177e4SLinus Torvalds return ret; 18091da177e4SLinus Torvalds } 18101da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_driver_target); 18111da177e4SLinus Torvalds 1812153d7f3fSArjan van de Ven /* 1813153d7f3fSArjan van de Ven * when "event" is CPUFREQ_GOV_LIMITS 1814153d7f3fSArjan van de Ven */ 18151da177e4SLinus Torvalds 1816e08f5f5bSGautham R Shenoy static int __cpufreq_governor(struct cpufreq_policy *policy, 1817e08f5f5bSGautham R Shenoy unsigned int event) 18181da177e4SLinus Torvalds { 1819cc993cabSDave Jones int ret; 18206afde10cSThomas Renninger 18216afde10cSThomas Renninger /* Only must be defined when default governor is known to have latency 18226afde10cSThomas Renninger restrictions, like e.g. conservative or ondemand. 18236afde10cSThomas Renninger That this is the case is already ensured in Kconfig 18246afde10cSThomas Renninger */ 18256afde10cSThomas Renninger #ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE 18266afde10cSThomas Renninger struct cpufreq_governor *gov = &cpufreq_gov_performance; 18276afde10cSThomas Renninger #else 18286afde10cSThomas Renninger struct cpufreq_governor *gov = NULL; 18296afde10cSThomas Renninger #endif 18301c256245SThomas Renninger 18311c256245SThomas Renninger if (policy->governor->max_transition_latency && 18321c256245SThomas Renninger policy->cpuinfo.transition_latency > 18331c256245SThomas Renninger policy->governor->max_transition_latency) { 18346afde10cSThomas Renninger if (!gov) 18356afde10cSThomas Renninger return -EINVAL; 18366afde10cSThomas Renninger else { 18371c256245SThomas Renninger printk(KERN_WARNING "%s governor failed, too long" 18381c256245SThomas Renninger " transition latency of HW, fallback" 18391c256245SThomas Renninger " to %s governor\n", 18401c256245SThomas Renninger policy->governor->name, 18411c256245SThomas Renninger gov->name); 18421c256245SThomas Renninger policy->governor = gov; 18431c256245SThomas Renninger } 18446afde10cSThomas Renninger } 18451da177e4SLinus Torvalds 1846fe492f3fSViresh Kumar if (event == CPUFREQ_GOV_POLICY_INIT) 18471da177e4SLinus Torvalds if (!try_module_get(policy->governor->owner)) 18481da177e4SLinus Torvalds return -EINVAL; 18491da177e4SLinus Torvalds 18502d06d8c4SDominik Brodowski pr_debug("__cpufreq_governor for CPU %u, event %u\n", 1851e08f5f5bSGautham R Shenoy policy->cpu, event); 185295731ebbSXiaoguang Chen 185395731ebbSXiaoguang Chen mutex_lock(&cpufreq_governor_lock); 185456d07db2SSrivatsa S. Bhat if ((policy->governor_enabled && event == CPUFREQ_GOV_START) 1855f73d3933SViresh Kumar || (!policy->governor_enabled 1856f73d3933SViresh Kumar && (event == CPUFREQ_GOV_LIMITS || event == CPUFREQ_GOV_STOP))) { 185795731ebbSXiaoguang Chen mutex_unlock(&cpufreq_governor_lock); 185895731ebbSXiaoguang Chen return -EBUSY; 185995731ebbSXiaoguang Chen } 186095731ebbSXiaoguang Chen 186195731ebbSXiaoguang Chen if (event == CPUFREQ_GOV_STOP) 186295731ebbSXiaoguang Chen policy->governor_enabled = false; 186395731ebbSXiaoguang Chen else if (event == CPUFREQ_GOV_START) 186495731ebbSXiaoguang Chen policy->governor_enabled = true; 186595731ebbSXiaoguang Chen 186695731ebbSXiaoguang Chen mutex_unlock(&cpufreq_governor_lock); 186795731ebbSXiaoguang Chen 18681da177e4SLinus Torvalds ret = policy->governor->governor(policy, event); 18691da177e4SLinus Torvalds 18704d5dcc42SViresh Kumar if (!ret) { 18714d5dcc42SViresh Kumar if (event == CPUFREQ_GOV_POLICY_INIT) 18728e53695fSViresh Kumar policy->governor->initialized++; 18734d5dcc42SViresh Kumar else if (event == CPUFREQ_GOV_POLICY_EXIT) 18748e53695fSViresh Kumar policy->governor->initialized--; 187595731ebbSXiaoguang Chen } else { 187695731ebbSXiaoguang Chen /* Restore original values */ 187795731ebbSXiaoguang Chen mutex_lock(&cpufreq_governor_lock); 187895731ebbSXiaoguang Chen if (event == CPUFREQ_GOV_STOP) 187995731ebbSXiaoguang Chen policy->governor_enabled = true; 188095731ebbSXiaoguang Chen else if (event == CPUFREQ_GOV_START) 188195731ebbSXiaoguang Chen policy->governor_enabled = false; 188295731ebbSXiaoguang Chen mutex_unlock(&cpufreq_governor_lock); 18834d5dcc42SViresh Kumar } 1884b394058fSViresh Kumar 1885fe492f3fSViresh Kumar if (((event == CPUFREQ_GOV_POLICY_INIT) && ret) || 1886fe492f3fSViresh Kumar ((event == CPUFREQ_GOV_POLICY_EXIT) && !ret)) 18871da177e4SLinus Torvalds module_put(policy->governor->owner); 18881da177e4SLinus Torvalds 18891da177e4SLinus Torvalds return ret; 18901da177e4SLinus Torvalds } 18911da177e4SLinus Torvalds 18921da177e4SLinus Torvalds int cpufreq_register_governor(struct cpufreq_governor *governor) 18931da177e4SLinus Torvalds { 18943bcb09a3SJeremy Fitzhardinge int err; 18951da177e4SLinus Torvalds 18961da177e4SLinus Torvalds if (!governor) 18971da177e4SLinus Torvalds return -EINVAL; 18981da177e4SLinus Torvalds 1899a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1900a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 1901a7b422cdSKonrad Rzeszutek Wilk 19023fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 19031da177e4SLinus Torvalds 1904b394058fSViresh Kumar governor->initialized = 0; 19053bcb09a3SJeremy Fitzhardinge err = -EBUSY; 19063bcb09a3SJeremy Fitzhardinge if (__find_governor(governor->name) == NULL) { 19073bcb09a3SJeremy Fitzhardinge err = 0; 19081da177e4SLinus Torvalds list_add(&governor->governor_list, &cpufreq_governor_list); 19093bcb09a3SJeremy Fitzhardinge } 19101da177e4SLinus Torvalds 19113fc54d37Sakpm@osdl.org mutex_unlock(&cpufreq_governor_mutex); 19123bcb09a3SJeremy Fitzhardinge return err; 19131da177e4SLinus Torvalds } 19141da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_register_governor); 19151da177e4SLinus Torvalds 19161da177e4SLinus Torvalds void cpufreq_unregister_governor(struct cpufreq_governor *governor) 19171da177e4SLinus Torvalds { 191890e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 191990e41bacSPrarit Bhargava int cpu; 192090e41bacSPrarit Bhargava #endif 192190e41bacSPrarit Bhargava 19221da177e4SLinus Torvalds if (!governor) 19231da177e4SLinus Torvalds return; 19241da177e4SLinus Torvalds 1925a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1926a7b422cdSKonrad Rzeszutek Wilk return; 1927a7b422cdSKonrad Rzeszutek Wilk 192890e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 192990e41bacSPrarit Bhargava for_each_present_cpu(cpu) { 193090e41bacSPrarit Bhargava if (cpu_online(cpu)) 193190e41bacSPrarit Bhargava continue; 193290e41bacSPrarit Bhargava if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name)) 193390e41bacSPrarit Bhargava strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0"); 193490e41bacSPrarit Bhargava } 193590e41bacSPrarit Bhargava #endif 193690e41bacSPrarit Bhargava 19373fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 19381da177e4SLinus Torvalds list_del(&governor->governor_list); 19393fc54d37Sakpm@osdl.org mutex_unlock(&cpufreq_governor_mutex); 19401da177e4SLinus Torvalds return; 19411da177e4SLinus Torvalds } 19421da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_unregister_governor); 19431da177e4SLinus Torvalds 19441da177e4SLinus Torvalds 19451da177e4SLinus Torvalds /********************************************************************* 19461da177e4SLinus Torvalds * POLICY INTERFACE * 19471da177e4SLinus Torvalds *********************************************************************/ 19481da177e4SLinus Torvalds 19491da177e4SLinus Torvalds /** 19501da177e4SLinus Torvalds * cpufreq_get_policy - get the current cpufreq_policy 195129464f28SDave Jones * @policy: struct cpufreq_policy into which the current cpufreq_policy 195229464f28SDave Jones * is written 19531da177e4SLinus Torvalds * 19541da177e4SLinus Torvalds * Reads the current cpufreq policy. 19551da177e4SLinus Torvalds */ 19561da177e4SLinus Torvalds int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) 19571da177e4SLinus Torvalds { 19581da177e4SLinus Torvalds struct cpufreq_policy *cpu_policy; 19591da177e4SLinus Torvalds if (!policy) 19601da177e4SLinus Torvalds return -EINVAL; 19611da177e4SLinus Torvalds 19621da177e4SLinus Torvalds cpu_policy = cpufreq_cpu_get(cpu); 19631da177e4SLinus Torvalds if (!cpu_policy) 19641da177e4SLinus Torvalds return -EINVAL; 19651da177e4SLinus Torvalds 1966d5b73cd8SViresh Kumar memcpy(policy, cpu_policy, sizeof(*policy)); 19671da177e4SLinus Torvalds 19681da177e4SLinus Torvalds cpufreq_cpu_put(cpu_policy); 19691da177e4SLinus Torvalds return 0; 19701da177e4SLinus Torvalds } 19711da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_get_policy); 19721da177e4SLinus Torvalds 1973153d7f3fSArjan van de Ven /* 1974037ce839SViresh Kumar * policy : current policy. 1975037ce839SViresh Kumar * new_policy: policy to be set. 1976153d7f3fSArjan van de Ven */ 1977037ce839SViresh Kumar static int cpufreq_set_policy(struct cpufreq_policy *policy, 19783a3e9e06SViresh Kumar struct cpufreq_policy *new_policy) 19791da177e4SLinus Torvalds { 19807bd353a9SViresh Kumar int ret = 0, failed = 1; 19811da177e4SLinus Torvalds 19823a3e9e06SViresh Kumar pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu, 19833a3e9e06SViresh Kumar new_policy->min, new_policy->max); 19841da177e4SLinus Torvalds 1985d5b73cd8SViresh Kumar memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo)); 19861da177e4SLinus Torvalds 19873a3e9e06SViresh Kumar if (new_policy->min > policy->max || new_policy->max < policy->min) { 19889c9a43edSMattia Dongili ret = -EINVAL; 19899c9a43edSMattia Dongili goto error_out; 19909c9a43edSMattia Dongili } 19919c9a43edSMattia Dongili 19921da177e4SLinus Torvalds /* verify the cpu speed can be set within this limit */ 19933a3e9e06SViresh Kumar ret = cpufreq_driver->verify(new_policy); 19941da177e4SLinus Torvalds if (ret) 19951da177e4SLinus Torvalds goto error_out; 19961da177e4SLinus Torvalds 19971da177e4SLinus Torvalds /* adjust if necessary - all reasons */ 1998e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 19993a3e9e06SViresh Kumar CPUFREQ_ADJUST, new_policy); 20001da177e4SLinus Torvalds 20011da177e4SLinus Torvalds /* adjust if necessary - hardware incompatibility*/ 2002e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 20033a3e9e06SViresh Kumar CPUFREQ_INCOMPATIBLE, new_policy); 20041da177e4SLinus Torvalds 2005bb176f7dSViresh Kumar /* 2006bb176f7dSViresh Kumar * verify the cpu speed can be set within this limit, which might be 2007bb176f7dSViresh Kumar * different to the first one 2008bb176f7dSViresh Kumar */ 20093a3e9e06SViresh Kumar ret = cpufreq_driver->verify(new_policy); 2010e041c683SAlan Stern if (ret) 20111da177e4SLinus Torvalds goto error_out; 20121da177e4SLinus Torvalds 20131da177e4SLinus Torvalds /* notification of the new policy */ 2014e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 20153a3e9e06SViresh Kumar CPUFREQ_NOTIFY, new_policy); 20161da177e4SLinus Torvalds 20173a3e9e06SViresh Kumar policy->min = new_policy->min; 20183a3e9e06SViresh Kumar policy->max = new_policy->max; 20191da177e4SLinus Torvalds 20202d06d8c4SDominik Brodowski pr_debug("new min and max freqs are %u - %u kHz\n", 20213a3e9e06SViresh Kumar policy->min, policy->max); 20221da177e4SLinus Torvalds 20231c3d85ddSRafael J. Wysocki if (cpufreq_driver->setpolicy) { 20243a3e9e06SViresh Kumar policy->policy = new_policy->policy; 20252d06d8c4SDominik Brodowski pr_debug("setting range\n"); 20263a3e9e06SViresh Kumar ret = cpufreq_driver->setpolicy(new_policy); 20271da177e4SLinus Torvalds } else { 20283a3e9e06SViresh Kumar if (new_policy->governor != policy->governor) { 20291da177e4SLinus Torvalds /* save old, working values */ 20303a3e9e06SViresh Kumar struct cpufreq_governor *old_gov = policy->governor; 20311da177e4SLinus Torvalds 20322d06d8c4SDominik Brodowski pr_debug("governor switch\n"); 20331da177e4SLinus Torvalds 20341da177e4SLinus Torvalds /* end old governor */ 20353a3e9e06SViresh Kumar if (policy->governor) { 20363a3e9e06SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_STOP); 2037ad7722daSviresh kumar up_write(&policy->rwsem); 20383a3e9e06SViresh Kumar __cpufreq_governor(policy, 20397bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 2040ad7722daSviresh kumar down_write(&policy->rwsem); 20417bd353a9SViresh Kumar } 20421da177e4SLinus Torvalds 20431da177e4SLinus Torvalds /* start new governor */ 20443a3e9e06SViresh Kumar policy->governor = new_policy->governor; 20453a3e9e06SViresh Kumar if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) { 20463a3e9e06SViresh Kumar if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) { 20477bd353a9SViresh Kumar failed = 0; 2048955ef483SViresh Kumar } else { 2049ad7722daSviresh kumar up_write(&policy->rwsem); 20503a3e9e06SViresh Kumar __cpufreq_governor(policy, 20517bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 2052ad7722daSviresh kumar down_write(&policy->rwsem); 2053955ef483SViresh Kumar } 20547bd353a9SViresh Kumar } 20557bd353a9SViresh Kumar 20567bd353a9SViresh Kumar if (failed) { 20571da177e4SLinus Torvalds /* new governor failed, so re-start old one */ 20582d06d8c4SDominik Brodowski pr_debug("starting governor %s failed\n", 20593a3e9e06SViresh Kumar policy->governor->name); 20601da177e4SLinus Torvalds if (old_gov) { 20613a3e9e06SViresh Kumar policy->governor = old_gov; 20623a3e9e06SViresh Kumar __cpufreq_governor(policy, 20637bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_INIT); 20643a3e9e06SViresh Kumar __cpufreq_governor(policy, 2065e08f5f5bSGautham R Shenoy CPUFREQ_GOV_START); 20661da177e4SLinus Torvalds } 20671da177e4SLinus Torvalds ret = -EINVAL; 20681da177e4SLinus Torvalds goto error_out; 20691da177e4SLinus Torvalds } 20701da177e4SLinus Torvalds /* might be a policy change, too, so fall through */ 20711da177e4SLinus Torvalds } 20722d06d8c4SDominik Brodowski pr_debug("governor: change or update limits\n"); 20733de9bdebSViresh Kumar ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); 20741da177e4SLinus Torvalds } 20751da177e4SLinus Torvalds 20761da177e4SLinus Torvalds error_out: 20771da177e4SLinus Torvalds return ret; 20781da177e4SLinus Torvalds } 20791da177e4SLinus Torvalds 20801da177e4SLinus Torvalds /** 20811da177e4SLinus Torvalds * cpufreq_update_policy - re-evaluate an existing cpufreq policy 20821da177e4SLinus Torvalds * @cpu: CPU which shall be re-evaluated 20831da177e4SLinus Torvalds * 208425985edcSLucas De Marchi * Useful for policy notifiers which have different necessities 20851da177e4SLinus Torvalds * at different times. 20861da177e4SLinus Torvalds */ 20871da177e4SLinus Torvalds int cpufreq_update_policy(unsigned int cpu) 20881da177e4SLinus Torvalds { 20893a3e9e06SViresh Kumar struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 20903a3e9e06SViresh Kumar struct cpufreq_policy new_policy; 2091f1829e4aSJulia Lawall int ret; 20921da177e4SLinus Torvalds 20933a3e9e06SViresh Kumar if (!policy) { 2094f1829e4aSJulia Lawall ret = -ENODEV; 2095f1829e4aSJulia Lawall goto no_policy; 2096f1829e4aSJulia Lawall } 20971da177e4SLinus Torvalds 2098ad7722daSviresh kumar down_write(&policy->rwsem); 20991da177e4SLinus Torvalds 21002d06d8c4SDominik Brodowski pr_debug("updating policy for CPU %u\n", cpu); 2101d5b73cd8SViresh Kumar memcpy(&new_policy, policy, sizeof(*policy)); 21023a3e9e06SViresh Kumar new_policy.min = policy->user_policy.min; 21033a3e9e06SViresh Kumar new_policy.max = policy->user_policy.max; 21043a3e9e06SViresh Kumar new_policy.policy = policy->user_policy.policy; 21053a3e9e06SViresh Kumar new_policy.governor = policy->user_policy.governor; 21061da177e4SLinus Torvalds 2107bb176f7dSViresh Kumar /* 2108bb176f7dSViresh Kumar * BIOS might change freq behind our back 2109bb176f7dSViresh Kumar * -> ask driver for current freq and notify governors about a change 2110bb176f7dSViresh Kumar */ 21111c3d85ddSRafael J. Wysocki if (cpufreq_driver->get) { 21123a3e9e06SViresh Kumar new_policy.cur = cpufreq_driver->get(cpu); 21133a3e9e06SViresh Kumar if (!policy->cur) { 21142d06d8c4SDominik Brodowski pr_debug("Driver did not initialize current freq"); 21153a3e9e06SViresh Kumar policy->cur = new_policy.cur; 2116a85f7bd3SThomas Renninger } else { 21179c0ebcf7SViresh Kumar if (policy->cur != new_policy.cur && has_target()) 21183a3e9e06SViresh Kumar cpufreq_out_of_sync(cpu, policy->cur, 21193a3e9e06SViresh Kumar new_policy.cur); 21200961dd0dSThomas Renninger } 2121a85f7bd3SThomas Renninger } 21220961dd0dSThomas Renninger 2123037ce839SViresh Kumar ret = cpufreq_set_policy(policy, &new_policy); 21241da177e4SLinus Torvalds 2125ad7722daSviresh kumar up_write(&policy->rwsem); 21265a01f2e8SVenkatesh Pallipadi 21273a3e9e06SViresh Kumar cpufreq_cpu_put(policy); 2128f1829e4aSJulia Lawall no_policy: 21291da177e4SLinus Torvalds return ret; 21301da177e4SLinus Torvalds } 21311da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_update_policy); 21321da177e4SLinus Torvalds 21332760984fSPaul Gortmaker static int cpufreq_cpu_callback(struct notifier_block *nfb, 2134c32b6b8eSAshok Raj unsigned long action, void *hcpu) 2135c32b6b8eSAshok Raj { 2136c32b6b8eSAshok Raj unsigned int cpu = (unsigned long)hcpu; 21378a25a2fdSKay Sievers struct device *dev; 21385302c3fbSSrivatsa S. Bhat bool frozen = false; 2139c32b6b8eSAshok Raj 21408a25a2fdSKay Sievers dev = get_cpu_device(cpu); 21418a25a2fdSKay Sievers if (dev) { 21425302c3fbSSrivatsa S. Bhat 2143d4faadd5SRafael J. Wysocki if (action & CPU_TASKS_FROZEN) 2144d4faadd5SRafael J. Wysocki frozen = true; 2145d4faadd5SRafael J. Wysocki 21465302c3fbSSrivatsa S. Bhat switch (action & ~CPU_TASKS_FROZEN) { 2147c32b6b8eSAshok Raj case CPU_ONLINE: 21485302c3fbSSrivatsa S. Bhat __cpufreq_add_dev(dev, NULL, frozen); 214923d32899SSrivatsa S. Bhat cpufreq_update_policy(cpu); 2150c32b6b8eSAshok Raj break; 21515302c3fbSSrivatsa S. Bhat 2152c32b6b8eSAshok Raj case CPU_DOWN_PREPARE: 2153cedb70afSSrivatsa S. Bhat __cpufreq_remove_dev_prepare(dev, NULL, frozen); 21541aee40acSSrivatsa S. Bhat break; 21551aee40acSSrivatsa S. Bhat 21561aee40acSSrivatsa S. Bhat case CPU_POST_DEAD: 2157cedb70afSSrivatsa S. Bhat __cpufreq_remove_dev_finish(dev, NULL, frozen); 2158c32b6b8eSAshok Raj break; 21595302c3fbSSrivatsa S. Bhat 21605a01f2e8SVenkatesh Pallipadi case CPU_DOWN_FAILED: 21615302c3fbSSrivatsa S. Bhat __cpufreq_add_dev(dev, NULL, frozen); 2162c32b6b8eSAshok Raj break; 2163c32b6b8eSAshok Raj } 2164c32b6b8eSAshok Raj } 2165c32b6b8eSAshok Raj return NOTIFY_OK; 2166c32b6b8eSAshok Raj } 2167c32b6b8eSAshok Raj 21689c36f746SNeal Buckendahl static struct notifier_block __refdata cpufreq_cpu_notifier = { 2169c32b6b8eSAshok Raj .notifier_call = cpufreq_cpu_callback, 2170c32b6b8eSAshok Raj }; 21711da177e4SLinus Torvalds 21721da177e4SLinus Torvalds /********************************************************************* 21731da177e4SLinus Torvalds * REGISTER / UNREGISTER CPUFREQ DRIVER * 21741da177e4SLinus Torvalds *********************************************************************/ 21751da177e4SLinus Torvalds 21761da177e4SLinus Torvalds /** 21771da177e4SLinus Torvalds * cpufreq_register_driver - register a CPU Frequency driver 21781da177e4SLinus Torvalds * @driver_data: A struct cpufreq_driver containing the values# 21791da177e4SLinus Torvalds * submitted by the CPU Frequency driver. 21801da177e4SLinus Torvalds * 21811da177e4SLinus Torvalds * Registers a CPU Frequency driver to this core code. This code 21821da177e4SLinus Torvalds * returns zero on success, -EBUSY when another driver got here first 21831da177e4SLinus Torvalds * (and isn't unregistered in the meantime). 21841da177e4SLinus Torvalds * 21851da177e4SLinus Torvalds */ 2186221dee28SLinus Torvalds int cpufreq_register_driver(struct cpufreq_driver *driver_data) 21871da177e4SLinus Torvalds { 21881da177e4SLinus Torvalds unsigned long flags; 21891da177e4SLinus Torvalds int ret; 21901da177e4SLinus Torvalds 2191a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 2192a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 2193a7b422cdSKonrad Rzeszutek Wilk 21941da177e4SLinus Torvalds if (!driver_data || !driver_data->verify || !driver_data->init || 21959c0ebcf7SViresh Kumar !(driver_data->setpolicy || driver_data->target_index || 21969c0ebcf7SViresh Kumar driver_data->target)) 21971da177e4SLinus Torvalds return -EINVAL; 21981da177e4SLinus Torvalds 21992d06d8c4SDominik Brodowski pr_debug("trying to register driver %s\n", driver_data->name); 22001da177e4SLinus Torvalds 22011da177e4SLinus Torvalds if (driver_data->setpolicy) 22021da177e4SLinus Torvalds driver_data->flags |= CPUFREQ_CONST_LOOPS; 22031da177e4SLinus Torvalds 22040d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 22051c3d85ddSRafael J. Wysocki if (cpufreq_driver) { 22060d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 22074dea5806SYinghai Lu return -EEXIST; 22081da177e4SLinus Torvalds } 22091c3d85ddSRafael J. Wysocki cpufreq_driver = driver_data; 22100d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 22111da177e4SLinus Torvalds 22128a25a2fdSKay Sievers ret = subsys_interface_register(&cpufreq_interface); 22138f5bc2abSJiri Slaby if (ret) 22148f5bc2abSJiri Slaby goto err_null_driver; 22151da177e4SLinus Torvalds 22161c3d85ddSRafael J. Wysocki if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) { 22171da177e4SLinus Torvalds int i; 22181da177e4SLinus Torvalds ret = -ENODEV; 22191da177e4SLinus Torvalds 22201da177e4SLinus Torvalds /* check for at least one working CPU */ 22217a6aedfaSMike Travis for (i = 0; i < nr_cpu_ids; i++) 22227a6aedfaSMike Travis if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) { 22231da177e4SLinus Torvalds ret = 0; 22247a6aedfaSMike Travis break; 22257a6aedfaSMike Travis } 22261da177e4SLinus Torvalds 22271da177e4SLinus Torvalds /* if all ->init() calls failed, unregister */ 22281da177e4SLinus Torvalds if (ret) { 22292d06d8c4SDominik Brodowski pr_debug("no CPU initialized for driver %s\n", 2230e08f5f5bSGautham R Shenoy driver_data->name); 22318a25a2fdSKay Sievers goto err_if_unreg; 22321da177e4SLinus Torvalds } 22331da177e4SLinus Torvalds } 22341da177e4SLinus Torvalds 223565edc68cSChandra Seetharaman register_hotcpu_notifier(&cpufreq_cpu_notifier); 22362d06d8c4SDominik Brodowski pr_debug("driver %s up and running\n", driver_data->name); 22371da177e4SLinus Torvalds 22388f5bc2abSJiri Slaby return 0; 22398a25a2fdSKay Sievers err_if_unreg: 22408a25a2fdSKay Sievers subsys_interface_unregister(&cpufreq_interface); 22418f5bc2abSJiri Slaby err_null_driver: 22420d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 22431c3d85ddSRafael J. Wysocki cpufreq_driver = NULL; 22440d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 22454d34a67dSDave Jones return ret; 22461da177e4SLinus Torvalds } 22471da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_register_driver); 22481da177e4SLinus Torvalds 22491da177e4SLinus Torvalds /** 22501da177e4SLinus Torvalds * cpufreq_unregister_driver - unregister the current CPUFreq driver 22511da177e4SLinus Torvalds * 22521da177e4SLinus Torvalds * Unregister the current CPUFreq driver. Only call this if you have 22531da177e4SLinus Torvalds * the right to do so, i.e. if you have succeeded in initialising before! 22541da177e4SLinus Torvalds * Returns zero if successful, and -EINVAL if the cpufreq_driver is 22551da177e4SLinus Torvalds * currently not initialised. 22561da177e4SLinus Torvalds */ 2257221dee28SLinus Torvalds int cpufreq_unregister_driver(struct cpufreq_driver *driver) 22581da177e4SLinus Torvalds { 22591da177e4SLinus Torvalds unsigned long flags; 22601da177e4SLinus Torvalds 22611c3d85ddSRafael J. Wysocki if (!cpufreq_driver || (driver != cpufreq_driver)) 22621da177e4SLinus Torvalds return -EINVAL; 22631da177e4SLinus Torvalds 22642d06d8c4SDominik Brodowski pr_debug("unregistering driver %s\n", driver->name); 22651da177e4SLinus Torvalds 22668a25a2fdSKay Sievers subsys_interface_unregister(&cpufreq_interface); 226765edc68cSChandra Seetharaman unregister_hotcpu_notifier(&cpufreq_cpu_notifier); 22681da177e4SLinus Torvalds 22696eed9404SViresh Kumar down_write(&cpufreq_rwsem); 22700d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 22716eed9404SViresh Kumar 22721c3d85ddSRafael J. Wysocki cpufreq_driver = NULL; 22736eed9404SViresh Kumar 22740d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 22756eed9404SViresh Kumar up_write(&cpufreq_rwsem); 22761da177e4SLinus Torvalds 22771da177e4SLinus Torvalds return 0; 22781da177e4SLinus Torvalds } 22791da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); 22805a01f2e8SVenkatesh Pallipadi 22815a01f2e8SVenkatesh Pallipadi static int __init cpufreq_core_init(void) 22825a01f2e8SVenkatesh Pallipadi { 2283a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 2284a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 2285a7b422cdSKonrad Rzeszutek Wilk 22862361be23SViresh Kumar cpufreq_global_kobject = kobject_create(); 22878aa84ad8SThomas Renninger BUG_ON(!cpufreq_global_kobject); 2288e00e56dfSRafael J. Wysocki register_syscore_ops(&cpufreq_syscore_ops); 22898aa84ad8SThomas Renninger 22905a01f2e8SVenkatesh Pallipadi return 0; 22915a01f2e8SVenkatesh Pallipadi } 22925a01f2e8SVenkatesh Pallipadi core_initcall(cpufreq_core_init); 2293