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 20*72a4ce34SViresh Kumar #include <asm/cputime.h> 211da177e4SLinus Torvalds #include <linux/kernel.h> 22*72a4ce34SViresh Kumar #include <linux/kernel_stat.h> 231da177e4SLinus Torvalds #include <linux/module.h> 241da177e4SLinus Torvalds #include <linux/init.h> 251da177e4SLinus Torvalds #include <linux/notifier.h> 261da177e4SLinus Torvalds #include <linux/cpufreq.h> 271da177e4SLinus Torvalds #include <linux/delay.h> 281da177e4SLinus Torvalds #include <linux/interrupt.h> 291da177e4SLinus Torvalds #include <linux/spinlock.h> 30*72a4ce34SViresh Kumar #include <linux/tick.h> 311da177e4SLinus Torvalds #include <linux/device.h> 321da177e4SLinus Torvalds #include <linux/slab.h> 331da177e4SLinus Torvalds #include <linux/cpu.h> 341da177e4SLinus Torvalds #include <linux/completion.h> 353fc54d37Sakpm@osdl.org #include <linux/mutex.h> 36e00e56dfSRafael J. Wysocki #include <linux/syscore_ops.h> 371da177e4SLinus Torvalds 386f4f2723SThomas Renninger #include <trace/events/power.h> 396f4f2723SThomas Renninger 401da177e4SLinus Torvalds /** 41cd878479SDave Jones * The "cpufreq driver" - the arch- or hardware-dependent low 421da177e4SLinus Torvalds * level driver of CPUFreq support, and its spinlock. This lock 431da177e4SLinus Torvalds * also protects the cpufreq_cpu_data array. 441da177e4SLinus Torvalds */ 451c3d85ddSRafael J. Wysocki static struct cpufreq_driver *cpufreq_driver; 467a6aedfaSMike Travis static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); 47084f3493SThomas Renninger #ifdef CONFIG_HOTPLUG_CPU 48084f3493SThomas Renninger /* This one keeps track of the previously set governor of a removed CPU */ 49e77b89f1SDmitry Monakhov static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); 50084f3493SThomas Renninger #endif 510d1857a1SNathan Zimmer static DEFINE_RWLOCK(cpufreq_driver_lock); 521da177e4SLinus Torvalds 535a01f2e8SVenkatesh Pallipadi /* 545a01f2e8SVenkatesh Pallipadi * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure 555a01f2e8SVenkatesh Pallipadi * all cpufreq/hotplug/workqueue/etc related lock issues. 565a01f2e8SVenkatesh Pallipadi * 575a01f2e8SVenkatesh Pallipadi * The rules for this semaphore: 585a01f2e8SVenkatesh Pallipadi * - Any routine that wants to read from the policy structure will 595a01f2e8SVenkatesh Pallipadi * do a down_read on this semaphore. 605a01f2e8SVenkatesh Pallipadi * - Any routine that will write to the policy structure and/or may take away 615a01f2e8SVenkatesh Pallipadi * the policy altogether (eg. CPU hotplug), will hold this lock in write 625a01f2e8SVenkatesh Pallipadi * mode before doing so. 635a01f2e8SVenkatesh Pallipadi * 645a01f2e8SVenkatesh Pallipadi * Additional rules: 655a01f2e8SVenkatesh Pallipadi * - Governor routines that can be called in cpufreq hotplug path should not 665a01f2e8SVenkatesh Pallipadi * take this sem as top level hotplug notifier handler takes this. 67395913d0SMathieu Desnoyers * - Lock should not be held across 68395913d0SMathieu Desnoyers * __cpufreq_governor(data, CPUFREQ_GOV_STOP); 695a01f2e8SVenkatesh Pallipadi */ 70f1625066STejun Heo static DEFINE_PER_CPU(int, cpufreq_policy_cpu); 715a01f2e8SVenkatesh Pallipadi static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem); 725a01f2e8SVenkatesh Pallipadi 735a01f2e8SVenkatesh Pallipadi #define lock_policy_rwsem(mode, cpu) \ 74fa1d8af4SViresh Kumar static int lock_policy_rwsem_##mode(int cpu) \ 755a01f2e8SVenkatesh Pallipadi { \ 76f1625066STejun Heo int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \ 775a01f2e8SVenkatesh Pallipadi BUG_ON(policy_cpu == -1); \ 785a01f2e8SVenkatesh Pallipadi down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ 795a01f2e8SVenkatesh Pallipadi \ 805a01f2e8SVenkatesh Pallipadi return 0; \ 815a01f2e8SVenkatesh Pallipadi } 825a01f2e8SVenkatesh Pallipadi 835a01f2e8SVenkatesh Pallipadi lock_policy_rwsem(read, cpu); 845a01f2e8SVenkatesh Pallipadi lock_policy_rwsem(write, cpu); 855a01f2e8SVenkatesh Pallipadi 86fa1d8af4SViresh Kumar #define unlock_policy_rwsem(mode, cpu) \ 87fa1d8af4SViresh Kumar static void unlock_policy_rwsem_##mode(int cpu) \ 88fa1d8af4SViresh Kumar { \ 89fa1d8af4SViresh Kumar int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \ 90fa1d8af4SViresh Kumar BUG_ON(policy_cpu == -1); \ 91fa1d8af4SViresh Kumar up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ 925a01f2e8SVenkatesh Pallipadi } 935a01f2e8SVenkatesh Pallipadi 94fa1d8af4SViresh Kumar unlock_policy_rwsem(read, cpu); 95fa1d8af4SViresh Kumar unlock_policy_rwsem(write, cpu); 965a01f2e8SVenkatesh Pallipadi 971da177e4SLinus Torvalds /* internal prototypes */ 9829464f28SDave Jones static int __cpufreq_governor(struct cpufreq_policy *policy, 9929464f28SDave Jones unsigned int event); 1005a01f2e8SVenkatesh Pallipadi static unsigned int __cpufreq_get(unsigned int cpu); 10165f27f38SDavid Howells static void handle_update(struct work_struct *work); 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /** 1041da177e4SLinus Torvalds * Two notifier lists: the "policy" list is involved in the 1051da177e4SLinus Torvalds * validation process for a new CPU frequency policy; the 1061da177e4SLinus Torvalds * "transition" list for kernel code that needs to handle 1071da177e4SLinus Torvalds * changes to devices when the CPU clock speed changes. 1081da177e4SLinus Torvalds * The mutex locks both lists. 1091da177e4SLinus Torvalds */ 110e041c683SAlan Stern static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); 111b4dfdbb3SAlan Stern static struct srcu_notifier_head cpufreq_transition_notifier_list; 1121da177e4SLinus Torvalds 11374212ca4SCesar Eduardo Barros static bool init_cpufreq_transition_notifier_list_called; 114b4dfdbb3SAlan Stern static int __init init_cpufreq_transition_notifier_list(void) 115b4dfdbb3SAlan Stern { 116b4dfdbb3SAlan Stern srcu_init_notifier_head(&cpufreq_transition_notifier_list); 11774212ca4SCesar Eduardo Barros init_cpufreq_transition_notifier_list_called = true; 118b4dfdbb3SAlan Stern return 0; 119b4dfdbb3SAlan Stern } 120b3438f82SLinus Torvalds pure_initcall(init_cpufreq_transition_notifier_list); 1211da177e4SLinus Torvalds 122a7b422cdSKonrad Rzeszutek Wilk static int off __read_mostly; 123da584455SViresh Kumar static int cpufreq_disabled(void) 124a7b422cdSKonrad Rzeszutek Wilk { 125a7b422cdSKonrad Rzeszutek Wilk return off; 126a7b422cdSKonrad Rzeszutek Wilk } 127a7b422cdSKonrad Rzeszutek Wilk void disable_cpufreq(void) 128a7b422cdSKonrad Rzeszutek Wilk { 129a7b422cdSKonrad Rzeszutek Wilk off = 1; 130a7b422cdSKonrad Rzeszutek Wilk } 1311da177e4SLinus Torvalds static LIST_HEAD(cpufreq_governor_list); 1323fc54d37Sakpm@osdl.org static DEFINE_MUTEX(cpufreq_governor_mutex); 1331da177e4SLinus Torvalds 1344d5dcc42SViresh Kumar bool have_governor_per_policy(void) 1354d5dcc42SViresh Kumar { 1361c3d85ddSRafael J. Wysocki return cpufreq_driver->have_governor_per_policy; 1374d5dcc42SViresh Kumar } 1383f869d6dSViresh Kumar EXPORT_SYMBOL_GPL(have_governor_per_policy); 1394d5dcc42SViresh Kumar 140944e9a03SViresh Kumar struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy) 141944e9a03SViresh Kumar { 142944e9a03SViresh Kumar if (have_governor_per_policy()) 143944e9a03SViresh Kumar return &policy->kobj; 144944e9a03SViresh Kumar else 145944e9a03SViresh Kumar return cpufreq_global_kobject; 146944e9a03SViresh Kumar } 147944e9a03SViresh Kumar EXPORT_SYMBOL_GPL(get_governor_parent_kobj); 148944e9a03SViresh Kumar 149*72a4ce34SViresh Kumar static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) 150*72a4ce34SViresh Kumar { 151*72a4ce34SViresh Kumar u64 idle_time; 152*72a4ce34SViresh Kumar u64 cur_wall_time; 153*72a4ce34SViresh Kumar u64 busy_time; 154*72a4ce34SViresh Kumar 155*72a4ce34SViresh Kumar cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); 156*72a4ce34SViresh Kumar 157*72a4ce34SViresh Kumar busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; 158*72a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; 159*72a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; 160*72a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; 161*72a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; 162*72a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; 163*72a4ce34SViresh Kumar 164*72a4ce34SViresh Kumar idle_time = cur_wall_time - busy_time; 165*72a4ce34SViresh Kumar if (wall) 166*72a4ce34SViresh Kumar *wall = cputime_to_usecs(cur_wall_time); 167*72a4ce34SViresh Kumar 168*72a4ce34SViresh Kumar return cputime_to_usecs(idle_time); 169*72a4ce34SViresh Kumar } 170*72a4ce34SViresh Kumar 171*72a4ce34SViresh Kumar u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy) 172*72a4ce34SViresh Kumar { 173*72a4ce34SViresh Kumar u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL); 174*72a4ce34SViresh Kumar 175*72a4ce34SViresh Kumar if (idle_time == -1ULL) 176*72a4ce34SViresh Kumar return get_cpu_idle_time_jiffy(cpu, wall); 177*72a4ce34SViresh Kumar else if (!io_busy) 178*72a4ce34SViresh Kumar idle_time += get_cpu_iowait_time_us(cpu, wall); 179*72a4ce34SViresh Kumar 180*72a4ce34SViresh Kumar return idle_time; 181*72a4ce34SViresh Kumar } 182*72a4ce34SViresh Kumar EXPORT_SYMBOL_GPL(get_cpu_idle_time); 183*72a4ce34SViresh Kumar 184a9144436SStephen Boyd static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) 1851da177e4SLinus Torvalds { 1861da177e4SLinus Torvalds struct cpufreq_policy *data; 1871da177e4SLinus Torvalds unsigned long flags; 1881da177e4SLinus Torvalds 1897a6aedfaSMike Travis if (cpu >= nr_cpu_ids) 1901da177e4SLinus Torvalds goto err_out; 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds /* get the cpufreq driver */ 1930d1857a1SNathan Zimmer read_lock_irqsave(&cpufreq_driver_lock, flags); 1941da177e4SLinus Torvalds 1951c3d85ddSRafael J. Wysocki if (!cpufreq_driver) 1961c3d85ddSRafael J. Wysocki goto err_out_unlock; 1971c3d85ddSRafael J. Wysocki 1981c3d85ddSRafael J. Wysocki if (!try_module_get(cpufreq_driver->owner)) 1991c3d85ddSRafael J. Wysocki goto err_out_unlock; 2001c3d85ddSRafael J. Wysocki 2011c3d85ddSRafael J. Wysocki 2021da177e4SLinus Torvalds /* get the CPU */ 2037a6aedfaSMike Travis data = per_cpu(cpufreq_cpu_data, cpu); 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds if (!data) 2061da177e4SLinus Torvalds goto err_out_put_module; 2071da177e4SLinus Torvalds 208a9144436SStephen Boyd if (!sysfs && !kobject_get(&data->kobj)) 2091da177e4SLinus Torvalds goto err_out_put_module; 2101da177e4SLinus Torvalds 2110d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 2121da177e4SLinus Torvalds return data; 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds err_out_put_module: 2151c3d85ddSRafael J. Wysocki module_put(cpufreq_driver->owner); 2165800043bSNathan Zimmer err_out_unlock: 2171c3d85ddSRafael J. Wysocki read_unlock_irqrestore(&cpufreq_driver_lock, flags); 2181da177e4SLinus Torvalds err_out: 2191da177e4SLinus Torvalds return NULL; 2201da177e4SLinus Torvalds } 221a9144436SStephen Boyd 222a9144436SStephen Boyd struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) 223a9144436SStephen Boyd { 224d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 225d5aaffa9SDirk Brandewie return NULL; 226d5aaffa9SDirk Brandewie 227a9144436SStephen Boyd return __cpufreq_cpu_get(cpu, false); 228a9144436SStephen Boyd } 2291da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_cpu_get); 2301da177e4SLinus Torvalds 231a9144436SStephen Boyd static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu) 2321da177e4SLinus Torvalds { 233a9144436SStephen Boyd return __cpufreq_cpu_get(cpu, true); 234a9144436SStephen Boyd } 235a9144436SStephen Boyd 236a9144436SStephen Boyd static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs) 237a9144436SStephen Boyd { 238a9144436SStephen Boyd if (!sysfs) 2391da177e4SLinus Torvalds kobject_put(&data->kobj); 2401c3d85ddSRafael J. Wysocki module_put(cpufreq_driver->owner); 2411da177e4SLinus Torvalds } 242a9144436SStephen Boyd 243a9144436SStephen Boyd void cpufreq_cpu_put(struct cpufreq_policy *data) 244a9144436SStephen Boyd { 245d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 246d5aaffa9SDirk Brandewie return; 247d5aaffa9SDirk Brandewie 248a9144436SStephen Boyd __cpufreq_cpu_put(data, false); 249a9144436SStephen Boyd } 2501da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_cpu_put); 2511da177e4SLinus Torvalds 252a9144436SStephen Boyd static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data) 253a9144436SStephen Boyd { 254a9144436SStephen Boyd __cpufreq_cpu_put(data, true); 255a9144436SStephen Boyd } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds /********************************************************************* 2581da177e4SLinus Torvalds * EXTERNALLY AFFECTING FREQUENCY CHANGES * 2591da177e4SLinus Torvalds *********************************************************************/ 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds /** 2621da177e4SLinus Torvalds * adjust_jiffies - adjust the system "loops_per_jiffy" 2631da177e4SLinus Torvalds * 2641da177e4SLinus Torvalds * This function alters the system "loops_per_jiffy" for the clock 2651da177e4SLinus Torvalds * speed change. Note that loops_per_jiffy cannot be updated on SMP 2661da177e4SLinus Torvalds * systems as each CPU might be scaled differently. So, use the arch 2671da177e4SLinus Torvalds * per-CPU loops_per_jiffy value wherever possible. 2681da177e4SLinus Torvalds */ 2691da177e4SLinus Torvalds #ifndef CONFIG_SMP 2701da177e4SLinus Torvalds static unsigned long l_p_j_ref; 2711da177e4SLinus Torvalds static unsigned int l_p_j_ref_freq; 2721da177e4SLinus Torvalds 273858119e1SArjan van de Ven static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) 2741da177e4SLinus Torvalds { 2751da177e4SLinus Torvalds if (ci->flags & CPUFREQ_CONST_LOOPS) 2761da177e4SLinus Torvalds return; 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds if (!l_p_j_ref_freq) { 2791da177e4SLinus Torvalds l_p_j_ref = loops_per_jiffy; 2801da177e4SLinus Torvalds l_p_j_ref_freq = ci->old; 2812d06d8c4SDominik Brodowski pr_debug("saving %lu as reference value for loops_per_jiffy; " 282e08f5f5bSGautham R Shenoy "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq); 2831da177e4SLinus Torvalds } 284d08de0c1SAfzal Mohammed if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) || 28542d4dc3fSBenjamin Herrenschmidt (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { 286e08f5f5bSGautham R Shenoy loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, 287e08f5f5bSGautham R Shenoy ci->new); 2882d06d8c4SDominik Brodowski pr_debug("scaling loops_per_jiffy to %lu " 289e08f5f5bSGautham R Shenoy "for frequency %u kHz\n", loops_per_jiffy, ci->new); 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds #else 293e08f5f5bSGautham R Shenoy static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) 294e08f5f5bSGautham R Shenoy { 295e08f5f5bSGautham R Shenoy return; 296e08f5f5bSGautham R Shenoy } 2971da177e4SLinus Torvalds #endif 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds 300b43a7ffbSViresh Kumar void __cpufreq_notify_transition(struct cpufreq_policy *policy, 301b43a7ffbSViresh Kumar struct cpufreq_freqs *freqs, unsigned int state) 3021da177e4SLinus Torvalds { 3031da177e4SLinus Torvalds BUG_ON(irqs_disabled()); 3041da177e4SLinus Torvalds 305d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 306d5aaffa9SDirk Brandewie return; 307d5aaffa9SDirk Brandewie 3081c3d85ddSRafael J. Wysocki freqs->flags = cpufreq_driver->flags; 3092d06d8c4SDominik Brodowski pr_debug("notification %u of frequency transition to %u kHz\n", 310e4472cb3SDave Jones state, freqs->new); 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds switch (state) { 313e4472cb3SDave Jones 3141da177e4SLinus Torvalds case CPUFREQ_PRECHANGE: 315e4472cb3SDave Jones /* detect if the driver reported a value as "old frequency" 316e4472cb3SDave Jones * which is not equal to what the cpufreq core thinks is 317e4472cb3SDave Jones * "old frequency". 3181da177e4SLinus Torvalds */ 3191c3d85ddSRafael J. Wysocki if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { 320e4472cb3SDave Jones if ((policy) && (policy->cpu == freqs->cpu) && 321e4472cb3SDave Jones (policy->cur) && (policy->cur != freqs->old)) { 3222d06d8c4SDominik Brodowski pr_debug("Warning: CPU frequency is" 323e4472cb3SDave Jones " %u, cpufreq assumed %u kHz.\n", 324e4472cb3SDave Jones freqs->old, policy->cur); 325e4472cb3SDave Jones freqs->old = policy->cur; 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds } 328b4dfdbb3SAlan Stern srcu_notifier_call_chain(&cpufreq_transition_notifier_list, 329e4472cb3SDave Jones CPUFREQ_PRECHANGE, freqs); 3301da177e4SLinus Torvalds adjust_jiffies(CPUFREQ_PRECHANGE, freqs); 3311da177e4SLinus Torvalds break; 332e4472cb3SDave Jones 3331da177e4SLinus Torvalds case CPUFREQ_POSTCHANGE: 3341da177e4SLinus Torvalds adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); 3352d06d8c4SDominik Brodowski pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, 3366f4f2723SThomas Renninger (unsigned long)freqs->cpu); 33725e41933SThomas Renninger trace_cpu_frequency(freqs->new, freqs->cpu); 338b4dfdbb3SAlan Stern srcu_notifier_call_chain(&cpufreq_transition_notifier_list, 339e4472cb3SDave Jones CPUFREQ_POSTCHANGE, freqs); 340e4472cb3SDave Jones if (likely(policy) && likely(policy->cpu == freqs->cpu)) 341e4472cb3SDave Jones policy->cur = freqs->new; 3421da177e4SLinus Torvalds break; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds } 345b43a7ffbSViresh Kumar /** 346b43a7ffbSViresh Kumar * cpufreq_notify_transition - call notifier chain and adjust_jiffies 347b43a7ffbSViresh Kumar * on frequency transition. 348b43a7ffbSViresh Kumar * 349b43a7ffbSViresh Kumar * This function calls the transition notifiers and the "adjust_jiffies" 350b43a7ffbSViresh Kumar * function. It is called twice on all CPU frequency changes that have 351b43a7ffbSViresh Kumar * external effects. 352b43a7ffbSViresh Kumar */ 353b43a7ffbSViresh Kumar void cpufreq_notify_transition(struct cpufreq_policy *policy, 354b43a7ffbSViresh Kumar struct cpufreq_freqs *freqs, unsigned int state) 355b43a7ffbSViresh Kumar { 356b43a7ffbSViresh Kumar for_each_cpu(freqs->cpu, policy->cpus) 357b43a7ffbSViresh Kumar __cpufreq_notify_transition(policy, freqs, state); 358b43a7ffbSViresh Kumar } 3591da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_notify_transition); 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds /********************************************************************* 3641da177e4SLinus Torvalds * SYSFS INTERFACE * 3651da177e4SLinus Torvalds *********************************************************************/ 3661da177e4SLinus Torvalds 3673bcb09a3SJeremy Fitzhardinge static struct cpufreq_governor *__find_governor(const char *str_governor) 3683bcb09a3SJeremy Fitzhardinge { 3693bcb09a3SJeremy Fitzhardinge struct cpufreq_governor *t; 3703bcb09a3SJeremy Fitzhardinge 3713bcb09a3SJeremy Fitzhardinge list_for_each_entry(t, &cpufreq_governor_list, governor_list) 3723bcb09a3SJeremy Fitzhardinge if (!strnicmp(str_governor, t->name, CPUFREQ_NAME_LEN)) 3733bcb09a3SJeremy Fitzhardinge return t; 3743bcb09a3SJeremy Fitzhardinge 3753bcb09a3SJeremy Fitzhardinge return NULL; 3763bcb09a3SJeremy Fitzhardinge } 3773bcb09a3SJeremy Fitzhardinge 3781da177e4SLinus Torvalds /** 3791da177e4SLinus Torvalds * cpufreq_parse_governor - parse a governor string 3801da177e4SLinus Torvalds */ 3811da177e4SLinus Torvalds static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, 3821da177e4SLinus Torvalds struct cpufreq_governor **governor) 3831da177e4SLinus Torvalds { 3843bcb09a3SJeremy Fitzhardinge int err = -EINVAL; 3853bcb09a3SJeremy Fitzhardinge 3861c3d85ddSRafael J. Wysocki if (!cpufreq_driver) 3873bcb09a3SJeremy Fitzhardinge goto out; 3883bcb09a3SJeremy Fitzhardinge 3891c3d85ddSRafael J. Wysocki if (cpufreq_driver->setpolicy) { 3901da177e4SLinus Torvalds if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { 3911da177e4SLinus Torvalds *policy = CPUFREQ_POLICY_PERFORMANCE; 3923bcb09a3SJeremy Fitzhardinge err = 0; 393e08f5f5bSGautham R Shenoy } else if (!strnicmp(str_governor, "powersave", 394e08f5f5bSGautham R Shenoy CPUFREQ_NAME_LEN)) { 3951da177e4SLinus Torvalds *policy = CPUFREQ_POLICY_POWERSAVE; 3963bcb09a3SJeremy Fitzhardinge err = 0; 3971da177e4SLinus Torvalds } 3981c3d85ddSRafael J. Wysocki } else if (cpufreq_driver->target) { 3991da177e4SLinus Torvalds struct cpufreq_governor *t; 4003bcb09a3SJeremy Fitzhardinge 4013fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 4023bcb09a3SJeremy Fitzhardinge 4033bcb09a3SJeremy Fitzhardinge t = __find_governor(str_governor); 4043bcb09a3SJeremy Fitzhardinge 405ea714970SJeremy Fitzhardinge if (t == NULL) { 406ea714970SJeremy Fitzhardinge int ret; 407ea714970SJeremy Fitzhardinge 408ea714970SJeremy Fitzhardinge mutex_unlock(&cpufreq_governor_mutex); 4091a8e1463SKees Cook ret = request_module("cpufreq_%s", str_governor); 410ea714970SJeremy Fitzhardinge mutex_lock(&cpufreq_governor_mutex); 411ea714970SJeremy Fitzhardinge 412ea714970SJeremy Fitzhardinge if (ret == 0) 413ea714970SJeremy Fitzhardinge t = __find_governor(str_governor); 414ea714970SJeremy Fitzhardinge } 415ea714970SJeremy Fitzhardinge 4163bcb09a3SJeremy Fitzhardinge if (t != NULL) { 4171da177e4SLinus Torvalds *governor = t; 4183bcb09a3SJeremy Fitzhardinge err = 0; 4191da177e4SLinus Torvalds } 4203bcb09a3SJeremy Fitzhardinge 4213bcb09a3SJeremy Fitzhardinge mutex_unlock(&cpufreq_governor_mutex); 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds out: 4243bcb09a3SJeremy Fitzhardinge return err; 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds /** 429e08f5f5bSGautham R Shenoy * cpufreq_per_cpu_attr_read() / show_##file_name() - 430e08f5f5bSGautham R Shenoy * print out cpufreq information 4311da177e4SLinus Torvalds * 4321da177e4SLinus Torvalds * Write out information from cpufreq_driver->policy[cpu]; object must be 4331da177e4SLinus Torvalds * "unsigned int". 4341da177e4SLinus Torvalds */ 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds #define show_one(file_name, object) \ 4371da177e4SLinus Torvalds static ssize_t show_##file_name \ 4381da177e4SLinus Torvalds (struct cpufreq_policy *policy, char *buf) \ 4391da177e4SLinus Torvalds { \ 4401da177e4SLinus Torvalds return sprintf(buf, "%u\n", policy->object); \ 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds show_one(cpuinfo_min_freq, cpuinfo.min_freq); 4441da177e4SLinus Torvalds show_one(cpuinfo_max_freq, cpuinfo.max_freq); 445ed129784SThomas Renninger show_one(cpuinfo_transition_latency, cpuinfo.transition_latency); 4461da177e4SLinus Torvalds show_one(scaling_min_freq, min); 4471da177e4SLinus Torvalds show_one(scaling_max_freq, max); 4481da177e4SLinus Torvalds show_one(scaling_cur_freq, cur); 4491da177e4SLinus Torvalds 450e08f5f5bSGautham R Shenoy static int __cpufreq_set_policy(struct cpufreq_policy *data, 451e08f5f5bSGautham R Shenoy struct cpufreq_policy *policy); 4527970e08bSThomas Renninger 4531da177e4SLinus Torvalds /** 4541da177e4SLinus Torvalds * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access 4551da177e4SLinus Torvalds */ 4561da177e4SLinus Torvalds #define store_one(file_name, object) \ 4571da177e4SLinus Torvalds static ssize_t store_##file_name \ 4581da177e4SLinus Torvalds (struct cpufreq_policy *policy, const char *buf, size_t count) \ 4591da177e4SLinus Torvalds { \ 460f55c9c26SJingoo Han unsigned int ret; \ 4611da177e4SLinus Torvalds struct cpufreq_policy new_policy; \ 4621da177e4SLinus Torvalds \ 4631da177e4SLinus Torvalds ret = cpufreq_get_policy(&new_policy, policy->cpu); \ 4641da177e4SLinus Torvalds if (ret) \ 4651da177e4SLinus Torvalds return -EINVAL; \ 4661da177e4SLinus Torvalds \ 4671da177e4SLinus Torvalds ret = sscanf(buf, "%u", &new_policy.object); \ 4681da177e4SLinus Torvalds if (ret != 1) \ 4691da177e4SLinus Torvalds return -EINVAL; \ 4701da177e4SLinus Torvalds \ 4717970e08bSThomas Renninger ret = __cpufreq_set_policy(policy, &new_policy); \ 4727970e08bSThomas Renninger policy->user_policy.object = policy->object; \ 4731da177e4SLinus Torvalds \ 4741da177e4SLinus Torvalds return ret ? ret : count; \ 4751da177e4SLinus Torvalds } 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds store_one(scaling_min_freq, min); 4781da177e4SLinus Torvalds store_one(scaling_max_freq, max); 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds /** 4811da177e4SLinus Torvalds * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware 4821da177e4SLinus Torvalds */ 483e08f5f5bSGautham R Shenoy static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy, 484e08f5f5bSGautham R Shenoy char *buf) 4851da177e4SLinus Torvalds { 4865a01f2e8SVenkatesh Pallipadi unsigned int cur_freq = __cpufreq_get(policy->cpu); 4871da177e4SLinus Torvalds if (!cur_freq) 4881da177e4SLinus Torvalds return sprintf(buf, "<unknown>"); 4891da177e4SLinus Torvalds return sprintf(buf, "%u\n", cur_freq); 4901da177e4SLinus Torvalds } 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds /** 4941da177e4SLinus Torvalds * show_scaling_governor - show the current policy for the specified CPU 4951da177e4SLinus Torvalds */ 496905d77cdSDave Jones static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) 4971da177e4SLinus Torvalds { 4981da177e4SLinus Torvalds if (policy->policy == CPUFREQ_POLICY_POWERSAVE) 4991da177e4SLinus Torvalds return sprintf(buf, "powersave\n"); 5001da177e4SLinus Torvalds else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) 5011da177e4SLinus Torvalds return sprintf(buf, "performance\n"); 5021da177e4SLinus Torvalds else if (policy->governor) 5034b972f0bSviresh kumar return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", 50429464f28SDave Jones policy->governor->name); 5051da177e4SLinus Torvalds return -EINVAL; 5061da177e4SLinus Torvalds } 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds /** 5101da177e4SLinus Torvalds * store_scaling_governor - store policy for the specified CPU 5111da177e4SLinus Torvalds */ 5121da177e4SLinus Torvalds static ssize_t store_scaling_governor(struct cpufreq_policy *policy, 5131da177e4SLinus Torvalds const char *buf, size_t count) 5141da177e4SLinus Torvalds { 515f55c9c26SJingoo Han unsigned int ret; 5161da177e4SLinus Torvalds char str_governor[16]; 5171da177e4SLinus Torvalds struct cpufreq_policy new_policy; 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds ret = cpufreq_get_policy(&new_policy, policy->cpu); 5201da177e4SLinus Torvalds if (ret) 5211da177e4SLinus Torvalds return ret; 5221da177e4SLinus Torvalds 5231da177e4SLinus Torvalds ret = sscanf(buf, "%15s", str_governor); 5241da177e4SLinus Torvalds if (ret != 1) 5251da177e4SLinus Torvalds return -EINVAL; 5261da177e4SLinus Torvalds 527e08f5f5bSGautham R Shenoy if (cpufreq_parse_governor(str_governor, &new_policy.policy, 528e08f5f5bSGautham R Shenoy &new_policy.governor)) 5291da177e4SLinus Torvalds return -EINVAL; 5301da177e4SLinus Torvalds 5317970e08bSThomas Renninger /* Do not use cpufreq_set_policy here or the user_policy.max 5327970e08bSThomas Renninger will be wrongly overridden */ 5337970e08bSThomas Renninger ret = __cpufreq_set_policy(policy, &new_policy); 5347970e08bSThomas Renninger 5357970e08bSThomas Renninger policy->user_policy.policy = policy->policy; 5367970e08bSThomas Renninger policy->user_policy.governor = policy->governor; 5377970e08bSThomas Renninger 538e08f5f5bSGautham R Shenoy if (ret) 539e08f5f5bSGautham R Shenoy return ret; 540e08f5f5bSGautham R Shenoy else 541e08f5f5bSGautham R Shenoy return count; 5421da177e4SLinus Torvalds } 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds /** 5451da177e4SLinus Torvalds * show_scaling_driver - show the cpufreq driver currently loaded 5461da177e4SLinus Torvalds */ 5471da177e4SLinus Torvalds static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) 5481da177e4SLinus Torvalds { 5491c3d85ddSRafael J. Wysocki return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", cpufreq_driver->name); 5501da177e4SLinus Torvalds } 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds /** 5531da177e4SLinus Torvalds * show_scaling_available_governors - show the available CPUfreq governors 5541da177e4SLinus Torvalds */ 5551da177e4SLinus Torvalds static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, 5561da177e4SLinus Torvalds char *buf) 5571da177e4SLinus Torvalds { 5581da177e4SLinus Torvalds ssize_t i = 0; 5591da177e4SLinus Torvalds struct cpufreq_governor *t; 5601da177e4SLinus Torvalds 5611c3d85ddSRafael J. Wysocki if (!cpufreq_driver->target) { 5621da177e4SLinus Torvalds i += sprintf(buf, "performance powersave"); 5631da177e4SLinus Torvalds goto out; 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds list_for_each_entry(t, &cpufreq_governor_list, governor_list) { 56729464f28SDave Jones if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) 56829464f28SDave Jones - (CPUFREQ_NAME_LEN + 2))) 5691da177e4SLinus Torvalds goto out; 5704b972f0bSviresh kumar i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name); 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds out: 5731da177e4SLinus Torvalds i += sprintf(&buf[i], "\n"); 5741da177e4SLinus Torvalds return i; 5751da177e4SLinus Torvalds } 576e8628dd0SDarrick J. Wong 577835481d9SRusty Russell static ssize_t show_cpus(const struct cpumask *mask, char *buf) 5781da177e4SLinus Torvalds { 5791da177e4SLinus Torvalds ssize_t i = 0; 5801da177e4SLinus Torvalds unsigned int cpu; 5811da177e4SLinus Torvalds 582835481d9SRusty Russell for_each_cpu(cpu, mask) { 5831da177e4SLinus Torvalds if (i) 5841da177e4SLinus Torvalds i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " "); 5851da177e4SLinus Torvalds i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu); 5861da177e4SLinus Torvalds if (i >= (PAGE_SIZE - 5)) 5871da177e4SLinus Torvalds break; 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds i += sprintf(&buf[i], "\n"); 5901da177e4SLinus Torvalds return i; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds 593e8628dd0SDarrick J. Wong /** 594e8628dd0SDarrick J. Wong * show_related_cpus - show the CPUs affected by each transition even if 595e8628dd0SDarrick J. Wong * hw coordination is in use 596e8628dd0SDarrick J. Wong */ 597e8628dd0SDarrick J. Wong static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf) 598e8628dd0SDarrick J. Wong { 599e8628dd0SDarrick J. Wong return show_cpus(policy->related_cpus, buf); 600e8628dd0SDarrick J. Wong } 601e8628dd0SDarrick J. Wong 602e8628dd0SDarrick J. Wong /** 603e8628dd0SDarrick J. Wong * show_affected_cpus - show the CPUs affected by each transition 604e8628dd0SDarrick J. Wong */ 605e8628dd0SDarrick J. Wong static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) 606e8628dd0SDarrick J. Wong { 607e8628dd0SDarrick J. Wong return show_cpus(policy->cpus, buf); 608e8628dd0SDarrick J. Wong } 609e8628dd0SDarrick J. Wong 6109e76988eSVenki Pallipadi static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy, 6119e76988eSVenki Pallipadi const char *buf, size_t count) 6129e76988eSVenki Pallipadi { 6139e76988eSVenki Pallipadi unsigned int freq = 0; 6149e76988eSVenki Pallipadi unsigned int ret; 6159e76988eSVenki Pallipadi 616879000f9SCHIKAMA masaki if (!policy->governor || !policy->governor->store_setspeed) 6179e76988eSVenki Pallipadi return -EINVAL; 6189e76988eSVenki Pallipadi 6199e76988eSVenki Pallipadi ret = sscanf(buf, "%u", &freq); 6209e76988eSVenki Pallipadi if (ret != 1) 6219e76988eSVenki Pallipadi return -EINVAL; 6229e76988eSVenki Pallipadi 6239e76988eSVenki Pallipadi policy->governor->store_setspeed(policy, freq); 6249e76988eSVenki Pallipadi 6259e76988eSVenki Pallipadi return count; 6269e76988eSVenki Pallipadi } 6279e76988eSVenki Pallipadi 6289e76988eSVenki Pallipadi static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf) 6299e76988eSVenki Pallipadi { 630879000f9SCHIKAMA masaki if (!policy->governor || !policy->governor->show_setspeed) 6319e76988eSVenki Pallipadi return sprintf(buf, "<unsupported>\n"); 6329e76988eSVenki Pallipadi 6339e76988eSVenki Pallipadi return policy->governor->show_setspeed(policy, buf); 6349e76988eSVenki Pallipadi } 6351da177e4SLinus Torvalds 636e2f74f35SThomas Renninger /** 6378bf1ac72Sviresh kumar * show_bios_limit - show the current cpufreq HW/BIOS limitation 638e2f74f35SThomas Renninger */ 639e2f74f35SThomas Renninger static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) 640e2f74f35SThomas Renninger { 641e2f74f35SThomas Renninger unsigned int limit; 642e2f74f35SThomas Renninger int ret; 6431c3d85ddSRafael J. Wysocki if (cpufreq_driver->bios_limit) { 6441c3d85ddSRafael J. Wysocki ret = cpufreq_driver->bios_limit(policy->cpu, &limit); 645e2f74f35SThomas Renninger if (!ret) 646e2f74f35SThomas Renninger return sprintf(buf, "%u\n", limit); 647e2f74f35SThomas Renninger } 648e2f74f35SThomas Renninger return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); 649e2f74f35SThomas Renninger } 650e2f74f35SThomas Renninger 6516dad2a29SBorislav Petkov cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400); 6526dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_min_freq); 6536dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_max_freq); 6546dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_transition_latency); 6556dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_available_governors); 6566dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_driver); 6576dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_cur_freq); 6586dad2a29SBorislav Petkov cpufreq_freq_attr_ro(bios_limit); 6596dad2a29SBorislav Petkov cpufreq_freq_attr_ro(related_cpus); 6606dad2a29SBorislav Petkov cpufreq_freq_attr_ro(affected_cpus); 6616dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_min_freq); 6626dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_max_freq); 6636dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_governor); 6646dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_setspeed); 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds static struct attribute *default_attrs[] = { 6671da177e4SLinus Torvalds &cpuinfo_min_freq.attr, 6681da177e4SLinus Torvalds &cpuinfo_max_freq.attr, 669ed129784SThomas Renninger &cpuinfo_transition_latency.attr, 6701da177e4SLinus Torvalds &scaling_min_freq.attr, 6711da177e4SLinus Torvalds &scaling_max_freq.attr, 6721da177e4SLinus Torvalds &affected_cpus.attr, 673e8628dd0SDarrick J. Wong &related_cpus.attr, 6741da177e4SLinus Torvalds &scaling_governor.attr, 6751da177e4SLinus Torvalds &scaling_driver.attr, 6761da177e4SLinus Torvalds &scaling_available_governors.attr, 6779e76988eSVenki Pallipadi &scaling_setspeed.attr, 6781da177e4SLinus Torvalds NULL 6791da177e4SLinus Torvalds }; 6801da177e4SLinus Torvalds 6818aa84ad8SThomas Renninger struct kobject *cpufreq_global_kobject; 6828aa84ad8SThomas Renninger EXPORT_SYMBOL(cpufreq_global_kobject); 6838aa84ad8SThomas Renninger 6841da177e4SLinus Torvalds #define to_policy(k) container_of(k, struct cpufreq_policy, kobj) 6851da177e4SLinus Torvalds #define to_attr(a) container_of(a, struct freq_attr, attr) 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) 6881da177e4SLinus Torvalds { 6891da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 6901da177e4SLinus Torvalds struct freq_attr *fattr = to_attr(attr); 6910db4a8a9SDave Jones ssize_t ret = -EINVAL; 692a9144436SStephen Boyd policy = cpufreq_cpu_get_sysfs(policy->cpu); 6931da177e4SLinus Torvalds if (!policy) 6940db4a8a9SDave Jones goto no_policy; 6955a01f2e8SVenkatesh Pallipadi 6965a01f2e8SVenkatesh Pallipadi if (lock_policy_rwsem_read(policy->cpu) < 0) 6970db4a8a9SDave Jones goto fail; 6985a01f2e8SVenkatesh Pallipadi 699e08f5f5bSGautham R Shenoy if (fattr->show) 700e08f5f5bSGautham R Shenoy ret = fattr->show(policy, buf); 701e08f5f5bSGautham R Shenoy else 702e08f5f5bSGautham R Shenoy ret = -EIO; 703e08f5f5bSGautham R Shenoy 7045a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_read(policy->cpu); 7050db4a8a9SDave Jones fail: 706a9144436SStephen Boyd cpufreq_cpu_put_sysfs(policy); 7070db4a8a9SDave Jones no_policy: 7081da177e4SLinus Torvalds return ret; 7091da177e4SLinus Torvalds } 7101da177e4SLinus Torvalds 7111da177e4SLinus Torvalds static ssize_t store(struct kobject *kobj, struct attribute *attr, 7121da177e4SLinus Torvalds const char *buf, size_t count) 7131da177e4SLinus Torvalds { 7141da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 7151da177e4SLinus Torvalds struct freq_attr *fattr = to_attr(attr); 716a07530b4SDave Jones ssize_t ret = -EINVAL; 717a9144436SStephen Boyd policy = cpufreq_cpu_get_sysfs(policy->cpu); 7181da177e4SLinus Torvalds if (!policy) 719a07530b4SDave Jones goto no_policy; 7205a01f2e8SVenkatesh Pallipadi 7215a01f2e8SVenkatesh Pallipadi if (lock_policy_rwsem_write(policy->cpu) < 0) 722a07530b4SDave Jones goto fail; 7235a01f2e8SVenkatesh Pallipadi 724e08f5f5bSGautham R Shenoy if (fattr->store) 725e08f5f5bSGautham R Shenoy ret = fattr->store(policy, buf, count); 726e08f5f5bSGautham R Shenoy else 727e08f5f5bSGautham R Shenoy ret = -EIO; 728e08f5f5bSGautham R Shenoy 7295a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(policy->cpu); 730a07530b4SDave Jones fail: 731a9144436SStephen Boyd cpufreq_cpu_put_sysfs(policy); 732a07530b4SDave Jones no_policy: 7331da177e4SLinus Torvalds return ret; 7341da177e4SLinus Torvalds } 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds static void cpufreq_sysfs_release(struct kobject *kobj) 7371da177e4SLinus Torvalds { 7381da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 7392d06d8c4SDominik Brodowski pr_debug("last reference is dropped\n"); 7401da177e4SLinus Torvalds complete(&policy->kobj_unregister); 7411da177e4SLinus Torvalds } 7421da177e4SLinus Torvalds 74352cf25d0SEmese Revfy static const struct sysfs_ops sysfs_ops = { 7441da177e4SLinus Torvalds .show = show, 7451da177e4SLinus Torvalds .store = store, 7461da177e4SLinus Torvalds }; 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds static struct kobj_type ktype_cpufreq = { 7491da177e4SLinus Torvalds .sysfs_ops = &sysfs_ops, 7501da177e4SLinus Torvalds .default_attrs = default_attrs, 7511da177e4SLinus Torvalds .release = cpufreq_sysfs_release, 7521da177e4SLinus Torvalds }; 7531da177e4SLinus Torvalds 75419d6f7ecSDave Jones /* symlink affected CPUs */ 755cf3289d0SAlex Chiang static int cpufreq_add_dev_symlink(unsigned int cpu, 756cf3289d0SAlex Chiang struct cpufreq_policy *policy) 75719d6f7ecSDave Jones { 75819d6f7ecSDave Jones unsigned int j; 75919d6f7ecSDave Jones int ret = 0; 76019d6f7ecSDave Jones 76119d6f7ecSDave Jones for_each_cpu(j, policy->cpus) { 76219d6f7ecSDave Jones struct cpufreq_policy *managed_policy; 7638a25a2fdSKay Sievers struct device *cpu_dev; 76419d6f7ecSDave Jones 76519d6f7ecSDave Jones if (j == cpu) 76619d6f7ecSDave Jones continue; 76719d6f7ecSDave Jones 7682d06d8c4SDominik Brodowski pr_debug("CPU %u already managed, adding link\n", j); 76919d6f7ecSDave Jones managed_policy = cpufreq_cpu_get(cpu); 7708a25a2fdSKay Sievers cpu_dev = get_cpu_device(j); 7718a25a2fdSKay Sievers ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, 77219d6f7ecSDave Jones "cpufreq"); 77319d6f7ecSDave Jones if (ret) { 77419d6f7ecSDave Jones cpufreq_cpu_put(managed_policy); 77519d6f7ecSDave Jones return ret; 77619d6f7ecSDave Jones } 77719d6f7ecSDave Jones } 77819d6f7ecSDave Jones return ret; 77919d6f7ecSDave Jones } 78019d6f7ecSDave Jones 781cf3289d0SAlex Chiang static int cpufreq_add_dev_interface(unsigned int cpu, 782cf3289d0SAlex Chiang struct cpufreq_policy *policy, 7838a25a2fdSKay Sievers struct device *dev) 784909a694eSDave Jones { 785ecf7e461SDave Jones struct cpufreq_policy new_policy; 786909a694eSDave Jones struct freq_attr **drv_attr; 787909a694eSDave Jones unsigned long flags; 788909a694eSDave Jones int ret = 0; 789909a694eSDave Jones unsigned int j; 790909a694eSDave Jones 791909a694eSDave Jones /* prepare interface data */ 792909a694eSDave Jones ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, 7938a25a2fdSKay Sievers &dev->kobj, "cpufreq"); 794909a694eSDave Jones if (ret) 795909a694eSDave Jones return ret; 796909a694eSDave Jones 797909a694eSDave Jones /* set up files for this cpu device */ 7981c3d85ddSRafael J. Wysocki drv_attr = cpufreq_driver->attr; 799909a694eSDave Jones while ((drv_attr) && (*drv_attr)) { 800909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); 801909a694eSDave Jones if (ret) 8021c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 803909a694eSDave Jones drv_attr++; 804909a694eSDave Jones } 8051c3d85ddSRafael J. Wysocki if (cpufreq_driver->get) { 806909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); 807909a694eSDave Jones if (ret) 8081c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 809909a694eSDave Jones } 8101c3d85ddSRafael J. Wysocki if (cpufreq_driver->target) { 811909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); 812909a694eSDave Jones if (ret) 8131c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 814909a694eSDave Jones } 8151c3d85ddSRafael J. Wysocki if (cpufreq_driver->bios_limit) { 816e2f74f35SThomas Renninger ret = sysfs_create_file(&policy->kobj, &bios_limit.attr); 817e2f74f35SThomas Renninger if (ret) 8181c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 819e2f74f35SThomas Renninger } 820909a694eSDave Jones 8210d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 822909a694eSDave Jones for_each_cpu(j, policy->cpus) { 823909a694eSDave Jones per_cpu(cpufreq_cpu_data, j) = policy; 824f1625066STejun Heo per_cpu(cpufreq_policy_cpu, j) = policy->cpu; 825909a694eSDave Jones } 8260d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 827909a694eSDave Jones 828909a694eSDave Jones ret = cpufreq_add_dev_symlink(cpu, policy); 829ecf7e461SDave Jones if (ret) 830ecf7e461SDave Jones goto err_out_kobj_put; 831ecf7e461SDave Jones 832ecf7e461SDave Jones memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); 833ecf7e461SDave Jones /* assure that the starting sequence is run in __cpufreq_set_policy */ 834ecf7e461SDave Jones policy->governor = NULL; 835ecf7e461SDave Jones 836ecf7e461SDave Jones /* set default policy */ 837ecf7e461SDave Jones ret = __cpufreq_set_policy(policy, &new_policy); 838ecf7e461SDave Jones policy->user_policy.policy = policy->policy; 839ecf7e461SDave Jones policy->user_policy.governor = policy->governor; 840ecf7e461SDave Jones 841ecf7e461SDave Jones if (ret) { 8422d06d8c4SDominik Brodowski pr_debug("setting policy failed\n"); 8431c3d85ddSRafael J. Wysocki if (cpufreq_driver->exit) 8441c3d85ddSRafael J. Wysocki cpufreq_driver->exit(policy); 845ecf7e461SDave Jones } 846909a694eSDave Jones return ret; 847909a694eSDave Jones 848909a694eSDave Jones err_out_kobj_put: 849909a694eSDave Jones kobject_put(&policy->kobj); 850909a694eSDave Jones wait_for_completion(&policy->kobj_unregister); 851909a694eSDave Jones return ret; 852909a694eSDave Jones } 853909a694eSDave Jones 854fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 855fcf80582SViresh Kumar static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, 856fcf80582SViresh Kumar struct device *dev) 857fcf80582SViresh Kumar { 858fcf80582SViresh Kumar struct cpufreq_policy *policy; 8591c3d85ddSRafael J. Wysocki int ret = 0, has_target = !!cpufreq_driver->target; 860fcf80582SViresh Kumar unsigned long flags; 861fcf80582SViresh Kumar 862fcf80582SViresh Kumar policy = cpufreq_cpu_get(sibling); 863fcf80582SViresh Kumar WARN_ON(!policy); 864fcf80582SViresh Kumar 865820c6ca2SViresh Kumar if (has_target) 866fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_STOP); 867fcf80582SViresh Kumar 8682eaa3e2dSViresh Kumar lock_policy_rwsem_write(sibling); 8692eaa3e2dSViresh Kumar 8700d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 8712eaa3e2dSViresh Kumar 872fcf80582SViresh Kumar cpumask_set_cpu(cpu, policy->cpus); 8732eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu; 874fcf80582SViresh Kumar per_cpu(cpufreq_cpu_data, cpu) = policy; 8750d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 876fcf80582SViresh Kumar 8772eaa3e2dSViresh Kumar unlock_policy_rwsem_write(sibling); 8782eaa3e2dSViresh Kumar 879820c6ca2SViresh Kumar if (has_target) { 880fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_START); 881fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); 882820c6ca2SViresh Kumar } 883fcf80582SViresh Kumar 884fcf80582SViresh Kumar ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); 885fcf80582SViresh Kumar if (ret) { 886fcf80582SViresh Kumar cpufreq_cpu_put(policy); 887fcf80582SViresh Kumar return ret; 888fcf80582SViresh Kumar } 889fcf80582SViresh Kumar 890fcf80582SViresh Kumar return 0; 891fcf80582SViresh Kumar } 892fcf80582SViresh Kumar #endif 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds /** 8951da177e4SLinus Torvalds * cpufreq_add_dev - add a CPU device 8961da177e4SLinus Torvalds * 8971da177e4SLinus Torvalds * Adds the cpufreq interface for a CPU device. 8983f4a782bSMathieu Desnoyers * 8993f4a782bSMathieu Desnoyers * The Oracle says: try running cpufreq registration/unregistration concurrently 9003f4a782bSMathieu Desnoyers * with with cpu hotplugging and all hell will break loose. Tried to clean this 9013f4a782bSMathieu Desnoyers * mess up, but more thorough testing is needed. - Mathieu 9021da177e4SLinus Torvalds */ 9038a25a2fdSKay Sievers static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) 9041da177e4SLinus Torvalds { 905fcf80582SViresh Kumar unsigned int j, cpu = dev->id; 90665922465SViresh Kumar int ret = -ENOMEM; 9071da177e4SLinus Torvalds struct cpufreq_policy *policy; 9081da177e4SLinus Torvalds unsigned long flags; 90990e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 910fcf80582SViresh Kumar struct cpufreq_governor *gov; 91190e41bacSPrarit Bhargava int sibling; 91290e41bacSPrarit Bhargava #endif 9131da177e4SLinus Torvalds 914c32b6b8eSAshok Raj if (cpu_is_offline(cpu)) 915c32b6b8eSAshok Raj return 0; 916c32b6b8eSAshok Raj 9172d06d8c4SDominik Brodowski pr_debug("adding CPU %u\n", cpu); 9181da177e4SLinus Torvalds 9191da177e4SLinus Torvalds #ifdef CONFIG_SMP 9201da177e4SLinus Torvalds /* check whether a different CPU already registered this 9211da177e4SLinus Torvalds * CPU because it is in the same boat. */ 9221da177e4SLinus Torvalds policy = cpufreq_cpu_get(cpu); 9231da177e4SLinus Torvalds if (unlikely(policy)) { 9248ff69732SDave Jones cpufreq_cpu_put(policy); 9251da177e4SLinus Torvalds return 0; 9261da177e4SLinus Torvalds } 927fcf80582SViresh Kumar 928fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 929fcf80582SViresh Kumar /* Check if this cpu was hot-unplugged earlier and has siblings */ 9300d1857a1SNathan Zimmer read_lock_irqsave(&cpufreq_driver_lock, flags); 931fcf80582SViresh Kumar for_each_online_cpu(sibling) { 932fcf80582SViresh Kumar struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); 9332eaa3e2dSViresh Kumar if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { 9340d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 935fcf80582SViresh Kumar return cpufreq_add_policy_cpu(cpu, sibling, dev); 936fcf80582SViresh Kumar } 9372eaa3e2dSViresh Kumar } 9380d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 939fcf80582SViresh Kumar #endif 9401da177e4SLinus Torvalds #endif 9411da177e4SLinus Torvalds 9421c3d85ddSRafael J. Wysocki if (!try_module_get(cpufreq_driver->owner)) { 9431da177e4SLinus Torvalds ret = -EINVAL; 9441da177e4SLinus Torvalds goto module_out; 9451da177e4SLinus Torvalds } 9461da177e4SLinus Torvalds 947e98df50cSDave Jones policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); 948059019a3SDave Jones if (!policy) 9491da177e4SLinus Torvalds goto nomem_out; 950059019a3SDave Jones 951059019a3SDave Jones if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) 9523f4a782bSMathieu Desnoyers goto err_free_policy; 953059019a3SDave Jones 954059019a3SDave Jones if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) 9553f4a782bSMathieu Desnoyers goto err_free_cpumask; 9561da177e4SLinus Torvalds 9571da177e4SLinus Torvalds policy->cpu = cpu; 95865922465SViresh Kumar policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 959835481d9SRusty Russell cpumask_copy(policy->cpus, cpumask_of(cpu)); 9601da177e4SLinus Torvalds 9615a01f2e8SVenkatesh Pallipadi /* Initially set CPU itself as the policy_cpu */ 962f1625066STejun Heo per_cpu(cpufreq_policy_cpu, cpu) = cpu; 9635a01f2e8SVenkatesh Pallipadi 9641da177e4SLinus Torvalds init_completion(&policy->kobj_unregister); 96565f27f38SDavid Howells INIT_WORK(&policy->update, handle_update); 9661da177e4SLinus Torvalds 9671da177e4SLinus Torvalds /* call driver. From then on the cpufreq must be able 9681da177e4SLinus Torvalds * to accept all calls to ->verify and ->setpolicy for this CPU 9691da177e4SLinus Torvalds */ 9701c3d85ddSRafael J. Wysocki ret = cpufreq_driver->init(policy); 9711da177e4SLinus Torvalds if (ret) { 9722d06d8c4SDominik Brodowski pr_debug("initialization failed\n"); 9732eaa3e2dSViresh Kumar goto err_set_policy_cpu; 9741da177e4SLinus Torvalds } 975643ae6e8SViresh Kumar 976fcf80582SViresh Kumar /* related cpus should atleast have policy->cpus */ 977fcf80582SViresh Kumar cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); 978fcf80582SViresh Kumar 979643ae6e8SViresh Kumar /* 980643ae6e8SViresh Kumar * affected cpus must always be the one, which are online. We aren't 981643ae6e8SViresh Kumar * managing offline cpus here. 982643ae6e8SViresh Kumar */ 983643ae6e8SViresh Kumar cpumask_and(policy->cpus, policy->cpus, cpu_online_mask); 984643ae6e8SViresh Kumar 985187d9f4eSMike Chan policy->user_policy.min = policy->min; 986187d9f4eSMike Chan policy->user_policy.max = policy->max; 9871da177e4SLinus Torvalds 988a1531acdSThomas Renninger blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 989a1531acdSThomas Renninger CPUFREQ_START, policy); 990a1531acdSThomas Renninger 991fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 992fcf80582SViresh Kumar gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu)); 993fcf80582SViresh Kumar if (gov) { 994fcf80582SViresh Kumar policy->governor = gov; 995fcf80582SViresh Kumar pr_debug("Restoring governor %s for cpu %d\n", 996fcf80582SViresh Kumar policy->governor->name, cpu); 9974bfa042cSThomas Renninger } 998fcf80582SViresh Kumar #endif 9991da177e4SLinus Torvalds 10008a25a2fdSKay Sievers ret = cpufreq_add_dev_interface(cpu, policy, dev); 100119d6f7ecSDave Jones if (ret) 10020142f9dcSAhmed S. Darwish goto err_out_unregister; 10038ff69732SDave Jones 1004038c5b3eSGreg Kroah-Hartman kobject_uevent(&policy->kobj, KOBJ_ADD); 10051c3d85ddSRafael J. Wysocki module_put(cpufreq_driver->owner); 10062d06d8c4SDominik Brodowski pr_debug("initialization complete\n"); 10071da177e4SLinus Torvalds 10081da177e4SLinus Torvalds return 0; 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds err_out_unregister: 10110d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 1012835481d9SRusty Russell for_each_cpu(j, policy->cpus) 10137a6aedfaSMike Travis per_cpu(cpufreq_cpu_data, j) = NULL; 10140d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 10151da177e4SLinus Torvalds 1016c10997f6SGreg Kroah-Hartman kobject_put(&policy->kobj); 10171da177e4SLinus Torvalds wait_for_completion(&policy->kobj_unregister); 10181da177e4SLinus Torvalds 10192eaa3e2dSViresh Kumar err_set_policy_cpu: 10202eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = -1; 1021cad70a6aSXiaotian Feng free_cpumask_var(policy->related_cpus); 10223f4a782bSMathieu Desnoyers err_free_cpumask: 10233f4a782bSMathieu Desnoyers free_cpumask_var(policy->cpus); 10243f4a782bSMathieu Desnoyers err_free_policy: 10251da177e4SLinus Torvalds kfree(policy); 10261da177e4SLinus Torvalds nomem_out: 10271c3d85ddSRafael J. Wysocki module_put(cpufreq_driver->owner); 10281da177e4SLinus Torvalds module_out: 10291da177e4SLinus Torvalds return ret; 10301da177e4SLinus Torvalds } 10311da177e4SLinus Torvalds 1032b8eed8afSViresh Kumar static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) 1033b8eed8afSViresh Kumar { 1034b8eed8afSViresh Kumar int j; 1035b8eed8afSViresh Kumar 1036b8eed8afSViresh Kumar policy->last_cpu = policy->cpu; 1037b8eed8afSViresh Kumar policy->cpu = cpu; 1038b8eed8afSViresh Kumar 10393361b7b1SViresh Kumar for_each_cpu(j, policy->cpus) 1040b8eed8afSViresh Kumar per_cpu(cpufreq_policy_cpu, j) = cpu; 1041b8eed8afSViresh Kumar 1042b8eed8afSViresh Kumar #ifdef CONFIG_CPU_FREQ_TABLE 1043b8eed8afSViresh Kumar cpufreq_frequency_table_update_policy_cpu(policy); 1044b8eed8afSViresh Kumar #endif 1045b8eed8afSViresh Kumar blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1046b8eed8afSViresh Kumar CPUFREQ_UPDATE_POLICY_CPU, policy); 1047b8eed8afSViresh Kumar } 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds /** 10505a01f2e8SVenkatesh Pallipadi * __cpufreq_remove_dev - remove a CPU device 10511da177e4SLinus Torvalds * 10521da177e4SLinus Torvalds * Removes the cpufreq interface for a CPU device. 10535a01f2e8SVenkatesh Pallipadi * Caller should already have policy_rwsem in write mode for this CPU. 10545a01f2e8SVenkatesh Pallipadi * This routine frees the rwsem before returning. 10551da177e4SLinus Torvalds */ 10568a25a2fdSKay Sievers static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) 10571da177e4SLinus Torvalds { 1058b8eed8afSViresh Kumar unsigned int cpu = dev->id, ret, cpus; 10591da177e4SLinus Torvalds unsigned long flags; 10601da177e4SLinus Torvalds struct cpufreq_policy *data; 1061499bca9bSAmerigo Wang struct kobject *kobj; 1062499bca9bSAmerigo Wang struct completion *cmp; 10638a25a2fdSKay Sievers struct device *cpu_dev; 10641da177e4SLinus Torvalds 1065b8eed8afSViresh Kumar pr_debug("%s: unregistering CPU %u\n", __func__, cpu); 10661da177e4SLinus Torvalds 10670d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 10681da177e4SLinus Torvalds 10691da177e4SLinus Torvalds data = per_cpu(cpufreq_cpu_data, cpu); 10707a6aedfaSMike Travis per_cpu(cpufreq_cpu_data, cpu) = NULL; 10711da177e4SLinus Torvalds 10720d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 10731da177e4SLinus Torvalds 10741da177e4SLinus Torvalds if (!data) { 1075b8eed8afSViresh Kumar pr_debug("%s: No cpu_data found\n", __func__); 10761da177e4SLinus Torvalds return -EINVAL; 10771da177e4SLinus Torvalds } 10781da177e4SLinus Torvalds 10791c3d85ddSRafael J. Wysocki if (cpufreq_driver->target) 10801da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_STOP); 10815a01f2e8SVenkatesh Pallipadi 10821da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG_CPU 10831c3d85ddSRafael J. Wysocki if (!cpufreq_driver->setpolicy) 1084fa69e33fSDirk Brandewie strncpy(per_cpu(cpufreq_cpu_governor, cpu), 1085fa69e33fSDirk Brandewie data->governor->name, CPUFREQ_NAME_LEN); 10861da177e4SLinus Torvalds #endif 10871da177e4SLinus Torvalds 10882eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1089b8eed8afSViresh Kumar cpus = cpumask_weight(data->cpus); 1090e4969ebaSViresh Kumar 1091e4969ebaSViresh Kumar if (cpus > 1) 1092b8eed8afSViresh Kumar cpumask_clear_cpu(cpu, data->cpus); 10932eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 10941da177e4SLinus Torvalds 109573bf0fc2SViresh Kumar if (cpu != data->cpu) { 109673bf0fc2SViresh Kumar sysfs_remove_link(&dev->kobj, "cpufreq"); 109773bf0fc2SViresh Kumar } else if (cpus > 1) { 1098b8eed8afSViresh Kumar /* first sibling now owns the new sysfs dir */ 1099b8eed8afSViresh Kumar cpu_dev = get_cpu_device(cpumask_first(data->cpus)); 1100b8eed8afSViresh Kumar sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); 1101b8eed8afSViresh Kumar ret = kobject_move(&data->kobj, &cpu_dev->kobj); 1102b8eed8afSViresh Kumar if (ret) { 1103b8eed8afSViresh Kumar pr_err("%s: Failed to move kobj: %d", __func__, ret); 11042eaa3e2dSViresh Kumar 11052eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1106b8eed8afSViresh Kumar cpumask_set_cpu(cpu, data->cpus); 11072eaa3e2dSViresh Kumar 11080d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 11092eaa3e2dSViresh Kumar per_cpu(cpufreq_cpu_data, cpu) = data; 11100d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 11112eaa3e2dSViresh Kumar 11122eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 11132eaa3e2dSViresh Kumar 1114b8eed8afSViresh Kumar ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj, 1115b8eed8afSViresh Kumar "cpufreq"); 1116b8eed8afSViresh Kumar return -EINVAL; 11171da177e4SLinus Torvalds } 1118b8eed8afSViresh Kumar 11192eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1120b8eed8afSViresh Kumar update_policy_cpu(data, cpu_dev->id); 11212eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 1122b8eed8afSViresh Kumar pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", 1123b8eed8afSViresh Kumar __func__, cpu_dev->id, cpu); 11241da177e4SLinus Torvalds } 1125b8eed8afSViresh Kumar 1126d96038e0SViresh Kumar if ((cpus == 1) && (cpufreq_driver->target)) 1127d96038e0SViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); 1128d96038e0SViresh Kumar 1129b8eed8afSViresh Kumar pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); 1130b8eed8afSViresh Kumar cpufreq_cpu_put(data); 11315a01f2e8SVenkatesh Pallipadi 1132b8eed8afSViresh Kumar /* If cpu is last user of policy, free policy */ 1133b8eed8afSViresh Kumar if (cpus == 1) { 11342eaa3e2dSViresh Kumar lock_policy_rwsem_read(cpu); 1135499bca9bSAmerigo Wang kobj = &data->kobj; 1136499bca9bSAmerigo Wang cmp = &data->kobj_unregister; 11372eaa3e2dSViresh Kumar unlock_policy_rwsem_read(cpu); 1138499bca9bSAmerigo Wang kobject_put(kobj); 11391da177e4SLinus Torvalds 11401da177e4SLinus Torvalds /* we need to make sure that the underlying kobj is actually 11411da177e4SLinus Torvalds * not referenced anymore by anybody before we proceed with 11421da177e4SLinus Torvalds * unloading. 11431da177e4SLinus Torvalds */ 11442d06d8c4SDominik Brodowski pr_debug("waiting for dropping of refcount\n"); 1145499bca9bSAmerigo Wang wait_for_completion(cmp); 11462d06d8c4SDominik Brodowski pr_debug("wait complete\n"); 11471da177e4SLinus Torvalds 11481c3d85ddSRafael J. Wysocki if (cpufreq_driver->exit) 11491c3d85ddSRafael J. Wysocki cpufreq_driver->exit(data); 115027ecddc2SJacob Shin 1151835481d9SRusty Russell free_cpumask_var(data->related_cpus); 1152835481d9SRusty Russell free_cpumask_var(data->cpus); 11531da177e4SLinus Torvalds kfree(data); 11541c3d85ddSRafael J. Wysocki } else if (cpufreq_driver->target) { 1155b8eed8afSViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_START); 1156b8eed8afSViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); 1157b8eed8afSViresh Kumar } 11581da177e4SLinus Torvalds 11592eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = -1; 11601da177e4SLinus Torvalds return 0; 11611da177e4SLinus Torvalds } 11621da177e4SLinus Torvalds 11631da177e4SLinus Torvalds 11648a25a2fdSKay Sievers static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) 11655a01f2e8SVenkatesh Pallipadi { 11668a25a2fdSKay Sievers unsigned int cpu = dev->id; 11675a01f2e8SVenkatesh Pallipadi int retval; 1168ec28297aSVenki Pallipadi 1169ec28297aSVenki Pallipadi if (cpu_is_offline(cpu)) 1170ec28297aSVenki Pallipadi return 0; 1171ec28297aSVenki Pallipadi 11728a25a2fdSKay Sievers retval = __cpufreq_remove_dev(dev, sif); 11735a01f2e8SVenkatesh Pallipadi return retval; 11745a01f2e8SVenkatesh Pallipadi } 11755a01f2e8SVenkatesh Pallipadi 11765a01f2e8SVenkatesh Pallipadi 117765f27f38SDavid Howells static void handle_update(struct work_struct *work) 11781da177e4SLinus Torvalds { 117965f27f38SDavid Howells struct cpufreq_policy *policy = 118065f27f38SDavid Howells container_of(work, struct cpufreq_policy, update); 118165f27f38SDavid Howells unsigned int cpu = policy->cpu; 11822d06d8c4SDominik Brodowski pr_debug("handle_update for cpu %u called\n", cpu); 11831da177e4SLinus Torvalds cpufreq_update_policy(cpu); 11841da177e4SLinus Torvalds } 11851da177e4SLinus Torvalds 11861da177e4SLinus Torvalds /** 11871da177e4SLinus Torvalds * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble. 11881da177e4SLinus Torvalds * @cpu: cpu number 11891da177e4SLinus Torvalds * @old_freq: CPU frequency the kernel thinks the CPU runs at 11901da177e4SLinus Torvalds * @new_freq: CPU frequency the CPU actually runs at 11911da177e4SLinus Torvalds * 119229464f28SDave Jones * We adjust to current frequency first, and need to clean up later. 119329464f28SDave Jones * So either call to cpufreq_update_policy() or schedule handle_update()). 11941da177e4SLinus Torvalds */ 1195e08f5f5bSGautham R Shenoy static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, 1196e08f5f5bSGautham R Shenoy unsigned int new_freq) 11971da177e4SLinus Torvalds { 1198b43a7ffbSViresh Kumar struct cpufreq_policy *policy; 11991da177e4SLinus Torvalds struct cpufreq_freqs freqs; 1200b43a7ffbSViresh Kumar unsigned long flags; 1201b43a7ffbSViresh Kumar 12021da177e4SLinus Torvalds 12032d06d8c4SDominik Brodowski pr_debug("Warning: CPU frequency out of sync: cpufreq and timing " 12041da177e4SLinus Torvalds "core thinks of %u, is %u kHz.\n", old_freq, new_freq); 12051da177e4SLinus Torvalds 12061da177e4SLinus Torvalds freqs.old = old_freq; 12071da177e4SLinus Torvalds freqs.new = new_freq; 1208b43a7ffbSViresh Kumar 1209b43a7ffbSViresh Kumar read_lock_irqsave(&cpufreq_driver_lock, flags); 1210b43a7ffbSViresh Kumar policy = per_cpu(cpufreq_cpu_data, cpu); 1211b43a7ffbSViresh Kumar read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1212b43a7ffbSViresh Kumar 1213b43a7ffbSViresh Kumar cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); 1214b43a7ffbSViresh Kumar cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); 12151da177e4SLinus Torvalds } 12161da177e4SLinus Torvalds 12171da177e4SLinus Torvalds 12181da177e4SLinus Torvalds /** 12194ab70df4SDhaval Giani * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur 122095235ca2SVenkatesh Pallipadi * @cpu: CPU number 122195235ca2SVenkatesh Pallipadi * 122295235ca2SVenkatesh Pallipadi * This is the last known freq, without actually getting it from the driver. 122395235ca2SVenkatesh Pallipadi * Return value will be same as what is shown in scaling_cur_freq in sysfs. 122495235ca2SVenkatesh Pallipadi */ 122595235ca2SVenkatesh Pallipadi unsigned int cpufreq_quick_get(unsigned int cpu) 122695235ca2SVenkatesh Pallipadi { 12279e21ba8bSDirk Brandewie struct cpufreq_policy *policy; 1228e08f5f5bSGautham R Shenoy unsigned int ret_freq = 0; 122995235ca2SVenkatesh Pallipadi 12301c3d85ddSRafael J. Wysocki if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get) 12311c3d85ddSRafael J. Wysocki return cpufreq_driver->get(cpu); 12329e21ba8bSDirk Brandewie 12339e21ba8bSDirk Brandewie policy = cpufreq_cpu_get(cpu); 123495235ca2SVenkatesh Pallipadi if (policy) { 1235e08f5f5bSGautham R Shenoy ret_freq = policy->cur; 123695235ca2SVenkatesh Pallipadi cpufreq_cpu_put(policy); 123795235ca2SVenkatesh Pallipadi } 123895235ca2SVenkatesh Pallipadi 12394d34a67dSDave Jones return ret_freq; 124095235ca2SVenkatesh Pallipadi } 124195235ca2SVenkatesh Pallipadi EXPORT_SYMBOL(cpufreq_quick_get); 124295235ca2SVenkatesh Pallipadi 12433d737108SJesse Barnes /** 12443d737108SJesse Barnes * cpufreq_quick_get_max - get the max reported CPU frequency for this CPU 12453d737108SJesse Barnes * @cpu: CPU number 12463d737108SJesse Barnes * 12473d737108SJesse Barnes * Just return the max possible frequency for a given CPU. 12483d737108SJesse Barnes */ 12493d737108SJesse Barnes unsigned int cpufreq_quick_get_max(unsigned int cpu) 12503d737108SJesse Barnes { 12513d737108SJesse Barnes struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 12523d737108SJesse Barnes unsigned int ret_freq = 0; 12533d737108SJesse Barnes 12543d737108SJesse Barnes if (policy) { 12553d737108SJesse Barnes ret_freq = policy->max; 12563d737108SJesse Barnes cpufreq_cpu_put(policy); 12573d737108SJesse Barnes } 12583d737108SJesse Barnes 12593d737108SJesse Barnes return ret_freq; 12603d737108SJesse Barnes } 12613d737108SJesse Barnes EXPORT_SYMBOL(cpufreq_quick_get_max); 12623d737108SJesse Barnes 126395235ca2SVenkatesh Pallipadi 12645a01f2e8SVenkatesh Pallipadi static unsigned int __cpufreq_get(unsigned int cpu) 12651da177e4SLinus Torvalds { 12667a6aedfaSMike Travis struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); 1267e08f5f5bSGautham R Shenoy unsigned int ret_freq = 0; 12681da177e4SLinus Torvalds 12691c3d85ddSRafael J. Wysocki if (!cpufreq_driver->get) 12704d34a67dSDave Jones return ret_freq; 12711da177e4SLinus Torvalds 12721c3d85ddSRafael J. Wysocki ret_freq = cpufreq_driver->get(cpu); 12731da177e4SLinus Torvalds 1274e08f5f5bSGautham R Shenoy if (ret_freq && policy->cur && 12751c3d85ddSRafael J. Wysocki !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { 1276e08f5f5bSGautham R Shenoy /* verify no discrepancy between actual and 1277e08f5f5bSGautham R Shenoy saved value exists */ 1278e08f5f5bSGautham R Shenoy if (unlikely(ret_freq != policy->cur)) { 1279e08f5f5bSGautham R Shenoy cpufreq_out_of_sync(cpu, policy->cur, ret_freq); 12801da177e4SLinus Torvalds schedule_work(&policy->update); 12811da177e4SLinus Torvalds } 12821da177e4SLinus Torvalds } 12831da177e4SLinus Torvalds 12844d34a67dSDave Jones return ret_freq; 12855a01f2e8SVenkatesh Pallipadi } 12861da177e4SLinus Torvalds 12875a01f2e8SVenkatesh Pallipadi /** 12885a01f2e8SVenkatesh Pallipadi * cpufreq_get - get the current CPU frequency (in kHz) 12895a01f2e8SVenkatesh Pallipadi * @cpu: CPU number 12905a01f2e8SVenkatesh Pallipadi * 12915a01f2e8SVenkatesh Pallipadi * Get the CPU current (static) CPU frequency 12925a01f2e8SVenkatesh Pallipadi */ 12935a01f2e8SVenkatesh Pallipadi unsigned int cpufreq_get(unsigned int cpu) 12945a01f2e8SVenkatesh Pallipadi { 12955a01f2e8SVenkatesh Pallipadi unsigned int ret_freq = 0; 12965a01f2e8SVenkatesh Pallipadi struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 12975a01f2e8SVenkatesh Pallipadi 12985a01f2e8SVenkatesh Pallipadi if (!policy) 12995a01f2e8SVenkatesh Pallipadi goto out; 13005a01f2e8SVenkatesh Pallipadi 13015a01f2e8SVenkatesh Pallipadi if (unlikely(lock_policy_rwsem_read(cpu))) 13025a01f2e8SVenkatesh Pallipadi goto out_policy; 13035a01f2e8SVenkatesh Pallipadi 13045a01f2e8SVenkatesh Pallipadi ret_freq = __cpufreq_get(cpu); 13055a01f2e8SVenkatesh Pallipadi 13065a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_read(cpu); 13075a01f2e8SVenkatesh Pallipadi 13085a01f2e8SVenkatesh Pallipadi out_policy: 13091da177e4SLinus Torvalds cpufreq_cpu_put(policy); 13105a01f2e8SVenkatesh Pallipadi out: 13114d34a67dSDave Jones return ret_freq; 13121da177e4SLinus Torvalds } 13131da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_get); 13141da177e4SLinus Torvalds 13158a25a2fdSKay Sievers static struct subsys_interface cpufreq_interface = { 13168a25a2fdSKay Sievers .name = "cpufreq", 13178a25a2fdSKay Sievers .subsys = &cpu_subsys, 13188a25a2fdSKay Sievers .add_dev = cpufreq_add_dev, 13198a25a2fdSKay Sievers .remove_dev = cpufreq_remove_dev, 1320e00e56dfSRafael J. Wysocki }; 1321e00e56dfSRafael J. Wysocki 13221da177e4SLinus Torvalds 13231da177e4SLinus Torvalds /** 1324e00e56dfSRafael J. Wysocki * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. 1325e00e56dfSRafael J. Wysocki * 1326e00e56dfSRafael J. Wysocki * This function is only executed for the boot processor. The other CPUs 1327e00e56dfSRafael J. Wysocki * have been put offline by means of CPU hotplug. 132842d4dc3fSBenjamin Herrenschmidt */ 1329e00e56dfSRafael J. Wysocki static int cpufreq_bp_suspend(void) 133042d4dc3fSBenjamin Herrenschmidt { 1331e08f5f5bSGautham R Shenoy int ret = 0; 13324bc5d341SDave Jones 1333e00e56dfSRafael J. Wysocki int cpu = smp_processor_id(); 133442d4dc3fSBenjamin Herrenschmidt struct cpufreq_policy *cpu_policy; 133542d4dc3fSBenjamin Herrenschmidt 13362d06d8c4SDominik Brodowski pr_debug("suspending cpu %u\n", cpu); 133742d4dc3fSBenjamin Herrenschmidt 1338e00e56dfSRafael J. Wysocki /* If there's no policy for the boot CPU, we have nothing to do. */ 133942d4dc3fSBenjamin Herrenschmidt cpu_policy = cpufreq_cpu_get(cpu); 134042d4dc3fSBenjamin Herrenschmidt if (!cpu_policy) 1341e00e56dfSRafael J. Wysocki return 0; 134242d4dc3fSBenjamin Herrenschmidt 13431c3d85ddSRafael J. Wysocki if (cpufreq_driver->suspend) { 13441c3d85ddSRafael J. Wysocki ret = cpufreq_driver->suspend(cpu_policy); 1345ce6c3997SDominik Brodowski if (ret) 134642d4dc3fSBenjamin Herrenschmidt printk(KERN_ERR "cpufreq: suspend failed in ->suspend " 134742d4dc3fSBenjamin Herrenschmidt "step on CPU %u\n", cpu_policy->cpu); 134842d4dc3fSBenjamin Herrenschmidt } 134942d4dc3fSBenjamin Herrenschmidt 135042d4dc3fSBenjamin Herrenschmidt cpufreq_cpu_put(cpu_policy); 1351c9060494SDave Jones return ret; 135242d4dc3fSBenjamin Herrenschmidt } 135342d4dc3fSBenjamin Herrenschmidt 135442d4dc3fSBenjamin Herrenschmidt /** 1355e00e56dfSRafael J. Wysocki * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU. 13561da177e4SLinus Torvalds * 13571da177e4SLinus Torvalds * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) 1358ce6c3997SDominik Brodowski * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are 1359ce6c3997SDominik Brodowski * restored. It will verify that the current freq is in sync with 1360ce6c3997SDominik Brodowski * what we believe it to be. This is a bit later than when it 1361ce6c3997SDominik Brodowski * should be, but nonethteless it's better than calling 1362ce6c3997SDominik Brodowski * cpufreq_driver->get() here which might re-enable interrupts... 1363e00e56dfSRafael J. Wysocki * 1364e00e56dfSRafael J. Wysocki * This function is only executed for the boot CPU. The other CPUs have not 1365e00e56dfSRafael J. Wysocki * been turned on yet. 13661da177e4SLinus Torvalds */ 1367e00e56dfSRafael J. Wysocki static void cpufreq_bp_resume(void) 13681da177e4SLinus Torvalds { 1369e08f5f5bSGautham R Shenoy int ret = 0; 13704bc5d341SDave Jones 1371e00e56dfSRafael J. Wysocki int cpu = smp_processor_id(); 13721da177e4SLinus Torvalds struct cpufreq_policy *cpu_policy; 13731da177e4SLinus Torvalds 13742d06d8c4SDominik Brodowski pr_debug("resuming cpu %u\n", cpu); 13751da177e4SLinus Torvalds 1376e00e56dfSRafael J. Wysocki /* If there's no policy for the boot CPU, we have nothing to do. */ 13771da177e4SLinus Torvalds cpu_policy = cpufreq_cpu_get(cpu); 13781da177e4SLinus Torvalds if (!cpu_policy) 1379e00e56dfSRafael J. Wysocki return; 13801da177e4SLinus Torvalds 13811c3d85ddSRafael J. Wysocki if (cpufreq_driver->resume) { 13821c3d85ddSRafael J. Wysocki ret = cpufreq_driver->resume(cpu_policy); 13831da177e4SLinus Torvalds if (ret) { 13841da177e4SLinus Torvalds printk(KERN_ERR "cpufreq: resume failed in ->resume " 13851da177e4SLinus Torvalds "step on CPU %u\n", cpu_policy->cpu); 1386c9060494SDave Jones goto fail; 13871da177e4SLinus Torvalds } 13881da177e4SLinus Torvalds } 13891da177e4SLinus Torvalds 13901da177e4SLinus Torvalds schedule_work(&cpu_policy->update); 1391ce6c3997SDominik Brodowski 1392c9060494SDave Jones fail: 13931da177e4SLinus Torvalds cpufreq_cpu_put(cpu_policy); 13941da177e4SLinus Torvalds } 13951da177e4SLinus Torvalds 1396e00e56dfSRafael J. Wysocki static struct syscore_ops cpufreq_syscore_ops = { 1397e00e56dfSRafael J. Wysocki .suspend = cpufreq_bp_suspend, 1398e00e56dfSRafael J. Wysocki .resume = cpufreq_bp_resume, 13991da177e4SLinus Torvalds }; 14001da177e4SLinus Torvalds 14019d95046eSBorislav Petkov /** 14029d95046eSBorislav Petkov * cpufreq_get_current_driver - return current driver's name 14039d95046eSBorislav Petkov * 14049d95046eSBorislav Petkov * Return the name string of the currently loaded cpufreq driver 14059d95046eSBorislav Petkov * or NULL, if none. 14069d95046eSBorislav Petkov */ 14079d95046eSBorislav Petkov const char *cpufreq_get_current_driver(void) 14089d95046eSBorislav Petkov { 14091c3d85ddSRafael J. Wysocki if (cpufreq_driver) 14101c3d85ddSRafael J. Wysocki return cpufreq_driver->name; 14111c3d85ddSRafael J. Wysocki 14121c3d85ddSRafael J. Wysocki return NULL; 14139d95046eSBorislav Petkov } 14149d95046eSBorislav Petkov EXPORT_SYMBOL_GPL(cpufreq_get_current_driver); 14151da177e4SLinus Torvalds 14161da177e4SLinus Torvalds /********************************************************************* 14171da177e4SLinus Torvalds * NOTIFIER LISTS INTERFACE * 14181da177e4SLinus Torvalds *********************************************************************/ 14191da177e4SLinus Torvalds 14201da177e4SLinus Torvalds /** 14211da177e4SLinus Torvalds * cpufreq_register_notifier - register a driver with cpufreq 14221da177e4SLinus Torvalds * @nb: notifier function to register 14231da177e4SLinus Torvalds * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER 14241da177e4SLinus Torvalds * 14251da177e4SLinus Torvalds * Add a driver to one of two lists: either a list of drivers that 14261da177e4SLinus Torvalds * are notified about clock rate changes (once before and once after 14271da177e4SLinus Torvalds * the transition), or a list of drivers that are notified about 14281da177e4SLinus Torvalds * changes in cpufreq policy. 14291da177e4SLinus Torvalds * 14301da177e4SLinus Torvalds * This function may sleep, and has the same return conditions as 1431e041c683SAlan Stern * blocking_notifier_chain_register. 14321da177e4SLinus Torvalds */ 14331da177e4SLinus Torvalds int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) 14341da177e4SLinus Torvalds { 14351da177e4SLinus Torvalds int ret; 14361da177e4SLinus Torvalds 1437d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1438d5aaffa9SDirk Brandewie return -EINVAL; 1439d5aaffa9SDirk Brandewie 144074212ca4SCesar Eduardo Barros WARN_ON(!init_cpufreq_transition_notifier_list_called); 144174212ca4SCesar Eduardo Barros 14421da177e4SLinus Torvalds switch (list) { 14431da177e4SLinus Torvalds case CPUFREQ_TRANSITION_NOTIFIER: 1444b4dfdbb3SAlan Stern ret = srcu_notifier_chain_register( 1445e041c683SAlan Stern &cpufreq_transition_notifier_list, nb); 14461da177e4SLinus Torvalds break; 14471da177e4SLinus Torvalds case CPUFREQ_POLICY_NOTIFIER: 1448e041c683SAlan Stern ret = blocking_notifier_chain_register( 1449e041c683SAlan Stern &cpufreq_policy_notifier_list, nb); 14501da177e4SLinus Torvalds break; 14511da177e4SLinus Torvalds default: 14521da177e4SLinus Torvalds ret = -EINVAL; 14531da177e4SLinus Torvalds } 14541da177e4SLinus Torvalds 14551da177e4SLinus Torvalds return ret; 14561da177e4SLinus Torvalds } 14571da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_register_notifier); 14581da177e4SLinus Torvalds 14591da177e4SLinus Torvalds 14601da177e4SLinus Torvalds /** 14611da177e4SLinus Torvalds * cpufreq_unregister_notifier - unregister a driver with cpufreq 14621da177e4SLinus Torvalds * @nb: notifier block to be unregistered 14631da177e4SLinus Torvalds * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER 14641da177e4SLinus Torvalds * 14651da177e4SLinus Torvalds * Remove a driver from the CPU frequency notifier list. 14661da177e4SLinus Torvalds * 14671da177e4SLinus Torvalds * This function may sleep, and has the same return conditions as 1468e041c683SAlan Stern * blocking_notifier_chain_unregister. 14691da177e4SLinus Torvalds */ 14701da177e4SLinus Torvalds int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) 14711da177e4SLinus Torvalds { 14721da177e4SLinus Torvalds int ret; 14731da177e4SLinus Torvalds 1474d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1475d5aaffa9SDirk Brandewie return -EINVAL; 1476d5aaffa9SDirk Brandewie 14771da177e4SLinus Torvalds switch (list) { 14781da177e4SLinus Torvalds case CPUFREQ_TRANSITION_NOTIFIER: 1479b4dfdbb3SAlan Stern ret = srcu_notifier_chain_unregister( 1480e041c683SAlan Stern &cpufreq_transition_notifier_list, nb); 14811da177e4SLinus Torvalds break; 14821da177e4SLinus Torvalds case CPUFREQ_POLICY_NOTIFIER: 1483e041c683SAlan Stern ret = blocking_notifier_chain_unregister( 1484e041c683SAlan Stern &cpufreq_policy_notifier_list, nb); 14851da177e4SLinus Torvalds break; 14861da177e4SLinus Torvalds default: 14871da177e4SLinus Torvalds ret = -EINVAL; 14881da177e4SLinus Torvalds } 14891da177e4SLinus Torvalds 14901da177e4SLinus Torvalds return ret; 14911da177e4SLinus Torvalds } 14921da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_unregister_notifier); 14931da177e4SLinus Torvalds 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds /********************************************************************* 14961da177e4SLinus Torvalds * GOVERNORS * 14971da177e4SLinus Torvalds *********************************************************************/ 14981da177e4SLinus Torvalds 14991da177e4SLinus Torvalds 15001da177e4SLinus Torvalds int __cpufreq_driver_target(struct cpufreq_policy *policy, 15011da177e4SLinus Torvalds unsigned int target_freq, 15021da177e4SLinus Torvalds unsigned int relation) 15031da177e4SLinus Torvalds { 15041da177e4SLinus Torvalds int retval = -EINVAL; 15057249924eSViresh Kumar unsigned int old_target_freq = target_freq; 1506c32b6b8eSAshok Raj 1507a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1508a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 1509a7b422cdSKonrad Rzeszutek Wilk 15107249924eSViresh Kumar /* Make sure that target_freq is within supported range */ 15117249924eSViresh Kumar if (target_freq > policy->max) 15127249924eSViresh Kumar target_freq = policy->max; 15137249924eSViresh Kumar if (target_freq < policy->min) 15147249924eSViresh Kumar target_freq = policy->min; 15157249924eSViresh Kumar 15167249924eSViresh Kumar pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", 15177249924eSViresh Kumar policy->cpu, target_freq, relation, old_target_freq); 15185a1c0228SViresh Kumar 15195a1c0228SViresh Kumar if (target_freq == policy->cur) 15205a1c0228SViresh Kumar return 0; 15215a1c0228SViresh Kumar 15221c3d85ddSRafael J. Wysocki if (cpufreq_driver->target) 15231c3d85ddSRafael J. Wysocki retval = cpufreq_driver->target(policy, target_freq, relation); 152490d45d17SAshok Raj 15251da177e4SLinus Torvalds return retval; 15261da177e4SLinus Torvalds } 15271da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(__cpufreq_driver_target); 15281da177e4SLinus Torvalds 15291da177e4SLinus Torvalds int cpufreq_driver_target(struct cpufreq_policy *policy, 15301da177e4SLinus Torvalds unsigned int target_freq, 15311da177e4SLinus Torvalds unsigned int relation) 15321da177e4SLinus Torvalds { 1533f1829e4aSJulia Lawall int ret = -EINVAL; 15341da177e4SLinus Torvalds 15351da177e4SLinus Torvalds policy = cpufreq_cpu_get(policy->cpu); 15361da177e4SLinus Torvalds if (!policy) 1537f1829e4aSJulia Lawall goto no_policy; 15381da177e4SLinus Torvalds 15395a01f2e8SVenkatesh Pallipadi if (unlikely(lock_policy_rwsem_write(policy->cpu))) 1540f1829e4aSJulia Lawall goto fail; 15411da177e4SLinus Torvalds 15421da177e4SLinus Torvalds ret = __cpufreq_driver_target(policy, target_freq, relation); 15431da177e4SLinus Torvalds 15445a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(policy->cpu); 15451da177e4SLinus Torvalds 1546f1829e4aSJulia Lawall fail: 15471da177e4SLinus Torvalds cpufreq_cpu_put(policy); 1548f1829e4aSJulia Lawall no_policy: 15491da177e4SLinus Torvalds return ret; 15501da177e4SLinus Torvalds } 15511da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_driver_target); 15521da177e4SLinus Torvalds 1553bf0b90e3Svenkatesh.pallipadi@intel.com int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) 1554dfde5d62SVenkatesh Pallipadi { 1555dfde5d62SVenkatesh Pallipadi int ret = 0; 1556dfde5d62SVenkatesh Pallipadi 1557d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1558d5aaffa9SDirk Brandewie return ret; 1559d5aaffa9SDirk Brandewie 15601c3d85ddSRafael J. Wysocki if (!cpufreq_driver->getavg) 15610676f7f2SViresh Kumar return 0; 15620676f7f2SViresh Kumar 1563dfde5d62SVenkatesh Pallipadi policy = cpufreq_cpu_get(policy->cpu); 1564dfde5d62SVenkatesh Pallipadi if (!policy) 1565dfde5d62SVenkatesh Pallipadi return -EINVAL; 1566dfde5d62SVenkatesh Pallipadi 15671c3d85ddSRafael J. Wysocki ret = cpufreq_driver->getavg(policy, cpu); 1568dfde5d62SVenkatesh Pallipadi 1569dfde5d62SVenkatesh Pallipadi cpufreq_cpu_put(policy); 1570dfde5d62SVenkatesh Pallipadi return ret; 1571dfde5d62SVenkatesh Pallipadi } 15725a01f2e8SVenkatesh Pallipadi EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg); 1573dfde5d62SVenkatesh Pallipadi 1574153d7f3fSArjan van de Ven /* 1575153d7f3fSArjan van de Ven * when "event" is CPUFREQ_GOV_LIMITS 1576153d7f3fSArjan van de Ven */ 15771da177e4SLinus Torvalds 1578e08f5f5bSGautham R Shenoy static int __cpufreq_governor(struct cpufreq_policy *policy, 1579e08f5f5bSGautham R Shenoy unsigned int event) 15801da177e4SLinus Torvalds { 1581cc993cabSDave Jones int ret; 15826afde10cSThomas Renninger 15836afde10cSThomas Renninger /* Only must be defined when default governor is known to have latency 15846afde10cSThomas Renninger restrictions, like e.g. conservative or ondemand. 15856afde10cSThomas Renninger That this is the case is already ensured in Kconfig 15866afde10cSThomas Renninger */ 15876afde10cSThomas Renninger #ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE 15886afde10cSThomas Renninger struct cpufreq_governor *gov = &cpufreq_gov_performance; 15896afde10cSThomas Renninger #else 15906afde10cSThomas Renninger struct cpufreq_governor *gov = NULL; 15916afde10cSThomas Renninger #endif 15921c256245SThomas Renninger 15931c256245SThomas Renninger if (policy->governor->max_transition_latency && 15941c256245SThomas Renninger policy->cpuinfo.transition_latency > 15951c256245SThomas Renninger policy->governor->max_transition_latency) { 15966afde10cSThomas Renninger if (!gov) 15976afde10cSThomas Renninger return -EINVAL; 15986afde10cSThomas Renninger else { 15991c256245SThomas Renninger printk(KERN_WARNING "%s governor failed, too long" 16001c256245SThomas Renninger " transition latency of HW, fallback" 16011c256245SThomas Renninger " to %s governor\n", 16021c256245SThomas Renninger policy->governor->name, 16031c256245SThomas Renninger gov->name); 16041c256245SThomas Renninger policy->governor = gov; 16051c256245SThomas Renninger } 16066afde10cSThomas Renninger } 16071da177e4SLinus Torvalds 16081da177e4SLinus Torvalds if (!try_module_get(policy->governor->owner)) 16091da177e4SLinus Torvalds return -EINVAL; 16101da177e4SLinus Torvalds 16112d06d8c4SDominik Brodowski pr_debug("__cpufreq_governor for CPU %u, event %u\n", 1612e08f5f5bSGautham R Shenoy policy->cpu, event); 16131da177e4SLinus Torvalds ret = policy->governor->governor(policy, event); 16141da177e4SLinus Torvalds 16154d5dcc42SViresh Kumar if (!ret) { 16164d5dcc42SViresh Kumar if (event == CPUFREQ_GOV_POLICY_INIT) 16178e53695fSViresh Kumar policy->governor->initialized++; 16184d5dcc42SViresh Kumar else if (event == CPUFREQ_GOV_POLICY_EXIT) 16198e53695fSViresh Kumar policy->governor->initialized--; 16204d5dcc42SViresh Kumar } 1621b394058fSViresh Kumar 1622e08f5f5bSGautham R Shenoy /* we keep one module reference alive for 1623e08f5f5bSGautham R Shenoy each CPU governed by this CPU */ 16241da177e4SLinus Torvalds if ((event != CPUFREQ_GOV_START) || ret) 16251da177e4SLinus Torvalds module_put(policy->governor->owner); 16261da177e4SLinus Torvalds if ((event == CPUFREQ_GOV_STOP) && !ret) 16271da177e4SLinus Torvalds module_put(policy->governor->owner); 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds return ret; 16301da177e4SLinus Torvalds } 16311da177e4SLinus Torvalds 16321da177e4SLinus Torvalds 16331da177e4SLinus Torvalds int cpufreq_register_governor(struct cpufreq_governor *governor) 16341da177e4SLinus Torvalds { 16353bcb09a3SJeremy Fitzhardinge int err; 16361da177e4SLinus Torvalds 16371da177e4SLinus Torvalds if (!governor) 16381da177e4SLinus Torvalds return -EINVAL; 16391da177e4SLinus Torvalds 1640a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1641a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 1642a7b422cdSKonrad Rzeszutek Wilk 16433fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 16441da177e4SLinus Torvalds 1645b394058fSViresh Kumar governor->initialized = 0; 16463bcb09a3SJeremy Fitzhardinge err = -EBUSY; 16473bcb09a3SJeremy Fitzhardinge if (__find_governor(governor->name) == NULL) { 16483bcb09a3SJeremy Fitzhardinge err = 0; 16491da177e4SLinus Torvalds list_add(&governor->governor_list, &cpufreq_governor_list); 16503bcb09a3SJeremy Fitzhardinge } 16511da177e4SLinus Torvalds 16523fc54d37Sakpm@osdl.org mutex_unlock(&cpufreq_governor_mutex); 16533bcb09a3SJeremy Fitzhardinge return err; 16541da177e4SLinus Torvalds } 16551da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_register_governor); 16561da177e4SLinus Torvalds 16571da177e4SLinus Torvalds 16581da177e4SLinus Torvalds void cpufreq_unregister_governor(struct cpufreq_governor *governor) 16591da177e4SLinus Torvalds { 166090e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 166190e41bacSPrarit Bhargava int cpu; 166290e41bacSPrarit Bhargava #endif 166390e41bacSPrarit Bhargava 16641da177e4SLinus Torvalds if (!governor) 16651da177e4SLinus Torvalds return; 16661da177e4SLinus Torvalds 1667a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1668a7b422cdSKonrad Rzeszutek Wilk return; 1669a7b422cdSKonrad Rzeszutek Wilk 167090e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 167190e41bacSPrarit Bhargava for_each_present_cpu(cpu) { 167290e41bacSPrarit Bhargava if (cpu_online(cpu)) 167390e41bacSPrarit Bhargava continue; 167490e41bacSPrarit Bhargava if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name)) 167590e41bacSPrarit Bhargava strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0"); 167690e41bacSPrarit Bhargava } 167790e41bacSPrarit Bhargava #endif 167890e41bacSPrarit Bhargava 16793fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 16801da177e4SLinus Torvalds list_del(&governor->governor_list); 16813fc54d37Sakpm@osdl.org mutex_unlock(&cpufreq_governor_mutex); 16821da177e4SLinus Torvalds return; 16831da177e4SLinus Torvalds } 16841da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_unregister_governor); 16851da177e4SLinus Torvalds 16861da177e4SLinus Torvalds 16871da177e4SLinus Torvalds 16881da177e4SLinus Torvalds /********************************************************************* 16891da177e4SLinus Torvalds * POLICY INTERFACE * 16901da177e4SLinus Torvalds *********************************************************************/ 16911da177e4SLinus Torvalds 16921da177e4SLinus Torvalds /** 16931da177e4SLinus Torvalds * cpufreq_get_policy - get the current cpufreq_policy 169429464f28SDave Jones * @policy: struct cpufreq_policy into which the current cpufreq_policy 169529464f28SDave Jones * is written 16961da177e4SLinus Torvalds * 16971da177e4SLinus Torvalds * Reads the current cpufreq policy. 16981da177e4SLinus Torvalds */ 16991da177e4SLinus Torvalds int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) 17001da177e4SLinus Torvalds { 17011da177e4SLinus Torvalds struct cpufreq_policy *cpu_policy; 17021da177e4SLinus Torvalds if (!policy) 17031da177e4SLinus Torvalds return -EINVAL; 17041da177e4SLinus Torvalds 17051da177e4SLinus Torvalds cpu_policy = cpufreq_cpu_get(cpu); 17061da177e4SLinus Torvalds if (!cpu_policy) 17071da177e4SLinus Torvalds return -EINVAL; 17081da177e4SLinus Torvalds 17091da177e4SLinus Torvalds memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy)); 17101da177e4SLinus Torvalds 17111da177e4SLinus Torvalds cpufreq_cpu_put(cpu_policy); 17121da177e4SLinus Torvalds return 0; 17131da177e4SLinus Torvalds } 17141da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_get_policy); 17151da177e4SLinus Torvalds 17161da177e4SLinus Torvalds 1717153d7f3fSArjan van de Ven /* 1718e08f5f5bSGautham R Shenoy * data : current policy. 1719e08f5f5bSGautham R Shenoy * policy : policy to be set. 1720153d7f3fSArjan van de Ven */ 1721e08f5f5bSGautham R Shenoy static int __cpufreq_set_policy(struct cpufreq_policy *data, 1722e08f5f5bSGautham R Shenoy struct cpufreq_policy *policy) 17231da177e4SLinus Torvalds { 17247bd353a9SViresh Kumar int ret = 0, failed = 1; 17251da177e4SLinus Torvalds 17262d06d8c4SDominik Brodowski pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, 17271da177e4SLinus Torvalds policy->min, policy->max); 17281da177e4SLinus Torvalds 1729e08f5f5bSGautham R Shenoy memcpy(&policy->cpuinfo, &data->cpuinfo, 1730e08f5f5bSGautham R Shenoy sizeof(struct cpufreq_cpuinfo)); 17311da177e4SLinus Torvalds 173253391fa2SYi Yang if (policy->min > data->max || policy->max < data->min) { 17339c9a43edSMattia Dongili ret = -EINVAL; 17349c9a43edSMattia Dongili goto error_out; 17359c9a43edSMattia Dongili } 17369c9a43edSMattia Dongili 17371da177e4SLinus Torvalds /* verify the cpu speed can be set within this limit */ 17381c3d85ddSRafael J. Wysocki ret = cpufreq_driver->verify(policy); 17391da177e4SLinus Torvalds if (ret) 17401da177e4SLinus Torvalds goto error_out; 17411da177e4SLinus Torvalds 17421da177e4SLinus Torvalds /* adjust if necessary - all reasons */ 1743e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1744e041c683SAlan Stern CPUFREQ_ADJUST, policy); 17451da177e4SLinus Torvalds 17461da177e4SLinus Torvalds /* adjust if necessary - hardware incompatibility*/ 1747e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1748e041c683SAlan Stern CPUFREQ_INCOMPATIBLE, policy); 17491da177e4SLinus Torvalds 17501da177e4SLinus Torvalds /* verify the cpu speed can be set within this limit, 17511da177e4SLinus Torvalds which might be different to the first one */ 17521c3d85ddSRafael J. Wysocki ret = cpufreq_driver->verify(policy); 1753e041c683SAlan Stern if (ret) 17541da177e4SLinus Torvalds goto error_out; 17551da177e4SLinus Torvalds 17561da177e4SLinus Torvalds /* notification of the new policy */ 1757e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1758e041c683SAlan Stern CPUFREQ_NOTIFY, policy); 17591da177e4SLinus Torvalds 17601da177e4SLinus Torvalds data->min = policy->min; 17611da177e4SLinus Torvalds data->max = policy->max; 17621da177e4SLinus Torvalds 17632d06d8c4SDominik Brodowski pr_debug("new min and max freqs are %u - %u kHz\n", 1764e08f5f5bSGautham R Shenoy data->min, data->max); 17651da177e4SLinus Torvalds 17661c3d85ddSRafael J. Wysocki if (cpufreq_driver->setpolicy) { 17671da177e4SLinus Torvalds data->policy = policy->policy; 17682d06d8c4SDominik Brodowski pr_debug("setting range\n"); 17691c3d85ddSRafael J. Wysocki ret = cpufreq_driver->setpolicy(policy); 17701da177e4SLinus Torvalds } else { 17711da177e4SLinus Torvalds if (policy->governor != data->governor) { 17721da177e4SLinus Torvalds /* save old, working values */ 17731da177e4SLinus Torvalds struct cpufreq_governor *old_gov = data->governor; 17741da177e4SLinus Torvalds 17752d06d8c4SDominik Brodowski pr_debug("governor switch\n"); 17761da177e4SLinus Torvalds 17771da177e4SLinus Torvalds /* end old governor */ 17787bd353a9SViresh Kumar if (data->governor) { 17791da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_STOP); 1780955ef483SViresh Kumar unlock_policy_rwsem_write(policy->cpu); 17817bd353a9SViresh Kumar __cpufreq_governor(data, 17827bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 1783955ef483SViresh Kumar lock_policy_rwsem_write(policy->cpu); 17847bd353a9SViresh Kumar } 17851da177e4SLinus Torvalds 17861da177e4SLinus Torvalds /* start new governor */ 17871da177e4SLinus Torvalds data->governor = policy->governor; 17887bd353a9SViresh Kumar if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) { 1789955ef483SViresh Kumar if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) { 17907bd353a9SViresh Kumar failed = 0; 1791955ef483SViresh Kumar } else { 1792955ef483SViresh Kumar unlock_policy_rwsem_write(policy->cpu); 17937bd353a9SViresh Kumar __cpufreq_governor(data, 17947bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 1795955ef483SViresh Kumar lock_policy_rwsem_write(policy->cpu); 1796955ef483SViresh Kumar } 17977bd353a9SViresh Kumar } 17987bd353a9SViresh Kumar 17997bd353a9SViresh Kumar if (failed) { 18001da177e4SLinus Torvalds /* new governor failed, so re-start old one */ 18012d06d8c4SDominik Brodowski pr_debug("starting governor %s failed\n", 1802e08f5f5bSGautham R Shenoy data->governor->name); 18031da177e4SLinus Torvalds if (old_gov) { 18041da177e4SLinus Torvalds data->governor = old_gov; 1805e08f5f5bSGautham R Shenoy __cpufreq_governor(data, 18067bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_INIT); 18077bd353a9SViresh Kumar __cpufreq_governor(data, 1808e08f5f5bSGautham R Shenoy CPUFREQ_GOV_START); 18091da177e4SLinus Torvalds } 18101da177e4SLinus Torvalds ret = -EINVAL; 18111da177e4SLinus Torvalds goto error_out; 18121da177e4SLinus Torvalds } 18131da177e4SLinus Torvalds /* might be a policy change, too, so fall through */ 18141da177e4SLinus Torvalds } 18152d06d8c4SDominik Brodowski pr_debug("governor: change or update limits\n"); 18161da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); 18171da177e4SLinus Torvalds } 18181da177e4SLinus Torvalds 18191da177e4SLinus Torvalds error_out: 18201da177e4SLinus Torvalds return ret; 18211da177e4SLinus Torvalds } 18221da177e4SLinus Torvalds 18231da177e4SLinus Torvalds /** 18241da177e4SLinus Torvalds * cpufreq_update_policy - re-evaluate an existing cpufreq policy 18251da177e4SLinus Torvalds * @cpu: CPU which shall be re-evaluated 18261da177e4SLinus Torvalds * 182725985edcSLucas De Marchi * Useful for policy notifiers which have different necessities 18281da177e4SLinus Torvalds * at different times. 18291da177e4SLinus Torvalds */ 18301da177e4SLinus Torvalds int cpufreq_update_policy(unsigned int cpu) 18311da177e4SLinus Torvalds { 18321da177e4SLinus Torvalds struct cpufreq_policy *data = cpufreq_cpu_get(cpu); 18331da177e4SLinus Torvalds struct cpufreq_policy policy; 1834f1829e4aSJulia Lawall int ret; 18351da177e4SLinus Torvalds 1836f1829e4aSJulia Lawall if (!data) { 1837f1829e4aSJulia Lawall ret = -ENODEV; 1838f1829e4aSJulia Lawall goto no_policy; 1839f1829e4aSJulia Lawall } 18401da177e4SLinus Torvalds 1841f1829e4aSJulia Lawall if (unlikely(lock_policy_rwsem_write(cpu))) { 1842f1829e4aSJulia Lawall ret = -EINVAL; 1843f1829e4aSJulia Lawall goto fail; 1844f1829e4aSJulia Lawall } 18451da177e4SLinus Torvalds 18462d06d8c4SDominik Brodowski pr_debug("updating policy for CPU %u\n", cpu); 18477d5e350fSDave Jones memcpy(&policy, data, sizeof(struct cpufreq_policy)); 18481da177e4SLinus Torvalds policy.min = data->user_policy.min; 18491da177e4SLinus Torvalds policy.max = data->user_policy.max; 18501da177e4SLinus Torvalds policy.policy = data->user_policy.policy; 18511da177e4SLinus Torvalds policy.governor = data->user_policy.governor; 18521da177e4SLinus Torvalds 18530961dd0dSThomas Renninger /* BIOS might change freq behind our back 18540961dd0dSThomas Renninger -> ask driver for current freq and notify governors about a change */ 18551c3d85ddSRafael J. Wysocki if (cpufreq_driver->get) { 18561c3d85ddSRafael J. Wysocki policy.cur = cpufreq_driver->get(cpu); 1857a85f7bd3SThomas Renninger if (!data->cur) { 18582d06d8c4SDominik Brodowski pr_debug("Driver did not initialize current freq"); 1859a85f7bd3SThomas Renninger data->cur = policy.cur; 1860a85f7bd3SThomas Renninger } else { 18611c3d85ddSRafael J. Wysocki if (data->cur != policy.cur && cpufreq_driver->target) 1862e08f5f5bSGautham R Shenoy cpufreq_out_of_sync(cpu, data->cur, 1863e08f5f5bSGautham R Shenoy policy.cur); 18640961dd0dSThomas Renninger } 1865a85f7bd3SThomas Renninger } 18660961dd0dSThomas Renninger 18671da177e4SLinus Torvalds ret = __cpufreq_set_policy(data, &policy); 18681da177e4SLinus Torvalds 18695a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(cpu); 18705a01f2e8SVenkatesh Pallipadi 1871f1829e4aSJulia Lawall fail: 18721da177e4SLinus Torvalds cpufreq_cpu_put(data); 1873f1829e4aSJulia Lawall no_policy: 18741da177e4SLinus Torvalds return ret; 18751da177e4SLinus Torvalds } 18761da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_update_policy); 18771da177e4SLinus Torvalds 1878dd184a01SSatyam Sharma static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, 1879c32b6b8eSAshok Raj unsigned long action, void *hcpu) 1880c32b6b8eSAshok Raj { 1881c32b6b8eSAshok Raj unsigned int cpu = (unsigned long)hcpu; 18828a25a2fdSKay Sievers struct device *dev; 1883c32b6b8eSAshok Raj 18848a25a2fdSKay Sievers dev = get_cpu_device(cpu); 18858a25a2fdSKay Sievers if (dev) { 1886c32b6b8eSAshok Raj switch (action) { 1887c32b6b8eSAshok Raj case CPU_ONLINE: 18888a25a2fdSKay Sievers cpufreq_add_dev(dev, NULL); 1889c32b6b8eSAshok Raj break; 1890c32b6b8eSAshok Raj case CPU_DOWN_PREPARE: 1891a66b2e50SSrivatsa S. Bhat case CPU_UP_CANCELED_FROZEN: 18928a25a2fdSKay Sievers __cpufreq_remove_dev(dev, NULL); 1893c32b6b8eSAshok Raj break; 18945a01f2e8SVenkatesh Pallipadi case CPU_DOWN_FAILED: 18958a25a2fdSKay Sievers cpufreq_add_dev(dev, NULL); 1896c32b6b8eSAshok Raj break; 1897c32b6b8eSAshok Raj } 1898c32b6b8eSAshok Raj } 1899c32b6b8eSAshok Raj return NOTIFY_OK; 1900c32b6b8eSAshok Raj } 1901c32b6b8eSAshok Raj 19029c36f746SNeal Buckendahl static struct notifier_block __refdata cpufreq_cpu_notifier = { 1903c32b6b8eSAshok Raj .notifier_call = cpufreq_cpu_callback, 1904c32b6b8eSAshok Raj }; 19051da177e4SLinus Torvalds 19061da177e4SLinus Torvalds /********************************************************************* 19071da177e4SLinus Torvalds * REGISTER / UNREGISTER CPUFREQ DRIVER * 19081da177e4SLinus Torvalds *********************************************************************/ 19091da177e4SLinus Torvalds 19101da177e4SLinus Torvalds /** 19111da177e4SLinus Torvalds * cpufreq_register_driver - register a CPU Frequency driver 19121da177e4SLinus Torvalds * @driver_data: A struct cpufreq_driver containing the values# 19131da177e4SLinus Torvalds * submitted by the CPU Frequency driver. 19141da177e4SLinus Torvalds * 19151da177e4SLinus Torvalds * Registers a CPU Frequency driver to this core code. This code 19161da177e4SLinus Torvalds * returns zero on success, -EBUSY when another driver got here first 19171da177e4SLinus Torvalds * (and isn't unregistered in the meantime). 19181da177e4SLinus Torvalds * 19191da177e4SLinus Torvalds */ 1920221dee28SLinus Torvalds int cpufreq_register_driver(struct cpufreq_driver *driver_data) 19211da177e4SLinus Torvalds { 19221da177e4SLinus Torvalds unsigned long flags; 19231da177e4SLinus Torvalds int ret; 19241da177e4SLinus Torvalds 1925a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1926a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 1927a7b422cdSKonrad Rzeszutek Wilk 19281da177e4SLinus Torvalds if (!driver_data || !driver_data->verify || !driver_data->init || 19291da177e4SLinus Torvalds ((!driver_data->setpolicy) && (!driver_data->target))) 19301da177e4SLinus Torvalds return -EINVAL; 19311da177e4SLinus Torvalds 19322d06d8c4SDominik Brodowski pr_debug("trying to register driver %s\n", driver_data->name); 19331da177e4SLinus Torvalds 19341da177e4SLinus Torvalds if (driver_data->setpolicy) 19351da177e4SLinus Torvalds driver_data->flags |= CPUFREQ_CONST_LOOPS; 19361da177e4SLinus Torvalds 19370d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 19381c3d85ddSRafael J. Wysocki if (cpufreq_driver) { 19390d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 19401da177e4SLinus Torvalds return -EBUSY; 19411da177e4SLinus Torvalds } 19421c3d85ddSRafael J. Wysocki cpufreq_driver = driver_data; 19430d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 19441da177e4SLinus Torvalds 19458a25a2fdSKay Sievers ret = subsys_interface_register(&cpufreq_interface); 19468f5bc2abSJiri Slaby if (ret) 19478f5bc2abSJiri Slaby goto err_null_driver; 19481da177e4SLinus Torvalds 19491c3d85ddSRafael J. Wysocki if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) { 19501da177e4SLinus Torvalds int i; 19511da177e4SLinus Torvalds ret = -ENODEV; 19521da177e4SLinus Torvalds 19531da177e4SLinus Torvalds /* check for at least one working CPU */ 19547a6aedfaSMike Travis for (i = 0; i < nr_cpu_ids; i++) 19557a6aedfaSMike Travis if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) { 19561da177e4SLinus Torvalds ret = 0; 19577a6aedfaSMike Travis break; 19587a6aedfaSMike Travis } 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvalds /* if all ->init() calls failed, unregister */ 19611da177e4SLinus Torvalds if (ret) { 19622d06d8c4SDominik Brodowski pr_debug("no CPU initialized for driver %s\n", 1963e08f5f5bSGautham R Shenoy driver_data->name); 19648a25a2fdSKay Sievers goto err_if_unreg; 19651da177e4SLinus Torvalds } 19661da177e4SLinus Torvalds } 19671da177e4SLinus Torvalds 196865edc68cSChandra Seetharaman register_hotcpu_notifier(&cpufreq_cpu_notifier); 19692d06d8c4SDominik Brodowski pr_debug("driver %s up and running\n", driver_data->name); 19701da177e4SLinus Torvalds 19718f5bc2abSJiri Slaby return 0; 19728a25a2fdSKay Sievers err_if_unreg: 19738a25a2fdSKay Sievers subsys_interface_unregister(&cpufreq_interface); 19748f5bc2abSJiri Slaby err_null_driver: 19750d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 19761c3d85ddSRafael J. Wysocki cpufreq_driver = NULL; 19770d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 19784d34a67dSDave Jones return ret; 19791da177e4SLinus Torvalds } 19801da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_register_driver); 19811da177e4SLinus Torvalds 19821da177e4SLinus Torvalds 19831da177e4SLinus Torvalds /** 19841da177e4SLinus Torvalds * cpufreq_unregister_driver - unregister the current CPUFreq driver 19851da177e4SLinus Torvalds * 19861da177e4SLinus Torvalds * Unregister the current CPUFreq driver. Only call this if you have 19871da177e4SLinus Torvalds * the right to do so, i.e. if you have succeeded in initialising before! 19881da177e4SLinus Torvalds * Returns zero if successful, and -EINVAL if the cpufreq_driver is 19891da177e4SLinus Torvalds * currently not initialised. 19901da177e4SLinus Torvalds */ 1991221dee28SLinus Torvalds int cpufreq_unregister_driver(struct cpufreq_driver *driver) 19921da177e4SLinus Torvalds { 19931da177e4SLinus Torvalds unsigned long flags; 19941da177e4SLinus Torvalds 19951c3d85ddSRafael J. Wysocki if (!cpufreq_driver || (driver != cpufreq_driver)) 19961da177e4SLinus Torvalds return -EINVAL; 19971da177e4SLinus Torvalds 19982d06d8c4SDominik Brodowski pr_debug("unregistering driver %s\n", driver->name); 19991da177e4SLinus Torvalds 20008a25a2fdSKay Sievers subsys_interface_unregister(&cpufreq_interface); 200165edc68cSChandra Seetharaman unregister_hotcpu_notifier(&cpufreq_cpu_notifier); 20021da177e4SLinus Torvalds 20030d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 20041c3d85ddSRafael J. Wysocki cpufreq_driver = NULL; 20050d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20061da177e4SLinus Torvalds 20071da177e4SLinus Torvalds return 0; 20081da177e4SLinus Torvalds } 20091da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); 20105a01f2e8SVenkatesh Pallipadi 20115a01f2e8SVenkatesh Pallipadi static int __init cpufreq_core_init(void) 20125a01f2e8SVenkatesh Pallipadi { 20135a01f2e8SVenkatesh Pallipadi int cpu; 20145a01f2e8SVenkatesh Pallipadi 2015a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 2016a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 2017a7b422cdSKonrad Rzeszutek Wilk 20185a01f2e8SVenkatesh Pallipadi for_each_possible_cpu(cpu) { 2019f1625066STejun Heo per_cpu(cpufreq_policy_cpu, cpu) = -1; 20205a01f2e8SVenkatesh Pallipadi init_rwsem(&per_cpu(cpu_policy_rwsem, cpu)); 20215a01f2e8SVenkatesh Pallipadi } 20228aa84ad8SThomas Renninger 20238a25a2fdSKay Sievers cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj); 20248aa84ad8SThomas Renninger BUG_ON(!cpufreq_global_kobject); 2025e00e56dfSRafael J. Wysocki register_syscore_ops(&cpufreq_syscore_ops); 20268aa84ad8SThomas Renninger 20275a01f2e8SVenkatesh Pallipadi return 0; 20285a01f2e8SVenkatesh Pallipadi } 20295a01f2e8SVenkatesh Pallipadi core_initcall(cpufreq_core_init); 2030