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> 61da177e4SLinus Torvalds * 7c32b6b8eSAshok Raj * Oct 2005 - Ashok Raj <ashok.raj@intel.com> 8c32b6b8eSAshok Raj * Added handling for CPU hotplug 98ff69732SDave Jones * Feb 2006 - Jacob Shin <jacob.shin@amd.com> 108ff69732SDave Jones * Fix handling for CPU hotplug -- affected CPUs 11c32b6b8eSAshok Raj * 121da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 131da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 141da177e4SLinus Torvalds * published by the Free Software Foundation. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds */ 171da177e4SLinus Torvalds 18db701151SViresh Kumar #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19db701151SViresh Kumar 201da177e4SLinus Torvalds #include <linux/kernel.h> 211da177e4SLinus Torvalds #include <linux/module.h> 221da177e4SLinus Torvalds #include <linux/init.h> 231da177e4SLinus Torvalds #include <linux/notifier.h> 241da177e4SLinus Torvalds #include <linux/cpufreq.h> 251da177e4SLinus Torvalds #include <linux/delay.h> 261da177e4SLinus Torvalds #include <linux/interrupt.h> 271da177e4SLinus Torvalds #include <linux/spinlock.h> 281da177e4SLinus Torvalds #include <linux/device.h> 291da177e4SLinus Torvalds #include <linux/slab.h> 301da177e4SLinus Torvalds #include <linux/cpu.h> 311da177e4SLinus Torvalds #include <linux/completion.h> 323fc54d37Sakpm@osdl.org #include <linux/mutex.h> 33e00e56dfSRafael J. Wysocki #include <linux/syscore_ops.h> 341da177e4SLinus Torvalds 356f4f2723SThomas Renninger #include <trace/events/power.h> 366f4f2723SThomas Renninger 371da177e4SLinus Torvalds /** 38cd878479SDave Jones * The "cpufreq driver" - the arch- or hardware-dependent low 391da177e4SLinus Torvalds * level driver of CPUFreq support, and its spinlock. This lock 401da177e4SLinus Torvalds * also protects the cpufreq_cpu_data array. 411da177e4SLinus Torvalds */ 425800043bSNathan Zimmer static struct cpufreq_driver __rcu *cpufreq_driver; 437a6aedfaSMike Travis static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); 44084f3493SThomas Renninger #ifdef CONFIG_HOTPLUG_CPU 45084f3493SThomas Renninger /* This one keeps track of the previously set governor of a removed CPU */ 46e77b89f1SDmitry Monakhov static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); 47084f3493SThomas Renninger #endif 480d1857a1SNathan Zimmer static DEFINE_RWLOCK(cpufreq_driver_lock); 491da177e4SLinus Torvalds 505a01f2e8SVenkatesh Pallipadi /* 515a01f2e8SVenkatesh Pallipadi * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure 525a01f2e8SVenkatesh Pallipadi * all cpufreq/hotplug/workqueue/etc related lock issues. 535a01f2e8SVenkatesh Pallipadi * 545a01f2e8SVenkatesh Pallipadi * The rules for this semaphore: 555a01f2e8SVenkatesh Pallipadi * - Any routine that wants to read from the policy structure will 565a01f2e8SVenkatesh Pallipadi * do a down_read on this semaphore. 575a01f2e8SVenkatesh Pallipadi * - Any routine that will write to the policy structure and/or may take away 585a01f2e8SVenkatesh Pallipadi * the policy altogether (eg. CPU hotplug), will hold this lock in write 595a01f2e8SVenkatesh Pallipadi * mode before doing so. 605a01f2e8SVenkatesh Pallipadi * 615a01f2e8SVenkatesh Pallipadi * Additional rules: 625a01f2e8SVenkatesh Pallipadi * - Governor routines that can be called in cpufreq hotplug path should not 635a01f2e8SVenkatesh Pallipadi * take this sem as top level hotplug notifier handler takes this. 64395913d0SMathieu Desnoyers * - Lock should not be held across 65395913d0SMathieu Desnoyers * __cpufreq_governor(data, CPUFREQ_GOV_STOP); 665a01f2e8SVenkatesh Pallipadi */ 67f1625066STejun Heo static DEFINE_PER_CPU(int, cpufreq_policy_cpu); 685a01f2e8SVenkatesh Pallipadi static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem); 695a01f2e8SVenkatesh Pallipadi 705a01f2e8SVenkatesh Pallipadi #define lock_policy_rwsem(mode, cpu) \ 71fa1d8af4SViresh Kumar static int lock_policy_rwsem_##mode(int cpu) \ 725a01f2e8SVenkatesh Pallipadi { \ 73f1625066STejun Heo int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \ 745a01f2e8SVenkatesh Pallipadi BUG_ON(policy_cpu == -1); \ 755a01f2e8SVenkatesh Pallipadi down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ 765a01f2e8SVenkatesh Pallipadi \ 775a01f2e8SVenkatesh Pallipadi return 0; \ 785a01f2e8SVenkatesh Pallipadi } 795a01f2e8SVenkatesh Pallipadi 805a01f2e8SVenkatesh Pallipadi lock_policy_rwsem(read, cpu); 815a01f2e8SVenkatesh Pallipadi lock_policy_rwsem(write, cpu); 825a01f2e8SVenkatesh Pallipadi 83fa1d8af4SViresh Kumar #define unlock_policy_rwsem(mode, cpu) \ 84fa1d8af4SViresh Kumar static void unlock_policy_rwsem_##mode(int cpu) \ 85fa1d8af4SViresh Kumar { \ 86fa1d8af4SViresh Kumar int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \ 87fa1d8af4SViresh Kumar BUG_ON(policy_cpu == -1); \ 88fa1d8af4SViresh Kumar up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ 895a01f2e8SVenkatesh Pallipadi } 905a01f2e8SVenkatesh Pallipadi 91fa1d8af4SViresh Kumar unlock_policy_rwsem(read, cpu); 92fa1d8af4SViresh Kumar unlock_policy_rwsem(write, cpu); 935a01f2e8SVenkatesh Pallipadi 941da177e4SLinus Torvalds /* internal prototypes */ 9529464f28SDave Jones static int __cpufreq_governor(struct cpufreq_policy *policy, 9629464f28SDave Jones unsigned int event); 975a01f2e8SVenkatesh Pallipadi static unsigned int __cpufreq_get(unsigned int cpu); 9865f27f38SDavid Howells static void handle_update(struct work_struct *work); 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds /** 1011da177e4SLinus Torvalds * Two notifier lists: the "policy" list is involved in the 1021da177e4SLinus Torvalds * validation process for a new CPU frequency policy; the 1031da177e4SLinus Torvalds * "transition" list for kernel code that needs to handle 1041da177e4SLinus Torvalds * changes to devices when the CPU clock speed changes. 1051da177e4SLinus Torvalds * The mutex locks both lists. 1061da177e4SLinus Torvalds */ 107e041c683SAlan Stern static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); 108b4dfdbb3SAlan Stern static struct srcu_notifier_head cpufreq_transition_notifier_list; 1091da177e4SLinus Torvalds 11074212ca4SCesar Eduardo Barros static bool init_cpufreq_transition_notifier_list_called; 111b4dfdbb3SAlan Stern static int __init init_cpufreq_transition_notifier_list(void) 112b4dfdbb3SAlan Stern { 113b4dfdbb3SAlan Stern srcu_init_notifier_head(&cpufreq_transition_notifier_list); 11474212ca4SCesar Eduardo Barros init_cpufreq_transition_notifier_list_called = true; 115b4dfdbb3SAlan Stern return 0; 116b4dfdbb3SAlan Stern } 117b3438f82SLinus Torvalds pure_initcall(init_cpufreq_transition_notifier_list); 1181da177e4SLinus Torvalds 119a7b422cdSKonrad Rzeszutek Wilk static int off __read_mostly; 120da584455SViresh Kumar static int cpufreq_disabled(void) 121a7b422cdSKonrad Rzeszutek Wilk { 122a7b422cdSKonrad Rzeszutek Wilk return off; 123a7b422cdSKonrad Rzeszutek Wilk } 124a7b422cdSKonrad Rzeszutek Wilk void disable_cpufreq(void) 125a7b422cdSKonrad Rzeszutek Wilk { 126a7b422cdSKonrad Rzeszutek Wilk off = 1; 127a7b422cdSKonrad Rzeszutek Wilk } 1281da177e4SLinus Torvalds static LIST_HEAD(cpufreq_governor_list); 1293fc54d37Sakpm@osdl.org static DEFINE_MUTEX(cpufreq_governor_mutex); 1301da177e4SLinus Torvalds 1314d5dcc42SViresh Kumar bool have_governor_per_policy(void) 1324d5dcc42SViresh Kumar { 1335800043bSNathan Zimmer bool have_governor_per_policy; 1345800043bSNathan Zimmer rcu_read_lock(); 1355800043bSNathan Zimmer have_governor_per_policy = 1365800043bSNathan Zimmer rcu_dereference(cpufreq_driver)->have_governor_per_policy; 1375800043bSNathan Zimmer rcu_read_unlock(); 1385800043bSNathan Zimmer return have_governor_per_policy; 1394d5dcc42SViresh Kumar } 1404d5dcc42SViresh Kumar 141a9144436SStephen Boyd static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) 1421da177e4SLinus Torvalds { 1431da177e4SLinus Torvalds struct cpufreq_policy *data; 1445800043bSNathan Zimmer struct cpufreq_driver *driver; 1451da177e4SLinus Torvalds unsigned long flags; 1461da177e4SLinus Torvalds 1477a6aedfaSMike Travis if (cpu >= nr_cpu_ids) 1481da177e4SLinus Torvalds goto err_out; 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds /* get the cpufreq driver */ 1515800043bSNathan Zimmer rcu_read_lock(); 1525800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 1535800043bSNathan Zimmer 1545800043bSNathan Zimmer if (!driver) 1555800043bSNathan Zimmer goto err_out_unlock; 1565800043bSNathan Zimmer 1575800043bSNathan Zimmer if (!try_module_get(driver->owner)) 1585800043bSNathan Zimmer goto err_out_unlock; 1595800043bSNathan Zimmer 1600d1857a1SNathan Zimmer read_lock_irqsave(&cpufreq_driver_lock, flags); 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds /* get the CPU */ 1637a6aedfaSMike Travis data = per_cpu(cpufreq_cpu_data, cpu); 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds if (!data) 1661da177e4SLinus Torvalds goto err_out_put_module; 1671da177e4SLinus Torvalds 168a9144436SStephen Boyd if (!sysfs && !kobject_get(&data->kobj)) 1691da177e4SLinus Torvalds goto err_out_put_module; 1701da177e4SLinus Torvalds 1710d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1725800043bSNathan Zimmer rcu_read_unlock(); 1731da177e4SLinus Torvalds return data; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds err_out_put_module: 1765800043bSNathan Zimmer module_put(driver->owner); 1770d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1785800043bSNathan Zimmer err_out_unlock: 1795800043bSNathan Zimmer rcu_read_unlock(); 1801da177e4SLinus Torvalds err_out: 1811da177e4SLinus Torvalds return NULL; 1821da177e4SLinus Torvalds } 183a9144436SStephen Boyd 184a9144436SStephen Boyd struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) 185a9144436SStephen Boyd { 186d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 187d5aaffa9SDirk Brandewie return NULL; 188d5aaffa9SDirk Brandewie 189a9144436SStephen Boyd return __cpufreq_cpu_get(cpu, false); 190a9144436SStephen Boyd } 1911da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_cpu_get); 1921da177e4SLinus Torvalds 193a9144436SStephen Boyd static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu) 1941da177e4SLinus Torvalds { 195a9144436SStephen Boyd return __cpufreq_cpu_get(cpu, true); 196a9144436SStephen Boyd } 197a9144436SStephen Boyd 198a9144436SStephen Boyd static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs) 199a9144436SStephen Boyd { 200a9144436SStephen Boyd if (!sysfs) 2011da177e4SLinus Torvalds kobject_put(&data->kobj); 2025800043bSNathan Zimmer rcu_read_lock(); 2035800043bSNathan Zimmer module_put(rcu_dereference(cpufreq_driver)->owner); 2045800043bSNathan Zimmer rcu_read_unlock(); 2051da177e4SLinus Torvalds } 206a9144436SStephen Boyd 207a9144436SStephen Boyd void cpufreq_cpu_put(struct cpufreq_policy *data) 208a9144436SStephen Boyd { 209d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 210d5aaffa9SDirk Brandewie return; 211d5aaffa9SDirk Brandewie 212a9144436SStephen Boyd __cpufreq_cpu_put(data, false); 213a9144436SStephen Boyd } 2141da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_cpu_put); 2151da177e4SLinus Torvalds 216a9144436SStephen Boyd static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data) 217a9144436SStephen Boyd { 218a9144436SStephen Boyd __cpufreq_cpu_put(data, true); 219a9144436SStephen Boyd } 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds /********************************************************************* 2221da177e4SLinus Torvalds * EXTERNALLY AFFECTING FREQUENCY CHANGES * 2231da177e4SLinus Torvalds *********************************************************************/ 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds /** 2261da177e4SLinus Torvalds * adjust_jiffies - adjust the system "loops_per_jiffy" 2271da177e4SLinus Torvalds * 2281da177e4SLinus Torvalds * This function alters the system "loops_per_jiffy" for the clock 2291da177e4SLinus Torvalds * speed change. Note that loops_per_jiffy cannot be updated on SMP 2301da177e4SLinus Torvalds * systems as each CPU might be scaled differently. So, use the arch 2311da177e4SLinus Torvalds * per-CPU loops_per_jiffy value wherever possible. 2321da177e4SLinus Torvalds */ 2331da177e4SLinus Torvalds #ifndef CONFIG_SMP 2341da177e4SLinus Torvalds static unsigned long l_p_j_ref; 2351da177e4SLinus Torvalds static unsigned int l_p_j_ref_freq; 2361da177e4SLinus Torvalds 237858119e1SArjan van de Ven static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds if (ci->flags & CPUFREQ_CONST_LOOPS) 2401da177e4SLinus Torvalds return; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds if (!l_p_j_ref_freq) { 2431da177e4SLinus Torvalds l_p_j_ref = loops_per_jiffy; 2441da177e4SLinus Torvalds l_p_j_ref_freq = ci->old; 2452d06d8c4SDominik Brodowski pr_debug("saving %lu as reference value for loops_per_jiffy; " 246e08f5f5bSGautham R Shenoy "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq); 2471da177e4SLinus Torvalds } 248d08de0c1SAfzal Mohammed if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) || 24942d4dc3fSBenjamin Herrenschmidt (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { 250e08f5f5bSGautham R Shenoy loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, 251e08f5f5bSGautham R Shenoy ci->new); 2522d06d8c4SDominik Brodowski pr_debug("scaling loops_per_jiffy to %lu " 253e08f5f5bSGautham R Shenoy "for frequency %u kHz\n", loops_per_jiffy, ci->new); 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds #else 257e08f5f5bSGautham R Shenoy static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) 258e08f5f5bSGautham R Shenoy { 259e08f5f5bSGautham R Shenoy return; 260e08f5f5bSGautham R Shenoy } 2611da177e4SLinus Torvalds #endif 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds 264b43a7ffbSViresh Kumar void __cpufreq_notify_transition(struct cpufreq_policy *policy, 265b43a7ffbSViresh Kumar struct cpufreq_freqs *freqs, unsigned int state) 2661da177e4SLinus Torvalds { 2671da177e4SLinus Torvalds BUG_ON(irqs_disabled()); 2681da177e4SLinus Torvalds 269d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 270d5aaffa9SDirk Brandewie return; 271d5aaffa9SDirk Brandewie 2725800043bSNathan Zimmer rcu_read_lock(); 2735800043bSNathan Zimmer freqs->flags = rcu_dereference(cpufreq_driver)->flags; 2745800043bSNathan Zimmer rcu_read_unlock(); 2752d06d8c4SDominik Brodowski pr_debug("notification %u of frequency transition to %u kHz\n", 276e4472cb3SDave Jones state, freqs->new); 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds switch (state) { 279e4472cb3SDave Jones 2801da177e4SLinus Torvalds case CPUFREQ_PRECHANGE: 281e4472cb3SDave Jones /* detect if the driver reported a value as "old frequency" 282e4472cb3SDave Jones * which is not equal to what the cpufreq core thinks is 283e4472cb3SDave Jones * "old frequency". 2841da177e4SLinus Torvalds */ 2855800043bSNathan Zimmer if (!(freqs->flags & CPUFREQ_CONST_LOOPS)) { 286e4472cb3SDave Jones if ((policy) && (policy->cpu == freqs->cpu) && 287e4472cb3SDave Jones (policy->cur) && (policy->cur != freqs->old)) { 2882d06d8c4SDominik Brodowski pr_debug("Warning: CPU frequency is" 289e4472cb3SDave Jones " %u, cpufreq assumed %u kHz.\n", 290e4472cb3SDave Jones freqs->old, policy->cur); 291e4472cb3SDave Jones freqs->old = policy->cur; 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds } 294b4dfdbb3SAlan Stern srcu_notifier_call_chain(&cpufreq_transition_notifier_list, 295e4472cb3SDave Jones CPUFREQ_PRECHANGE, freqs); 2961da177e4SLinus Torvalds adjust_jiffies(CPUFREQ_PRECHANGE, freqs); 2971da177e4SLinus Torvalds break; 298e4472cb3SDave Jones 2991da177e4SLinus Torvalds case CPUFREQ_POSTCHANGE: 3001da177e4SLinus Torvalds adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); 3012d06d8c4SDominik Brodowski pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, 3026f4f2723SThomas Renninger (unsigned long)freqs->cpu); 30325e41933SThomas Renninger trace_cpu_frequency(freqs->new, freqs->cpu); 304b4dfdbb3SAlan Stern srcu_notifier_call_chain(&cpufreq_transition_notifier_list, 305e4472cb3SDave Jones CPUFREQ_POSTCHANGE, freqs); 306e4472cb3SDave Jones if (likely(policy) && likely(policy->cpu == freqs->cpu)) 307e4472cb3SDave Jones policy->cur = freqs->new; 3081da177e4SLinus Torvalds break; 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds } 311b43a7ffbSViresh Kumar /** 312b43a7ffbSViresh Kumar * cpufreq_notify_transition - call notifier chain and adjust_jiffies 313b43a7ffbSViresh Kumar * on frequency transition. 314b43a7ffbSViresh Kumar * 315b43a7ffbSViresh Kumar * This function calls the transition notifiers and the "adjust_jiffies" 316b43a7ffbSViresh Kumar * function. It is called twice on all CPU frequency changes that have 317b43a7ffbSViresh Kumar * external effects. 318b43a7ffbSViresh Kumar */ 319b43a7ffbSViresh Kumar void cpufreq_notify_transition(struct cpufreq_policy *policy, 320b43a7ffbSViresh Kumar struct cpufreq_freqs *freqs, unsigned int state) 321b43a7ffbSViresh Kumar { 322b43a7ffbSViresh Kumar for_each_cpu(freqs->cpu, policy->cpus) 323b43a7ffbSViresh Kumar __cpufreq_notify_transition(policy, freqs, state); 324b43a7ffbSViresh Kumar } 3251da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_notify_transition); 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds /********************************************************************* 3301da177e4SLinus Torvalds * SYSFS INTERFACE * 3311da177e4SLinus Torvalds *********************************************************************/ 3321da177e4SLinus Torvalds 3333bcb09a3SJeremy Fitzhardinge static struct cpufreq_governor *__find_governor(const char *str_governor) 3343bcb09a3SJeremy Fitzhardinge { 3353bcb09a3SJeremy Fitzhardinge struct cpufreq_governor *t; 3363bcb09a3SJeremy Fitzhardinge 3373bcb09a3SJeremy Fitzhardinge list_for_each_entry(t, &cpufreq_governor_list, governor_list) 3383bcb09a3SJeremy Fitzhardinge if (!strnicmp(str_governor, t->name, CPUFREQ_NAME_LEN)) 3393bcb09a3SJeremy Fitzhardinge return t; 3403bcb09a3SJeremy Fitzhardinge 3413bcb09a3SJeremy Fitzhardinge return NULL; 3423bcb09a3SJeremy Fitzhardinge } 3433bcb09a3SJeremy Fitzhardinge 3441da177e4SLinus Torvalds /** 3451da177e4SLinus Torvalds * cpufreq_parse_governor - parse a governor string 3461da177e4SLinus Torvalds */ 3471da177e4SLinus Torvalds static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, 3481da177e4SLinus Torvalds struct cpufreq_governor **governor) 3491da177e4SLinus Torvalds { 3503bcb09a3SJeremy Fitzhardinge int err = -EINVAL; 3515800043bSNathan Zimmer struct cpufreq_driver *driver; 3525800043bSNathan Zimmer bool has_setpolicy; 3535800043bSNathan Zimmer bool has_target; 3543bcb09a3SJeremy Fitzhardinge 3555800043bSNathan Zimmer rcu_read_lock(); 3565800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 3575800043bSNathan Zimmer if (!driver) { 3585800043bSNathan Zimmer rcu_read_unlock(); 3593bcb09a3SJeremy Fitzhardinge goto out; 3605800043bSNathan Zimmer } 3615800043bSNathan Zimmer has_setpolicy = driver->setpolicy ? true : false; 3625800043bSNathan Zimmer has_target = driver->target ? true : false; 3635800043bSNathan Zimmer rcu_read_unlock(); 3643bcb09a3SJeremy Fitzhardinge 3655800043bSNathan Zimmer if (has_setpolicy) { 3661da177e4SLinus Torvalds if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { 3671da177e4SLinus Torvalds *policy = CPUFREQ_POLICY_PERFORMANCE; 3683bcb09a3SJeremy Fitzhardinge err = 0; 369e08f5f5bSGautham R Shenoy } else if (!strnicmp(str_governor, "powersave", 370e08f5f5bSGautham R Shenoy CPUFREQ_NAME_LEN)) { 3711da177e4SLinus Torvalds *policy = CPUFREQ_POLICY_POWERSAVE; 3723bcb09a3SJeremy Fitzhardinge err = 0; 3731da177e4SLinus Torvalds } 3745800043bSNathan Zimmer } else if (has_target) { 3751da177e4SLinus Torvalds struct cpufreq_governor *t; 3763bcb09a3SJeremy Fitzhardinge 3773fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 3783bcb09a3SJeremy Fitzhardinge 3793bcb09a3SJeremy Fitzhardinge t = __find_governor(str_governor); 3803bcb09a3SJeremy Fitzhardinge 381ea714970SJeremy Fitzhardinge if (t == NULL) { 382ea714970SJeremy Fitzhardinge int ret; 383ea714970SJeremy Fitzhardinge 384ea714970SJeremy Fitzhardinge mutex_unlock(&cpufreq_governor_mutex); 3851a8e1463SKees Cook ret = request_module("cpufreq_%s", str_governor); 386ea714970SJeremy Fitzhardinge mutex_lock(&cpufreq_governor_mutex); 387ea714970SJeremy Fitzhardinge 388ea714970SJeremy Fitzhardinge if (ret == 0) 389ea714970SJeremy Fitzhardinge t = __find_governor(str_governor); 390ea714970SJeremy Fitzhardinge } 391ea714970SJeremy Fitzhardinge 3923bcb09a3SJeremy Fitzhardinge if (t != NULL) { 3931da177e4SLinus Torvalds *governor = t; 3943bcb09a3SJeremy Fitzhardinge err = 0; 3951da177e4SLinus Torvalds } 3963bcb09a3SJeremy Fitzhardinge 3973bcb09a3SJeremy Fitzhardinge mutex_unlock(&cpufreq_governor_mutex); 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds out: 4003bcb09a3SJeremy Fitzhardinge return err; 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds /** 405e08f5f5bSGautham R Shenoy * cpufreq_per_cpu_attr_read() / show_##file_name() - 406e08f5f5bSGautham R Shenoy * print out cpufreq information 4071da177e4SLinus Torvalds * 4081da177e4SLinus Torvalds * Write out information from cpufreq_driver->policy[cpu]; object must be 4091da177e4SLinus Torvalds * "unsigned int". 4101da177e4SLinus Torvalds */ 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds #define show_one(file_name, object) \ 4131da177e4SLinus Torvalds static ssize_t show_##file_name \ 4141da177e4SLinus Torvalds (struct cpufreq_policy *policy, char *buf) \ 4151da177e4SLinus Torvalds { \ 4161da177e4SLinus Torvalds return sprintf(buf, "%u\n", policy->object); \ 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds show_one(cpuinfo_min_freq, cpuinfo.min_freq); 4201da177e4SLinus Torvalds show_one(cpuinfo_max_freq, cpuinfo.max_freq); 421ed129784SThomas Renninger show_one(cpuinfo_transition_latency, cpuinfo.transition_latency); 4221da177e4SLinus Torvalds show_one(scaling_min_freq, min); 4231da177e4SLinus Torvalds show_one(scaling_max_freq, max); 4241da177e4SLinus Torvalds show_one(scaling_cur_freq, cur); 4251da177e4SLinus Torvalds 426e08f5f5bSGautham R Shenoy static int __cpufreq_set_policy(struct cpufreq_policy *data, 427e08f5f5bSGautham R Shenoy struct cpufreq_policy *policy); 4287970e08bSThomas Renninger 4291da177e4SLinus Torvalds /** 4301da177e4SLinus Torvalds * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access 4311da177e4SLinus Torvalds */ 4321da177e4SLinus Torvalds #define store_one(file_name, object) \ 4331da177e4SLinus Torvalds static ssize_t store_##file_name \ 4341da177e4SLinus Torvalds (struct cpufreq_policy *policy, const char *buf, size_t count) \ 4351da177e4SLinus Torvalds { \ 436f55c9c26SJingoo Han unsigned int ret; \ 4371da177e4SLinus Torvalds struct cpufreq_policy new_policy; \ 4381da177e4SLinus Torvalds \ 4391da177e4SLinus Torvalds ret = cpufreq_get_policy(&new_policy, policy->cpu); \ 4401da177e4SLinus Torvalds if (ret) \ 4411da177e4SLinus Torvalds return -EINVAL; \ 4421da177e4SLinus Torvalds \ 4431da177e4SLinus Torvalds ret = sscanf(buf, "%u", &new_policy.object); \ 4441da177e4SLinus Torvalds if (ret != 1) \ 4451da177e4SLinus Torvalds return -EINVAL; \ 4461da177e4SLinus Torvalds \ 4477970e08bSThomas Renninger ret = __cpufreq_set_policy(policy, &new_policy); \ 4487970e08bSThomas Renninger policy->user_policy.object = policy->object; \ 4491da177e4SLinus Torvalds \ 4501da177e4SLinus Torvalds return ret ? ret : count; \ 4511da177e4SLinus Torvalds } 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds store_one(scaling_min_freq, min); 4541da177e4SLinus Torvalds store_one(scaling_max_freq, max); 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds /** 4571da177e4SLinus Torvalds * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware 4581da177e4SLinus Torvalds */ 459e08f5f5bSGautham R Shenoy static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy, 460e08f5f5bSGautham R Shenoy char *buf) 4611da177e4SLinus Torvalds { 4625a01f2e8SVenkatesh Pallipadi unsigned int cur_freq = __cpufreq_get(policy->cpu); 4631da177e4SLinus Torvalds if (!cur_freq) 4641da177e4SLinus Torvalds return sprintf(buf, "<unknown>"); 4651da177e4SLinus Torvalds return sprintf(buf, "%u\n", cur_freq); 4661da177e4SLinus Torvalds } 4671da177e4SLinus Torvalds 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds /** 4701da177e4SLinus Torvalds * show_scaling_governor - show the current policy for the specified CPU 4711da177e4SLinus Torvalds */ 472905d77cdSDave Jones static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) 4731da177e4SLinus Torvalds { 4741da177e4SLinus Torvalds if (policy->policy == CPUFREQ_POLICY_POWERSAVE) 4751da177e4SLinus Torvalds return sprintf(buf, "powersave\n"); 4761da177e4SLinus Torvalds else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) 4771da177e4SLinus Torvalds return sprintf(buf, "performance\n"); 4781da177e4SLinus Torvalds else if (policy->governor) 4794b972f0bSviresh kumar return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", 48029464f28SDave Jones policy->governor->name); 4811da177e4SLinus Torvalds return -EINVAL; 4821da177e4SLinus Torvalds } 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds /** 4861da177e4SLinus Torvalds * store_scaling_governor - store policy for the specified CPU 4871da177e4SLinus Torvalds */ 4881da177e4SLinus Torvalds static ssize_t store_scaling_governor(struct cpufreq_policy *policy, 4891da177e4SLinus Torvalds const char *buf, size_t count) 4901da177e4SLinus Torvalds { 491f55c9c26SJingoo Han unsigned int ret; 4921da177e4SLinus Torvalds char str_governor[16]; 4931da177e4SLinus Torvalds struct cpufreq_policy new_policy; 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds ret = cpufreq_get_policy(&new_policy, policy->cpu); 4961da177e4SLinus Torvalds if (ret) 4971da177e4SLinus Torvalds return ret; 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds ret = sscanf(buf, "%15s", str_governor); 5001da177e4SLinus Torvalds if (ret != 1) 5011da177e4SLinus Torvalds return -EINVAL; 5021da177e4SLinus Torvalds 503e08f5f5bSGautham R Shenoy if (cpufreq_parse_governor(str_governor, &new_policy.policy, 504e08f5f5bSGautham R Shenoy &new_policy.governor)) 5051da177e4SLinus Torvalds return -EINVAL; 5061da177e4SLinus Torvalds 5077970e08bSThomas Renninger /* Do not use cpufreq_set_policy here or the user_policy.max 5087970e08bSThomas Renninger will be wrongly overridden */ 5097970e08bSThomas Renninger ret = __cpufreq_set_policy(policy, &new_policy); 5107970e08bSThomas Renninger 5117970e08bSThomas Renninger policy->user_policy.policy = policy->policy; 5127970e08bSThomas Renninger policy->user_policy.governor = policy->governor; 5137970e08bSThomas Renninger 514e08f5f5bSGautham R Shenoy if (ret) 515e08f5f5bSGautham R Shenoy return ret; 516e08f5f5bSGautham R Shenoy else 517e08f5f5bSGautham R Shenoy return count; 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds /** 5211da177e4SLinus Torvalds * show_scaling_driver - show the cpufreq driver currently loaded 5221da177e4SLinus Torvalds */ 5231da177e4SLinus Torvalds static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) 5241da177e4SLinus Torvalds { 5255800043bSNathan Zimmer ssize_t size; 5265800043bSNathan Zimmer rcu_read_lock(); 5275800043bSNathan Zimmer size = scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", 5285800043bSNathan Zimmer rcu_dereference(cpufreq_driver)->name); 5295800043bSNathan Zimmer rcu_read_unlock(); 5305800043bSNathan Zimmer return size; 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds /** 5341da177e4SLinus Torvalds * show_scaling_available_governors - show the available CPUfreq governors 5351da177e4SLinus Torvalds */ 5361da177e4SLinus Torvalds static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, 5371da177e4SLinus Torvalds char *buf) 5381da177e4SLinus Torvalds { 5391da177e4SLinus Torvalds ssize_t i = 0; 5401da177e4SLinus Torvalds struct cpufreq_governor *t; 5411da177e4SLinus Torvalds 5425800043bSNathan Zimmer rcu_read_lock(); 5435800043bSNathan Zimmer if (!rcu_dereference(cpufreq_driver)->target) { 5445800043bSNathan Zimmer rcu_read_unlock(); 5451da177e4SLinus Torvalds i += sprintf(buf, "performance powersave"); 5461da177e4SLinus Torvalds goto out; 5471da177e4SLinus Torvalds } 5485800043bSNathan Zimmer rcu_read_unlock(); 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds list_for_each_entry(t, &cpufreq_governor_list, governor_list) { 55129464f28SDave Jones if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) 55229464f28SDave Jones - (CPUFREQ_NAME_LEN + 2))) 5531da177e4SLinus Torvalds goto out; 5544b972f0bSviresh kumar i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name); 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds out: 5571da177e4SLinus Torvalds i += sprintf(&buf[i], "\n"); 5581da177e4SLinus Torvalds return i; 5591da177e4SLinus Torvalds } 560e8628dd0SDarrick J. Wong 561835481d9SRusty Russell static ssize_t show_cpus(const struct cpumask *mask, char *buf) 5621da177e4SLinus Torvalds { 5631da177e4SLinus Torvalds ssize_t i = 0; 5641da177e4SLinus Torvalds unsigned int cpu; 5651da177e4SLinus Torvalds 566835481d9SRusty Russell for_each_cpu(cpu, mask) { 5671da177e4SLinus Torvalds if (i) 5681da177e4SLinus Torvalds i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " "); 5691da177e4SLinus Torvalds i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu); 5701da177e4SLinus Torvalds if (i >= (PAGE_SIZE - 5)) 5711da177e4SLinus Torvalds break; 5721da177e4SLinus Torvalds } 5731da177e4SLinus Torvalds i += sprintf(&buf[i], "\n"); 5741da177e4SLinus Torvalds return i; 5751da177e4SLinus Torvalds } 5761da177e4SLinus Torvalds 577e8628dd0SDarrick J. Wong /** 578e8628dd0SDarrick J. Wong * show_related_cpus - show the CPUs affected by each transition even if 579e8628dd0SDarrick J. Wong * hw coordination is in use 580e8628dd0SDarrick J. Wong */ 581e8628dd0SDarrick J. Wong static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf) 582e8628dd0SDarrick J. Wong { 583e8628dd0SDarrick J. Wong return show_cpus(policy->related_cpus, buf); 584e8628dd0SDarrick J. Wong } 585e8628dd0SDarrick J. Wong 586e8628dd0SDarrick J. Wong /** 587e8628dd0SDarrick J. Wong * show_affected_cpus - show the CPUs affected by each transition 588e8628dd0SDarrick J. Wong */ 589e8628dd0SDarrick J. Wong static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) 590e8628dd0SDarrick J. Wong { 591e8628dd0SDarrick J. Wong return show_cpus(policy->cpus, buf); 592e8628dd0SDarrick J. Wong } 593e8628dd0SDarrick J. Wong 5949e76988eSVenki Pallipadi static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy, 5959e76988eSVenki Pallipadi const char *buf, size_t count) 5969e76988eSVenki Pallipadi { 5979e76988eSVenki Pallipadi unsigned int freq = 0; 5989e76988eSVenki Pallipadi unsigned int ret; 5999e76988eSVenki Pallipadi 600879000f9SCHIKAMA masaki if (!policy->governor || !policy->governor->store_setspeed) 6019e76988eSVenki Pallipadi return -EINVAL; 6029e76988eSVenki Pallipadi 6039e76988eSVenki Pallipadi ret = sscanf(buf, "%u", &freq); 6049e76988eSVenki Pallipadi if (ret != 1) 6059e76988eSVenki Pallipadi return -EINVAL; 6069e76988eSVenki Pallipadi 6079e76988eSVenki Pallipadi policy->governor->store_setspeed(policy, freq); 6089e76988eSVenki Pallipadi 6099e76988eSVenki Pallipadi return count; 6109e76988eSVenki Pallipadi } 6119e76988eSVenki Pallipadi 6129e76988eSVenki Pallipadi static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf) 6139e76988eSVenki Pallipadi { 614879000f9SCHIKAMA masaki if (!policy->governor || !policy->governor->show_setspeed) 6159e76988eSVenki Pallipadi return sprintf(buf, "<unsupported>\n"); 6169e76988eSVenki Pallipadi 6179e76988eSVenki Pallipadi return policy->governor->show_setspeed(policy, buf); 6189e76988eSVenki Pallipadi } 6191da177e4SLinus Torvalds 620e2f74f35SThomas Renninger /** 6218bf1ac72Sviresh kumar * show_bios_limit - show the current cpufreq HW/BIOS limitation 622e2f74f35SThomas Renninger */ 623e2f74f35SThomas Renninger static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) 624e2f74f35SThomas Renninger { 625e2f74f35SThomas Renninger unsigned int limit; 6265800043bSNathan Zimmer int (*bios_limit)(int cpu, unsigned int *limit); 627e2f74f35SThomas Renninger int ret; 6285800043bSNathan Zimmer 6295800043bSNathan Zimmer rcu_read_lock(); 6305800043bSNathan Zimmer bios_limit = rcu_dereference(cpufreq_driver)->bios_limit; 6315800043bSNathan Zimmer rcu_read_unlock(); 6325800043bSNathan Zimmer 6335800043bSNathan Zimmer if (bios_limit) { 6345800043bSNathan Zimmer ret = bios_limit(policy->cpu, &limit); 635e2f74f35SThomas Renninger if (!ret) 636e2f74f35SThomas Renninger return sprintf(buf, "%u\n", limit); 637e2f74f35SThomas Renninger } 638e2f74f35SThomas Renninger return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); 639e2f74f35SThomas Renninger } 640e2f74f35SThomas Renninger 6416dad2a29SBorislav Petkov cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400); 6426dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_min_freq); 6436dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_max_freq); 6446dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_transition_latency); 6456dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_available_governors); 6466dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_driver); 6476dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_cur_freq); 6486dad2a29SBorislav Petkov cpufreq_freq_attr_ro(bios_limit); 6496dad2a29SBorislav Petkov cpufreq_freq_attr_ro(related_cpus); 6506dad2a29SBorislav Petkov cpufreq_freq_attr_ro(affected_cpus); 6516dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_min_freq); 6526dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_max_freq); 6536dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_governor); 6546dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_setspeed); 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds static struct attribute *default_attrs[] = { 6571da177e4SLinus Torvalds &cpuinfo_min_freq.attr, 6581da177e4SLinus Torvalds &cpuinfo_max_freq.attr, 659ed129784SThomas Renninger &cpuinfo_transition_latency.attr, 6601da177e4SLinus Torvalds &scaling_min_freq.attr, 6611da177e4SLinus Torvalds &scaling_max_freq.attr, 6621da177e4SLinus Torvalds &affected_cpus.attr, 663e8628dd0SDarrick J. Wong &related_cpus.attr, 6641da177e4SLinus Torvalds &scaling_governor.attr, 6651da177e4SLinus Torvalds &scaling_driver.attr, 6661da177e4SLinus Torvalds &scaling_available_governors.attr, 6679e76988eSVenki Pallipadi &scaling_setspeed.attr, 6681da177e4SLinus Torvalds NULL 6691da177e4SLinus Torvalds }; 6701da177e4SLinus Torvalds 6718aa84ad8SThomas Renninger struct kobject *cpufreq_global_kobject; 6728aa84ad8SThomas Renninger EXPORT_SYMBOL(cpufreq_global_kobject); 6738aa84ad8SThomas Renninger 6741da177e4SLinus Torvalds #define to_policy(k) container_of(k, struct cpufreq_policy, kobj) 6751da177e4SLinus Torvalds #define to_attr(a) container_of(a, struct freq_attr, attr) 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) 6781da177e4SLinus Torvalds { 6791da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 6801da177e4SLinus Torvalds struct freq_attr *fattr = to_attr(attr); 6810db4a8a9SDave Jones ssize_t ret = -EINVAL; 682a9144436SStephen Boyd policy = cpufreq_cpu_get_sysfs(policy->cpu); 6831da177e4SLinus Torvalds if (!policy) 6840db4a8a9SDave Jones goto no_policy; 6855a01f2e8SVenkatesh Pallipadi 6865a01f2e8SVenkatesh Pallipadi if (lock_policy_rwsem_read(policy->cpu) < 0) 6870db4a8a9SDave Jones goto fail; 6885a01f2e8SVenkatesh Pallipadi 689e08f5f5bSGautham R Shenoy if (fattr->show) 690e08f5f5bSGautham R Shenoy ret = fattr->show(policy, buf); 691e08f5f5bSGautham R Shenoy else 692e08f5f5bSGautham R Shenoy ret = -EIO; 693e08f5f5bSGautham R Shenoy 6945a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_read(policy->cpu); 6950db4a8a9SDave Jones fail: 696a9144436SStephen Boyd cpufreq_cpu_put_sysfs(policy); 6970db4a8a9SDave Jones no_policy: 6981da177e4SLinus Torvalds return ret; 6991da177e4SLinus Torvalds } 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds static ssize_t store(struct kobject *kobj, struct attribute *attr, 7021da177e4SLinus Torvalds const char *buf, size_t count) 7031da177e4SLinus Torvalds { 7041da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 7051da177e4SLinus Torvalds struct freq_attr *fattr = to_attr(attr); 706a07530b4SDave Jones ssize_t ret = -EINVAL; 707a9144436SStephen Boyd policy = cpufreq_cpu_get_sysfs(policy->cpu); 7081da177e4SLinus Torvalds if (!policy) 709a07530b4SDave Jones goto no_policy; 7105a01f2e8SVenkatesh Pallipadi 7115a01f2e8SVenkatesh Pallipadi if (lock_policy_rwsem_write(policy->cpu) < 0) 712a07530b4SDave Jones goto fail; 7135a01f2e8SVenkatesh Pallipadi 714e08f5f5bSGautham R Shenoy if (fattr->store) 715e08f5f5bSGautham R Shenoy ret = fattr->store(policy, buf, count); 716e08f5f5bSGautham R Shenoy else 717e08f5f5bSGautham R Shenoy ret = -EIO; 718e08f5f5bSGautham R Shenoy 7195a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(policy->cpu); 720a07530b4SDave Jones fail: 721a9144436SStephen Boyd cpufreq_cpu_put_sysfs(policy); 722a07530b4SDave Jones no_policy: 7231da177e4SLinus Torvalds return ret; 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds static void cpufreq_sysfs_release(struct kobject *kobj) 7271da177e4SLinus Torvalds { 7281da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 7292d06d8c4SDominik Brodowski pr_debug("last reference is dropped\n"); 7301da177e4SLinus Torvalds complete(&policy->kobj_unregister); 7311da177e4SLinus Torvalds } 7321da177e4SLinus Torvalds 73352cf25d0SEmese Revfy static const struct sysfs_ops sysfs_ops = { 7341da177e4SLinus Torvalds .show = show, 7351da177e4SLinus Torvalds .store = store, 7361da177e4SLinus Torvalds }; 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds static struct kobj_type ktype_cpufreq = { 7391da177e4SLinus Torvalds .sysfs_ops = &sysfs_ops, 7401da177e4SLinus Torvalds .default_attrs = default_attrs, 7411da177e4SLinus Torvalds .release = cpufreq_sysfs_release, 7421da177e4SLinus Torvalds }; 7431da177e4SLinus Torvalds 74419d6f7ecSDave Jones /* symlink affected CPUs */ 745cf3289d0SAlex Chiang static int cpufreq_add_dev_symlink(unsigned int cpu, 746cf3289d0SAlex Chiang struct cpufreq_policy *policy) 74719d6f7ecSDave Jones { 74819d6f7ecSDave Jones unsigned int j; 74919d6f7ecSDave Jones int ret = 0; 75019d6f7ecSDave Jones 75119d6f7ecSDave Jones for_each_cpu(j, policy->cpus) { 75219d6f7ecSDave Jones struct cpufreq_policy *managed_policy; 7538a25a2fdSKay Sievers struct device *cpu_dev; 75419d6f7ecSDave Jones 75519d6f7ecSDave Jones if (j == cpu) 75619d6f7ecSDave Jones continue; 75719d6f7ecSDave Jones 7582d06d8c4SDominik Brodowski pr_debug("CPU %u already managed, adding link\n", j); 75919d6f7ecSDave Jones managed_policy = cpufreq_cpu_get(cpu); 7608a25a2fdSKay Sievers cpu_dev = get_cpu_device(j); 7618a25a2fdSKay Sievers ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, 76219d6f7ecSDave Jones "cpufreq"); 76319d6f7ecSDave Jones if (ret) { 76419d6f7ecSDave Jones cpufreq_cpu_put(managed_policy); 76519d6f7ecSDave Jones return ret; 76619d6f7ecSDave Jones } 76719d6f7ecSDave Jones } 76819d6f7ecSDave Jones return ret; 76919d6f7ecSDave Jones } 77019d6f7ecSDave Jones 771cf3289d0SAlex Chiang static int cpufreq_add_dev_interface(unsigned int cpu, 772cf3289d0SAlex Chiang struct cpufreq_policy *policy, 7738a25a2fdSKay Sievers struct device *dev) 774909a694eSDave Jones { 775ecf7e461SDave Jones struct cpufreq_policy new_policy; 776909a694eSDave Jones struct freq_attr **drv_attr; 7775800043bSNathan Zimmer struct cpufreq_driver *driver; 778909a694eSDave Jones unsigned long flags; 779909a694eSDave Jones int ret = 0; 780909a694eSDave Jones unsigned int j; 781909a694eSDave Jones 782909a694eSDave Jones /* prepare interface data */ 783909a694eSDave Jones ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, 7848a25a2fdSKay Sievers &dev->kobj, "cpufreq"); 785909a694eSDave Jones if (ret) 786909a694eSDave Jones return ret; 787909a694eSDave Jones 788909a694eSDave Jones /* set up files for this cpu device */ 7895800043bSNathan Zimmer rcu_read_lock(); 7905800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 7915800043bSNathan Zimmer drv_attr = driver->attr; 792909a694eSDave Jones while ((drv_attr) && (*drv_attr)) { 793909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); 794909a694eSDave Jones if (ret) 7955800043bSNathan Zimmer goto err_out_unlock; 796909a694eSDave Jones drv_attr++; 797909a694eSDave Jones } 7985800043bSNathan Zimmer if (driver->get) { 799909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); 800909a694eSDave Jones if (ret) 8015800043bSNathan Zimmer goto err_out_unlock; 802909a694eSDave Jones } 8035800043bSNathan Zimmer if (driver->target) { 804909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); 805909a694eSDave Jones if (ret) 8065800043bSNathan Zimmer goto err_out_unlock; 807909a694eSDave Jones } 8085800043bSNathan Zimmer if (driver->bios_limit) { 809e2f74f35SThomas Renninger ret = sysfs_create_file(&policy->kobj, &bios_limit.attr); 810e2f74f35SThomas Renninger if (ret) 8115800043bSNathan Zimmer goto err_out_unlock; 812e2f74f35SThomas Renninger } 8135800043bSNathan Zimmer rcu_read_unlock(); 814909a694eSDave Jones 8150d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 816909a694eSDave Jones for_each_cpu(j, policy->cpus) { 817909a694eSDave Jones per_cpu(cpufreq_cpu_data, j) = policy; 818f1625066STejun Heo per_cpu(cpufreq_policy_cpu, j) = policy->cpu; 819909a694eSDave Jones } 8200d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 821909a694eSDave Jones 822909a694eSDave Jones ret = cpufreq_add_dev_symlink(cpu, policy); 823ecf7e461SDave Jones if (ret) 824ecf7e461SDave Jones goto err_out_kobj_put; 825ecf7e461SDave Jones 826ecf7e461SDave Jones memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); 827ecf7e461SDave Jones /* assure that the starting sequence is run in __cpufreq_set_policy */ 828ecf7e461SDave Jones policy->governor = NULL; 829ecf7e461SDave Jones 830ecf7e461SDave Jones /* set default policy */ 831ecf7e461SDave Jones ret = __cpufreq_set_policy(policy, &new_policy); 832ecf7e461SDave Jones policy->user_policy.policy = policy->policy; 833ecf7e461SDave Jones policy->user_policy.governor = policy->governor; 834ecf7e461SDave Jones 835ecf7e461SDave Jones if (ret) { 8365800043bSNathan Zimmer int (*exit)(struct cpufreq_policy *policy); 8375800043bSNathan Zimmer 8382d06d8c4SDominik Brodowski pr_debug("setting policy failed\n"); 8395800043bSNathan Zimmer rcu_read_lock(); 8405800043bSNathan Zimmer exit = rcu_dereference(cpufreq_driver)->exit; 8415800043bSNathan Zimmer rcu_read_unlock(); 8425800043bSNathan Zimmer if (exit) 8435800043bSNathan Zimmer exit(policy); 8445800043bSNathan Zimmer 845ecf7e461SDave Jones } 846909a694eSDave Jones return ret; 847909a694eSDave Jones 8485800043bSNathan Zimmer err_out_unlock: 8495800043bSNathan Zimmer rcu_read_unlock(); 850909a694eSDave Jones err_out_kobj_put: 851909a694eSDave Jones kobject_put(&policy->kobj); 852909a694eSDave Jones wait_for_completion(&policy->kobj_unregister); 853909a694eSDave Jones return ret; 854909a694eSDave Jones } 855909a694eSDave Jones 856fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 857fcf80582SViresh Kumar static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, 858fcf80582SViresh Kumar struct device *dev) 859fcf80582SViresh Kumar { 860fcf80582SViresh Kumar struct cpufreq_policy *policy; 861*820c6ca2SViresh Kumar int ret = 0, has_target = 0; 862fcf80582SViresh Kumar unsigned long flags; 863fcf80582SViresh Kumar 864fcf80582SViresh Kumar policy = cpufreq_cpu_get(sibling); 865fcf80582SViresh Kumar WARN_ON(!policy); 866fcf80582SViresh Kumar 867*820c6ca2SViresh Kumar rcu_read_lock(); 868*820c6ca2SViresh Kumar has_target = !!rcu_dereference(cpufreq_driver)->target; 869*820c6ca2SViresh Kumar rcu_read_unlock(); 870*820c6ca2SViresh Kumar 871*820c6ca2SViresh Kumar if (has_target) 872fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_STOP); 873fcf80582SViresh Kumar 8742eaa3e2dSViresh Kumar lock_policy_rwsem_write(sibling); 8752eaa3e2dSViresh Kumar 8760d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 8772eaa3e2dSViresh Kumar 878fcf80582SViresh Kumar cpumask_set_cpu(cpu, policy->cpus); 8792eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu; 880fcf80582SViresh Kumar per_cpu(cpufreq_cpu_data, cpu) = policy; 8810d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 882fcf80582SViresh Kumar 8832eaa3e2dSViresh Kumar unlock_policy_rwsem_write(sibling); 8842eaa3e2dSViresh Kumar 885*820c6ca2SViresh Kumar if (has_target) { 886fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_START); 887fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); 888*820c6ca2SViresh Kumar } 889fcf80582SViresh Kumar 890fcf80582SViresh Kumar ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); 891fcf80582SViresh Kumar if (ret) { 892fcf80582SViresh Kumar cpufreq_cpu_put(policy); 893fcf80582SViresh Kumar return ret; 894fcf80582SViresh Kumar } 895fcf80582SViresh Kumar 896fcf80582SViresh Kumar return 0; 897fcf80582SViresh Kumar } 898fcf80582SViresh Kumar #endif 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds /** 9011da177e4SLinus Torvalds * cpufreq_add_dev - add a CPU device 9021da177e4SLinus Torvalds * 9031da177e4SLinus Torvalds * Adds the cpufreq interface for a CPU device. 9043f4a782bSMathieu Desnoyers * 9053f4a782bSMathieu Desnoyers * The Oracle says: try running cpufreq registration/unregistration concurrently 9063f4a782bSMathieu Desnoyers * with with cpu hotplugging and all hell will break loose. Tried to clean this 9073f4a782bSMathieu Desnoyers * mess up, but more thorough testing is needed. - Mathieu 9081da177e4SLinus Torvalds */ 9098a25a2fdSKay Sievers static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) 9101da177e4SLinus Torvalds { 911fcf80582SViresh Kumar unsigned int j, cpu = dev->id; 91265922465SViresh Kumar int ret = -ENOMEM; 9131da177e4SLinus Torvalds struct cpufreq_policy *policy; 9145800043bSNathan Zimmer struct cpufreq_driver *driver; 9155800043bSNathan Zimmer int (*init)(struct cpufreq_policy *policy); 9161da177e4SLinus Torvalds unsigned long flags; 91790e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 918fcf80582SViresh Kumar struct cpufreq_governor *gov; 91990e41bacSPrarit Bhargava int sibling; 92090e41bacSPrarit Bhargava #endif 9211da177e4SLinus Torvalds 922c32b6b8eSAshok Raj if (cpu_is_offline(cpu)) 923c32b6b8eSAshok Raj return 0; 924c32b6b8eSAshok Raj 9252d06d8c4SDominik Brodowski pr_debug("adding CPU %u\n", cpu); 9261da177e4SLinus Torvalds 9271da177e4SLinus Torvalds #ifdef CONFIG_SMP 9281da177e4SLinus Torvalds /* check whether a different CPU already registered this 9291da177e4SLinus Torvalds * CPU because it is in the same boat. */ 9301da177e4SLinus Torvalds policy = cpufreq_cpu_get(cpu); 9311da177e4SLinus Torvalds if (unlikely(policy)) { 9328ff69732SDave Jones cpufreq_cpu_put(policy); 9331da177e4SLinus Torvalds return 0; 9341da177e4SLinus Torvalds } 935fcf80582SViresh Kumar 936fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 937fcf80582SViresh Kumar /* Check if this cpu was hot-unplugged earlier and has siblings */ 9380d1857a1SNathan Zimmer read_lock_irqsave(&cpufreq_driver_lock, flags); 939fcf80582SViresh Kumar for_each_online_cpu(sibling) { 940fcf80582SViresh Kumar struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); 9412eaa3e2dSViresh Kumar if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { 9420d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 943fcf80582SViresh Kumar return cpufreq_add_policy_cpu(cpu, sibling, dev); 944fcf80582SViresh Kumar } 9452eaa3e2dSViresh Kumar } 9460d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 947fcf80582SViresh Kumar #endif 9481da177e4SLinus Torvalds #endif 9491da177e4SLinus Torvalds 9505800043bSNathan Zimmer rcu_read_lock(); 9515800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 9525800043bSNathan Zimmer if (!try_module_get(driver->owner)) { 9535800043bSNathan Zimmer rcu_read_unlock(); 9541da177e4SLinus Torvalds ret = -EINVAL; 9551da177e4SLinus Torvalds goto module_out; 9561da177e4SLinus Torvalds } 9575800043bSNathan Zimmer init = driver->init; 9585800043bSNathan Zimmer rcu_read_unlock(); 9591da177e4SLinus Torvalds 960e98df50cSDave Jones policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); 961059019a3SDave Jones if (!policy) 9621da177e4SLinus Torvalds goto nomem_out; 963059019a3SDave Jones 964059019a3SDave Jones if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) 9653f4a782bSMathieu Desnoyers goto err_free_policy; 966059019a3SDave Jones 967059019a3SDave Jones if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) 9683f4a782bSMathieu Desnoyers goto err_free_cpumask; 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds policy->cpu = cpu; 97165922465SViresh Kumar policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 972835481d9SRusty Russell cpumask_copy(policy->cpus, cpumask_of(cpu)); 9731da177e4SLinus Torvalds 9745a01f2e8SVenkatesh Pallipadi /* Initially set CPU itself as the policy_cpu */ 975f1625066STejun Heo per_cpu(cpufreq_policy_cpu, cpu) = cpu; 9765a01f2e8SVenkatesh Pallipadi 9771da177e4SLinus Torvalds init_completion(&policy->kobj_unregister); 97865f27f38SDavid Howells INIT_WORK(&policy->update, handle_update); 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds /* call driver. From then on the cpufreq must be able 9811da177e4SLinus Torvalds * to accept all calls to ->verify and ->setpolicy for this CPU 9821da177e4SLinus Torvalds */ 9835800043bSNathan Zimmer ret = init(policy); 9841da177e4SLinus Torvalds if (ret) { 9852d06d8c4SDominik Brodowski pr_debug("initialization failed\n"); 9862eaa3e2dSViresh Kumar goto err_set_policy_cpu; 9871da177e4SLinus Torvalds } 988643ae6e8SViresh Kumar 989fcf80582SViresh Kumar /* related cpus should atleast have policy->cpus */ 990fcf80582SViresh Kumar cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); 991fcf80582SViresh Kumar 992643ae6e8SViresh Kumar /* 993643ae6e8SViresh Kumar * affected cpus must always be the one, which are online. We aren't 994643ae6e8SViresh Kumar * managing offline cpus here. 995643ae6e8SViresh Kumar */ 996643ae6e8SViresh Kumar cpumask_and(policy->cpus, policy->cpus, cpu_online_mask); 997643ae6e8SViresh Kumar 998187d9f4eSMike Chan policy->user_policy.min = policy->min; 999187d9f4eSMike Chan policy->user_policy.max = policy->max; 10001da177e4SLinus Torvalds 1001a1531acdSThomas Renninger blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1002a1531acdSThomas Renninger CPUFREQ_START, policy); 1003a1531acdSThomas Renninger 1004fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 1005fcf80582SViresh Kumar gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu)); 1006fcf80582SViresh Kumar if (gov) { 1007fcf80582SViresh Kumar policy->governor = gov; 1008fcf80582SViresh Kumar pr_debug("Restoring governor %s for cpu %d\n", 1009fcf80582SViresh Kumar policy->governor->name, cpu); 10104bfa042cSThomas Renninger } 1011fcf80582SViresh Kumar #endif 10121da177e4SLinus Torvalds 10138a25a2fdSKay Sievers ret = cpufreq_add_dev_interface(cpu, policy, dev); 101419d6f7ecSDave Jones if (ret) 10150142f9dcSAhmed S. Darwish goto err_out_unregister; 10168ff69732SDave Jones 1017038c5b3eSGreg Kroah-Hartman kobject_uevent(&policy->kobj, KOBJ_ADD); 10185800043bSNathan Zimmer rcu_read_lock(); 10195800043bSNathan Zimmer module_put(rcu_dereference(cpufreq_driver)->owner); 10205800043bSNathan Zimmer rcu_read_unlock(); 10212d06d8c4SDominik Brodowski pr_debug("initialization complete\n"); 10221da177e4SLinus Torvalds 10231da177e4SLinus Torvalds return 0; 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds err_out_unregister: 10260d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 1027835481d9SRusty Russell for_each_cpu(j, policy->cpus) 10287a6aedfaSMike Travis per_cpu(cpufreq_cpu_data, j) = NULL; 10290d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 10301da177e4SLinus Torvalds 1031c10997f6SGreg Kroah-Hartman kobject_put(&policy->kobj); 10321da177e4SLinus Torvalds wait_for_completion(&policy->kobj_unregister); 10331da177e4SLinus Torvalds 10342eaa3e2dSViresh Kumar err_set_policy_cpu: 10352eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = -1; 1036cad70a6aSXiaotian Feng free_cpumask_var(policy->related_cpus); 10373f4a782bSMathieu Desnoyers err_free_cpumask: 10383f4a782bSMathieu Desnoyers free_cpumask_var(policy->cpus); 10393f4a782bSMathieu Desnoyers err_free_policy: 10401da177e4SLinus Torvalds kfree(policy); 10411da177e4SLinus Torvalds nomem_out: 10425800043bSNathan Zimmer rcu_read_lock(); 10435800043bSNathan Zimmer module_put(rcu_dereference(cpufreq_driver)->owner); 10445800043bSNathan Zimmer rcu_read_unlock(); 10451da177e4SLinus Torvalds module_out: 10461da177e4SLinus Torvalds return ret; 10471da177e4SLinus Torvalds } 10481da177e4SLinus Torvalds 1049b8eed8afSViresh Kumar static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) 1050b8eed8afSViresh Kumar { 1051b8eed8afSViresh Kumar int j; 1052b8eed8afSViresh Kumar 1053b8eed8afSViresh Kumar policy->last_cpu = policy->cpu; 1054b8eed8afSViresh Kumar policy->cpu = cpu; 1055b8eed8afSViresh Kumar 10563361b7b1SViresh Kumar for_each_cpu(j, policy->cpus) 1057b8eed8afSViresh Kumar per_cpu(cpufreq_policy_cpu, j) = cpu; 1058b8eed8afSViresh Kumar 1059b8eed8afSViresh Kumar #ifdef CONFIG_CPU_FREQ_TABLE 1060b8eed8afSViresh Kumar cpufreq_frequency_table_update_policy_cpu(policy); 1061b8eed8afSViresh Kumar #endif 1062b8eed8afSViresh Kumar blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1063b8eed8afSViresh Kumar CPUFREQ_UPDATE_POLICY_CPU, policy); 1064b8eed8afSViresh Kumar } 10651da177e4SLinus Torvalds 10661da177e4SLinus Torvalds /** 10675a01f2e8SVenkatesh Pallipadi * __cpufreq_remove_dev - remove a CPU device 10681da177e4SLinus Torvalds * 10691da177e4SLinus Torvalds * Removes the cpufreq interface for a CPU device. 10705a01f2e8SVenkatesh Pallipadi * Caller should already have policy_rwsem in write mode for this CPU. 10715a01f2e8SVenkatesh Pallipadi * This routine frees the rwsem before returning. 10721da177e4SLinus Torvalds */ 10738a25a2fdSKay Sievers static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) 10741da177e4SLinus Torvalds { 1075b8eed8afSViresh Kumar unsigned int cpu = dev->id, ret, cpus; 10761da177e4SLinus Torvalds unsigned long flags; 10771da177e4SLinus Torvalds struct cpufreq_policy *data; 10785800043bSNathan Zimmer struct cpufreq_driver *driver; 1079499bca9bSAmerigo Wang struct kobject *kobj; 1080499bca9bSAmerigo Wang struct completion *cmp; 10818a25a2fdSKay Sievers struct device *cpu_dev; 10825800043bSNathan Zimmer bool has_target; 10835800043bSNathan Zimmer int (*exit)(struct cpufreq_policy *policy); 10841da177e4SLinus Torvalds 1085b8eed8afSViresh Kumar pr_debug("%s: unregistering CPU %u\n", __func__, cpu); 10861da177e4SLinus Torvalds 10870d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 10881da177e4SLinus Torvalds 10891da177e4SLinus Torvalds data = per_cpu(cpufreq_cpu_data, cpu); 10907a6aedfaSMike Travis per_cpu(cpufreq_cpu_data, cpu) = NULL; 10911da177e4SLinus Torvalds 10920d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 10931da177e4SLinus Torvalds 10941da177e4SLinus Torvalds if (!data) { 1095b8eed8afSViresh Kumar pr_debug("%s: No cpu_data found\n", __func__); 10961da177e4SLinus Torvalds return -EINVAL; 10971da177e4SLinus Torvalds } 10981da177e4SLinus Torvalds 10995800043bSNathan Zimmer rcu_read_lock(); 11005800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 11015800043bSNathan Zimmer has_target = driver->target ? true : false; 11025800043bSNathan Zimmer exit = driver->exit; 11035800043bSNathan Zimmer if (has_target) 11041da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_STOP); 11055a01f2e8SVenkatesh Pallipadi 11061da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG_CPU 11075800043bSNathan Zimmer if (!driver->setpolicy) 1108fa69e33fSDirk Brandewie strncpy(per_cpu(cpufreq_cpu_governor, cpu), 1109fa69e33fSDirk Brandewie data->governor->name, CPUFREQ_NAME_LEN); 11101da177e4SLinus Torvalds #endif 11115800043bSNathan Zimmer rcu_read_unlock(); 11121da177e4SLinus Torvalds 11132eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1114b8eed8afSViresh Kumar cpus = cpumask_weight(data->cpus); 1115e4969ebaSViresh Kumar 1116e4969ebaSViresh Kumar if (cpus > 1) 1117b8eed8afSViresh Kumar cpumask_clear_cpu(cpu, data->cpus); 11182eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 11191da177e4SLinus Torvalds 112073bf0fc2SViresh Kumar if (cpu != data->cpu) { 112173bf0fc2SViresh Kumar sysfs_remove_link(&dev->kobj, "cpufreq"); 112273bf0fc2SViresh Kumar } else if (cpus > 1) { 1123b8eed8afSViresh Kumar /* first sibling now owns the new sysfs dir */ 1124b8eed8afSViresh Kumar cpu_dev = get_cpu_device(cpumask_first(data->cpus)); 1125b8eed8afSViresh Kumar sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); 1126b8eed8afSViresh Kumar ret = kobject_move(&data->kobj, &cpu_dev->kobj); 1127b8eed8afSViresh Kumar if (ret) { 1128b8eed8afSViresh Kumar pr_err("%s: Failed to move kobj: %d", __func__, ret); 11292eaa3e2dSViresh Kumar 11302eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1131b8eed8afSViresh Kumar cpumask_set_cpu(cpu, data->cpus); 11322eaa3e2dSViresh Kumar 11330d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 11342eaa3e2dSViresh Kumar per_cpu(cpufreq_cpu_data, cpu) = data; 11350d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 11362eaa3e2dSViresh Kumar 11372eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 11382eaa3e2dSViresh Kumar 1139b8eed8afSViresh Kumar ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj, 1140b8eed8afSViresh Kumar "cpufreq"); 1141b8eed8afSViresh Kumar return -EINVAL; 11421da177e4SLinus Torvalds } 1143b8eed8afSViresh Kumar 11442eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1145b8eed8afSViresh Kumar update_policy_cpu(data, cpu_dev->id); 11462eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 1147b8eed8afSViresh Kumar pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", 1148b8eed8afSViresh Kumar __func__, cpu_dev->id, cpu); 11491da177e4SLinus Torvalds } 1150b8eed8afSViresh Kumar 1151b8eed8afSViresh Kumar pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); 1152b8eed8afSViresh Kumar cpufreq_cpu_put(data); 11535a01f2e8SVenkatesh Pallipadi 1154b8eed8afSViresh Kumar /* If cpu is last user of policy, free policy */ 1155b8eed8afSViresh Kumar if (cpus == 1) { 1156*820c6ca2SViresh Kumar if (has_target) 11577bd353a9SViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); 11587bd353a9SViresh Kumar 11592eaa3e2dSViresh Kumar lock_policy_rwsem_read(cpu); 1160499bca9bSAmerigo Wang kobj = &data->kobj; 1161499bca9bSAmerigo Wang cmp = &data->kobj_unregister; 11622eaa3e2dSViresh Kumar unlock_policy_rwsem_read(cpu); 1163499bca9bSAmerigo Wang kobject_put(kobj); 11641da177e4SLinus Torvalds 11651da177e4SLinus Torvalds /* we need to make sure that the underlying kobj is actually 11661da177e4SLinus Torvalds * not referenced anymore by anybody before we proceed with 11671da177e4SLinus Torvalds * unloading. 11681da177e4SLinus Torvalds */ 11692d06d8c4SDominik Brodowski pr_debug("waiting for dropping of refcount\n"); 1170499bca9bSAmerigo Wang wait_for_completion(cmp); 11712d06d8c4SDominik Brodowski pr_debug("wait complete\n"); 11721da177e4SLinus Torvalds 11735800043bSNathan Zimmer if (exit) 11745800043bSNathan Zimmer exit(data); 117527ecddc2SJacob Shin 1176835481d9SRusty Russell free_cpumask_var(data->related_cpus); 1177835481d9SRusty Russell free_cpumask_var(data->cpus); 11781da177e4SLinus Torvalds kfree(data); 11795800043bSNathan Zimmer } else if (has_target) { 1180b8eed8afSViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_START); 1181b8eed8afSViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); 1182b8eed8afSViresh Kumar } 11831da177e4SLinus Torvalds 11842eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = -1; 11851da177e4SLinus Torvalds return 0; 11861da177e4SLinus Torvalds } 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds 11898a25a2fdSKay Sievers static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) 11905a01f2e8SVenkatesh Pallipadi { 11918a25a2fdSKay Sievers unsigned int cpu = dev->id; 11925a01f2e8SVenkatesh Pallipadi int retval; 1193ec28297aSVenki Pallipadi 1194ec28297aSVenki Pallipadi if (cpu_is_offline(cpu)) 1195ec28297aSVenki Pallipadi return 0; 1196ec28297aSVenki Pallipadi 11978a25a2fdSKay Sievers retval = __cpufreq_remove_dev(dev, sif); 11985a01f2e8SVenkatesh Pallipadi return retval; 11995a01f2e8SVenkatesh Pallipadi } 12005a01f2e8SVenkatesh Pallipadi 12015a01f2e8SVenkatesh Pallipadi 120265f27f38SDavid Howells static void handle_update(struct work_struct *work) 12031da177e4SLinus Torvalds { 120465f27f38SDavid Howells struct cpufreq_policy *policy = 120565f27f38SDavid Howells container_of(work, struct cpufreq_policy, update); 120665f27f38SDavid Howells unsigned int cpu = policy->cpu; 12072d06d8c4SDominik Brodowski pr_debug("handle_update for cpu %u called\n", cpu); 12081da177e4SLinus Torvalds cpufreq_update_policy(cpu); 12091da177e4SLinus Torvalds } 12101da177e4SLinus Torvalds 12111da177e4SLinus Torvalds /** 12121da177e4SLinus Torvalds * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble. 12131da177e4SLinus Torvalds * @cpu: cpu number 12141da177e4SLinus Torvalds * @old_freq: CPU frequency the kernel thinks the CPU runs at 12151da177e4SLinus Torvalds * @new_freq: CPU frequency the CPU actually runs at 12161da177e4SLinus Torvalds * 121729464f28SDave Jones * We adjust to current frequency first, and need to clean up later. 121829464f28SDave Jones * So either call to cpufreq_update_policy() or schedule handle_update()). 12191da177e4SLinus Torvalds */ 1220e08f5f5bSGautham R Shenoy static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, 1221e08f5f5bSGautham R Shenoy unsigned int new_freq) 12221da177e4SLinus Torvalds { 1223b43a7ffbSViresh Kumar struct cpufreq_policy *policy; 12241da177e4SLinus Torvalds struct cpufreq_freqs freqs; 1225b43a7ffbSViresh Kumar unsigned long flags; 1226b43a7ffbSViresh Kumar 12271da177e4SLinus Torvalds 12282d06d8c4SDominik Brodowski pr_debug("Warning: CPU frequency out of sync: cpufreq and timing " 12291da177e4SLinus Torvalds "core thinks of %u, is %u kHz.\n", old_freq, new_freq); 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds freqs.old = old_freq; 12321da177e4SLinus Torvalds freqs.new = new_freq; 1233b43a7ffbSViresh Kumar 1234b43a7ffbSViresh Kumar read_lock_irqsave(&cpufreq_driver_lock, flags); 1235b43a7ffbSViresh Kumar policy = per_cpu(cpufreq_cpu_data, cpu); 1236b43a7ffbSViresh Kumar read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1237b43a7ffbSViresh Kumar 1238b43a7ffbSViresh Kumar cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); 1239b43a7ffbSViresh Kumar cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); 12401da177e4SLinus Torvalds } 12411da177e4SLinus Torvalds 12421da177e4SLinus Torvalds 12431da177e4SLinus Torvalds /** 12444ab70df4SDhaval Giani * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur 124595235ca2SVenkatesh Pallipadi * @cpu: CPU number 124695235ca2SVenkatesh Pallipadi * 124795235ca2SVenkatesh Pallipadi * This is the last known freq, without actually getting it from the driver. 124895235ca2SVenkatesh Pallipadi * Return value will be same as what is shown in scaling_cur_freq in sysfs. 124995235ca2SVenkatesh Pallipadi */ 125095235ca2SVenkatesh Pallipadi unsigned int cpufreq_quick_get(unsigned int cpu) 125195235ca2SVenkatesh Pallipadi { 12529e21ba8bSDirk Brandewie struct cpufreq_policy *policy; 12535800043bSNathan Zimmer struct cpufreq_driver *driver; 12545800043bSNathan Zimmer unsigned int (*get)(unsigned int cpu); 1255e08f5f5bSGautham R Shenoy unsigned int ret_freq = 0; 125695235ca2SVenkatesh Pallipadi 12575800043bSNathan Zimmer rcu_read_lock(); 12585800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 12595800043bSNathan Zimmer if (driver && driver->setpolicy && driver->get) { 12605800043bSNathan Zimmer get = driver->get; 12615800043bSNathan Zimmer rcu_read_unlock(); 12625800043bSNathan Zimmer return get(cpu); 12635800043bSNathan Zimmer } 12645800043bSNathan Zimmer rcu_read_unlock(); 12659e21ba8bSDirk Brandewie 12669e21ba8bSDirk Brandewie policy = cpufreq_cpu_get(cpu); 126795235ca2SVenkatesh Pallipadi if (policy) { 1268e08f5f5bSGautham R Shenoy ret_freq = policy->cur; 126995235ca2SVenkatesh Pallipadi cpufreq_cpu_put(policy); 127095235ca2SVenkatesh Pallipadi } 127195235ca2SVenkatesh Pallipadi 12724d34a67dSDave Jones return ret_freq; 127395235ca2SVenkatesh Pallipadi } 127495235ca2SVenkatesh Pallipadi EXPORT_SYMBOL(cpufreq_quick_get); 127595235ca2SVenkatesh Pallipadi 12763d737108SJesse Barnes /** 12773d737108SJesse Barnes * cpufreq_quick_get_max - get the max reported CPU frequency for this CPU 12783d737108SJesse Barnes * @cpu: CPU number 12793d737108SJesse Barnes * 12803d737108SJesse Barnes * Just return the max possible frequency for a given CPU. 12813d737108SJesse Barnes */ 12823d737108SJesse Barnes unsigned int cpufreq_quick_get_max(unsigned int cpu) 12833d737108SJesse Barnes { 12843d737108SJesse Barnes struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 12853d737108SJesse Barnes unsigned int ret_freq = 0; 12863d737108SJesse Barnes 12873d737108SJesse Barnes if (policy) { 12883d737108SJesse Barnes ret_freq = policy->max; 12893d737108SJesse Barnes cpufreq_cpu_put(policy); 12903d737108SJesse Barnes } 12913d737108SJesse Barnes 12923d737108SJesse Barnes return ret_freq; 12933d737108SJesse Barnes } 12943d737108SJesse Barnes EXPORT_SYMBOL(cpufreq_quick_get_max); 12953d737108SJesse Barnes 129695235ca2SVenkatesh Pallipadi 12975a01f2e8SVenkatesh Pallipadi static unsigned int __cpufreq_get(unsigned int cpu) 12981da177e4SLinus Torvalds { 12997a6aedfaSMike Travis struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); 13005800043bSNathan Zimmer struct cpufreq_driver *driver; 13015800043bSNathan Zimmer unsigned int (*get)(unsigned int cpu); 1302e08f5f5bSGautham R Shenoy unsigned int ret_freq = 0; 13035800043bSNathan Zimmer u8 flags; 13041da177e4SLinus Torvalds 13055800043bSNathan Zimmer 13065800043bSNathan Zimmer rcu_read_lock(); 13075800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 13085800043bSNathan Zimmer if (!driver->get) { 13095800043bSNathan Zimmer rcu_read_unlock(); 13104d34a67dSDave Jones return ret_freq; 13115800043bSNathan Zimmer } 13125800043bSNathan Zimmer flags = driver->flags; 13135800043bSNathan Zimmer get = driver->get; 13145800043bSNathan Zimmer rcu_read_unlock(); 13151da177e4SLinus Torvalds 13165800043bSNathan Zimmer ret_freq = get(cpu); 13171da177e4SLinus Torvalds 1318e08f5f5bSGautham R Shenoy if (ret_freq && policy->cur && 13195800043bSNathan Zimmer !(flags & CPUFREQ_CONST_LOOPS)) { 1320e08f5f5bSGautham R Shenoy /* verify no discrepancy between actual and 1321e08f5f5bSGautham R Shenoy saved value exists */ 1322e08f5f5bSGautham R Shenoy if (unlikely(ret_freq != policy->cur)) { 1323e08f5f5bSGautham R Shenoy cpufreq_out_of_sync(cpu, policy->cur, ret_freq); 13241da177e4SLinus Torvalds schedule_work(&policy->update); 13251da177e4SLinus Torvalds } 13261da177e4SLinus Torvalds } 13271da177e4SLinus Torvalds 13284d34a67dSDave Jones return ret_freq; 13295a01f2e8SVenkatesh Pallipadi } 13301da177e4SLinus Torvalds 13315a01f2e8SVenkatesh Pallipadi /** 13325a01f2e8SVenkatesh Pallipadi * cpufreq_get - get the current CPU frequency (in kHz) 13335a01f2e8SVenkatesh Pallipadi * @cpu: CPU number 13345a01f2e8SVenkatesh Pallipadi * 13355a01f2e8SVenkatesh Pallipadi * Get the CPU current (static) CPU frequency 13365a01f2e8SVenkatesh Pallipadi */ 13375a01f2e8SVenkatesh Pallipadi unsigned int cpufreq_get(unsigned int cpu) 13385a01f2e8SVenkatesh Pallipadi { 13395a01f2e8SVenkatesh Pallipadi unsigned int ret_freq = 0; 13405a01f2e8SVenkatesh Pallipadi struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 13415a01f2e8SVenkatesh Pallipadi 13425a01f2e8SVenkatesh Pallipadi if (!policy) 13435a01f2e8SVenkatesh Pallipadi goto out; 13445a01f2e8SVenkatesh Pallipadi 13455a01f2e8SVenkatesh Pallipadi if (unlikely(lock_policy_rwsem_read(cpu))) 13465a01f2e8SVenkatesh Pallipadi goto out_policy; 13475a01f2e8SVenkatesh Pallipadi 13485a01f2e8SVenkatesh Pallipadi ret_freq = __cpufreq_get(cpu); 13495a01f2e8SVenkatesh Pallipadi 13505a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_read(cpu); 13515a01f2e8SVenkatesh Pallipadi 13525a01f2e8SVenkatesh Pallipadi out_policy: 13531da177e4SLinus Torvalds cpufreq_cpu_put(policy); 13545a01f2e8SVenkatesh Pallipadi out: 13554d34a67dSDave Jones return ret_freq; 13561da177e4SLinus Torvalds } 13571da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_get); 13581da177e4SLinus Torvalds 13598a25a2fdSKay Sievers static struct subsys_interface cpufreq_interface = { 13608a25a2fdSKay Sievers .name = "cpufreq", 13618a25a2fdSKay Sievers .subsys = &cpu_subsys, 13628a25a2fdSKay Sievers .add_dev = cpufreq_add_dev, 13638a25a2fdSKay Sievers .remove_dev = cpufreq_remove_dev, 1364e00e56dfSRafael J. Wysocki }; 1365e00e56dfSRafael J. Wysocki 13661da177e4SLinus Torvalds 13671da177e4SLinus Torvalds /** 1368e00e56dfSRafael J. Wysocki * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. 1369e00e56dfSRafael J. Wysocki * 1370e00e56dfSRafael J. Wysocki * This function is only executed for the boot processor. The other CPUs 1371e00e56dfSRafael J. Wysocki * have been put offline by means of CPU hotplug. 137242d4dc3fSBenjamin Herrenschmidt */ 1373e00e56dfSRafael J. Wysocki static int cpufreq_bp_suspend(void) 137442d4dc3fSBenjamin Herrenschmidt { 13755800043bSNathan Zimmer int (*suspend)(struct cpufreq_policy *policy); 1376e08f5f5bSGautham R Shenoy int ret = 0; 13774bc5d341SDave Jones 1378e00e56dfSRafael J. Wysocki int cpu = smp_processor_id(); 137942d4dc3fSBenjamin Herrenschmidt struct cpufreq_policy *cpu_policy; 138042d4dc3fSBenjamin Herrenschmidt 13812d06d8c4SDominik Brodowski pr_debug("suspending cpu %u\n", cpu); 138242d4dc3fSBenjamin Herrenschmidt 1383e00e56dfSRafael J. Wysocki /* If there's no policy for the boot CPU, we have nothing to do. */ 138442d4dc3fSBenjamin Herrenschmidt cpu_policy = cpufreq_cpu_get(cpu); 138542d4dc3fSBenjamin Herrenschmidt if (!cpu_policy) 1386e00e56dfSRafael J. Wysocki return 0; 138742d4dc3fSBenjamin Herrenschmidt 13885800043bSNathan Zimmer rcu_read_lock(); 13895800043bSNathan Zimmer suspend = rcu_dereference(cpufreq_driver)->suspend; 13905800043bSNathan Zimmer rcu_read_unlock(); 13915800043bSNathan Zimmer if (suspend) { 13925800043bSNathan Zimmer ret = suspend(cpu_policy); 1393ce6c3997SDominik Brodowski if (ret) 139442d4dc3fSBenjamin Herrenschmidt printk(KERN_ERR "cpufreq: suspend failed in ->suspend " 139542d4dc3fSBenjamin Herrenschmidt "step on CPU %u\n", cpu_policy->cpu); 139642d4dc3fSBenjamin Herrenschmidt } 139742d4dc3fSBenjamin Herrenschmidt 139842d4dc3fSBenjamin Herrenschmidt cpufreq_cpu_put(cpu_policy); 1399c9060494SDave Jones return ret; 140042d4dc3fSBenjamin Herrenschmidt } 140142d4dc3fSBenjamin Herrenschmidt 140242d4dc3fSBenjamin Herrenschmidt /** 1403e00e56dfSRafael J. Wysocki * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU. 14041da177e4SLinus Torvalds * 14051da177e4SLinus Torvalds * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) 1406ce6c3997SDominik Brodowski * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are 1407ce6c3997SDominik Brodowski * restored. It will verify that the current freq is in sync with 1408ce6c3997SDominik Brodowski * what we believe it to be. This is a bit later than when it 1409ce6c3997SDominik Brodowski * should be, but nonethteless it's better than calling 1410ce6c3997SDominik Brodowski * cpufreq_driver->get() here which might re-enable interrupts... 1411e00e56dfSRafael J. Wysocki * 1412e00e56dfSRafael J. Wysocki * This function is only executed for the boot CPU. The other CPUs have not 1413e00e56dfSRafael J. Wysocki * been turned on yet. 14141da177e4SLinus Torvalds */ 1415e00e56dfSRafael J. Wysocki static void cpufreq_bp_resume(void) 14161da177e4SLinus Torvalds { 1417e08f5f5bSGautham R Shenoy int ret = 0; 14185800043bSNathan Zimmer int (*resume)(struct cpufreq_policy *policy); 14194bc5d341SDave Jones 1420e00e56dfSRafael J. Wysocki int cpu = smp_processor_id(); 14211da177e4SLinus Torvalds struct cpufreq_policy *cpu_policy; 14221da177e4SLinus Torvalds 14232d06d8c4SDominik Brodowski pr_debug("resuming cpu %u\n", cpu); 14241da177e4SLinus Torvalds 1425e00e56dfSRafael J. Wysocki /* If there's no policy for the boot CPU, we have nothing to do. */ 14261da177e4SLinus Torvalds cpu_policy = cpufreq_cpu_get(cpu); 14271da177e4SLinus Torvalds if (!cpu_policy) 1428e00e56dfSRafael J. Wysocki return; 14291da177e4SLinus Torvalds 14305800043bSNathan Zimmer rcu_read_lock(); 14315800043bSNathan Zimmer resume = rcu_dereference(cpufreq_driver)->resume; 14325800043bSNathan Zimmer rcu_read_unlock(); 14335800043bSNathan Zimmer 14345800043bSNathan Zimmer if (resume) { 14355800043bSNathan Zimmer ret = resume(cpu_policy); 14361da177e4SLinus Torvalds if (ret) { 14371da177e4SLinus Torvalds printk(KERN_ERR "cpufreq: resume failed in ->resume " 14381da177e4SLinus Torvalds "step on CPU %u\n", cpu_policy->cpu); 1439c9060494SDave Jones goto fail; 14401da177e4SLinus Torvalds } 14411da177e4SLinus Torvalds } 14421da177e4SLinus Torvalds 14431da177e4SLinus Torvalds schedule_work(&cpu_policy->update); 1444ce6c3997SDominik Brodowski 1445c9060494SDave Jones fail: 14461da177e4SLinus Torvalds cpufreq_cpu_put(cpu_policy); 14471da177e4SLinus Torvalds } 14481da177e4SLinus Torvalds 1449e00e56dfSRafael J. Wysocki static struct syscore_ops cpufreq_syscore_ops = { 1450e00e56dfSRafael J. Wysocki .suspend = cpufreq_bp_suspend, 1451e00e56dfSRafael J. Wysocki .resume = cpufreq_bp_resume, 14521da177e4SLinus Torvalds }; 14531da177e4SLinus Torvalds 14549d95046eSBorislav Petkov /** 14559d95046eSBorislav Petkov * cpufreq_get_current_driver - return current driver's name 14569d95046eSBorislav Petkov * 14579d95046eSBorislav Petkov * Return the name string of the currently loaded cpufreq driver 14589d95046eSBorislav Petkov * or NULL, if none. 14599d95046eSBorislav Petkov */ 14609d95046eSBorislav Petkov const char *cpufreq_get_current_driver(void) 14619d95046eSBorislav Petkov { 14625800043bSNathan Zimmer struct cpufreq_driver *driver; 14635800043bSNathan Zimmer const char *name = NULL; 14645800043bSNathan Zimmer rcu_read_lock(); 14655800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 14665800043bSNathan Zimmer if (driver) 14675800043bSNathan Zimmer name = driver->name; 14685800043bSNathan Zimmer rcu_read_unlock(); 14695800043bSNathan Zimmer return name; 14709d95046eSBorislav Petkov } 14719d95046eSBorislav Petkov EXPORT_SYMBOL_GPL(cpufreq_get_current_driver); 14721da177e4SLinus Torvalds 14731da177e4SLinus Torvalds /********************************************************************* 14741da177e4SLinus Torvalds * NOTIFIER LISTS INTERFACE * 14751da177e4SLinus Torvalds *********************************************************************/ 14761da177e4SLinus Torvalds 14771da177e4SLinus Torvalds /** 14781da177e4SLinus Torvalds * cpufreq_register_notifier - register a driver with cpufreq 14791da177e4SLinus Torvalds * @nb: notifier function to register 14801da177e4SLinus Torvalds * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER 14811da177e4SLinus Torvalds * 14821da177e4SLinus Torvalds * Add a driver to one of two lists: either a list of drivers that 14831da177e4SLinus Torvalds * are notified about clock rate changes (once before and once after 14841da177e4SLinus Torvalds * the transition), or a list of drivers that are notified about 14851da177e4SLinus Torvalds * changes in cpufreq policy. 14861da177e4SLinus Torvalds * 14871da177e4SLinus Torvalds * This function may sleep, and has the same return conditions as 1488e041c683SAlan Stern * blocking_notifier_chain_register. 14891da177e4SLinus Torvalds */ 14901da177e4SLinus Torvalds int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) 14911da177e4SLinus Torvalds { 14921da177e4SLinus Torvalds int ret; 14931da177e4SLinus Torvalds 1494d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1495d5aaffa9SDirk Brandewie return -EINVAL; 1496d5aaffa9SDirk Brandewie 149774212ca4SCesar Eduardo Barros WARN_ON(!init_cpufreq_transition_notifier_list_called); 149874212ca4SCesar Eduardo Barros 14991da177e4SLinus Torvalds switch (list) { 15001da177e4SLinus Torvalds case CPUFREQ_TRANSITION_NOTIFIER: 1501b4dfdbb3SAlan Stern ret = srcu_notifier_chain_register( 1502e041c683SAlan Stern &cpufreq_transition_notifier_list, nb); 15031da177e4SLinus Torvalds break; 15041da177e4SLinus Torvalds case CPUFREQ_POLICY_NOTIFIER: 1505e041c683SAlan Stern ret = blocking_notifier_chain_register( 1506e041c683SAlan Stern &cpufreq_policy_notifier_list, nb); 15071da177e4SLinus Torvalds break; 15081da177e4SLinus Torvalds default: 15091da177e4SLinus Torvalds ret = -EINVAL; 15101da177e4SLinus Torvalds } 15111da177e4SLinus Torvalds 15121da177e4SLinus Torvalds return ret; 15131da177e4SLinus Torvalds } 15141da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_register_notifier); 15151da177e4SLinus Torvalds 15161da177e4SLinus Torvalds 15171da177e4SLinus Torvalds /** 15181da177e4SLinus Torvalds * cpufreq_unregister_notifier - unregister a driver with cpufreq 15191da177e4SLinus Torvalds * @nb: notifier block to be unregistered 15201da177e4SLinus Torvalds * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER 15211da177e4SLinus Torvalds * 15221da177e4SLinus Torvalds * Remove a driver from the CPU frequency notifier list. 15231da177e4SLinus Torvalds * 15241da177e4SLinus Torvalds * This function may sleep, and has the same return conditions as 1525e041c683SAlan Stern * blocking_notifier_chain_unregister. 15261da177e4SLinus Torvalds */ 15271da177e4SLinus Torvalds int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) 15281da177e4SLinus Torvalds { 15291da177e4SLinus Torvalds int ret; 15301da177e4SLinus Torvalds 1531d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1532d5aaffa9SDirk Brandewie return -EINVAL; 1533d5aaffa9SDirk Brandewie 15341da177e4SLinus Torvalds switch (list) { 15351da177e4SLinus Torvalds case CPUFREQ_TRANSITION_NOTIFIER: 1536b4dfdbb3SAlan Stern ret = srcu_notifier_chain_unregister( 1537e041c683SAlan Stern &cpufreq_transition_notifier_list, nb); 15381da177e4SLinus Torvalds break; 15391da177e4SLinus Torvalds case CPUFREQ_POLICY_NOTIFIER: 1540e041c683SAlan Stern ret = blocking_notifier_chain_unregister( 1541e041c683SAlan Stern &cpufreq_policy_notifier_list, nb); 15421da177e4SLinus Torvalds break; 15431da177e4SLinus Torvalds default: 15441da177e4SLinus Torvalds ret = -EINVAL; 15451da177e4SLinus Torvalds } 15461da177e4SLinus Torvalds 15471da177e4SLinus Torvalds return ret; 15481da177e4SLinus Torvalds } 15491da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_unregister_notifier); 15501da177e4SLinus Torvalds 15511da177e4SLinus Torvalds 15521da177e4SLinus Torvalds /********************************************************************* 15531da177e4SLinus Torvalds * GOVERNORS * 15541da177e4SLinus Torvalds *********************************************************************/ 15551da177e4SLinus Torvalds 15561da177e4SLinus Torvalds 15571da177e4SLinus Torvalds int __cpufreq_driver_target(struct cpufreq_policy *policy, 15581da177e4SLinus Torvalds unsigned int target_freq, 15591da177e4SLinus Torvalds unsigned int relation) 15601da177e4SLinus Torvalds { 15611da177e4SLinus Torvalds int retval = -EINVAL; 15627249924eSViresh Kumar unsigned int old_target_freq = target_freq; 15635800043bSNathan Zimmer int (*target)(struct cpufreq_policy *policy, 15645800043bSNathan Zimmer unsigned int target_freq, 15655800043bSNathan Zimmer unsigned int relation); 1566c32b6b8eSAshok Raj 1567a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1568a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 1569a7b422cdSKonrad Rzeszutek Wilk 15707249924eSViresh Kumar /* Make sure that target_freq is within supported range */ 15717249924eSViresh Kumar if (target_freq > policy->max) 15727249924eSViresh Kumar target_freq = policy->max; 15737249924eSViresh Kumar if (target_freq < policy->min) 15747249924eSViresh Kumar target_freq = policy->min; 15757249924eSViresh Kumar 15767249924eSViresh Kumar pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", 15777249924eSViresh Kumar policy->cpu, target_freq, relation, old_target_freq); 15785a1c0228SViresh Kumar 15795a1c0228SViresh Kumar if (target_freq == policy->cur) 15805a1c0228SViresh Kumar return 0; 15815a1c0228SViresh Kumar 15825800043bSNathan Zimmer rcu_read_lock(); 15835800043bSNathan Zimmer target = rcu_dereference(cpufreq_driver)->target; 15845800043bSNathan Zimmer rcu_read_unlock(); 15855800043bSNathan Zimmer if (target) 15865800043bSNathan Zimmer retval = target(policy, target_freq, relation); 158790d45d17SAshok Raj 15881da177e4SLinus Torvalds return retval; 15891da177e4SLinus Torvalds } 15901da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(__cpufreq_driver_target); 15911da177e4SLinus Torvalds 15921da177e4SLinus Torvalds int cpufreq_driver_target(struct cpufreq_policy *policy, 15931da177e4SLinus Torvalds unsigned int target_freq, 15941da177e4SLinus Torvalds unsigned int relation) 15951da177e4SLinus Torvalds { 1596f1829e4aSJulia Lawall int ret = -EINVAL; 15971da177e4SLinus Torvalds 15981da177e4SLinus Torvalds policy = cpufreq_cpu_get(policy->cpu); 15991da177e4SLinus Torvalds if (!policy) 1600f1829e4aSJulia Lawall goto no_policy; 16011da177e4SLinus Torvalds 16025a01f2e8SVenkatesh Pallipadi if (unlikely(lock_policy_rwsem_write(policy->cpu))) 1603f1829e4aSJulia Lawall goto fail; 16041da177e4SLinus Torvalds 16051da177e4SLinus Torvalds ret = __cpufreq_driver_target(policy, target_freq, relation); 16061da177e4SLinus Torvalds 16075a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(policy->cpu); 16081da177e4SLinus Torvalds 1609f1829e4aSJulia Lawall fail: 16101da177e4SLinus Torvalds cpufreq_cpu_put(policy); 1611f1829e4aSJulia Lawall no_policy: 16121da177e4SLinus Torvalds return ret; 16131da177e4SLinus Torvalds } 16141da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_driver_target); 16151da177e4SLinus Torvalds 1616bf0b90e3Svenkatesh.pallipadi@intel.com int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) 1617dfde5d62SVenkatesh Pallipadi { 1618dfde5d62SVenkatesh Pallipadi int ret = 0; 16195800043bSNathan Zimmer unsigned int (*getavg)(struct cpufreq_policy *policy, 16205800043bSNathan Zimmer unsigned int cpu); 1621dfde5d62SVenkatesh Pallipadi 1622d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1623d5aaffa9SDirk Brandewie return ret; 1624d5aaffa9SDirk Brandewie 16255800043bSNathan Zimmer rcu_read_lock(); 16265800043bSNathan Zimmer getavg = rcu_dereference(cpufreq_driver)->getavg; 16275800043bSNathan Zimmer rcu_read_unlock(); 16285800043bSNathan Zimmer 16295800043bSNathan Zimmer if (!getavg) 16300676f7f2SViresh Kumar return 0; 16310676f7f2SViresh Kumar 1632dfde5d62SVenkatesh Pallipadi policy = cpufreq_cpu_get(policy->cpu); 1633dfde5d62SVenkatesh Pallipadi if (!policy) 1634dfde5d62SVenkatesh Pallipadi return -EINVAL; 1635dfde5d62SVenkatesh Pallipadi 16365800043bSNathan Zimmer ret = getavg(policy, cpu); 1637dfde5d62SVenkatesh Pallipadi 1638dfde5d62SVenkatesh Pallipadi cpufreq_cpu_put(policy); 1639dfde5d62SVenkatesh Pallipadi return ret; 1640dfde5d62SVenkatesh Pallipadi } 16415a01f2e8SVenkatesh Pallipadi EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg); 1642dfde5d62SVenkatesh Pallipadi 1643153d7f3fSArjan van de Ven /* 1644153d7f3fSArjan van de Ven * when "event" is CPUFREQ_GOV_LIMITS 1645153d7f3fSArjan van de Ven */ 16461da177e4SLinus Torvalds 1647e08f5f5bSGautham R Shenoy static int __cpufreq_governor(struct cpufreq_policy *policy, 1648e08f5f5bSGautham R Shenoy unsigned int event) 16491da177e4SLinus Torvalds { 1650cc993cabSDave Jones int ret; 16516afde10cSThomas Renninger 16526afde10cSThomas Renninger /* Only must be defined when default governor is known to have latency 16536afde10cSThomas Renninger restrictions, like e.g. conservative or ondemand. 16546afde10cSThomas Renninger That this is the case is already ensured in Kconfig 16556afde10cSThomas Renninger */ 16566afde10cSThomas Renninger #ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE 16576afde10cSThomas Renninger struct cpufreq_governor *gov = &cpufreq_gov_performance; 16586afde10cSThomas Renninger #else 16596afde10cSThomas Renninger struct cpufreq_governor *gov = NULL; 16606afde10cSThomas Renninger #endif 16611c256245SThomas Renninger 16621c256245SThomas Renninger if (policy->governor->max_transition_latency && 16631c256245SThomas Renninger policy->cpuinfo.transition_latency > 16641c256245SThomas Renninger policy->governor->max_transition_latency) { 16656afde10cSThomas Renninger if (!gov) 16666afde10cSThomas Renninger return -EINVAL; 16676afde10cSThomas Renninger else { 16681c256245SThomas Renninger printk(KERN_WARNING "%s governor failed, too long" 16691c256245SThomas Renninger " transition latency of HW, fallback" 16701c256245SThomas Renninger " to %s governor\n", 16711c256245SThomas Renninger policy->governor->name, 16721c256245SThomas Renninger gov->name); 16731c256245SThomas Renninger policy->governor = gov; 16741c256245SThomas Renninger } 16756afde10cSThomas Renninger } 16761da177e4SLinus Torvalds 16771da177e4SLinus Torvalds if (!try_module_get(policy->governor->owner)) 16781da177e4SLinus Torvalds return -EINVAL; 16791da177e4SLinus Torvalds 16802d06d8c4SDominik Brodowski pr_debug("__cpufreq_governor for CPU %u, event %u\n", 1681e08f5f5bSGautham R Shenoy policy->cpu, event); 16821da177e4SLinus Torvalds ret = policy->governor->governor(policy, event); 16831da177e4SLinus Torvalds 16844d5dcc42SViresh Kumar if (!ret) { 16854d5dcc42SViresh Kumar if (event == CPUFREQ_GOV_POLICY_INIT) 16868e53695fSViresh Kumar policy->governor->initialized++; 16874d5dcc42SViresh Kumar else if (event == CPUFREQ_GOV_POLICY_EXIT) 16888e53695fSViresh Kumar policy->governor->initialized--; 16894d5dcc42SViresh Kumar } 1690b394058fSViresh Kumar 1691e08f5f5bSGautham R Shenoy /* we keep one module reference alive for 1692e08f5f5bSGautham R Shenoy each CPU governed by this CPU */ 16931da177e4SLinus Torvalds if ((event != CPUFREQ_GOV_START) || ret) 16941da177e4SLinus Torvalds module_put(policy->governor->owner); 16951da177e4SLinus Torvalds if ((event == CPUFREQ_GOV_STOP) && !ret) 16961da177e4SLinus Torvalds module_put(policy->governor->owner); 16971da177e4SLinus Torvalds 16981da177e4SLinus Torvalds return ret; 16991da177e4SLinus Torvalds } 17001da177e4SLinus Torvalds 17011da177e4SLinus Torvalds 17021da177e4SLinus Torvalds int cpufreq_register_governor(struct cpufreq_governor *governor) 17031da177e4SLinus Torvalds { 17043bcb09a3SJeremy Fitzhardinge int err; 17051da177e4SLinus Torvalds 17061da177e4SLinus Torvalds if (!governor) 17071da177e4SLinus Torvalds return -EINVAL; 17081da177e4SLinus Torvalds 1709a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1710a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 1711a7b422cdSKonrad Rzeszutek Wilk 17123fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 17131da177e4SLinus Torvalds 1714b394058fSViresh Kumar governor->initialized = 0; 17153bcb09a3SJeremy Fitzhardinge err = -EBUSY; 17163bcb09a3SJeremy Fitzhardinge if (__find_governor(governor->name) == NULL) { 17173bcb09a3SJeremy Fitzhardinge err = 0; 17181da177e4SLinus Torvalds list_add(&governor->governor_list, &cpufreq_governor_list); 17193bcb09a3SJeremy Fitzhardinge } 17201da177e4SLinus Torvalds 17213fc54d37Sakpm@osdl.org mutex_unlock(&cpufreq_governor_mutex); 17223bcb09a3SJeremy Fitzhardinge return err; 17231da177e4SLinus Torvalds } 17241da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_register_governor); 17251da177e4SLinus Torvalds 17261da177e4SLinus Torvalds 17271da177e4SLinus Torvalds void cpufreq_unregister_governor(struct cpufreq_governor *governor) 17281da177e4SLinus Torvalds { 172990e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 173090e41bacSPrarit Bhargava int cpu; 173190e41bacSPrarit Bhargava #endif 173290e41bacSPrarit Bhargava 17331da177e4SLinus Torvalds if (!governor) 17341da177e4SLinus Torvalds return; 17351da177e4SLinus Torvalds 1736a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1737a7b422cdSKonrad Rzeszutek Wilk return; 1738a7b422cdSKonrad Rzeszutek Wilk 173990e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 174090e41bacSPrarit Bhargava for_each_present_cpu(cpu) { 174190e41bacSPrarit Bhargava if (cpu_online(cpu)) 174290e41bacSPrarit Bhargava continue; 174390e41bacSPrarit Bhargava if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name)) 174490e41bacSPrarit Bhargava strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0"); 174590e41bacSPrarit Bhargava } 174690e41bacSPrarit Bhargava #endif 174790e41bacSPrarit Bhargava 17483fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 17491da177e4SLinus Torvalds list_del(&governor->governor_list); 17503fc54d37Sakpm@osdl.org mutex_unlock(&cpufreq_governor_mutex); 17511da177e4SLinus Torvalds return; 17521da177e4SLinus Torvalds } 17531da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_unregister_governor); 17541da177e4SLinus Torvalds 17551da177e4SLinus Torvalds 17561da177e4SLinus Torvalds 17571da177e4SLinus Torvalds /********************************************************************* 17581da177e4SLinus Torvalds * POLICY INTERFACE * 17591da177e4SLinus Torvalds *********************************************************************/ 17601da177e4SLinus Torvalds 17611da177e4SLinus Torvalds /** 17621da177e4SLinus Torvalds * cpufreq_get_policy - get the current cpufreq_policy 176329464f28SDave Jones * @policy: struct cpufreq_policy into which the current cpufreq_policy 176429464f28SDave Jones * is written 17651da177e4SLinus Torvalds * 17661da177e4SLinus Torvalds * Reads the current cpufreq policy. 17671da177e4SLinus Torvalds */ 17681da177e4SLinus Torvalds int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) 17691da177e4SLinus Torvalds { 17701da177e4SLinus Torvalds struct cpufreq_policy *cpu_policy; 17711da177e4SLinus Torvalds if (!policy) 17721da177e4SLinus Torvalds return -EINVAL; 17731da177e4SLinus Torvalds 17741da177e4SLinus Torvalds cpu_policy = cpufreq_cpu_get(cpu); 17751da177e4SLinus Torvalds if (!cpu_policy) 17761da177e4SLinus Torvalds return -EINVAL; 17771da177e4SLinus Torvalds 17781da177e4SLinus Torvalds memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy)); 17791da177e4SLinus Torvalds 17801da177e4SLinus Torvalds cpufreq_cpu_put(cpu_policy); 17811da177e4SLinus Torvalds return 0; 17821da177e4SLinus Torvalds } 17831da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_get_policy); 17841da177e4SLinus Torvalds 17851da177e4SLinus Torvalds 1786153d7f3fSArjan van de Ven /* 1787e08f5f5bSGautham R Shenoy * data : current policy. 1788e08f5f5bSGautham R Shenoy * policy : policy to be set. 1789153d7f3fSArjan van de Ven */ 1790e08f5f5bSGautham R Shenoy static int __cpufreq_set_policy(struct cpufreq_policy *data, 1791e08f5f5bSGautham R Shenoy struct cpufreq_policy *policy) 17921da177e4SLinus Torvalds { 17937bd353a9SViresh Kumar int ret = 0, failed = 1; 17945800043bSNathan Zimmer struct cpufreq_driver *driver; 17955800043bSNathan Zimmer int (*verify)(struct cpufreq_policy *policy); 17965800043bSNathan Zimmer int (*setpolicy)(struct cpufreq_policy *policy); 17971da177e4SLinus Torvalds 17982d06d8c4SDominik Brodowski pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, 17991da177e4SLinus Torvalds policy->min, policy->max); 18001da177e4SLinus Torvalds 1801e08f5f5bSGautham R Shenoy memcpy(&policy->cpuinfo, &data->cpuinfo, 1802e08f5f5bSGautham R Shenoy sizeof(struct cpufreq_cpuinfo)); 18031da177e4SLinus Torvalds 180453391fa2SYi Yang if (policy->min > data->max || policy->max < data->min) { 18059c9a43edSMattia Dongili ret = -EINVAL; 18069c9a43edSMattia Dongili goto error_out; 18079c9a43edSMattia Dongili } 18089c9a43edSMattia Dongili 18091da177e4SLinus Torvalds /* verify the cpu speed can be set within this limit */ 18105800043bSNathan Zimmer rcu_read_lock(); 18115800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 18125800043bSNathan Zimmer verify = driver->verify; 18135800043bSNathan Zimmer setpolicy = driver->setpolicy; 18145800043bSNathan Zimmer rcu_read_unlock(); 18155800043bSNathan Zimmer 18165800043bSNathan Zimmer ret = verify(policy); 18171da177e4SLinus Torvalds if (ret) 18181da177e4SLinus Torvalds goto error_out; 18191da177e4SLinus Torvalds 18201da177e4SLinus Torvalds /* adjust if necessary - all reasons */ 1821e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1822e041c683SAlan Stern CPUFREQ_ADJUST, policy); 18231da177e4SLinus Torvalds 18241da177e4SLinus Torvalds /* adjust if necessary - hardware incompatibility*/ 1825e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1826e041c683SAlan Stern CPUFREQ_INCOMPATIBLE, policy); 18271da177e4SLinus Torvalds 18281da177e4SLinus Torvalds /* verify the cpu speed can be set within this limit, 18291da177e4SLinus Torvalds which might be different to the first one */ 18305800043bSNathan Zimmer ret = verify(policy); 1831e041c683SAlan Stern if (ret) 18321da177e4SLinus Torvalds goto error_out; 18331da177e4SLinus Torvalds 18341da177e4SLinus Torvalds /* notification of the new policy */ 1835e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1836e041c683SAlan Stern CPUFREQ_NOTIFY, policy); 18371da177e4SLinus Torvalds 18381da177e4SLinus Torvalds data->min = policy->min; 18391da177e4SLinus Torvalds data->max = policy->max; 18401da177e4SLinus Torvalds 18412d06d8c4SDominik Brodowski pr_debug("new min and max freqs are %u - %u kHz\n", 1842e08f5f5bSGautham R Shenoy data->min, data->max); 18431da177e4SLinus Torvalds 18445800043bSNathan Zimmer if (setpolicy) { 18451da177e4SLinus Torvalds data->policy = policy->policy; 18462d06d8c4SDominik Brodowski pr_debug("setting range\n"); 18475800043bSNathan Zimmer ret = setpolicy(policy); 18481da177e4SLinus Torvalds } else { 18491da177e4SLinus Torvalds if (policy->governor != data->governor) { 18501da177e4SLinus Torvalds /* save old, working values */ 18511da177e4SLinus Torvalds struct cpufreq_governor *old_gov = data->governor; 18521da177e4SLinus Torvalds 18532d06d8c4SDominik Brodowski pr_debug("governor switch\n"); 18541da177e4SLinus Torvalds 18551da177e4SLinus Torvalds /* end old governor */ 18567bd353a9SViresh Kumar if (data->governor) { 18571da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_STOP); 18587bd353a9SViresh Kumar __cpufreq_governor(data, 18597bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 18607bd353a9SViresh Kumar } 18611da177e4SLinus Torvalds 18621da177e4SLinus Torvalds /* start new governor */ 18631da177e4SLinus Torvalds data->governor = policy->governor; 18647bd353a9SViresh Kumar if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) { 18657bd353a9SViresh Kumar if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) 18667bd353a9SViresh Kumar failed = 0; 18677bd353a9SViresh Kumar else 18687bd353a9SViresh Kumar __cpufreq_governor(data, 18697bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 18707bd353a9SViresh Kumar } 18717bd353a9SViresh Kumar 18727bd353a9SViresh Kumar if (failed) { 18731da177e4SLinus Torvalds /* new governor failed, so re-start old one */ 18742d06d8c4SDominik Brodowski pr_debug("starting governor %s failed\n", 1875e08f5f5bSGautham R Shenoy data->governor->name); 18761da177e4SLinus Torvalds if (old_gov) { 18771da177e4SLinus Torvalds data->governor = old_gov; 1878e08f5f5bSGautham R Shenoy __cpufreq_governor(data, 18797bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_INIT); 18807bd353a9SViresh Kumar __cpufreq_governor(data, 1881e08f5f5bSGautham R Shenoy CPUFREQ_GOV_START); 18821da177e4SLinus Torvalds } 18831da177e4SLinus Torvalds ret = -EINVAL; 18841da177e4SLinus Torvalds goto error_out; 18851da177e4SLinus Torvalds } 18861da177e4SLinus Torvalds /* might be a policy change, too, so fall through */ 18871da177e4SLinus Torvalds } 18882d06d8c4SDominik Brodowski pr_debug("governor: change or update limits\n"); 18891da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); 18901da177e4SLinus Torvalds } 18911da177e4SLinus Torvalds 18921da177e4SLinus Torvalds error_out: 18931da177e4SLinus Torvalds return ret; 18941da177e4SLinus Torvalds } 18951da177e4SLinus Torvalds 18961da177e4SLinus Torvalds /** 18971da177e4SLinus Torvalds * cpufreq_update_policy - re-evaluate an existing cpufreq policy 18981da177e4SLinus Torvalds * @cpu: CPU which shall be re-evaluated 18991da177e4SLinus Torvalds * 190025985edcSLucas De Marchi * Useful for policy notifiers which have different necessities 19011da177e4SLinus Torvalds * at different times. 19021da177e4SLinus Torvalds */ 19031da177e4SLinus Torvalds int cpufreq_update_policy(unsigned int cpu) 19041da177e4SLinus Torvalds { 19051da177e4SLinus Torvalds struct cpufreq_policy *data = cpufreq_cpu_get(cpu); 19061da177e4SLinus Torvalds struct cpufreq_policy policy; 19075800043bSNathan Zimmer struct cpufreq_driver *driver; 19085800043bSNathan Zimmer unsigned int (*get)(unsigned int cpu); 19095800043bSNathan Zimmer int (*target)(struct cpufreq_policy *policy, 19105800043bSNathan Zimmer unsigned int target_freq, 19115800043bSNathan Zimmer unsigned int relation); 1912f1829e4aSJulia Lawall int ret; 19131da177e4SLinus Torvalds 1914f1829e4aSJulia Lawall if (!data) { 1915f1829e4aSJulia Lawall ret = -ENODEV; 1916f1829e4aSJulia Lawall goto no_policy; 1917f1829e4aSJulia Lawall } 19181da177e4SLinus Torvalds 1919f1829e4aSJulia Lawall if (unlikely(lock_policy_rwsem_write(cpu))) { 1920f1829e4aSJulia Lawall ret = -EINVAL; 1921f1829e4aSJulia Lawall goto fail; 1922f1829e4aSJulia Lawall } 19231da177e4SLinus Torvalds 19242d06d8c4SDominik Brodowski pr_debug("updating policy for CPU %u\n", cpu); 19257d5e350fSDave Jones memcpy(&policy, data, sizeof(struct cpufreq_policy)); 19261da177e4SLinus Torvalds policy.min = data->user_policy.min; 19271da177e4SLinus Torvalds policy.max = data->user_policy.max; 19281da177e4SLinus Torvalds policy.policy = data->user_policy.policy; 19291da177e4SLinus Torvalds policy.governor = data->user_policy.governor; 19301da177e4SLinus Torvalds 19310961dd0dSThomas Renninger /* BIOS might change freq behind our back 19320961dd0dSThomas Renninger -> ask driver for current freq and notify governors about a change */ 19335800043bSNathan Zimmer rcu_read_lock(); 19345800043bSNathan Zimmer driver = rcu_access_pointer(cpufreq_driver); 19355800043bSNathan Zimmer get = driver->get; 19365800043bSNathan Zimmer target = driver->target; 19375800043bSNathan Zimmer rcu_read_unlock(); 19385800043bSNathan Zimmer if (get) { 19395800043bSNathan Zimmer policy.cur = get(cpu); 1940a85f7bd3SThomas Renninger if (!data->cur) { 19412d06d8c4SDominik Brodowski pr_debug("Driver did not initialize current freq"); 1942a85f7bd3SThomas Renninger data->cur = policy.cur; 1943a85f7bd3SThomas Renninger } else { 19445800043bSNathan Zimmer if (data->cur != policy.cur && target) 1945e08f5f5bSGautham R Shenoy cpufreq_out_of_sync(cpu, data->cur, 1946e08f5f5bSGautham R Shenoy policy.cur); 19470961dd0dSThomas Renninger } 1948a85f7bd3SThomas Renninger } 19490961dd0dSThomas Renninger 19501da177e4SLinus Torvalds ret = __cpufreq_set_policy(data, &policy); 19511da177e4SLinus Torvalds 19525a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(cpu); 19535a01f2e8SVenkatesh Pallipadi 1954f1829e4aSJulia Lawall fail: 19551da177e4SLinus Torvalds cpufreq_cpu_put(data); 1956f1829e4aSJulia Lawall no_policy: 19571da177e4SLinus Torvalds return ret; 19581da177e4SLinus Torvalds } 19591da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_update_policy); 19601da177e4SLinus Torvalds 1961dd184a01SSatyam Sharma static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, 1962c32b6b8eSAshok Raj unsigned long action, void *hcpu) 1963c32b6b8eSAshok Raj { 1964c32b6b8eSAshok Raj unsigned int cpu = (unsigned long)hcpu; 19658a25a2fdSKay Sievers struct device *dev; 1966c32b6b8eSAshok Raj 19678a25a2fdSKay Sievers dev = get_cpu_device(cpu); 19688a25a2fdSKay Sievers if (dev) { 1969c32b6b8eSAshok Raj switch (action) { 1970c32b6b8eSAshok Raj case CPU_ONLINE: 19718bb78442SRafael J. Wysocki case CPU_ONLINE_FROZEN: 19728a25a2fdSKay Sievers cpufreq_add_dev(dev, NULL); 1973c32b6b8eSAshok Raj break; 1974c32b6b8eSAshok Raj case CPU_DOWN_PREPARE: 19758bb78442SRafael J. Wysocki case CPU_DOWN_PREPARE_FROZEN: 19768a25a2fdSKay Sievers __cpufreq_remove_dev(dev, NULL); 1977c32b6b8eSAshok Raj break; 19785a01f2e8SVenkatesh Pallipadi case CPU_DOWN_FAILED: 19798bb78442SRafael J. Wysocki case CPU_DOWN_FAILED_FROZEN: 19808a25a2fdSKay Sievers cpufreq_add_dev(dev, NULL); 1981c32b6b8eSAshok Raj break; 1982c32b6b8eSAshok Raj } 1983c32b6b8eSAshok Raj } 1984c32b6b8eSAshok Raj return NOTIFY_OK; 1985c32b6b8eSAshok Raj } 1986c32b6b8eSAshok Raj 19879c36f746SNeal Buckendahl static struct notifier_block __refdata cpufreq_cpu_notifier = { 1988c32b6b8eSAshok Raj .notifier_call = cpufreq_cpu_callback, 1989c32b6b8eSAshok Raj }; 19901da177e4SLinus Torvalds 19911da177e4SLinus Torvalds /********************************************************************* 19921da177e4SLinus Torvalds * REGISTER / UNREGISTER CPUFREQ DRIVER * 19931da177e4SLinus Torvalds *********************************************************************/ 19941da177e4SLinus Torvalds 19951da177e4SLinus Torvalds /** 19961da177e4SLinus Torvalds * cpufreq_register_driver - register a CPU Frequency driver 19971da177e4SLinus Torvalds * @driver_data: A struct cpufreq_driver containing the values# 19981da177e4SLinus Torvalds * submitted by the CPU Frequency driver. 19991da177e4SLinus Torvalds * 20001da177e4SLinus Torvalds * Registers a CPU Frequency driver to this core code. This code 20011da177e4SLinus Torvalds * returns zero on success, -EBUSY when another driver got here first 20021da177e4SLinus Torvalds * (and isn't unregistered in the meantime). 20031da177e4SLinus Torvalds * 20041da177e4SLinus Torvalds */ 2005221dee28SLinus Torvalds int cpufreq_register_driver(struct cpufreq_driver *driver_data) 20061da177e4SLinus Torvalds { 20071da177e4SLinus Torvalds unsigned long flags; 20081da177e4SLinus Torvalds int ret; 20091da177e4SLinus Torvalds 2010a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 2011a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 2012a7b422cdSKonrad Rzeszutek Wilk 20131da177e4SLinus Torvalds if (!driver_data || !driver_data->verify || !driver_data->init || 20141da177e4SLinus Torvalds ((!driver_data->setpolicy) && (!driver_data->target))) 20151da177e4SLinus Torvalds return -EINVAL; 20161da177e4SLinus Torvalds 20172d06d8c4SDominik Brodowski pr_debug("trying to register driver %s\n", driver_data->name); 20181da177e4SLinus Torvalds 20191da177e4SLinus Torvalds if (driver_data->setpolicy) 20201da177e4SLinus Torvalds driver_data->flags |= CPUFREQ_CONST_LOOPS; 20211da177e4SLinus Torvalds 20220d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 20235800043bSNathan Zimmer if (rcu_access_pointer(cpufreq_driver)) { 20240d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20251da177e4SLinus Torvalds return -EBUSY; 20261da177e4SLinus Torvalds } 20275800043bSNathan Zimmer rcu_assign_pointer(cpufreq_driver, driver_data); 20280d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20295800043bSNathan Zimmer synchronize_rcu(); 20301da177e4SLinus Torvalds 20318a25a2fdSKay Sievers ret = subsys_interface_register(&cpufreq_interface); 20328f5bc2abSJiri Slaby if (ret) 20338f5bc2abSJiri Slaby goto err_null_driver; 20341da177e4SLinus Torvalds 20355800043bSNathan Zimmer if (!(driver_data->flags & CPUFREQ_STICKY)) { 20361da177e4SLinus Torvalds int i; 20371da177e4SLinus Torvalds ret = -ENODEV; 20381da177e4SLinus Torvalds 20391da177e4SLinus Torvalds /* check for at least one working CPU */ 20407a6aedfaSMike Travis for (i = 0; i < nr_cpu_ids; i++) 20417a6aedfaSMike Travis if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) { 20421da177e4SLinus Torvalds ret = 0; 20437a6aedfaSMike Travis break; 20447a6aedfaSMike Travis } 20451da177e4SLinus Torvalds 20461da177e4SLinus Torvalds /* if all ->init() calls failed, unregister */ 20471da177e4SLinus Torvalds if (ret) { 20482d06d8c4SDominik Brodowski pr_debug("no CPU initialized for driver %s\n", 2049e08f5f5bSGautham R Shenoy driver_data->name); 20508a25a2fdSKay Sievers goto err_if_unreg; 20511da177e4SLinus Torvalds } 20521da177e4SLinus Torvalds } 20531da177e4SLinus Torvalds 205465edc68cSChandra Seetharaman register_hotcpu_notifier(&cpufreq_cpu_notifier); 20552d06d8c4SDominik Brodowski pr_debug("driver %s up and running\n", driver_data->name); 20561da177e4SLinus Torvalds 20578f5bc2abSJiri Slaby return 0; 20588a25a2fdSKay Sievers err_if_unreg: 20598a25a2fdSKay Sievers subsys_interface_unregister(&cpufreq_interface); 20608f5bc2abSJiri Slaby err_null_driver: 20610d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 20625800043bSNathan Zimmer rcu_assign_pointer(cpufreq_driver, NULL); 20630d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20645800043bSNathan Zimmer synchronize_rcu(); 20654d34a67dSDave Jones return ret; 20661da177e4SLinus Torvalds } 20671da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_register_driver); 20681da177e4SLinus Torvalds 20691da177e4SLinus Torvalds 20701da177e4SLinus Torvalds /** 20711da177e4SLinus Torvalds * cpufreq_unregister_driver - unregister the current CPUFreq driver 20721da177e4SLinus Torvalds * 20731da177e4SLinus Torvalds * Unregister the current CPUFreq driver. Only call this if you have 20741da177e4SLinus Torvalds * the right to do so, i.e. if you have succeeded in initialising before! 20751da177e4SLinus Torvalds * Returns zero if successful, and -EINVAL if the cpufreq_driver is 20761da177e4SLinus Torvalds * currently not initialised. 20771da177e4SLinus Torvalds */ 2078221dee28SLinus Torvalds int cpufreq_unregister_driver(struct cpufreq_driver *driver) 20791da177e4SLinus Torvalds { 20801da177e4SLinus Torvalds unsigned long flags; 20815800043bSNathan Zimmer struct cpufreq_driver *old_driver; 20821da177e4SLinus Torvalds 20835800043bSNathan Zimmer rcu_read_lock(); 20845800043bSNathan Zimmer old_driver = rcu_access_pointer(cpufreq_driver); 20855800043bSNathan Zimmer if (!old_driver || (driver != old_driver)) { 20865800043bSNathan Zimmer rcu_read_unlock(); 20871da177e4SLinus Torvalds return -EINVAL; 20885800043bSNathan Zimmer } 20895800043bSNathan Zimmer rcu_read_unlock(); 20901da177e4SLinus Torvalds 20912d06d8c4SDominik Brodowski pr_debug("unregistering driver %s\n", driver->name); 20921da177e4SLinus Torvalds 20938a25a2fdSKay Sievers subsys_interface_unregister(&cpufreq_interface); 209465edc68cSChandra Seetharaman unregister_hotcpu_notifier(&cpufreq_cpu_notifier); 20951da177e4SLinus Torvalds 20960d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 20975800043bSNathan Zimmer rcu_assign_pointer(cpufreq_driver, NULL); 20980d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20995800043bSNathan Zimmer synchronize_rcu(); 21001da177e4SLinus Torvalds 21011da177e4SLinus Torvalds return 0; 21021da177e4SLinus Torvalds } 21031da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); 21045a01f2e8SVenkatesh Pallipadi 21055a01f2e8SVenkatesh Pallipadi static int __init cpufreq_core_init(void) 21065a01f2e8SVenkatesh Pallipadi { 21075a01f2e8SVenkatesh Pallipadi int cpu; 21085a01f2e8SVenkatesh Pallipadi 2109a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 2110a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 2111a7b422cdSKonrad Rzeszutek Wilk 21125a01f2e8SVenkatesh Pallipadi for_each_possible_cpu(cpu) { 2113f1625066STejun Heo per_cpu(cpufreq_policy_cpu, cpu) = -1; 21145a01f2e8SVenkatesh Pallipadi init_rwsem(&per_cpu(cpu_policy_rwsem, cpu)); 21155a01f2e8SVenkatesh Pallipadi } 21168aa84ad8SThomas Renninger 21178a25a2fdSKay Sievers cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj); 21188aa84ad8SThomas Renninger BUG_ON(!cpufreq_global_kobject); 2119e00e56dfSRafael J. Wysocki register_syscore_ops(&cpufreq_syscore_ops); 21208aa84ad8SThomas Renninger 21215a01f2e8SVenkatesh Pallipadi return 0; 21225a01f2e8SVenkatesh Pallipadi } 21235a01f2e8SVenkatesh Pallipadi core_initcall(cpufreq_core_init); 2124