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; 861fcf80582SViresh Kumar int ret = 0; 862fcf80582SViresh Kumar unsigned long flags; 863fcf80582SViresh Kumar 864fcf80582SViresh Kumar policy = cpufreq_cpu_get(sibling); 865fcf80582SViresh Kumar WARN_ON(!policy); 866fcf80582SViresh Kumar 867fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_STOP); 868fcf80582SViresh Kumar 8692eaa3e2dSViresh Kumar lock_policy_rwsem_write(sibling); 8702eaa3e2dSViresh Kumar 8710d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 8722eaa3e2dSViresh Kumar 873fcf80582SViresh Kumar cpumask_set_cpu(cpu, policy->cpus); 8742eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu; 875fcf80582SViresh Kumar per_cpu(cpufreq_cpu_data, cpu) = policy; 8760d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 877fcf80582SViresh Kumar 8782eaa3e2dSViresh Kumar unlock_policy_rwsem_write(sibling); 8792eaa3e2dSViresh Kumar 880fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_START); 881fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); 882fcf80582SViresh Kumar 883fcf80582SViresh Kumar ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); 884fcf80582SViresh Kumar if (ret) { 885fcf80582SViresh Kumar cpufreq_cpu_put(policy); 886fcf80582SViresh Kumar return ret; 887fcf80582SViresh Kumar } 888fcf80582SViresh Kumar 889fcf80582SViresh Kumar return 0; 890fcf80582SViresh Kumar } 891fcf80582SViresh Kumar #endif 8921da177e4SLinus Torvalds 8931da177e4SLinus Torvalds /** 8941da177e4SLinus Torvalds * cpufreq_add_dev - add a CPU device 8951da177e4SLinus Torvalds * 8961da177e4SLinus Torvalds * Adds the cpufreq interface for a CPU device. 8973f4a782bSMathieu Desnoyers * 8983f4a782bSMathieu Desnoyers * The Oracle says: try running cpufreq registration/unregistration concurrently 8993f4a782bSMathieu Desnoyers * with with cpu hotplugging and all hell will break loose. Tried to clean this 9003f4a782bSMathieu Desnoyers * mess up, but more thorough testing is needed. - Mathieu 9011da177e4SLinus Torvalds */ 9028a25a2fdSKay Sievers static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) 9031da177e4SLinus Torvalds { 904fcf80582SViresh Kumar unsigned int j, cpu = dev->id; 90565922465SViresh Kumar int ret = -ENOMEM; 9061da177e4SLinus Torvalds struct cpufreq_policy *policy; 9075800043bSNathan Zimmer struct cpufreq_driver *driver; 9085800043bSNathan Zimmer int (*init)(struct cpufreq_policy *policy); 9091da177e4SLinus Torvalds unsigned long flags; 91090e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 911fcf80582SViresh Kumar struct cpufreq_governor *gov; 91290e41bacSPrarit Bhargava int sibling; 91390e41bacSPrarit Bhargava #endif 9141da177e4SLinus Torvalds 915c32b6b8eSAshok Raj if (cpu_is_offline(cpu)) 916c32b6b8eSAshok Raj return 0; 917c32b6b8eSAshok Raj 9182d06d8c4SDominik Brodowski pr_debug("adding CPU %u\n", cpu); 9191da177e4SLinus Torvalds 9201da177e4SLinus Torvalds #ifdef CONFIG_SMP 9211da177e4SLinus Torvalds /* check whether a different CPU already registered this 9221da177e4SLinus Torvalds * CPU because it is in the same boat. */ 9231da177e4SLinus Torvalds policy = cpufreq_cpu_get(cpu); 9241da177e4SLinus Torvalds if (unlikely(policy)) { 9258ff69732SDave Jones cpufreq_cpu_put(policy); 9261da177e4SLinus Torvalds return 0; 9271da177e4SLinus Torvalds } 928fcf80582SViresh Kumar 929fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 930fcf80582SViresh Kumar /* Check if this cpu was hot-unplugged earlier and has siblings */ 9310d1857a1SNathan Zimmer read_lock_irqsave(&cpufreq_driver_lock, flags); 932fcf80582SViresh Kumar for_each_online_cpu(sibling) { 933fcf80582SViresh Kumar struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); 9342eaa3e2dSViresh Kumar if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { 9350d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 936fcf80582SViresh Kumar return cpufreq_add_policy_cpu(cpu, sibling, dev); 937fcf80582SViresh Kumar } 9382eaa3e2dSViresh Kumar } 9390d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 940fcf80582SViresh Kumar #endif 9411da177e4SLinus Torvalds #endif 9421da177e4SLinus Torvalds 9435800043bSNathan Zimmer rcu_read_lock(); 9445800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 9455800043bSNathan Zimmer if (!try_module_get(driver->owner)) { 9465800043bSNathan Zimmer rcu_read_unlock(); 9471da177e4SLinus Torvalds ret = -EINVAL; 9481da177e4SLinus Torvalds goto module_out; 9491da177e4SLinus Torvalds } 9505800043bSNathan Zimmer init = driver->init; 9515800043bSNathan Zimmer rcu_read_unlock(); 9521da177e4SLinus Torvalds 953e98df50cSDave Jones policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); 954059019a3SDave Jones if (!policy) 9551da177e4SLinus Torvalds goto nomem_out; 956059019a3SDave Jones 957059019a3SDave Jones if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) 9583f4a782bSMathieu Desnoyers goto err_free_policy; 959059019a3SDave Jones 960059019a3SDave Jones if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) 9613f4a782bSMathieu Desnoyers goto err_free_cpumask; 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds policy->cpu = cpu; 96465922465SViresh Kumar policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 965835481d9SRusty Russell cpumask_copy(policy->cpus, cpumask_of(cpu)); 9661da177e4SLinus Torvalds 9675a01f2e8SVenkatesh Pallipadi /* Initially set CPU itself as the policy_cpu */ 968f1625066STejun Heo per_cpu(cpufreq_policy_cpu, cpu) = cpu; 9695a01f2e8SVenkatesh Pallipadi 9701da177e4SLinus Torvalds init_completion(&policy->kobj_unregister); 97165f27f38SDavid Howells INIT_WORK(&policy->update, handle_update); 9721da177e4SLinus Torvalds 9731da177e4SLinus Torvalds /* call driver. From then on the cpufreq must be able 9741da177e4SLinus Torvalds * to accept all calls to ->verify and ->setpolicy for this CPU 9751da177e4SLinus Torvalds */ 9765800043bSNathan Zimmer ret = init(policy); 9771da177e4SLinus Torvalds if (ret) { 9782d06d8c4SDominik Brodowski pr_debug("initialization failed\n"); 9792eaa3e2dSViresh Kumar goto err_set_policy_cpu; 9801da177e4SLinus Torvalds } 981643ae6e8SViresh Kumar 982fcf80582SViresh Kumar /* related cpus should atleast have policy->cpus */ 983fcf80582SViresh Kumar cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); 984fcf80582SViresh Kumar 985643ae6e8SViresh Kumar /* 986643ae6e8SViresh Kumar * affected cpus must always be the one, which are online. We aren't 987643ae6e8SViresh Kumar * managing offline cpus here. 988643ae6e8SViresh Kumar */ 989643ae6e8SViresh Kumar cpumask_and(policy->cpus, policy->cpus, cpu_online_mask); 990643ae6e8SViresh Kumar 991187d9f4eSMike Chan policy->user_policy.min = policy->min; 992187d9f4eSMike Chan policy->user_policy.max = policy->max; 9931da177e4SLinus Torvalds 994a1531acdSThomas Renninger blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 995a1531acdSThomas Renninger CPUFREQ_START, policy); 996a1531acdSThomas Renninger 997fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 998fcf80582SViresh Kumar gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu)); 999fcf80582SViresh Kumar if (gov) { 1000fcf80582SViresh Kumar policy->governor = gov; 1001fcf80582SViresh Kumar pr_debug("Restoring governor %s for cpu %d\n", 1002fcf80582SViresh Kumar policy->governor->name, cpu); 10034bfa042cSThomas Renninger } 1004fcf80582SViresh Kumar #endif 10051da177e4SLinus Torvalds 10068a25a2fdSKay Sievers ret = cpufreq_add_dev_interface(cpu, policy, dev); 100719d6f7ecSDave Jones if (ret) 10080142f9dcSAhmed S. Darwish goto err_out_unregister; 10098ff69732SDave Jones 1010038c5b3eSGreg Kroah-Hartman kobject_uevent(&policy->kobj, KOBJ_ADD); 10115800043bSNathan Zimmer rcu_read_lock(); 10125800043bSNathan Zimmer module_put(rcu_dereference(cpufreq_driver)->owner); 10135800043bSNathan Zimmer rcu_read_unlock(); 10142d06d8c4SDominik Brodowski pr_debug("initialization complete\n"); 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds return 0; 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds err_out_unregister: 10190d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 1020835481d9SRusty Russell for_each_cpu(j, policy->cpus) 10217a6aedfaSMike Travis per_cpu(cpufreq_cpu_data, j) = NULL; 10220d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 10231da177e4SLinus Torvalds 1024c10997f6SGreg Kroah-Hartman kobject_put(&policy->kobj); 10251da177e4SLinus Torvalds wait_for_completion(&policy->kobj_unregister); 10261da177e4SLinus Torvalds 10272eaa3e2dSViresh Kumar err_set_policy_cpu: 10282eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = -1; 1029cad70a6aSXiaotian Feng free_cpumask_var(policy->related_cpus); 10303f4a782bSMathieu Desnoyers err_free_cpumask: 10313f4a782bSMathieu Desnoyers free_cpumask_var(policy->cpus); 10323f4a782bSMathieu Desnoyers err_free_policy: 10331da177e4SLinus Torvalds kfree(policy); 10341da177e4SLinus Torvalds nomem_out: 10355800043bSNathan Zimmer rcu_read_lock(); 10365800043bSNathan Zimmer module_put(rcu_dereference(cpufreq_driver)->owner); 10375800043bSNathan Zimmer rcu_read_unlock(); 10381da177e4SLinus Torvalds module_out: 10391da177e4SLinus Torvalds return ret; 10401da177e4SLinus Torvalds } 10411da177e4SLinus Torvalds 1042b8eed8afSViresh Kumar static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) 1043b8eed8afSViresh Kumar { 1044b8eed8afSViresh Kumar int j; 1045b8eed8afSViresh Kumar 1046b8eed8afSViresh Kumar policy->last_cpu = policy->cpu; 1047b8eed8afSViresh Kumar policy->cpu = cpu; 1048b8eed8afSViresh Kumar 10493361b7b1SViresh Kumar for_each_cpu(j, policy->cpus) 1050b8eed8afSViresh Kumar per_cpu(cpufreq_policy_cpu, j) = cpu; 1051b8eed8afSViresh Kumar 1052b8eed8afSViresh Kumar #ifdef CONFIG_CPU_FREQ_TABLE 1053b8eed8afSViresh Kumar cpufreq_frequency_table_update_policy_cpu(policy); 1054b8eed8afSViresh Kumar #endif 1055b8eed8afSViresh Kumar blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1056b8eed8afSViresh Kumar CPUFREQ_UPDATE_POLICY_CPU, policy); 1057b8eed8afSViresh Kumar } 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds /** 10605a01f2e8SVenkatesh Pallipadi * __cpufreq_remove_dev - remove a CPU device 10611da177e4SLinus Torvalds * 10621da177e4SLinus Torvalds * Removes the cpufreq interface for a CPU device. 10635a01f2e8SVenkatesh Pallipadi * Caller should already have policy_rwsem in write mode for this CPU. 10645a01f2e8SVenkatesh Pallipadi * This routine frees the rwsem before returning. 10651da177e4SLinus Torvalds */ 10668a25a2fdSKay Sievers static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) 10671da177e4SLinus Torvalds { 1068b8eed8afSViresh Kumar unsigned int cpu = dev->id, ret, cpus; 10691da177e4SLinus Torvalds unsigned long flags; 10701da177e4SLinus Torvalds struct cpufreq_policy *data; 10715800043bSNathan Zimmer struct cpufreq_driver *driver; 1072499bca9bSAmerigo Wang struct kobject *kobj; 1073499bca9bSAmerigo Wang struct completion *cmp; 10748a25a2fdSKay Sievers struct device *cpu_dev; 10755800043bSNathan Zimmer bool has_target; 10765800043bSNathan Zimmer int (*exit)(struct cpufreq_policy *policy); 10771da177e4SLinus Torvalds 1078b8eed8afSViresh Kumar pr_debug("%s: unregistering CPU %u\n", __func__, cpu); 10791da177e4SLinus Torvalds 10800d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 10811da177e4SLinus Torvalds 10821da177e4SLinus Torvalds data = per_cpu(cpufreq_cpu_data, cpu); 10837a6aedfaSMike Travis per_cpu(cpufreq_cpu_data, cpu) = NULL; 10841da177e4SLinus Torvalds 10850d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 10861da177e4SLinus Torvalds 10871da177e4SLinus Torvalds if (!data) { 1088b8eed8afSViresh Kumar pr_debug("%s: No cpu_data found\n", __func__); 10891da177e4SLinus Torvalds return -EINVAL; 10901da177e4SLinus Torvalds } 10911da177e4SLinus Torvalds 10925800043bSNathan Zimmer rcu_read_lock(); 10935800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 10945800043bSNathan Zimmer has_target = driver->target ? true : false; 10955800043bSNathan Zimmer exit = driver->exit; 10965800043bSNathan Zimmer if (has_target) 10971da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_STOP); 10985a01f2e8SVenkatesh Pallipadi 10991da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG_CPU 11005800043bSNathan Zimmer if (!driver->setpolicy) 1101fa69e33fSDirk Brandewie strncpy(per_cpu(cpufreq_cpu_governor, cpu), 1102fa69e33fSDirk Brandewie data->governor->name, CPUFREQ_NAME_LEN); 11031da177e4SLinus Torvalds #endif 11045800043bSNathan Zimmer rcu_read_unlock(); 11051da177e4SLinus Torvalds 11062eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1107b8eed8afSViresh Kumar cpus = cpumask_weight(data->cpus); 1108*e4969ebaSViresh Kumar 1109*e4969ebaSViresh Kumar if (cpus > 1) 1110b8eed8afSViresh Kumar cpumask_clear_cpu(cpu, data->cpus); 11112eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 11121da177e4SLinus Torvalds 111373bf0fc2SViresh Kumar if (cpu != data->cpu) { 111473bf0fc2SViresh Kumar sysfs_remove_link(&dev->kobj, "cpufreq"); 111573bf0fc2SViresh Kumar } else if (cpus > 1) { 1116b8eed8afSViresh Kumar /* first sibling now owns the new sysfs dir */ 1117b8eed8afSViresh Kumar cpu_dev = get_cpu_device(cpumask_first(data->cpus)); 1118b8eed8afSViresh Kumar sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); 1119b8eed8afSViresh Kumar ret = kobject_move(&data->kobj, &cpu_dev->kobj); 1120b8eed8afSViresh Kumar if (ret) { 1121b8eed8afSViresh Kumar pr_err("%s: Failed to move kobj: %d", __func__, ret); 11222eaa3e2dSViresh Kumar 11232eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1124b8eed8afSViresh Kumar cpumask_set_cpu(cpu, data->cpus); 11252eaa3e2dSViresh Kumar 11260d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 11272eaa3e2dSViresh Kumar per_cpu(cpufreq_cpu_data, cpu) = data; 11280d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 11292eaa3e2dSViresh Kumar 11302eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 11312eaa3e2dSViresh Kumar 1132b8eed8afSViresh Kumar ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj, 1133b8eed8afSViresh Kumar "cpufreq"); 1134b8eed8afSViresh Kumar return -EINVAL; 11351da177e4SLinus Torvalds } 1136b8eed8afSViresh Kumar 11372eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1138b8eed8afSViresh Kumar update_policy_cpu(data, cpu_dev->id); 11392eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 1140b8eed8afSViresh Kumar pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", 1141b8eed8afSViresh Kumar __func__, cpu_dev->id, cpu); 11421da177e4SLinus Torvalds } 1143b8eed8afSViresh Kumar 1144b8eed8afSViresh Kumar pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); 1145b8eed8afSViresh Kumar cpufreq_cpu_put(data); 11465a01f2e8SVenkatesh Pallipadi 1147b8eed8afSViresh Kumar /* If cpu is last user of policy, free policy */ 1148b8eed8afSViresh Kumar if (cpus == 1) { 11497bd353a9SViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); 11507bd353a9SViresh Kumar 11512eaa3e2dSViresh Kumar lock_policy_rwsem_read(cpu); 1152499bca9bSAmerigo Wang kobj = &data->kobj; 1153499bca9bSAmerigo Wang cmp = &data->kobj_unregister; 11542eaa3e2dSViresh Kumar unlock_policy_rwsem_read(cpu); 1155499bca9bSAmerigo Wang kobject_put(kobj); 11561da177e4SLinus Torvalds 11571da177e4SLinus Torvalds /* we need to make sure that the underlying kobj is actually 11581da177e4SLinus Torvalds * not referenced anymore by anybody before we proceed with 11591da177e4SLinus Torvalds * unloading. 11601da177e4SLinus Torvalds */ 11612d06d8c4SDominik Brodowski pr_debug("waiting for dropping of refcount\n"); 1162499bca9bSAmerigo Wang wait_for_completion(cmp); 11632d06d8c4SDominik Brodowski pr_debug("wait complete\n"); 11641da177e4SLinus Torvalds 11655800043bSNathan Zimmer if (exit) 11665800043bSNathan Zimmer exit(data); 116727ecddc2SJacob Shin 1168835481d9SRusty Russell free_cpumask_var(data->related_cpus); 1169835481d9SRusty Russell free_cpumask_var(data->cpus); 11701da177e4SLinus Torvalds kfree(data); 11715800043bSNathan Zimmer } else if (has_target) { 1172b8eed8afSViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_START); 1173b8eed8afSViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); 1174b8eed8afSViresh Kumar } 11751da177e4SLinus Torvalds 11762eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = -1; 11771da177e4SLinus Torvalds return 0; 11781da177e4SLinus Torvalds } 11791da177e4SLinus Torvalds 11801da177e4SLinus Torvalds 11818a25a2fdSKay Sievers static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) 11825a01f2e8SVenkatesh Pallipadi { 11838a25a2fdSKay Sievers unsigned int cpu = dev->id; 11845a01f2e8SVenkatesh Pallipadi int retval; 1185ec28297aSVenki Pallipadi 1186ec28297aSVenki Pallipadi if (cpu_is_offline(cpu)) 1187ec28297aSVenki Pallipadi return 0; 1188ec28297aSVenki Pallipadi 11898a25a2fdSKay Sievers retval = __cpufreq_remove_dev(dev, sif); 11905a01f2e8SVenkatesh Pallipadi return retval; 11915a01f2e8SVenkatesh Pallipadi } 11925a01f2e8SVenkatesh Pallipadi 11935a01f2e8SVenkatesh Pallipadi 119465f27f38SDavid Howells static void handle_update(struct work_struct *work) 11951da177e4SLinus Torvalds { 119665f27f38SDavid Howells struct cpufreq_policy *policy = 119765f27f38SDavid Howells container_of(work, struct cpufreq_policy, update); 119865f27f38SDavid Howells unsigned int cpu = policy->cpu; 11992d06d8c4SDominik Brodowski pr_debug("handle_update for cpu %u called\n", cpu); 12001da177e4SLinus Torvalds cpufreq_update_policy(cpu); 12011da177e4SLinus Torvalds } 12021da177e4SLinus Torvalds 12031da177e4SLinus Torvalds /** 12041da177e4SLinus Torvalds * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble. 12051da177e4SLinus Torvalds * @cpu: cpu number 12061da177e4SLinus Torvalds * @old_freq: CPU frequency the kernel thinks the CPU runs at 12071da177e4SLinus Torvalds * @new_freq: CPU frequency the CPU actually runs at 12081da177e4SLinus Torvalds * 120929464f28SDave Jones * We adjust to current frequency first, and need to clean up later. 121029464f28SDave Jones * So either call to cpufreq_update_policy() or schedule handle_update()). 12111da177e4SLinus Torvalds */ 1212e08f5f5bSGautham R Shenoy static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, 1213e08f5f5bSGautham R Shenoy unsigned int new_freq) 12141da177e4SLinus Torvalds { 1215b43a7ffbSViresh Kumar struct cpufreq_policy *policy; 12161da177e4SLinus Torvalds struct cpufreq_freqs freqs; 1217b43a7ffbSViresh Kumar unsigned long flags; 1218b43a7ffbSViresh Kumar 12191da177e4SLinus Torvalds 12202d06d8c4SDominik Brodowski pr_debug("Warning: CPU frequency out of sync: cpufreq and timing " 12211da177e4SLinus Torvalds "core thinks of %u, is %u kHz.\n", old_freq, new_freq); 12221da177e4SLinus Torvalds 12231da177e4SLinus Torvalds freqs.old = old_freq; 12241da177e4SLinus Torvalds freqs.new = new_freq; 1225b43a7ffbSViresh Kumar 1226b43a7ffbSViresh Kumar read_lock_irqsave(&cpufreq_driver_lock, flags); 1227b43a7ffbSViresh Kumar policy = per_cpu(cpufreq_cpu_data, cpu); 1228b43a7ffbSViresh Kumar read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1229b43a7ffbSViresh Kumar 1230b43a7ffbSViresh Kumar cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); 1231b43a7ffbSViresh Kumar cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); 12321da177e4SLinus Torvalds } 12331da177e4SLinus Torvalds 12341da177e4SLinus Torvalds 12351da177e4SLinus Torvalds /** 12364ab70df4SDhaval Giani * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur 123795235ca2SVenkatesh Pallipadi * @cpu: CPU number 123895235ca2SVenkatesh Pallipadi * 123995235ca2SVenkatesh Pallipadi * This is the last known freq, without actually getting it from the driver. 124095235ca2SVenkatesh Pallipadi * Return value will be same as what is shown in scaling_cur_freq in sysfs. 124195235ca2SVenkatesh Pallipadi */ 124295235ca2SVenkatesh Pallipadi unsigned int cpufreq_quick_get(unsigned int cpu) 124395235ca2SVenkatesh Pallipadi { 12449e21ba8bSDirk Brandewie struct cpufreq_policy *policy; 12455800043bSNathan Zimmer struct cpufreq_driver *driver; 12465800043bSNathan Zimmer unsigned int (*get)(unsigned int cpu); 1247e08f5f5bSGautham R Shenoy unsigned int ret_freq = 0; 124895235ca2SVenkatesh Pallipadi 12495800043bSNathan Zimmer rcu_read_lock(); 12505800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 12515800043bSNathan Zimmer if (driver && driver->setpolicy && driver->get) { 12525800043bSNathan Zimmer get = driver->get; 12535800043bSNathan Zimmer rcu_read_unlock(); 12545800043bSNathan Zimmer return get(cpu); 12555800043bSNathan Zimmer } 12565800043bSNathan Zimmer rcu_read_unlock(); 12579e21ba8bSDirk Brandewie 12589e21ba8bSDirk Brandewie policy = cpufreq_cpu_get(cpu); 125995235ca2SVenkatesh Pallipadi if (policy) { 1260e08f5f5bSGautham R Shenoy ret_freq = policy->cur; 126195235ca2SVenkatesh Pallipadi cpufreq_cpu_put(policy); 126295235ca2SVenkatesh Pallipadi } 126395235ca2SVenkatesh Pallipadi 12644d34a67dSDave Jones return ret_freq; 126595235ca2SVenkatesh Pallipadi } 126695235ca2SVenkatesh Pallipadi EXPORT_SYMBOL(cpufreq_quick_get); 126795235ca2SVenkatesh Pallipadi 12683d737108SJesse Barnes /** 12693d737108SJesse Barnes * cpufreq_quick_get_max - get the max reported CPU frequency for this CPU 12703d737108SJesse Barnes * @cpu: CPU number 12713d737108SJesse Barnes * 12723d737108SJesse Barnes * Just return the max possible frequency for a given CPU. 12733d737108SJesse Barnes */ 12743d737108SJesse Barnes unsigned int cpufreq_quick_get_max(unsigned int cpu) 12753d737108SJesse Barnes { 12763d737108SJesse Barnes struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 12773d737108SJesse Barnes unsigned int ret_freq = 0; 12783d737108SJesse Barnes 12793d737108SJesse Barnes if (policy) { 12803d737108SJesse Barnes ret_freq = policy->max; 12813d737108SJesse Barnes cpufreq_cpu_put(policy); 12823d737108SJesse Barnes } 12833d737108SJesse Barnes 12843d737108SJesse Barnes return ret_freq; 12853d737108SJesse Barnes } 12863d737108SJesse Barnes EXPORT_SYMBOL(cpufreq_quick_get_max); 12873d737108SJesse Barnes 128895235ca2SVenkatesh Pallipadi 12895a01f2e8SVenkatesh Pallipadi static unsigned int __cpufreq_get(unsigned int cpu) 12901da177e4SLinus Torvalds { 12917a6aedfaSMike Travis struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); 12925800043bSNathan Zimmer struct cpufreq_driver *driver; 12935800043bSNathan Zimmer unsigned int (*get)(unsigned int cpu); 1294e08f5f5bSGautham R Shenoy unsigned int ret_freq = 0; 12955800043bSNathan Zimmer u8 flags; 12961da177e4SLinus Torvalds 12975800043bSNathan Zimmer 12985800043bSNathan Zimmer rcu_read_lock(); 12995800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 13005800043bSNathan Zimmer if (!driver->get) { 13015800043bSNathan Zimmer rcu_read_unlock(); 13024d34a67dSDave Jones return ret_freq; 13035800043bSNathan Zimmer } 13045800043bSNathan Zimmer flags = driver->flags; 13055800043bSNathan Zimmer get = driver->get; 13065800043bSNathan Zimmer rcu_read_unlock(); 13071da177e4SLinus Torvalds 13085800043bSNathan Zimmer ret_freq = get(cpu); 13091da177e4SLinus Torvalds 1310e08f5f5bSGautham R Shenoy if (ret_freq && policy->cur && 13115800043bSNathan Zimmer !(flags & CPUFREQ_CONST_LOOPS)) { 1312e08f5f5bSGautham R Shenoy /* verify no discrepancy between actual and 1313e08f5f5bSGautham R Shenoy saved value exists */ 1314e08f5f5bSGautham R Shenoy if (unlikely(ret_freq != policy->cur)) { 1315e08f5f5bSGautham R Shenoy cpufreq_out_of_sync(cpu, policy->cur, ret_freq); 13161da177e4SLinus Torvalds schedule_work(&policy->update); 13171da177e4SLinus Torvalds } 13181da177e4SLinus Torvalds } 13191da177e4SLinus Torvalds 13204d34a67dSDave Jones return ret_freq; 13215a01f2e8SVenkatesh Pallipadi } 13221da177e4SLinus Torvalds 13235a01f2e8SVenkatesh Pallipadi /** 13245a01f2e8SVenkatesh Pallipadi * cpufreq_get - get the current CPU frequency (in kHz) 13255a01f2e8SVenkatesh Pallipadi * @cpu: CPU number 13265a01f2e8SVenkatesh Pallipadi * 13275a01f2e8SVenkatesh Pallipadi * Get the CPU current (static) CPU frequency 13285a01f2e8SVenkatesh Pallipadi */ 13295a01f2e8SVenkatesh Pallipadi unsigned int cpufreq_get(unsigned int cpu) 13305a01f2e8SVenkatesh Pallipadi { 13315a01f2e8SVenkatesh Pallipadi unsigned int ret_freq = 0; 13325a01f2e8SVenkatesh Pallipadi struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 13335a01f2e8SVenkatesh Pallipadi 13345a01f2e8SVenkatesh Pallipadi if (!policy) 13355a01f2e8SVenkatesh Pallipadi goto out; 13365a01f2e8SVenkatesh Pallipadi 13375a01f2e8SVenkatesh Pallipadi if (unlikely(lock_policy_rwsem_read(cpu))) 13385a01f2e8SVenkatesh Pallipadi goto out_policy; 13395a01f2e8SVenkatesh Pallipadi 13405a01f2e8SVenkatesh Pallipadi ret_freq = __cpufreq_get(cpu); 13415a01f2e8SVenkatesh Pallipadi 13425a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_read(cpu); 13435a01f2e8SVenkatesh Pallipadi 13445a01f2e8SVenkatesh Pallipadi out_policy: 13451da177e4SLinus Torvalds cpufreq_cpu_put(policy); 13465a01f2e8SVenkatesh Pallipadi out: 13474d34a67dSDave Jones return ret_freq; 13481da177e4SLinus Torvalds } 13491da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_get); 13501da177e4SLinus Torvalds 13518a25a2fdSKay Sievers static struct subsys_interface cpufreq_interface = { 13528a25a2fdSKay Sievers .name = "cpufreq", 13538a25a2fdSKay Sievers .subsys = &cpu_subsys, 13548a25a2fdSKay Sievers .add_dev = cpufreq_add_dev, 13558a25a2fdSKay Sievers .remove_dev = cpufreq_remove_dev, 1356e00e56dfSRafael J. Wysocki }; 1357e00e56dfSRafael J. Wysocki 13581da177e4SLinus Torvalds 13591da177e4SLinus Torvalds /** 1360e00e56dfSRafael J. Wysocki * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. 1361e00e56dfSRafael J. Wysocki * 1362e00e56dfSRafael J. Wysocki * This function is only executed for the boot processor. The other CPUs 1363e00e56dfSRafael J. Wysocki * have been put offline by means of CPU hotplug. 136442d4dc3fSBenjamin Herrenschmidt */ 1365e00e56dfSRafael J. Wysocki static int cpufreq_bp_suspend(void) 136642d4dc3fSBenjamin Herrenschmidt { 13675800043bSNathan Zimmer int (*suspend)(struct cpufreq_policy *policy); 1368e08f5f5bSGautham R Shenoy int ret = 0; 13694bc5d341SDave Jones 1370e00e56dfSRafael J. Wysocki int cpu = smp_processor_id(); 137142d4dc3fSBenjamin Herrenschmidt struct cpufreq_policy *cpu_policy; 137242d4dc3fSBenjamin Herrenschmidt 13732d06d8c4SDominik Brodowski pr_debug("suspending cpu %u\n", cpu); 137442d4dc3fSBenjamin Herrenschmidt 1375e00e56dfSRafael J. Wysocki /* If there's no policy for the boot CPU, we have nothing to do. */ 137642d4dc3fSBenjamin Herrenschmidt cpu_policy = cpufreq_cpu_get(cpu); 137742d4dc3fSBenjamin Herrenschmidt if (!cpu_policy) 1378e00e56dfSRafael J. Wysocki return 0; 137942d4dc3fSBenjamin Herrenschmidt 13805800043bSNathan Zimmer rcu_read_lock(); 13815800043bSNathan Zimmer suspend = rcu_dereference(cpufreq_driver)->suspend; 13825800043bSNathan Zimmer rcu_read_unlock(); 13835800043bSNathan Zimmer if (suspend) { 13845800043bSNathan Zimmer ret = suspend(cpu_policy); 1385ce6c3997SDominik Brodowski if (ret) 138642d4dc3fSBenjamin Herrenschmidt printk(KERN_ERR "cpufreq: suspend failed in ->suspend " 138742d4dc3fSBenjamin Herrenschmidt "step on CPU %u\n", cpu_policy->cpu); 138842d4dc3fSBenjamin Herrenschmidt } 138942d4dc3fSBenjamin Herrenschmidt 139042d4dc3fSBenjamin Herrenschmidt cpufreq_cpu_put(cpu_policy); 1391c9060494SDave Jones return ret; 139242d4dc3fSBenjamin Herrenschmidt } 139342d4dc3fSBenjamin Herrenschmidt 139442d4dc3fSBenjamin Herrenschmidt /** 1395e00e56dfSRafael J. Wysocki * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU. 13961da177e4SLinus Torvalds * 13971da177e4SLinus Torvalds * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) 1398ce6c3997SDominik Brodowski * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are 1399ce6c3997SDominik Brodowski * restored. It will verify that the current freq is in sync with 1400ce6c3997SDominik Brodowski * what we believe it to be. This is a bit later than when it 1401ce6c3997SDominik Brodowski * should be, but nonethteless it's better than calling 1402ce6c3997SDominik Brodowski * cpufreq_driver->get() here which might re-enable interrupts... 1403e00e56dfSRafael J. Wysocki * 1404e00e56dfSRafael J. Wysocki * This function is only executed for the boot CPU. The other CPUs have not 1405e00e56dfSRafael J. Wysocki * been turned on yet. 14061da177e4SLinus Torvalds */ 1407e00e56dfSRafael J. Wysocki static void cpufreq_bp_resume(void) 14081da177e4SLinus Torvalds { 1409e08f5f5bSGautham R Shenoy int ret = 0; 14105800043bSNathan Zimmer int (*resume)(struct cpufreq_policy *policy); 14114bc5d341SDave Jones 1412e00e56dfSRafael J. Wysocki int cpu = smp_processor_id(); 14131da177e4SLinus Torvalds struct cpufreq_policy *cpu_policy; 14141da177e4SLinus Torvalds 14152d06d8c4SDominik Brodowski pr_debug("resuming cpu %u\n", cpu); 14161da177e4SLinus Torvalds 1417e00e56dfSRafael J. Wysocki /* If there's no policy for the boot CPU, we have nothing to do. */ 14181da177e4SLinus Torvalds cpu_policy = cpufreq_cpu_get(cpu); 14191da177e4SLinus Torvalds if (!cpu_policy) 1420e00e56dfSRafael J. Wysocki return; 14211da177e4SLinus Torvalds 14225800043bSNathan Zimmer rcu_read_lock(); 14235800043bSNathan Zimmer resume = rcu_dereference(cpufreq_driver)->resume; 14245800043bSNathan Zimmer rcu_read_unlock(); 14255800043bSNathan Zimmer 14265800043bSNathan Zimmer if (resume) { 14275800043bSNathan Zimmer ret = resume(cpu_policy); 14281da177e4SLinus Torvalds if (ret) { 14291da177e4SLinus Torvalds printk(KERN_ERR "cpufreq: resume failed in ->resume " 14301da177e4SLinus Torvalds "step on CPU %u\n", cpu_policy->cpu); 1431c9060494SDave Jones goto fail; 14321da177e4SLinus Torvalds } 14331da177e4SLinus Torvalds } 14341da177e4SLinus Torvalds 14351da177e4SLinus Torvalds schedule_work(&cpu_policy->update); 1436ce6c3997SDominik Brodowski 1437c9060494SDave Jones fail: 14381da177e4SLinus Torvalds cpufreq_cpu_put(cpu_policy); 14391da177e4SLinus Torvalds } 14401da177e4SLinus Torvalds 1441e00e56dfSRafael J. Wysocki static struct syscore_ops cpufreq_syscore_ops = { 1442e00e56dfSRafael J. Wysocki .suspend = cpufreq_bp_suspend, 1443e00e56dfSRafael J. Wysocki .resume = cpufreq_bp_resume, 14441da177e4SLinus Torvalds }; 14451da177e4SLinus Torvalds 14469d95046eSBorislav Petkov /** 14479d95046eSBorislav Petkov * cpufreq_get_current_driver - return current driver's name 14489d95046eSBorislav Petkov * 14499d95046eSBorislav Petkov * Return the name string of the currently loaded cpufreq driver 14509d95046eSBorislav Petkov * or NULL, if none. 14519d95046eSBorislav Petkov */ 14529d95046eSBorislav Petkov const char *cpufreq_get_current_driver(void) 14539d95046eSBorislav Petkov { 14545800043bSNathan Zimmer struct cpufreq_driver *driver; 14555800043bSNathan Zimmer const char *name = NULL; 14565800043bSNathan Zimmer rcu_read_lock(); 14575800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 14585800043bSNathan Zimmer if (driver) 14595800043bSNathan Zimmer name = driver->name; 14605800043bSNathan Zimmer rcu_read_unlock(); 14615800043bSNathan Zimmer return name; 14629d95046eSBorislav Petkov } 14639d95046eSBorislav Petkov EXPORT_SYMBOL_GPL(cpufreq_get_current_driver); 14641da177e4SLinus Torvalds 14651da177e4SLinus Torvalds /********************************************************************* 14661da177e4SLinus Torvalds * NOTIFIER LISTS INTERFACE * 14671da177e4SLinus Torvalds *********************************************************************/ 14681da177e4SLinus Torvalds 14691da177e4SLinus Torvalds /** 14701da177e4SLinus Torvalds * cpufreq_register_notifier - register a driver with cpufreq 14711da177e4SLinus Torvalds * @nb: notifier function to register 14721da177e4SLinus Torvalds * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER 14731da177e4SLinus Torvalds * 14741da177e4SLinus Torvalds * Add a driver to one of two lists: either a list of drivers that 14751da177e4SLinus Torvalds * are notified about clock rate changes (once before and once after 14761da177e4SLinus Torvalds * the transition), or a list of drivers that are notified about 14771da177e4SLinus Torvalds * changes in cpufreq policy. 14781da177e4SLinus Torvalds * 14791da177e4SLinus Torvalds * This function may sleep, and has the same return conditions as 1480e041c683SAlan Stern * blocking_notifier_chain_register. 14811da177e4SLinus Torvalds */ 14821da177e4SLinus Torvalds int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) 14831da177e4SLinus Torvalds { 14841da177e4SLinus Torvalds int ret; 14851da177e4SLinus Torvalds 1486d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1487d5aaffa9SDirk Brandewie return -EINVAL; 1488d5aaffa9SDirk Brandewie 148974212ca4SCesar Eduardo Barros WARN_ON(!init_cpufreq_transition_notifier_list_called); 149074212ca4SCesar Eduardo Barros 14911da177e4SLinus Torvalds switch (list) { 14921da177e4SLinus Torvalds case CPUFREQ_TRANSITION_NOTIFIER: 1493b4dfdbb3SAlan Stern ret = srcu_notifier_chain_register( 1494e041c683SAlan Stern &cpufreq_transition_notifier_list, nb); 14951da177e4SLinus Torvalds break; 14961da177e4SLinus Torvalds case CPUFREQ_POLICY_NOTIFIER: 1497e041c683SAlan Stern ret = blocking_notifier_chain_register( 1498e041c683SAlan Stern &cpufreq_policy_notifier_list, nb); 14991da177e4SLinus Torvalds break; 15001da177e4SLinus Torvalds default: 15011da177e4SLinus Torvalds ret = -EINVAL; 15021da177e4SLinus Torvalds } 15031da177e4SLinus Torvalds 15041da177e4SLinus Torvalds return ret; 15051da177e4SLinus Torvalds } 15061da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_register_notifier); 15071da177e4SLinus Torvalds 15081da177e4SLinus Torvalds 15091da177e4SLinus Torvalds /** 15101da177e4SLinus Torvalds * cpufreq_unregister_notifier - unregister a driver with cpufreq 15111da177e4SLinus Torvalds * @nb: notifier block to be unregistered 15121da177e4SLinus Torvalds * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER 15131da177e4SLinus Torvalds * 15141da177e4SLinus Torvalds * Remove a driver from the CPU frequency notifier list. 15151da177e4SLinus Torvalds * 15161da177e4SLinus Torvalds * This function may sleep, and has the same return conditions as 1517e041c683SAlan Stern * blocking_notifier_chain_unregister. 15181da177e4SLinus Torvalds */ 15191da177e4SLinus Torvalds int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) 15201da177e4SLinus Torvalds { 15211da177e4SLinus Torvalds int ret; 15221da177e4SLinus Torvalds 1523d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1524d5aaffa9SDirk Brandewie return -EINVAL; 1525d5aaffa9SDirk Brandewie 15261da177e4SLinus Torvalds switch (list) { 15271da177e4SLinus Torvalds case CPUFREQ_TRANSITION_NOTIFIER: 1528b4dfdbb3SAlan Stern ret = srcu_notifier_chain_unregister( 1529e041c683SAlan Stern &cpufreq_transition_notifier_list, nb); 15301da177e4SLinus Torvalds break; 15311da177e4SLinus Torvalds case CPUFREQ_POLICY_NOTIFIER: 1532e041c683SAlan Stern ret = blocking_notifier_chain_unregister( 1533e041c683SAlan Stern &cpufreq_policy_notifier_list, nb); 15341da177e4SLinus Torvalds break; 15351da177e4SLinus Torvalds default: 15361da177e4SLinus Torvalds ret = -EINVAL; 15371da177e4SLinus Torvalds } 15381da177e4SLinus Torvalds 15391da177e4SLinus Torvalds return ret; 15401da177e4SLinus Torvalds } 15411da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_unregister_notifier); 15421da177e4SLinus Torvalds 15431da177e4SLinus Torvalds 15441da177e4SLinus Torvalds /********************************************************************* 15451da177e4SLinus Torvalds * GOVERNORS * 15461da177e4SLinus Torvalds *********************************************************************/ 15471da177e4SLinus Torvalds 15481da177e4SLinus Torvalds 15491da177e4SLinus Torvalds int __cpufreq_driver_target(struct cpufreq_policy *policy, 15501da177e4SLinus Torvalds unsigned int target_freq, 15511da177e4SLinus Torvalds unsigned int relation) 15521da177e4SLinus Torvalds { 15531da177e4SLinus Torvalds int retval = -EINVAL; 15547249924eSViresh Kumar unsigned int old_target_freq = target_freq; 15555800043bSNathan Zimmer int (*target)(struct cpufreq_policy *policy, 15565800043bSNathan Zimmer unsigned int target_freq, 15575800043bSNathan Zimmer unsigned int relation); 1558c32b6b8eSAshok Raj 1559a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1560a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 1561a7b422cdSKonrad Rzeszutek Wilk 15627249924eSViresh Kumar /* Make sure that target_freq is within supported range */ 15637249924eSViresh Kumar if (target_freq > policy->max) 15647249924eSViresh Kumar target_freq = policy->max; 15657249924eSViresh Kumar if (target_freq < policy->min) 15667249924eSViresh Kumar target_freq = policy->min; 15677249924eSViresh Kumar 15687249924eSViresh Kumar pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", 15697249924eSViresh Kumar policy->cpu, target_freq, relation, old_target_freq); 15705a1c0228SViresh Kumar 15715a1c0228SViresh Kumar if (target_freq == policy->cur) 15725a1c0228SViresh Kumar return 0; 15735a1c0228SViresh Kumar 15745800043bSNathan Zimmer rcu_read_lock(); 15755800043bSNathan Zimmer target = rcu_dereference(cpufreq_driver)->target; 15765800043bSNathan Zimmer rcu_read_unlock(); 15775800043bSNathan Zimmer if (target) 15785800043bSNathan Zimmer retval = target(policy, target_freq, relation); 157990d45d17SAshok Raj 15801da177e4SLinus Torvalds return retval; 15811da177e4SLinus Torvalds } 15821da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(__cpufreq_driver_target); 15831da177e4SLinus Torvalds 15841da177e4SLinus Torvalds int cpufreq_driver_target(struct cpufreq_policy *policy, 15851da177e4SLinus Torvalds unsigned int target_freq, 15861da177e4SLinus Torvalds unsigned int relation) 15871da177e4SLinus Torvalds { 1588f1829e4aSJulia Lawall int ret = -EINVAL; 15891da177e4SLinus Torvalds 15901da177e4SLinus Torvalds policy = cpufreq_cpu_get(policy->cpu); 15911da177e4SLinus Torvalds if (!policy) 1592f1829e4aSJulia Lawall goto no_policy; 15931da177e4SLinus Torvalds 15945a01f2e8SVenkatesh Pallipadi if (unlikely(lock_policy_rwsem_write(policy->cpu))) 1595f1829e4aSJulia Lawall goto fail; 15961da177e4SLinus Torvalds 15971da177e4SLinus Torvalds ret = __cpufreq_driver_target(policy, target_freq, relation); 15981da177e4SLinus Torvalds 15995a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(policy->cpu); 16001da177e4SLinus Torvalds 1601f1829e4aSJulia Lawall fail: 16021da177e4SLinus Torvalds cpufreq_cpu_put(policy); 1603f1829e4aSJulia Lawall no_policy: 16041da177e4SLinus Torvalds return ret; 16051da177e4SLinus Torvalds } 16061da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_driver_target); 16071da177e4SLinus Torvalds 1608bf0b90e3Svenkatesh.pallipadi@intel.com int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) 1609dfde5d62SVenkatesh Pallipadi { 1610dfde5d62SVenkatesh Pallipadi int ret = 0; 16115800043bSNathan Zimmer unsigned int (*getavg)(struct cpufreq_policy *policy, 16125800043bSNathan Zimmer unsigned int cpu); 1613dfde5d62SVenkatesh Pallipadi 1614d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1615d5aaffa9SDirk Brandewie return ret; 1616d5aaffa9SDirk Brandewie 16175800043bSNathan Zimmer rcu_read_lock(); 16185800043bSNathan Zimmer getavg = rcu_dereference(cpufreq_driver)->getavg; 16195800043bSNathan Zimmer rcu_read_unlock(); 16205800043bSNathan Zimmer 16215800043bSNathan Zimmer if (!getavg) 16220676f7f2SViresh Kumar return 0; 16230676f7f2SViresh Kumar 1624dfde5d62SVenkatesh Pallipadi policy = cpufreq_cpu_get(policy->cpu); 1625dfde5d62SVenkatesh Pallipadi if (!policy) 1626dfde5d62SVenkatesh Pallipadi return -EINVAL; 1627dfde5d62SVenkatesh Pallipadi 16285800043bSNathan Zimmer ret = getavg(policy, cpu); 1629dfde5d62SVenkatesh Pallipadi 1630dfde5d62SVenkatesh Pallipadi cpufreq_cpu_put(policy); 1631dfde5d62SVenkatesh Pallipadi return ret; 1632dfde5d62SVenkatesh Pallipadi } 16335a01f2e8SVenkatesh Pallipadi EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg); 1634dfde5d62SVenkatesh Pallipadi 1635153d7f3fSArjan van de Ven /* 1636153d7f3fSArjan van de Ven * when "event" is CPUFREQ_GOV_LIMITS 1637153d7f3fSArjan van de Ven */ 16381da177e4SLinus Torvalds 1639e08f5f5bSGautham R Shenoy static int __cpufreq_governor(struct cpufreq_policy *policy, 1640e08f5f5bSGautham R Shenoy unsigned int event) 16411da177e4SLinus Torvalds { 1642cc993cabSDave Jones int ret; 16436afde10cSThomas Renninger 16446afde10cSThomas Renninger /* Only must be defined when default governor is known to have latency 16456afde10cSThomas Renninger restrictions, like e.g. conservative or ondemand. 16466afde10cSThomas Renninger That this is the case is already ensured in Kconfig 16476afde10cSThomas Renninger */ 16486afde10cSThomas Renninger #ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE 16496afde10cSThomas Renninger struct cpufreq_governor *gov = &cpufreq_gov_performance; 16506afde10cSThomas Renninger #else 16516afde10cSThomas Renninger struct cpufreq_governor *gov = NULL; 16526afde10cSThomas Renninger #endif 16531c256245SThomas Renninger 16541c256245SThomas Renninger if (policy->governor->max_transition_latency && 16551c256245SThomas Renninger policy->cpuinfo.transition_latency > 16561c256245SThomas Renninger policy->governor->max_transition_latency) { 16576afde10cSThomas Renninger if (!gov) 16586afde10cSThomas Renninger return -EINVAL; 16596afde10cSThomas Renninger else { 16601c256245SThomas Renninger printk(KERN_WARNING "%s governor failed, too long" 16611c256245SThomas Renninger " transition latency of HW, fallback" 16621c256245SThomas Renninger " to %s governor\n", 16631c256245SThomas Renninger policy->governor->name, 16641c256245SThomas Renninger gov->name); 16651c256245SThomas Renninger policy->governor = gov; 16661c256245SThomas Renninger } 16676afde10cSThomas Renninger } 16681da177e4SLinus Torvalds 16691da177e4SLinus Torvalds if (!try_module_get(policy->governor->owner)) 16701da177e4SLinus Torvalds return -EINVAL; 16711da177e4SLinus Torvalds 16722d06d8c4SDominik Brodowski pr_debug("__cpufreq_governor for CPU %u, event %u\n", 1673e08f5f5bSGautham R Shenoy policy->cpu, event); 16741da177e4SLinus Torvalds ret = policy->governor->governor(policy, event); 16751da177e4SLinus Torvalds 16764d5dcc42SViresh Kumar if (!ret) { 16774d5dcc42SViresh Kumar if (event == CPUFREQ_GOV_POLICY_INIT) 16788e53695fSViresh Kumar policy->governor->initialized++; 16794d5dcc42SViresh Kumar else if (event == CPUFREQ_GOV_POLICY_EXIT) 16808e53695fSViresh Kumar policy->governor->initialized--; 16814d5dcc42SViresh Kumar } 1682b394058fSViresh Kumar 1683e08f5f5bSGautham R Shenoy /* we keep one module reference alive for 1684e08f5f5bSGautham R Shenoy each CPU governed by this CPU */ 16851da177e4SLinus Torvalds if ((event != CPUFREQ_GOV_START) || ret) 16861da177e4SLinus Torvalds module_put(policy->governor->owner); 16871da177e4SLinus Torvalds if ((event == CPUFREQ_GOV_STOP) && !ret) 16881da177e4SLinus Torvalds module_put(policy->governor->owner); 16891da177e4SLinus Torvalds 16901da177e4SLinus Torvalds return ret; 16911da177e4SLinus Torvalds } 16921da177e4SLinus Torvalds 16931da177e4SLinus Torvalds 16941da177e4SLinus Torvalds int cpufreq_register_governor(struct cpufreq_governor *governor) 16951da177e4SLinus Torvalds { 16963bcb09a3SJeremy Fitzhardinge int err; 16971da177e4SLinus Torvalds 16981da177e4SLinus Torvalds if (!governor) 16991da177e4SLinus Torvalds return -EINVAL; 17001da177e4SLinus Torvalds 1701a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1702a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 1703a7b422cdSKonrad Rzeszutek Wilk 17043fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 17051da177e4SLinus Torvalds 1706b394058fSViresh Kumar governor->initialized = 0; 17073bcb09a3SJeremy Fitzhardinge err = -EBUSY; 17083bcb09a3SJeremy Fitzhardinge if (__find_governor(governor->name) == NULL) { 17093bcb09a3SJeremy Fitzhardinge err = 0; 17101da177e4SLinus Torvalds list_add(&governor->governor_list, &cpufreq_governor_list); 17113bcb09a3SJeremy Fitzhardinge } 17121da177e4SLinus Torvalds 17133fc54d37Sakpm@osdl.org mutex_unlock(&cpufreq_governor_mutex); 17143bcb09a3SJeremy Fitzhardinge return err; 17151da177e4SLinus Torvalds } 17161da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_register_governor); 17171da177e4SLinus Torvalds 17181da177e4SLinus Torvalds 17191da177e4SLinus Torvalds void cpufreq_unregister_governor(struct cpufreq_governor *governor) 17201da177e4SLinus Torvalds { 172190e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 172290e41bacSPrarit Bhargava int cpu; 172390e41bacSPrarit Bhargava #endif 172490e41bacSPrarit Bhargava 17251da177e4SLinus Torvalds if (!governor) 17261da177e4SLinus Torvalds return; 17271da177e4SLinus Torvalds 1728a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1729a7b422cdSKonrad Rzeszutek Wilk return; 1730a7b422cdSKonrad Rzeszutek Wilk 173190e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 173290e41bacSPrarit Bhargava for_each_present_cpu(cpu) { 173390e41bacSPrarit Bhargava if (cpu_online(cpu)) 173490e41bacSPrarit Bhargava continue; 173590e41bacSPrarit Bhargava if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name)) 173690e41bacSPrarit Bhargava strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0"); 173790e41bacSPrarit Bhargava } 173890e41bacSPrarit Bhargava #endif 173990e41bacSPrarit Bhargava 17403fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 17411da177e4SLinus Torvalds list_del(&governor->governor_list); 17423fc54d37Sakpm@osdl.org mutex_unlock(&cpufreq_governor_mutex); 17431da177e4SLinus Torvalds return; 17441da177e4SLinus Torvalds } 17451da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_unregister_governor); 17461da177e4SLinus Torvalds 17471da177e4SLinus Torvalds 17481da177e4SLinus Torvalds 17491da177e4SLinus Torvalds /********************************************************************* 17501da177e4SLinus Torvalds * POLICY INTERFACE * 17511da177e4SLinus Torvalds *********************************************************************/ 17521da177e4SLinus Torvalds 17531da177e4SLinus Torvalds /** 17541da177e4SLinus Torvalds * cpufreq_get_policy - get the current cpufreq_policy 175529464f28SDave Jones * @policy: struct cpufreq_policy into which the current cpufreq_policy 175629464f28SDave Jones * is written 17571da177e4SLinus Torvalds * 17581da177e4SLinus Torvalds * Reads the current cpufreq policy. 17591da177e4SLinus Torvalds */ 17601da177e4SLinus Torvalds int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) 17611da177e4SLinus Torvalds { 17621da177e4SLinus Torvalds struct cpufreq_policy *cpu_policy; 17631da177e4SLinus Torvalds if (!policy) 17641da177e4SLinus Torvalds return -EINVAL; 17651da177e4SLinus Torvalds 17661da177e4SLinus Torvalds cpu_policy = cpufreq_cpu_get(cpu); 17671da177e4SLinus Torvalds if (!cpu_policy) 17681da177e4SLinus Torvalds return -EINVAL; 17691da177e4SLinus Torvalds 17701da177e4SLinus Torvalds memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy)); 17711da177e4SLinus Torvalds 17721da177e4SLinus Torvalds cpufreq_cpu_put(cpu_policy); 17731da177e4SLinus Torvalds return 0; 17741da177e4SLinus Torvalds } 17751da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_get_policy); 17761da177e4SLinus Torvalds 17771da177e4SLinus Torvalds 1778153d7f3fSArjan van de Ven /* 1779e08f5f5bSGautham R Shenoy * data : current policy. 1780e08f5f5bSGautham R Shenoy * policy : policy to be set. 1781153d7f3fSArjan van de Ven */ 1782e08f5f5bSGautham R Shenoy static int __cpufreq_set_policy(struct cpufreq_policy *data, 1783e08f5f5bSGautham R Shenoy struct cpufreq_policy *policy) 17841da177e4SLinus Torvalds { 17857bd353a9SViresh Kumar int ret = 0, failed = 1; 17865800043bSNathan Zimmer struct cpufreq_driver *driver; 17875800043bSNathan Zimmer int (*verify)(struct cpufreq_policy *policy); 17885800043bSNathan Zimmer int (*setpolicy)(struct cpufreq_policy *policy); 17891da177e4SLinus Torvalds 17902d06d8c4SDominik Brodowski pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, 17911da177e4SLinus Torvalds policy->min, policy->max); 17921da177e4SLinus Torvalds 1793e08f5f5bSGautham R Shenoy memcpy(&policy->cpuinfo, &data->cpuinfo, 1794e08f5f5bSGautham R Shenoy sizeof(struct cpufreq_cpuinfo)); 17951da177e4SLinus Torvalds 179653391fa2SYi Yang if (policy->min > data->max || policy->max < data->min) { 17979c9a43edSMattia Dongili ret = -EINVAL; 17989c9a43edSMattia Dongili goto error_out; 17999c9a43edSMattia Dongili } 18009c9a43edSMattia Dongili 18011da177e4SLinus Torvalds /* verify the cpu speed can be set within this limit */ 18025800043bSNathan Zimmer rcu_read_lock(); 18035800043bSNathan Zimmer driver = rcu_dereference(cpufreq_driver); 18045800043bSNathan Zimmer verify = driver->verify; 18055800043bSNathan Zimmer setpolicy = driver->setpolicy; 18065800043bSNathan Zimmer rcu_read_unlock(); 18075800043bSNathan Zimmer 18085800043bSNathan Zimmer ret = verify(policy); 18091da177e4SLinus Torvalds if (ret) 18101da177e4SLinus Torvalds goto error_out; 18111da177e4SLinus Torvalds 18121da177e4SLinus Torvalds /* adjust if necessary - all reasons */ 1813e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1814e041c683SAlan Stern CPUFREQ_ADJUST, policy); 18151da177e4SLinus Torvalds 18161da177e4SLinus Torvalds /* adjust if necessary - hardware incompatibility*/ 1817e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1818e041c683SAlan Stern CPUFREQ_INCOMPATIBLE, policy); 18191da177e4SLinus Torvalds 18201da177e4SLinus Torvalds /* verify the cpu speed can be set within this limit, 18211da177e4SLinus Torvalds which might be different to the first one */ 18225800043bSNathan Zimmer ret = verify(policy); 1823e041c683SAlan Stern if (ret) 18241da177e4SLinus Torvalds goto error_out; 18251da177e4SLinus Torvalds 18261da177e4SLinus Torvalds /* notification of the new policy */ 1827e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1828e041c683SAlan Stern CPUFREQ_NOTIFY, policy); 18291da177e4SLinus Torvalds 18301da177e4SLinus Torvalds data->min = policy->min; 18311da177e4SLinus Torvalds data->max = policy->max; 18321da177e4SLinus Torvalds 18332d06d8c4SDominik Brodowski pr_debug("new min and max freqs are %u - %u kHz\n", 1834e08f5f5bSGautham R Shenoy data->min, data->max); 18351da177e4SLinus Torvalds 18365800043bSNathan Zimmer if (setpolicy) { 18371da177e4SLinus Torvalds data->policy = policy->policy; 18382d06d8c4SDominik Brodowski pr_debug("setting range\n"); 18395800043bSNathan Zimmer ret = setpolicy(policy); 18401da177e4SLinus Torvalds } else { 18411da177e4SLinus Torvalds if (policy->governor != data->governor) { 18421da177e4SLinus Torvalds /* save old, working values */ 18431da177e4SLinus Torvalds struct cpufreq_governor *old_gov = data->governor; 18441da177e4SLinus Torvalds 18452d06d8c4SDominik Brodowski pr_debug("governor switch\n"); 18461da177e4SLinus Torvalds 18471da177e4SLinus Torvalds /* end old governor */ 18487bd353a9SViresh Kumar if (data->governor) { 18491da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_STOP); 18507bd353a9SViresh Kumar __cpufreq_governor(data, 18517bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 18527bd353a9SViresh Kumar } 18531da177e4SLinus Torvalds 18541da177e4SLinus Torvalds /* start new governor */ 18551da177e4SLinus Torvalds data->governor = policy->governor; 18567bd353a9SViresh Kumar if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) { 18577bd353a9SViresh Kumar if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) 18587bd353a9SViresh Kumar failed = 0; 18597bd353a9SViresh Kumar else 18607bd353a9SViresh Kumar __cpufreq_governor(data, 18617bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 18627bd353a9SViresh Kumar } 18637bd353a9SViresh Kumar 18647bd353a9SViresh Kumar if (failed) { 18651da177e4SLinus Torvalds /* new governor failed, so re-start old one */ 18662d06d8c4SDominik Brodowski pr_debug("starting governor %s failed\n", 1867e08f5f5bSGautham R Shenoy data->governor->name); 18681da177e4SLinus Torvalds if (old_gov) { 18691da177e4SLinus Torvalds data->governor = old_gov; 1870e08f5f5bSGautham R Shenoy __cpufreq_governor(data, 18717bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_INIT); 18727bd353a9SViresh Kumar __cpufreq_governor(data, 1873e08f5f5bSGautham R Shenoy CPUFREQ_GOV_START); 18741da177e4SLinus Torvalds } 18751da177e4SLinus Torvalds ret = -EINVAL; 18761da177e4SLinus Torvalds goto error_out; 18771da177e4SLinus Torvalds } 18781da177e4SLinus Torvalds /* might be a policy change, too, so fall through */ 18791da177e4SLinus Torvalds } 18802d06d8c4SDominik Brodowski pr_debug("governor: change or update limits\n"); 18811da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); 18821da177e4SLinus Torvalds } 18831da177e4SLinus Torvalds 18841da177e4SLinus Torvalds error_out: 18851da177e4SLinus Torvalds return ret; 18861da177e4SLinus Torvalds } 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds /** 18891da177e4SLinus Torvalds * cpufreq_update_policy - re-evaluate an existing cpufreq policy 18901da177e4SLinus Torvalds * @cpu: CPU which shall be re-evaluated 18911da177e4SLinus Torvalds * 189225985edcSLucas De Marchi * Useful for policy notifiers which have different necessities 18931da177e4SLinus Torvalds * at different times. 18941da177e4SLinus Torvalds */ 18951da177e4SLinus Torvalds int cpufreq_update_policy(unsigned int cpu) 18961da177e4SLinus Torvalds { 18971da177e4SLinus Torvalds struct cpufreq_policy *data = cpufreq_cpu_get(cpu); 18981da177e4SLinus Torvalds struct cpufreq_policy policy; 18995800043bSNathan Zimmer struct cpufreq_driver *driver; 19005800043bSNathan Zimmer unsigned int (*get)(unsigned int cpu); 19015800043bSNathan Zimmer int (*target)(struct cpufreq_policy *policy, 19025800043bSNathan Zimmer unsigned int target_freq, 19035800043bSNathan Zimmer unsigned int relation); 1904f1829e4aSJulia Lawall int ret; 19051da177e4SLinus Torvalds 1906f1829e4aSJulia Lawall if (!data) { 1907f1829e4aSJulia Lawall ret = -ENODEV; 1908f1829e4aSJulia Lawall goto no_policy; 1909f1829e4aSJulia Lawall } 19101da177e4SLinus Torvalds 1911f1829e4aSJulia Lawall if (unlikely(lock_policy_rwsem_write(cpu))) { 1912f1829e4aSJulia Lawall ret = -EINVAL; 1913f1829e4aSJulia Lawall goto fail; 1914f1829e4aSJulia Lawall } 19151da177e4SLinus Torvalds 19162d06d8c4SDominik Brodowski pr_debug("updating policy for CPU %u\n", cpu); 19177d5e350fSDave Jones memcpy(&policy, data, sizeof(struct cpufreq_policy)); 19181da177e4SLinus Torvalds policy.min = data->user_policy.min; 19191da177e4SLinus Torvalds policy.max = data->user_policy.max; 19201da177e4SLinus Torvalds policy.policy = data->user_policy.policy; 19211da177e4SLinus Torvalds policy.governor = data->user_policy.governor; 19221da177e4SLinus Torvalds 19230961dd0dSThomas Renninger /* BIOS might change freq behind our back 19240961dd0dSThomas Renninger -> ask driver for current freq and notify governors about a change */ 19255800043bSNathan Zimmer rcu_read_lock(); 19265800043bSNathan Zimmer driver = rcu_access_pointer(cpufreq_driver); 19275800043bSNathan Zimmer get = driver->get; 19285800043bSNathan Zimmer target = driver->target; 19295800043bSNathan Zimmer rcu_read_unlock(); 19305800043bSNathan Zimmer if (get) { 19315800043bSNathan Zimmer policy.cur = get(cpu); 1932a85f7bd3SThomas Renninger if (!data->cur) { 19332d06d8c4SDominik Brodowski pr_debug("Driver did not initialize current freq"); 1934a85f7bd3SThomas Renninger data->cur = policy.cur; 1935a85f7bd3SThomas Renninger } else { 19365800043bSNathan Zimmer if (data->cur != policy.cur && target) 1937e08f5f5bSGautham R Shenoy cpufreq_out_of_sync(cpu, data->cur, 1938e08f5f5bSGautham R Shenoy policy.cur); 19390961dd0dSThomas Renninger } 1940a85f7bd3SThomas Renninger } 19410961dd0dSThomas Renninger 19421da177e4SLinus Torvalds ret = __cpufreq_set_policy(data, &policy); 19431da177e4SLinus Torvalds 19445a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(cpu); 19455a01f2e8SVenkatesh Pallipadi 1946f1829e4aSJulia Lawall fail: 19471da177e4SLinus Torvalds cpufreq_cpu_put(data); 1948f1829e4aSJulia Lawall no_policy: 19491da177e4SLinus Torvalds return ret; 19501da177e4SLinus Torvalds } 19511da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_update_policy); 19521da177e4SLinus Torvalds 1953dd184a01SSatyam Sharma static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, 1954c32b6b8eSAshok Raj unsigned long action, void *hcpu) 1955c32b6b8eSAshok Raj { 1956c32b6b8eSAshok Raj unsigned int cpu = (unsigned long)hcpu; 19578a25a2fdSKay Sievers struct device *dev; 1958c32b6b8eSAshok Raj 19598a25a2fdSKay Sievers dev = get_cpu_device(cpu); 19608a25a2fdSKay Sievers if (dev) { 1961c32b6b8eSAshok Raj switch (action) { 1962c32b6b8eSAshok Raj case CPU_ONLINE: 19638bb78442SRafael J. Wysocki case CPU_ONLINE_FROZEN: 19648a25a2fdSKay Sievers cpufreq_add_dev(dev, NULL); 1965c32b6b8eSAshok Raj break; 1966c32b6b8eSAshok Raj case CPU_DOWN_PREPARE: 19678bb78442SRafael J. Wysocki case CPU_DOWN_PREPARE_FROZEN: 19688a25a2fdSKay Sievers __cpufreq_remove_dev(dev, NULL); 1969c32b6b8eSAshok Raj break; 19705a01f2e8SVenkatesh Pallipadi case CPU_DOWN_FAILED: 19718bb78442SRafael J. Wysocki case CPU_DOWN_FAILED_FROZEN: 19728a25a2fdSKay Sievers cpufreq_add_dev(dev, NULL); 1973c32b6b8eSAshok Raj break; 1974c32b6b8eSAshok Raj } 1975c32b6b8eSAshok Raj } 1976c32b6b8eSAshok Raj return NOTIFY_OK; 1977c32b6b8eSAshok Raj } 1978c32b6b8eSAshok Raj 19799c36f746SNeal Buckendahl static struct notifier_block __refdata cpufreq_cpu_notifier = { 1980c32b6b8eSAshok Raj .notifier_call = cpufreq_cpu_callback, 1981c32b6b8eSAshok Raj }; 19821da177e4SLinus Torvalds 19831da177e4SLinus Torvalds /********************************************************************* 19841da177e4SLinus Torvalds * REGISTER / UNREGISTER CPUFREQ DRIVER * 19851da177e4SLinus Torvalds *********************************************************************/ 19861da177e4SLinus Torvalds 19871da177e4SLinus Torvalds /** 19881da177e4SLinus Torvalds * cpufreq_register_driver - register a CPU Frequency driver 19891da177e4SLinus Torvalds * @driver_data: A struct cpufreq_driver containing the values# 19901da177e4SLinus Torvalds * submitted by the CPU Frequency driver. 19911da177e4SLinus Torvalds * 19921da177e4SLinus Torvalds * Registers a CPU Frequency driver to this core code. This code 19931da177e4SLinus Torvalds * returns zero on success, -EBUSY when another driver got here first 19941da177e4SLinus Torvalds * (and isn't unregistered in the meantime). 19951da177e4SLinus Torvalds * 19961da177e4SLinus Torvalds */ 1997221dee28SLinus Torvalds int cpufreq_register_driver(struct cpufreq_driver *driver_data) 19981da177e4SLinus Torvalds { 19991da177e4SLinus Torvalds unsigned long flags; 20001da177e4SLinus Torvalds int ret; 20011da177e4SLinus Torvalds 2002a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 2003a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 2004a7b422cdSKonrad Rzeszutek Wilk 20051da177e4SLinus Torvalds if (!driver_data || !driver_data->verify || !driver_data->init || 20061da177e4SLinus Torvalds ((!driver_data->setpolicy) && (!driver_data->target))) 20071da177e4SLinus Torvalds return -EINVAL; 20081da177e4SLinus Torvalds 20092d06d8c4SDominik Brodowski pr_debug("trying to register driver %s\n", driver_data->name); 20101da177e4SLinus Torvalds 20111da177e4SLinus Torvalds if (driver_data->setpolicy) 20121da177e4SLinus Torvalds driver_data->flags |= CPUFREQ_CONST_LOOPS; 20131da177e4SLinus Torvalds 20140d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 20155800043bSNathan Zimmer if (rcu_access_pointer(cpufreq_driver)) { 20160d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20171da177e4SLinus Torvalds return -EBUSY; 20181da177e4SLinus Torvalds } 20195800043bSNathan Zimmer rcu_assign_pointer(cpufreq_driver, driver_data); 20200d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20215800043bSNathan Zimmer synchronize_rcu(); 20221da177e4SLinus Torvalds 20238a25a2fdSKay Sievers ret = subsys_interface_register(&cpufreq_interface); 20248f5bc2abSJiri Slaby if (ret) 20258f5bc2abSJiri Slaby goto err_null_driver; 20261da177e4SLinus Torvalds 20275800043bSNathan Zimmer if (!(driver_data->flags & CPUFREQ_STICKY)) { 20281da177e4SLinus Torvalds int i; 20291da177e4SLinus Torvalds ret = -ENODEV; 20301da177e4SLinus Torvalds 20311da177e4SLinus Torvalds /* check for at least one working CPU */ 20327a6aedfaSMike Travis for (i = 0; i < nr_cpu_ids; i++) 20337a6aedfaSMike Travis if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) { 20341da177e4SLinus Torvalds ret = 0; 20357a6aedfaSMike Travis break; 20367a6aedfaSMike Travis } 20371da177e4SLinus Torvalds 20381da177e4SLinus Torvalds /* if all ->init() calls failed, unregister */ 20391da177e4SLinus Torvalds if (ret) { 20402d06d8c4SDominik Brodowski pr_debug("no CPU initialized for driver %s\n", 2041e08f5f5bSGautham R Shenoy driver_data->name); 20428a25a2fdSKay Sievers goto err_if_unreg; 20431da177e4SLinus Torvalds } 20441da177e4SLinus Torvalds } 20451da177e4SLinus Torvalds 204665edc68cSChandra Seetharaman register_hotcpu_notifier(&cpufreq_cpu_notifier); 20472d06d8c4SDominik Brodowski pr_debug("driver %s up and running\n", driver_data->name); 20481da177e4SLinus Torvalds 20498f5bc2abSJiri Slaby return 0; 20508a25a2fdSKay Sievers err_if_unreg: 20518a25a2fdSKay Sievers subsys_interface_unregister(&cpufreq_interface); 20528f5bc2abSJiri Slaby err_null_driver: 20530d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 20545800043bSNathan Zimmer rcu_assign_pointer(cpufreq_driver, NULL); 20550d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20565800043bSNathan Zimmer synchronize_rcu(); 20574d34a67dSDave Jones return ret; 20581da177e4SLinus Torvalds } 20591da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_register_driver); 20601da177e4SLinus Torvalds 20611da177e4SLinus Torvalds 20621da177e4SLinus Torvalds /** 20631da177e4SLinus Torvalds * cpufreq_unregister_driver - unregister the current CPUFreq driver 20641da177e4SLinus Torvalds * 20651da177e4SLinus Torvalds * Unregister the current CPUFreq driver. Only call this if you have 20661da177e4SLinus Torvalds * the right to do so, i.e. if you have succeeded in initialising before! 20671da177e4SLinus Torvalds * Returns zero if successful, and -EINVAL if the cpufreq_driver is 20681da177e4SLinus Torvalds * currently not initialised. 20691da177e4SLinus Torvalds */ 2070221dee28SLinus Torvalds int cpufreq_unregister_driver(struct cpufreq_driver *driver) 20711da177e4SLinus Torvalds { 20721da177e4SLinus Torvalds unsigned long flags; 20735800043bSNathan Zimmer struct cpufreq_driver *old_driver; 20741da177e4SLinus Torvalds 20755800043bSNathan Zimmer rcu_read_lock(); 20765800043bSNathan Zimmer old_driver = rcu_access_pointer(cpufreq_driver); 20775800043bSNathan Zimmer if (!old_driver || (driver != old_driver)) { 20785800043bSNathan Zimmer rcu_read_unlock(); 20791da177e4SLinus Torvalds return -EINVAL; 20805800043bSNathan Zimmer } 20815800043bSNathan Zimmer rcu_read_unlock(); 20821da177e4SLinus Torvalds 20832d06d8c4SDominik Brodowski pr_debug("unregistering driver %s\n", driver->name); 20841da177e4SLinus Torvalds 20858a25a2fdSKay Sievers subsys_interface_unregister(&cpufreq_interface); 208665edc68cSChandra Seetharaman unregister_hotcpu_notifier(&cpufreq_cpu_notifier); 20871da177e4SLinus Torvalds 20880d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 20895800043bSNathan Zimmer rcu_assign_pointer(cpufreq_driver, NULL); 20900d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20915800043bSNathan Zimmer synchronize_rcu(); 20921da177e4SLinus Torvalds 20931da177e4SLinus Torvalds return 0; 20941da177e4SLinus Torvalds } 20951da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); 20965a01f2e8SVenkatesh Pallipadi 20975a01f2e8SVenkatesh Pallipadi static int __init cpufreq_core_init(void) 20985a01f2e8SVenkatesh Pallipadi { 20995a01f2e8SVenkatesh Pallipadi int cpu; 21005a01f2e8SVenkatesh Pallipadi 2101a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 2102a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 2103a7b422cdSKonrad Rzeszutek Wilk 21045a01f2e8SVenkatesh Pallipadi for_each_possible_cpu(cpu) { 2105f1625066STejun Heo per_cpu(cpufreq_policy_cpu, cpu) = -1; 21065a01f2e8SVenkatesh Pallipadi init_rwsem(&per_cpu(cpu_policy_rwsem, cpu)); 21075a01f2e8SVenkatesh Pallipadi } 21088aa84ad8SThomas Renninger 21098a25a2fdSKay Sievers cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj); 21108aa84ad8SThomas Renninger BUG_ON(!cpufreq_global_kobject); 2111e00e56dfSRafael J. Wysocki register_syscore_ops(&cpufreq_syscore_ops); 21128aa84ad8SThomas Renninger 21135a01f2e8SVenkatesh Pallipadi return 0; 21145a01f2e8SVenkatesh Pallipadi } 21155a01f2e8SVenkatesh Pallipadi core_initcall(cpufreq_core_init); 2116