11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/drivers/cpufreq/cpufreq.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001 Russell King 51da177e4SLinus Torvalds * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de> 6bb176f7dSViresh Kumar * (C) 2013 Viresh Kumar <viresh.kumar@linaro.org> 71da177e4SLinus Torvalds * 8c32b6b8eSAshok Raj * Oct 2005 - Ashok Raj <ashok.raj@intel.com> 9c32b6b8eSAshok Raj * Added handling for CPU hotplug 108ff69732SDave Jones * Feb 2006 - Jacob Shin <jacob.shin@amd.com> 118ff69732SDave Jones * Fix handling for CPU hotplug -- affected CPUs 12c32b6b8eSAshok Raj * 131da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 141da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 151da177e4SLinus Torvalds * published by the Free Software Foundation. 161da177e4SLinus Torvalds */ 171da177e4SLinus Torvalds 18db701151SViresh Kumar #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19db701151SViresh Kumar 2072a4ce34SViresh Kumar #include <asm/cputime.h> 211da177e4SLinus Torvalds #include <linux/kernel.h> 2272a4ce34SViresh 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> 3072a4ce34SViresh 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); 478414809cSSrivatsa S. Bhat static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback); 48bb176f7dSViresh Kumar static DEFINE_RWLOCK(cpufreq_driver_lock); 49bb176f7dSViresh Kumar static DEFINE_MUTEX(cpufreq_governor_lock); 50bb176f7dSViresh Kumar 51084f3493SThomas Renninger #ifdef CONFIG_HOTPLUG_CPU 52084f3493SThomas Renninger /* This one keeps track of the previously set governor of a removed CPU */ 53e77b89f1SDmitry Monakhov static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); 54084f3493SThomas Renninger #endif 551da177e4SLinus Torvalds 565a01f2e8SVenkatesh Pallipadi /* 575a01f2e8SVenkatesh Pallipadi * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure 585a01f2e8SVenkatesh Pallipadi * all cpufreq/hotplug/workqueue/etc related lock issues. 595a01f2e8SVenkatesh Pallipadi * 605a01f2e8SVenkatesh Pallipadi * The rules for this semaphore: 615a01f2e8SVenkatesh Pallipadi * - Any routine that wants to read from the policy structure will 625a01f2e8SVenkatesh Pallipadi * do a down_read on this semaphore. 635a01f2e8SVenkatesh Pallipadi * - Any routine that will write to the policy structure and/or may take away 645a01f2e8SVenkatesh Pallipadi * the policy altogether (eg. CPU hotplug), will hold this lock in write 655a01f2e8SVenkatesh Pallipadi * mode before doing so. 665a01f2e8SVenkatesh Pallipadi * 675a01f2e8SVenkatesh Pallipadi * Additional rules: 685a01f2e8SVenkatesh Pallipadi * - Governor routines that can be called in cpufreq hotplug path should not 695a01f2e8SVenkatesh Pallipadi * take this sem as top level hotplug notifier handler takes this. 70395913d0SMathieu Desnoyers * - Lock should not be held across 71395913d0SMathieu Desnoyers * __cpufreq_governor(data, CPUFREQ_GOV_STOP); 725a01f2e8SVenkatesh Pallipadi */ 73f1625066STejun Heo static DEFINE_PER_CPU(int, cpufreq_policy_cpu); 745a01f2e8SVenkatesh Pallipadi static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem); 755a01f2e8SVenkatesh Pallipadi 765a01f2e8SVenkatesh Pallipadi #define lock_policy_rwsem(mode, cpu) \ 77fa1d8af4SViresh Kumar static int lock_policy_rwsem_##mode(int cpu) \ 785a01f2e8SVenkatesh Pallipadi { \ 79f1625066STejun Heo int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \ 805a01f2e8SVenkatesh Pallipadi BUG_ON(policy_cpu == -1); \ 815a01f2e8SVenkatesh Pallipadi down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ 825a01f2e8SVenkatesh Pallipadi \ 835a01f2e8SVenkatesh Pallipadi return 0; \ 845a01f2e8SVenkatesh Pallipadi } 855a01f2e8SVenkatesh Pallipadi 865a01f2e8SVenkatesh Pallipadi lock_policy_rwsem(read, cpu); 875a01f2e8SVenkatesh Pallipadi lock_policy_rwsem(write, cpu); 885a01f2e8SVenkatesh Pallipadi 89fa1d8af4SViresh Kumar #define unlock_policy_rwsem(mode, cpu) \ 90fa1d8af4SViresh Kumar static void unlock_policy_rwsem_##mode(int cpu) \ 91fa1d8af4SViresh Kumar { \ 92fa1d8af4SViresh Kumar int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \ 93fa1d8af4SViresh Kumar BUG_ON(policy_cpu == -1); \ 94fa1d8af4SViresh Kumar up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ 955a01f2e8SVenkatesh Pallipadi } 965a01f2e8SVenkatesh Pallipadi 97fa1d8af4SViresh Kumar unlock_policy_rwsem(read, cpu); 98fa1d8af4SViresh Kumar unlock_policy_rwsem(write, cpu); 995a01f2e8SVenkatesh Pallipadi 1001da177e4SLinus Torvalds /* internal prototypes */ 10129464f28SDave Jones static int __cpufreq_governor(struct cpufreq_policy *policy, 10229464f28SDave Jones unsigned int event); 1035a01f2e8SVenkatesh Pallipadi static unsigned int __cpufreq_get(unsigned int cpu); 10465f27f38SDavid Howells static void handle_update(struct work_struct *work); 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds /** 1071da177e4SLinus Torvalds * Two notifier lists: the "policy" list is involved in the 1081da177e4SLinus Torvalds * validation process for a new CPU frequency policy; the 1091da177e4SLinus Torvalds * "transition" list for kernel code that needs to handle 1101da177e4SLinus Torvalds * changes to devices when the CPU clock speed changes. 1111da177e4SLinus Torvalds * The mutex locks both lists. 1121da177e4SLinus Torvalds */ 113e041c683SAlan Stern static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); 114b4dfdbb3SAlan Stern static struct srcu_notifier_head cpufreq_transition_notifier_list; 1151da177e4SLinus Torvalds 11674212ca4SCesar Eduardo Barros static bool init_cpufreq_transition_notifier_list_called; 117b4dfdbb3SAlan Stern static int __init init_cpufreq_transition_notifier_list(void) 118b4dfdbb3SAlan Stern { 119b4dfdbb3SAlan Stern srcu_init_notifier_head(&cpufreq_transition_notifier_list); 12074212ca4SCesar Eduardo Barros init_cpufreq_transition_notifier_list_called = true; 121b4dfdbb3SAlan Stern return 0; 122b4dfdbb3SAlan Stern } 123b3438f82SLinus Torvalds pure_initcall(init_cpufreq_transition_notifier_list); 1241da177e4SLinus Torvalds 125a7b422cdSKonrad Rzeszutek Wilk static int off __read_mostly; 126da584455SViresh Kumar static int cpufreq_disabled(void) 127a7b422cdSKonrad Rzeszutek Wilk { 128a7b422cdSKonrad Rzeszutek Wilk return off; 129a7b422cdSKonrad Rzeszutek Wilk } 130a7b422cdSKonrad Rzeszutek Wilk void disable_cpufreq(void) 131a7b422cdSKonrad Rzeszutek Wilk { 132a7b422cdSKonrad Rzeszutek Wilk off = 1; 133a7b422cdSKonrad Rzeszutek Wilk } 1341da177e4SLinus Torvalds static LIST_HEAD(cpufreq_governor_list); 1353fc54d37Sakpm@osdl.org static DEFINE_MUTEX(cpufreq_governor_mutex); 1361da177e4SLinus Torvalds 1374d5dcc42SViresh Kumar bool have_governor_per_policy(void) 1384d5dcc42SViresh Kumar { 1391c3d85ddSRafael J. Wysocki return cpufreq_driver->have_governor_per_policy; 1404d5dcc42SViresh Kumar } 1413f869d6dSViresh Kumar EXPORT_SYMBOL_GPL(have_governor_per_policy); 1424d5dcc42SViresh Kumar 143944e9a03SViresh Kumar struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy) 144944e9a03SViresh Kumar { 145944e9a03SViresh Kumar if (have_governor_per_policy()) 146944e9a03SViresh Kumar return &policy->kobj; 147944e9a03SViresh Kumar else 148944e9a03SViresh Kumar return cpufreq_global_kobject; 149944e9a03SViresh Kumar } 150944e9a03SViresh Kumar EXPORT_SYMBOL_GPL(get_governor_parent_kobj); 151944e9a03SViresh Kumar 15272a4ce34SViresh Kumar static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) 15372a4ce34SViresh Kumar { 15472a4ce34SViresh Kumar u64 idle_time; 15572a4ce34SViresh Kumar u64 cur_wall_time; 15672a4ce34SViresh Kumar u64 busy_time; 15772a4ce34SViresh Kumar 15872a4ce34SViresh Kumar cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); 15972a4ce34SViresh Kumar 16072a4ce34SViresh Kumar busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; 16172a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; 16272a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; 16372a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; 16472a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; 16572a4ce34SViresh Kumar busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; 16672a4ce34SViresh Kumar 16772a4ce34SViresh Kumar idle_time = cur_wall_time - busy_time; 16872a4ce34SViresh Kumar if (wall) 16972a4ce34SViresh Kumar *wall = cputime_to_usecs(cur_wall_time); 17072a4ce34SViresh Kumar 17172a4ce34SViresh Kumar return cputime_to_usecs(idle_time); 17272a4ce34SViresh Kumar } 17372a4ce34SViresh Kumar 17472a4ce34SViresh Kumar u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy) 17572a4ce34SViresh Kumar { 17672a4ce34SViresh Kumar u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL); 17772a4ce34SViresh Kumar 17872a4ce34SViresh Kumar if (idle_time == -1ULL) 17972a4ce34SViresh Kumar return get_cpu_idle_time_jiffy(cpu, wall); 18072a4ce34SViresh Kumar else if (!io_busy) 18172a4ce34SViresh Kumar idle_time += get_cpu_iowait_time_us(cpu, wall); 18272a4ce34SViresh Kumar 18372a4ce34SViresh Kumar return idle_time; 18472a4ce34SViresh Kumar } 18572a4ce34SViresh Kumar EXPORT_SYMBOL_GPL(get_cpu_idle_time); 18672a4ce34SViresh Kumar 187a9144436SStephen Boyd static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) 1881da177e4SLinus Torvalds { 1891da177e4SLinus Torvalds struct cpufreq_policy *data; 1901da177e4SLinus Torvalds unsigned long flags; 1911da177e4SLinus Torvalds 1927a6aedfaSMike Travis if (cpu >= nr_cpu_ids) 1931da177e4SLinus Torvalds goto err_out; 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds /* get the cpufreq driver */ 1960d1857a1SNathan Zimmer read_lock_irqsave(&cpufreq_driver_lock, flags); 1971da177e4SLinus Torvalds 1981c3d85ddSRafael J. Wysocki if (!cpufreq_driver) 1991c3d85ddSRafael J. Wysocki goto err_out_unlock; 2001c3d85ddSRafael J. Wysocki 2011c3d85ddSRafael J. Wysocki if (!try_module_get(cpufreq_driver->owner)) 2021c3d85ddSRafael J. Wysocki goto err_out_unlock; 2031c3d85ddSRafael J. Wysocki 2041da177e4SLinus Torvalds /* get the CPU */ 2057a6aedfaSMike Travis data = per_cpu(cpufreq_cpu_data, cpu); 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds if (!data) 2081da177e4SLinus Torvalds goto err_out_put_module; 2091da177e4SLinus Torvalds 210a9144436SStephen Boyd if (!sysfs && !kobject_get(&data->kobj)) 2111da177e4SLinus Torvalds goto err_out_put_module; 2121da177e4SLinus Torvalds 2130d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 2141da177e4SLinus Torvalds return data; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds err_out_put_module: 2171c3d85ddSRafael J. Wysocki module_put(cpufreq_driver->owner); 2185800043bSNathan Zimmer err_out_unlock: 2191c3d85ddSRafael J. Wysocki read_unlock_irqrestore(&cpufreq_driver_lock, flags); 2201da177e4SLinus Torvalds err_out: 2211da177e4SLinus Torvalds return NULL; 2221da177e4SLinus Torvalds } 223a9144436SStephen Boyd 224a9144436SStephen Boyd struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) 225a9144436SStephen Boyd { 226d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 227d5aaffa9SDirk Brandewie return NULL; 228d5aaffa9SDirk Brandewie 229a9144436SStephen Boyd return __cpufreq_cpu_get(cpu, false); 230a9144436SStephen Boyd } 2311da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_cpu_get); 2321da177e4SLinus Torvalds 233a9144436SStephen Boyd static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu) 2341da177e4SLinus Torvalds { 235a9144436SStephen Boyd return __cpufreq_cpu_get(cpu, true); 236a9144436SStephen Boyd } 237a9144436SStephen Boyd 238a9144436SStephen Boyd static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs) 239a9144436SStephen Boyd { 240a9144436SStephen Boyd if (!sysfs) 2411da177e4SLinus Torvalds kobject_put(&data->kobj); 2421c3d85ddSRafael J. Wysocki module_put(cpufreq_driver->owner); 2431da177e4SLinus Torvalds } 244a9144436SStephen Boyd 245a9144436SStephen Boyd void cpufreq_cpu_put(struct cpufreq_policy *data) 246a9144436SStephen Boyd { 247d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 248d5aaffa9SDirk Brandewie return; 249d5aaffa9SDirk Brandewie 250a9144436SStephen Boyd __cpufreq_cpu_put(data, false); 251a9144436SStephen Boyd } 2521da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_cpu_put); 2531da177e4SLinus Torvalds 254a9144436SStephen Boyd static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data) 255a9144436SStephen Boyd { 256a9144436SStephen Boyd __cpufreq_cpu_put(data, true); 257a9144436SStephen Boyd } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds /********************************************************************* 2601da177e4SLinus Torvalds * EXTERNALLY AFFECTING FREQUENCY CHANGES * 2611da177e4SLinus Torvalds *********************************************************************/ 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds /** 2641da177e4SLinus Torvalds * adjust_jiffies - adjust the system "loops_per_jiffy" 2651da177e4SLinus Torvalds * 2661da177e4SLinus Torvalds * This function alters the system "loops_per_jiffy" for the clock 2671da177e4SLinus Torvalds * speed change. Note that loops_per_jiffy cannot be updated on SMP 2681da177e4SLinus Torvalds * systems as each CPU might be scaled differently. So, use the arch 2691da177e4SLinus Torvalds * per-CPU loops_per_jiffy value wherever possible. 2701da177e4SLinus Torvalds */ 2711da177e4SLinus Torvalds #ifndef CONFIG_SMP 2721da177e4SLinus Torvalds static unsigned long l_p_j_ref; 2731da177e4SLinus Torvalds static unsigned int l_p_j_ref_freq; 2741da177e4SLinus Torvalds 275858119e1SArjan van de Ven static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) 2761da177e4SLinus Torvalds { 2771da177e4SLinus Torvalds if (ci->flags & CPUFREQ_CONST_LOOPS) 2781da177e4SLinus Torvalds return; 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds if (!l_p_j_ref_freq) { 2811da177e4SLinus Torvalds l_p_j_ref = loops_per_jiffy; 2821da177e4SLinus Torvalds l_p_j_ref_freq = ci->old; 2832d06d8c4SDominik Brodowski pr_debug("saving %lu as reference value for loops_per_jiffy; " 284e08f5f5bSGautham R Shenoy "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq); 2851da177e4SLinus Torvalds } 286d08de0c1SAfzal Mohammed if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) || 28742d4dc3fSBenjamin Herrenschmidt (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { 288e08f5f5bSGautham R Shenoy loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, 289e08f5f5bSGautham R Shenoy ci->new); 2902d06d8c4SDominik Brodowski pr_debug("scaling loops_per_jiffy to %lu " 291e08f5f5bSGautham R Shenoy "for frequency %u kHz\n", loops_per_jiffy, ci->new); 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds #else 295e08f5f5bSGautham R Shenoy static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) 296e08f5f5bSGautham R Shenoy { 297e08f5f5bSGautham R Shenoy return; 298e08f5f5bSGautham R Shenoy } 2991da177e4SLinus Torvalds #endif 3001da177e4SLinus Torvalds 3010956df9cSViresh Kumar static void __cpufreq_notify_transition(struct cpufreq_policy *policy, 302b43a7ffbSViresh Kumar struct cpufreq_freqs *freqs, unsigned int state) 3031da177e4SLinus Torvalds { 3041da177e4SLinus Torvalds BUG_ON(irqs_disabled()); 3051da177e4SLinus Torvalds 306d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 307d5aaffa9SDirk Brandewie return; 308d5aaffa9SDirk Brandewie 3091c3d85ddSRafael J. Wysocki freqs->flags = cpufreq_driver->flags; 3102d06d8c4SDominik Brodowski pr_debug("notification %u of frequency transition to %u kHz\n", 311e4472cb3SDave Jones state, freqs->new); 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds switch (state) { 314e4472cb3SDave Jones 3151da177e4SLinus Torvalds case CPUFREQ_PRECHANGE: 316266c13d7SViresh Kumar if (WARN(policy->transition_ongoing == 317266c13d7SViresh Kumar cpumask_weight(policy->cpus), 3187c30ed53SViresh Kumar "In middle of another frequency transition\n")) 3197c30ed53SViresh Kumar return; 3207c30ed53SViresh Kumar 321266c13d7SViresh Kumar policy->transition_ongoing++; 3227c30ed53SViresh Kumar 323e4472cb3SDave Jones /* detect if the driver reported a value as "old frequency" 324e4472cb3SDave Jones * which is not equal to what the cpufreq core thinks is 325e4472cb3SDave Jones * "old frequency". 3261da177e4SLinus Torvalds */ 3271c3d85ddSRafael J. Wysocki if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { 328e4472cb3SDave Jones if ((policy) && (policy->cpu == freqs->cpu) && 329e4472cb3SDave Jones (policy->cur) && (policy->cur != freqs->old)) { 3302d06d8c4SDominik Brodowski pr_debug("Warning: CPU frequency is" 331e4472cb3SDave Jones " %u, cpufreq assumed %u kHz.\n", 332e4472cb3SDave Jones freqs->old, policy->cur); 333e4472cb3SDave Jones freqs->old = policy->cur; 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds } 336b4dfdbb3SAlan Stern srcu_notifier_call_chain(&cpufreq_transition_notifier_list, 337e4472cb3SDave Jones CPUFREQ_PRECHANGE, freqs); 3381da177e4SLinus Torvalds adjust_jiffies(CPUFREQ_PRECHANGE, freqs); 3391da177e4SLinus Torvalds break; 340e4472cb3SDave Jones 3411da177e4SLinus Torvalds case CPUFREQ_POSTCHANGE: 3427c30ed53SViresh Kumar if (WARN(!policy->transition_ongoing, 3437c30ed53SViresh Kumar "No frequency transition in progress\n")) 3447c30ed53SViresh Kumar return; 3457c30ed53SViresh Kumar 346266c13d7SViresh Kumar policy->transition_ongoing--; 3477c30ed53SViresh Kumar 3481da177e4SLinus Torvalds adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); 3492d06d8c4SDominik Brodowski pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, 3506f4f2723SThomas Renninger (unsigned long)freqs->cpu); 35125e41933SThomas Renninger trace_cpu_frequency(freqs->new, freqs->cpu); 352b4dfdbb3SAlan Stern srcu_notifier_call_chain(&cpufreq_transition_notifier_list, 353e4472cb3SDave Jones CPUFREQ_POSTCHANGE, freqs); 354e4472cb3SDave Jones if (likely(policy) && likely(policy->cpu == freqs->cpu)) 355e4472cb3SDave Jones policy->cur = freqs->new; 3561da177e4SLinus Torvalds break; 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds } 359bb176f7dSViresh Kumar 360b43a7ffbSViresh Kumar /** 361b43a7ffbSViresh Kumar * cpufreq_notify_transition - call notifier chain and adjust_jiffies 362b43a7ffbSViresh Kumar * on frequency transition. 363b43a7ffbSViresh Kumar * 364b43a7ffbSViresh Kumar * This function calls the transition notifiers and the "adjust_jiffies" 365b43a7ffbSViresh Kumar * function. It is called twice on all CPU frequency changes that have 366b43a7ffbSViresh Kumar * external effects. 367b43a7ffbSViresh Kumar */ 368b43a7ffbSViresh Kumar void cpufreq_notify_transition(struct cpufreq_policy *policy, 369b43a7ffbSViresh Kumar struct cpufreq_freqs *freqs, unsigned int state) 370b43a7ffbSViresh Kumar { 371b43a7ffbSViresh Kumar for_each_cpu(freqs->cpu, policy->cpus) 372b43a7ffbSViresh Kumar __cpufreq_notify_transition(policy, freqs, state); 373b43a7ffbSViresh Kumar } 3741da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_notify_transition); 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /********************************************************************* 3781da177e4SLinus Torvalds * SYSFS INTERFACE * 3791da177e4SLinus Torvalds *********************************************************************/ 3801da177e4SLinus Torvalds 3813bcb09a3SJeremy Fitzhardinge static struct cpufreq_governor *__find_governor(const char *str_governor) 3823bcb09a3SJeremy Fitzhardinge { 3833bcb09a3SJeremy Fitzhardinge struct cpufreq_governor *t; 3843bcb09a3SJeremy Fitzhardinge 3853bcb09a3SJeremy Fitzhardinge list_for_each_entry(t, &cpufreq_governor_list, governor_list) 3863bcb09a3SJeremy Fitzhardinge if (!strnicmp(str_governor, t->name, CPUFREQ_NAME_LEN)) 3873bcb09a3SJeremy Fitzhardinge return t; 3883bcb09a3SJeremy Fitzhardinge 3893bcb09a3SJeremy Fitzhardinge return NULL; 3903bcb09a3SJeremy Fitzhardinge } 3913bcb09a3SJeremy Fitzhardinge 3921da177e4SLinus Torvalds /** 3931da177e4SLinus Torvalds * cpufreq_parse_governor - parse a governor string 3941da177e4SLinus Torvalds */ 3951da177e4SLinus Torvalds static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, 3961da177e4SLinus Torvalds struct cpufreq_governor **governor) 3971da177e4SLinus Torvalds { 3983bcb09a3SJeremy Fitzhardinge int err = -EINVAL; 3993bcb09a3SJeremy Fitzhardinge 4001c3d85ddSRafael J. Wysocki if (!cpufreq_driver) 4013bcb09a3SJeremy Fitzhardinge goto out; 4023bcb09a3SJeremy Fitzhardinge 4031c3d85ddSRafael J. Wysocki if (cpufreq_driver->setpolicy) { 4041da177e4SLinus Torvalds if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { 4051da177e4SLinus Torvalds *policy = CPUFREQ_POLICY_PERFORMANCE; 4063bcb09a3SJeremy Fitzhardinge err = 0; 407e08f5f5bSGautham R Shenoy } else if (!strnicmp(str_governor, "powersave", 408e08f5f5bSGautham R Shenoy CPUFREQ_NAME_LEN)) { 4091da177e4SLinus Torvalds *policy = CPUFREQ_POLICY_POWERSAVE; 4103bcb09a3SJeremy Fitzhardinge err = 0; 4111da177e4SLinus Torvalds } 4121c3d85ddSRafael J. Wysocki } else if (cpufreq_driver->target) { 4131da177e4SLinus Torvalds struct cpufreq_governor *t; 4143bcb09a3SJeremy Fitzhardinge 4153fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 4163bcb09a3SJeremy Fitzhardinge 4173bcb09a3SJeremy Fitzhardinge t = __find_governor(str_governor); 4183bcb09a3SJeremy Fitzhardinge 419ea714970SJeremy Fitzhardinge if (t == NULL) { 420ea714970SJeremy Fitzhardinge int ret; 421ea714970SJeremy Fitzhardinge 422ea714970SJeremy Fitzhardinge mutex_unlock(&cpufreq_governor_mutex); 4231a8e1463SKees Cook ret = request_module("cpufreq_%s", str_governor); 424ea714970SJeremy Fitzhardinge mutex_lock(&cpufreq_governor_mutex); 425ea714970SJeremy Fitzhardinge 426ea714970SJeremy Fitzhardinge if (ret == 0) 427ea714970SJeremy Fitzhardinge t = __find_governor(str_governor); 428ea714970SJeremy Fitzhardinge } 429ea714970SJeremy Fitzhardinge 4303bcb09a3SJeremy Fitzhardinge if (t != NULL) { 4311da177e4SLinus Torvalds *governor = t; 4323bcb09a3SJeremy Fitzhardinge err = 0; 4331da177e4SLinus Torvalds } 4343bcb09a3SJeremy Fitzhardinge 4353bcb09a3SJeremy Fitzhardinge mutex_unlock(&cpufreq_governor_mutex); 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds out: 4383bcb09a3SJeremy Fitzhardinge return err; 4391da177e4SLinus Torvalds } 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds /** 442e08f5f5bSGautham R Shenoy * cpufreq_per_cpu_attr_read() / show_##file_name() - 443e08f5f5bSGautham R Shenoy * print out cpufreq information 4441da177e4SLinus Torvalds * 4451da177e4SLinus Torvalds * Write out information from cpufreq_driver->policy[cpu]; object must be 4461da177e4SLinus Torvalds * "unsigned int". 4471da177e4SLinus Torvalds */ 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds #define show_one(file_name, object) \ 4501da177e4SLinus Torvalds static ssize_t show_##file_name \ 4511da177e4SLinus Torvalds (struct cpufreq_policy *policy, char *buf) \ 4521da177e4SLinus Torvalds { \ 4531da177e4SLinus Torvalds return sprintf(buf, "%u\n", policy->object); \ 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds show_one(cpuinfo_min_freq, cpuinfo.min_freq); 4571da177e4SLinus Torvalds show_one(cpuinfo_max_freq, cpuinfo.max_freq); 458ed129784SThomas Renninger show_one(cpuinfo_transition_latency, cpuinfo.transition_latency); 4591da177e4SLinus Torvalds show_one(scaling_min_freq, min); 4601da177e4SLinus Torvalds show_one(scaling_max_freq, max); 4611da177e4SLinus Torvalds show_one(scaling_cur_freq, cur); 4621da177e4SLinus Torvalds 463e08f5f5bSGautham R Shenoy static int __cpufreq_set_policy(struct cpufreq_policy *data, 464e08f5f5bSGautham R Shenoy struct cpufreq_policy *policy); 4657970e08bSThomas Renninger 4661da177e4SLinus Torvalds /** 4671da177e4SLinus Torvalds * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access 4681da177e4SLinus Torvalds */ 4691da177e4SLinus Torvalds #define store_one(file_name, object) \ 4701da177e4SLinus Torvalds static ssize_t store_##file_name \ 4711da177e4SLinus Torvalds (struct cpufreq_policy *policy, const char *buf, size_t count) \ 4721da177e4SLinus Torvalds { \ 473f55c9c26SJingoo Han unsigned int ret; \ 4741da177e4SLinus Torvalds struct cpufreq_policy new_policy; \ 4751da177e4SLinus Torvalds \ 4761da177e4SLinus Torvalds ret = cpufreq_get_policy(&new_policy, policy->cpu); \ 4771da177e4SLinus Torvalds if (ret) \ 4781da177e4SLinus Torvalds return -EINVAL; \ 4791da177e4SLinus Torvalds \ 4801da177e4SLinus Torvalds ret = sscanf(buf, "%u", &new_policy.object); \ 4811da177e4SLinus Torvalds if (ret != 1) \ 4821da177e4SLinus Torvalds return -EINVAL; \ 4831da177e4SLinus Torvalds \ 4847970e08bSThomas Renninger ret = __cpufreq_set_policy(policy, &new_policy); \ 4857970e08bSThomas Renninger policy->user_policy.object = policy->object; \ 4861da177e4SLinus Torvalds \ 4871da177e4SLinus Torvalds return ret ? ret : count; \ 4881da177e4SLinus Torvalds } 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds store_one(scaling_min_freq, min); 4911da177e4SLinus Torvalds store_one(scaling_max_freq, max); 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds /** 4941da177e4SLinus Torvalds * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware 4951da177e4SLinus Torvalds */ 496e08f5f5bSGautham R Shenoy static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy, 497e08f5f5bSGautham R Shenoy char *buf) 4981da177e4SLinus Torvalds { 4995a01f2e8SVenkatesh Pallipadi unsigned int cur_freq = __cpufreq_get(policy->cpu); 5001da177e4SLinus Torvalds if (!cur_freq) 5011da177e4SLinus Torvalds return sprintf(buf, "<unknown>"); 5021da177e4SLinus Torvalds return sprintf(buf, "%u\n", cur_freq); 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds 5051da177e4SLinus Torvalds /** 5061da177e4SLinus Torvalds * show_scaling_governor - show the current policy for the specified CPU 5071da177e4SLinus Torvalds */ 508905d77cdSDave Jones static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) 5091da177e4SLinus Torvalds { 5101da177e4SLinus Torvalds if (policy->policy == CPUFREQ_POLICY_POWERSAVE) 5111da177e4SLinus Torvalds return sprintf(buf, "powersave\n"); 5121da177e4SLinus Torvalds else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) 5131da177e4SLinus Torvalds return sprintf(buf, "performance\n"); 5141da177e4SLinus Torvalds else if (policy->governor) 5154b972f0bSviresh kumar return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", 51629464f28SDave Jones policy->governor->name); 5171da177e4SLinus Torvalds return -EINVAL; 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds /** 5211da177e4SLinus Torvalds * store_scaling_governor - store policy for the specified CPU 5221da177e4SLinus Torvalds */ 5231da177e4SLinus Torvalds static ssize_t store_scaling_governor(struct cpufreq_policy *policy, 5241da177e4SLinus Torvalds const char *buf, size_t count) 5251da177e4SLinus Torvalds { 526f55c9c26SJingoo Han unsigned int ret; 5271da177e4SLinus Torvalds char str_governor[16]; 5281da177e4SLinus Torvalds struct cpufreq_policy new_policy; 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds ret = cpufreq_get_policy(&new_policy, policy->cpu); 5311da177e4SLinus Torvalds if (ret) 5321da177e4SLinus Torvalds return ret; 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds ret = sscanf(buf, "%15s", str_governor); 5351da177e4SLinus Torvalds if (ret != 1) 5361da177e4SLinus Torvalds return -EINVAL; 5371da177e4SLinus Torvalds 538e08f5f5bSGautham R Shenoy if (cpufreq_parse_governor(str_governor, &new_policy.policy, 539e08f5f5bSGautham R Shenoy &new_policy.governor)) 5401da177e4SLinus Torvalds return -EINVAL; 5411da177e4SLinus Torvalds 542bb176f7dSViresh Kumar /* 543bb176f7dSViresh Kumar * Do not use cpufreq_set_policy here or the user_policy.max 544bb176f7dSViresh Kumar * will be wrongly overridden 545bb176f7dSViresh Kumar */ 5467970e08bSThomas Renninger ret = __cpufreq_set_policy(policy, &new_policy); 5477970e08bSThomas Renninger 5487970e08bSThomas Renninger policy->user_policy.policy = policy->policy; 5497970e08bSThomas Renninger policy->user_policy.governor = policy->governor; 5507970e08bSThomas Renninger 551e08f5f5bSGautham R Shenoy if (ret) 552e08f5f5bSGautham R Shenoy return ret; 553e08f5f5bSGautham R Shenoy else 554e08f5f5bSGautham R Shenoy return count; 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds /** 5581da177e4SLinus Torvalds * show_scaling_driver - show the cpufreq driver currently loaded 5591da177e4SLinus Torvalds */ 5601da177e4SLinus Torvalds static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) 5611da177e4SLinus Torvalds { 5621c3d85ddSRafael J. Wysocki return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", cpufreq_driver->name); 5631da177e4SLinus Torvalds } 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds /** 5661da177e4SLinus Torvalds * show_scaling_available_governors - show the available CPUfreq governors 5671da177e4SLinus Torvalds */ 5681da177e4SLinus Torvalds static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, 5691da177e4SLinus Torvalds char *buf) 5701da177e4SLinus Torvalds { 5711da177e4SLinus Torvalds ssize_t i = 0; 5721da177e4SLinus Torvalds struct cpufreq_governor *t; 5731da177e4SLinus Torvalds 5741c3d85ddSRafael J. Wysocki if (!cpufreq_driver->target) { 5751da177e4SLinus Torvalds i += sprintf(buf, "performance powersave"); 5761da177e4SLinus Torvalds goto out; 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds list_for_each_entry(t, &cpufreq_governor_list, governor_list) { 58029464f28SDave Jones if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) 58129464f28SDave Jones - (CPUFREQ_NAME_LEN + 2))) 5821da177e4SLinus Torvalds goto out; 5834b972f0bSviresh kumar i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name); 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds out: 5861da177e4SLinus Torvalds i += sprintf(&buf[i], "\n"); 5871da177e4SLinus Torvalds return i; 5881da177e4SLinus Torvalds } 589e8628dd0SDarrick J. Wong 590f4fd3797SLan Tianyu ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf) 5911da177e4SLinus Torvalds { 5921da177e4SLinus Torvalds ssize_t i = 0; 5931da177e4SLinus Torvalds unsigned int cpu; 5941da177e4SLinus Torvalds 595835481d9SRusty Russell for_each_cpu(cpu, mask) { 5961da177e4SLinus Torvalds if (i) 5971da177e4SLinus Torvalds i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " "); 5981da177e4SLinus Torvalds i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu); 5991da177e4SLinus Torvalds if (i >= (PAGE_SIZE - 5)) 6001da177e4SLinus Torvalds break; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds i += sprintf(&buf[i], "\n"); 6031da177e4SLinus Torvalds return i; 6041da177e4SLinus Torvalds } 605f4fd3797SLan Tianyu EXPORT_SYMBOL_GPL(cpufreq_show_cpus); 6061da177e4SLinus Torvalds 607e8628dd0SDarrick J. Wong /** 608e8628dd0SDarrick J. Wong * show_related_cpus - show the CPUs affected by each transition even if 609e8628dd0SDarrick J. Wong * hw coordination is in use 610e8628dd0SDarrick J. Wong */ 611e8628dd0SDarrick J. Wong static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf) 612e8628dd0SDarrick J. Wong { 613f4fd3797SLan Tianyu return cpufreq_show_cpus(policy->related_cpus, buf); 614e8628dd0SDarrick J. Wong } 615e8628dd0SDarrick J. Wong 616e8628dd0SDarrick J. Wong /** 617e8628dd0SDarrick J. Wong * show_affected_cpus - show the CPUs affected by each transition 618e8628dd0SDarrick J. Wong */ 619e8628dd0SDarrick J. Wong static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) 620e8628dd0SDarrick J. Wong { 621f4fd3797SLan Tianyu return cpufreq_show_cpus(policy->cpus, buf); 622e8628dd0SDarrick J. Wong } 623e8628dd0SDarrick J. Wong 6249e76988eSVenki Pallipadi static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy, 6259e76988eSVenki Pallipadi const char *buf, size_t count) 6269e76988eSVenki Pallipadi { 6279e76988eSVenki Pallipadi unsigned int freq = 0; 6289e76988eSVenki Pallipadi unsigned int ret; 6299e76988eSVenki Pallipadi 630879000f9SCHIKAMA masaki if (!policy->governor || !policy->governor->store_setspeed) 6319e76988eSVenki Pallipadi return -EINVAL; 6329e76988eSVenki Pallipadi 6339e76988eSVenki Pallipadi ret = sscanf(buf, "%u", &freq); 6349e76988eSVenki Pallipadi if (ret != 1) 6359e76988eSVenki Pallipadi return -EINVAL; 6369e76988eSVenki Pallipadi 6379e76988eSVenki Pallipadi policy->governor->store_setspeed(policy, freq); 6389e76988eSVenki Pallipadi 6399e76988eSVenki Pallipadi return count; 6409e76988eSVenki Pallipadi } 6419e76988eSVenki Pallipadi 6429e76988eSVenki Pallipadi static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf) 6439e76988eSVenki Pallipadi { 644879000f9SCHIKAMA masaki if (!policy->governor || !policy->governor->show_setspeed) 6459e76988eSVenki Pallipadi return sprintf(buf, "<unsupported>\n"); 6469e76988eSVenki Pallipadi 6479e76988eSVenki Pallipadi return policy->governor->show_setspeed(policy, buf); 6489e76988eSVenki Pallipadi } 6491da177e4SLinus Torvalds 650e2f74f35SThomas Renninger /** 6518bf1ac72Sviresh kumar * show_bios_limit - show the current cpufreq HW/BIOS limitation 652e2f74f35SThomas Renninger */ 653e2f74f35SThomas Renninger static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) 654e2f74f35SThomas Renninger { 655e2f74f35SThomas Renninger unsigned int limit; 656e2f74f35SThomas Renninger int ret; 6571c3d85ddSRafael J. Wysocki if (cpufreq_driver->bios_limit) { 6581c3d85ddSRafael J. Wysocki ret = cpufreq_driver->bios_limit(policy->cpu, &limit); 659e2f74f35SThomas Renninger if (!ret) 660e2f74f35SThomas Renninger return sprintf(buf, "%u\n", limit); 661e2f74f35SThomas Renninger } 662e2f74f35SThomas Renninger return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); 663e2f74f35SThomas Renninger } 664e2f74f35SThomas Renninger 6656dad2a29SBorislav Petkov cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400); 6666dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_min_freq); 6676dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_max_freq); 6686dad2a29SBorislav Petkov cpufreq_freq_attr_ro(cpuinfo_transition_latency); 6696dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_available_governors); 6706dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_driver); 6716dad2a29SBorislav Petkov cpufreq_freq_attr_ro(scaling_cur_freq); 6726dad2a29SBorislav Petkov cpufreq_freq_attr_ro(bios_limit); 6736dad2a29SBorislav Petkov cpufreq_freq_attr_ro(related_cpus); 6746dad2a29SBorislav Petkov cpufreq_freq_attr_ro(affected_cpus); 6756dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_min_freq); 6766dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_max_freq); 6776dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_governor); 6786dad2a29SBorislav Petkov cpufreq_freq_attr_rw(scaling_setspeed); 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds static struct attribute *default_attrs[] = { 6811da177e4SLinus Torvalds &cpuinfo_min_freq.attr, 6821da177e4SLinus Torvalds &cpuinfo_max_freq.attr, 683ed129784SThomas Renninger &cpuinfo_transition_latency.attr, 6841da177e4SLinus Torvalds &scaling_min_freq.attr, 6851da177e4SLinus Torvalds &scaling_max_freq.attr, 6861da177e4SLinus Torvalds &affected_cpus.attr, 687e8628dd0SDarrick J. Wong &related_cpus.attr, 6881da177e4SLinus Torvalds &scaling_governor.attr, 6891da177e4SLinus Torvalds &scaling_driver.attr, 6901da177e4SLinus Torvalds &scaling_available_governors.attr, 6919e76988eSVenki Pallipadi &scaling_setspeed.attr, 6921da177e4SLinus Torvalds NULL 6931da177e4SLinus Torvalds }; 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds #define to_policy(k) container_of(k, struct cpufreq_policy, kobj) 6961da177e4SLinus Torvalds #define to_attr(a) container_of(a, struct freq_attr, attr) 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) 6991da177e4SLinus Torvalds { 7001da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 7011da177e4SLinus Torvalds struct freq_attr *fattr = to_attr(attr); 7020db4a8a9SDave Jones ssize_t ret = -EINVAL; 703a9144436SStephen Boyd policy = cpufreq_cpu_get_sysfs(policy->cpu); 7041da177e4SLinus Torvalds if (!policy) 7050db4a8a9SDave Jones goto no_policy; 7065a01f2e8SVenkatesh Pallipadi 7075a01f2e8SVenkatesh Pallipadi if (lock_policy_rwsem_read(policy->cpu) < 0) 7080db4a8a9SDave Jones goto fail; 7095a01f2e8SVenkatesh Pallipadi 710e08f5f5bSGautham R Shenoy if (fattr->show) 711e08f5f5bSGautham R Shenoy ret = fattr->show(policy, buf); 712e08f5f5bSGautham R Shenoy else 713e08f5f5bSGautham R Shenoy ret = -EIO; 714e08f5f5bSGautham R Shenoy 7155a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_read(policy->cpu); 7160db4a8a9SDave Jones fail: 717a9144436SStephen Boyd cpufreq_cpu_put_sysfs(policy); 7180db4a8a9SDave Jones no_policy: 7191da177e4SLinus Torvalds return ret; 7201da177e4SLinus Torvalds } 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds static ssize_t store(struct kobject *kobj, struct attribute *attr, 7231da177e4SLinus Torvalds const char *buf, size_t count) 7241da177e4SLinus Torvalds { 7251da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 7261da177e4SLinus Torvalds struct freq_attr *fattr = to_attr(attr); 727a07530b4SDave Jones ssize_t ret = -EINVAL; 728a9144436SStephen Boyd policy = cpufreq_cpu_get_sysfs(policy->cpu); 7291da177e4SLinus Torvalds if (!policy) 730a07530b4SDave Jones goto no_policy; 7315a01f2e8SVenkatesh Pallipadi 7325a01f2e8SVenkatesh Pallipadi if (lock_policy_rwsem_write(policy->cpu) < 0) 733a07530b4SDave Jones goto fail; 7345a01f2e8SVenkatesh Pallipadi 735e08f5f5bSGautham R Shenoy if (fattr->store) 736e08f5f5bSGautham R Shenoy ret = fattr->store(policy, buf, count); 737e08f5f5bSGautham R Shenoy else 738e08f5f5bSGautham R Shenoy ret = -EIO; 739e08f5f5bSGautham R Shenoy 7405a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(policy->cpu); 741a07530b4SDave Jones fail: 742a9144436SStephen Boyd cpufreq_cpu_put_sysfs(policy); 743a07530b4SDave Jones no_policy: 7441da177e4SLinus Torvalds return ret; 7451da177e4SLinus Torvalds } 7461da177e4SLinus Torvalds 7471da177e4SLinus Torvalds static void cpufreq_sysfs_release(struct kobject *kobj) 7481da177e4SLinus Torvalds { 7491da177e4SLinus Torvalds struct cpufreq_policy *policy = to_policy(kobj); 7502d06d8c4SDominik Brodowski pr_debug("last reference is dropped\n"); 7511da177e4SLinus Torvalds complete(&policy->kobj_unregister); 7521da177e4SLinus Torvalds } 7531da177e4SLinus Torvalds 75452cf25d0SEmese Revfy static const struct sysfs_ops sysfs_ops = { 7551da177e4SLinus Torvalds .show = show, 7561da177e4SLinus Torvalds .store = store, 7571da177e4SLinus Torvalds }; 7581da177e4SLinus Torvalds 7591da177e4SLinus Torvalds static struct kobj_type ktype_cpufreq = { 7601da177e4SLinus Torvalds .sysfs_ops = &sysfs_ops, 7611da177e4SLinus Torvalds .default_attrs = default_attrs, 7621da177e4SLinus Torvalds .release = cpufreq_sysfs_release, 7631da177e4SLinus Torvalds }; 7641da177e4SLinus Torvalds 7652361be23SViresh Kumar struct kobject *cpufreq_global_kobject; 7662361be23SViresh Kumar EXPORT_SYMBOL(cpufreq_global_kobject); 7672361be23SViresh Kumar 7682361be23SViresh Kumar static int cpufreq_global_kobject_usage; 7692361be23SViresh Kumar 7702361be23SViresh Kumar int cpufreq_get_global_kobject(void) 7712361be23SViresh Kumar { 7722361be23SViresh Kumar if (!cpufreq_global_kobject_usage++) 7732361be23SViresh Kumar return kobject_add(cpufreq_global_kobject, 7742361be23SViresh Kumar &cpu_subsys.dev_root->kobj, "%s", "cpufreq"); 7752361be23SViresh Kumar 7762361be23SViresh Kumar return 0; 7772361be23SViresh Kumar } 7782361be23SViresh Kumar EXPORT_SYMBOL(cpufreq_get_global_kobject); 7792361be23SViresh Kumar 7802361be23SViresh Kumar void cpufreq_put_global_kobject(void) 7812361be23SViresh Kumar { 7822361be23SViresh Kumar if (!--cpufreq_global_kobject_usage) 7832361be23SViresh Kumar kobject_del(cpufreq_global_kobject); 7842361be23SViresh Kumar } 7852361be23SViresh Kumar EXPORT_SYMBOL(cpufreq_put_global_kobject); 7862361be23SViresh Kumar 7872361be23SViresh Kumar int cpufreq_sysfs_create_file(const struct attribute *attr) 7882361be23SViresh Kumar { 7892361be23SViresh Kumar int ret = cpufreq_get_global_kobject(); 7902361be23SViresh Kumar 7912361be23SViresh Kumar if (!ret) { 7922361be23SViresh Kumar ret = sysfs_create_file(cpufreq_global_kobject, attr); 7932361be23SViresh Kumar if (ret) 7942361be23SViresh Kumar cpufreq_put_global_kobject(); 7952361be23SViresh Kumar } 7962361be23SViresh Kumar 7972361be23SViresh Kumar return ret; 7982361be23SViresh Kumar } 7992361be23SViresh Kumar EXPORT_SYMBOL(cpufreq_sysfs_create_file); 8002361be23SViresh Kumar 8012361be23SViresh Kumar void cpufreq_sysfs_remove_file(const struct attribute *attr) 8022361be23SViresh Kumar { 8032361be23SViresh Kumar sysfs_remove_file(cpufreq_global_kobject, attr); 8042361be23SViresh Kumar cpufreq_put_global_kobject(); 8052361be23SViresh Kumar } 8062361be23SViresh Kumar EXPORT_SYMBOL(cpufreq_sysfs_remove_file); 8072361be23SViresh Kumar 80819d6f7ecSDave Jones /* symlink affected CPUs */ 809308b60e7SViresh Kumar static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy) 81019d6f7ecSDave Jones { 81119d6f7ecSDave Jones unsigned int j; 81219d6f7ecSDave Jones int ret = 0; 81319d6f7ecSDave Jones 81419d6f7ecSDave Jones for_each_cpu(j, policy->cpus) { 8158a25a2fdSKay Sievers struct device *cpu_dev; 81619d6f7ecSDave Jones 817308b60e7SViresh Kumar if (j == policy->cpu) 81819d6f7ecSDave Jones continue; 81919d6f7ecSDave Jones 820e8fdde10SViresh Kumar pr_debug("Adding link for CPU: %u\n", j); 8218a25a2fdSKay Sievers cpu_dev = get_cpu_device(j); 8228a25a2fdSKay Sievers ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, 82319d6f7ecSDave Jones "cpufreq"); 824*71c3461eSRafael J. Wysocki if (ret) 825*71c3461eSRafael J. Wysocki break; 82619d6f7ecSDave Jones } 82719d6f7ecSDave Jones return ret; 82819d6f7ecSDave Jones } 82919d6f7ecSDave Jones 830308b60e7SViresh Kumar static int cpufreq_add_dev_interface(struct cpufreq_policy *policy, 8318a25a2fdSKay Sievers struct device *dev) 832909a694eSDave Jones { 833909a694eSDave Jones struct freq_attr **drv_attr; 834909a694eSDave Jones int ret = 0; 835909a694eSDave Jones 836909a694eSDave Jones /* prepare interface data */ 837909a694eSDave Jones ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, 8388a25a2fdSKay Sievers &dev->kobj, "cpufreq"); 839909a694eSDave Jones if (ret) 840909a694eSDave Jones return ret; 841909a694eSDave Jones 842909a694eSDave Jones /* set up files for this cpu device */ 8431c3d85ddSRafael J. Wysocki drv_attr = cpufreq_driver->attr; 844909a694eSDave Jones while ((drv_attr) && (*drv_attr)) { 845909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); 846909a694eSDave Jones if (ret) 8471c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 848909a694eSDave Jones drv_attr++; 849909a694eSDave Jones } 8501c3d85ddSRafael J. Wysocki if (cpufreq_driver->get) { 851909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); 852909a694eSDave Jones if (ret) 8531c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 854909a694eSDave Jones } 8551c3d85ddSRafael J. Wysocki if (cpufreq_driver->target) { 856909a694eSDave Jones ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); 857909a694eSDave Jones if (ret) 8581c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 859909a694eSDave Jones } 8601c3d85ddSRafael J. Wysocki if (cpufreq_driver->bios_limit) { 861e2f74f35SThomas Renninger ret = sysfs_create_file(&policy->kobj, &bios_limit.attr); 862e2f74f35SThomas Renninger if (ret) 8631c3d85ddSRafael J. Wysocki goto err_out_kobj_put; 864e2f74f35SThomas Renninger } 865909a694eSDave Jones 866308b60e7SViresh Kumar ret = cpufreq_add_dev_symlink(policy); 867ecf7e461SDave Jones if (ret) 868ecf7e461SDave Jones goto err_out_kobj_put; 869ecf7e461SDave Jones 870e18f1682SSrivatsa S. Bhat return ret; 871e18f1682SSrivatsa S. Bhat 872e18f1682SSrivatsa S. Bhat err_out_kobj_put: 873e18f1682SSrivatsa S. Bhat kobject_put(&policy->kobj); 874e18f1682SSrivatsa S. Bhat wait_for_completion(&policy->kobj_unregister); 875e18f1682SSrivatsa S. Bhat return ret; 876e18f1682SSrivatsa S. Bhat } 877e18f1682SSrivatsa S. Bhat 878e18f1682SSrivatsa S. Bhat static void cpufreq_init_policy(struct cpufreq_policy *policy) 879e18f1682SSrivatsa S. Bhat { 880e18f1682SSrivatsa S. Bhat struct cpufreq_policy new_policy; 881e18f1682SSrivatsa S. Bhat int ret = 0; 882e18f1682SSrivatsa S. Bhat 883ecf7e461SDave Jones memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); 884ecf7e461SDave Jones /* assure that the starting sequence is run in __cpufreq_set_policy */ 885ecf7e461SDave Jones policy->governor = NULL; 886ecf7e461SDave Jones 887ecf7e461SDave Jones /* set default policy */ 888ecf7e461SDave Jones ret = __cpufreq_set_policy(policy, &new_policy); 889ecf7e461SDave Jones policy->user_policy.policy = policy->policy; 890ecf7e461SDave Jones policy->user_policy.governor = policy->governor; 891ecf7e461SDave Jones 892ecf7e461SDave Jones if (ret) { 8932d06d8c4SDominik Brodowski pr_debug("setting policy failed\n"); 8941c3d85ddSRafael J. Wysocki if (cpufreq_driver->exit) 8951c3d85ddSRafael J. Wysocki cpufreq_driver->exit(policy); 896ecf7e461SDave Jones } 897909a694eSDave Jones } 898909a694eSDave Jones 899fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 900fcf80582SViresh Kumar static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, 901a82fab29SSrivatsa S. Bhat struct device *dev, bool frozen) 902fcf80582SViresh Kumar { 903fcf80582SViresh Kumar struct cpufreq_policy *policy; 9041c3d85ddSRafael J. Wysocki int ret = 0, has_target = !!cpufreq_driver->target; 905fcf80582SViresh Kumar unsigned long flags; 906fcf80582SViresh Kumar 907fcf80582SViresh Kumar policy = cpufreq_cpu_get(sibling); 908*71c3461eSRafael J. Wysocki if (WARN_ON_ONCE(!policy)) 909*71c3461eSRafael J. Wysocki return -ENODATA; 910fcf80582SViresh Kumar 911820c6ca2SViresh Kumar if (has_target) 912fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_STOP); 913fcf80582SViresh Kumar 9142eaa3e2dSViresh Kumar lock_policy_rwsem_write(sibling); 9152eaa3e2dSViresh Kumar 9160d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 9172eaa3e2dSViresh Kumar 918fcf80582SViresh Kumar cpumask_set_cpu(cpu, policy->cpus); 9192eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu; 920fcf80582SViresh Kumar per_cpu(cpufreq_cpu_data, cpu) = policy; 9210d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 922fcf80582SViresh Kumar 9232eaa3e2dSViresh Kumar unlock_policy_rwsem_write(sibling); 9242eaa3e2dSViresh Kumar 925820c6ca2SViresh Kumar if (has_target) { 926fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_START); 927fcf80582SViresh Kumar __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); 928820c6ca2SViresh Kumar } 929fcf80582SViresh Kumar 930a82fab29SSrivatsa S. Bhat /* Don't touch sysfs links during light-weight init */ 931*71c3461eSRafael J. Wysocki if (!frozen) 932a82fab29SSrivatsa S. Bhat ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); 933a82fab29SSrivatsa S. Bhat 934*71c3461eSRafael J. Wysocki cpufreq_cpu_put(policy); 935a82fab29SSrivatsa S. Bhat return ret; 936fcf80582SViresh Kumar } 937fcf80582SViresh Kumar #endif 9381da177e4SLinus Torvalds 9398414809cSSrivatsa S. Bhat static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu) 9408414809cSSrivatsa S. Bhat { 9418414809cSSrivatsa S. Bhat struct cpufreq_policy *policy; 9428414809cSSrivatsa S. Bhat unsigned long flags; 9438414809cSSrivatsa S. Bhat 9448414809cSSrivatsa S. Bhat write_lock_irqsave(&cpufreq_driver_lock, flags); 9458414809cSSrivatsa S. Bhat 9468414809cSSrivatsa S. Bhat policy = per_cpu(cpufreq_cpu_data_fallback, cpu); 9478414809cSSrivatsa S. Bhat 9488414809cSSrivatsa S. Bhat write_unlock_irqrestore(&cpufreq_driver_lock, flags); 9498414809cSSrivatsa S. Bhat 9508414809cSSrivatsa S. Bhat return policy; 9518414809cSSrivatsa S. Bhat } 9528414809cSSrivatsa S. Bhat 953e9698cc5SSrivatsa S. Bhat static struct cpufreq_policy *cpufreq_policy_alloc(void) 954e9698cc5SSrivatsa S. Bhat { 955e9698cc5SSrivatsa S. Bhat struct cpufreq_policy *policy; 956e9698cc5SSrivatsa S. Bhat 957e9698cc5SSrivatsa S. Bhat policy = kzalloc(sizeof(*policy), GFP_KERNEL); 958e9698cc5SSrivatsa S. Bhat if (!policy) 959e9698cc5SSrivatsa S. Bhat return NULL; 960e9698cc5SSrivatsa S. Bhat 961e9698cc5SSrivatsa S. Bhat if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) 962e9698cc5SSrivatsa S. Bhat goto err_free_policy; 963e9698cc5SSrivatsa S. Bhat 964e9698cc5SSrivatsa S. Bhat if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) 965e9698cc5SSrivatsa S. Bhat goto err_free_cpumask; 966e9698cc5SSrivatsa S. Bhat 967e9698cc5SSrivatsa S. Bhat return policy; 968e9698cc5SSrivatsa S. Bhat 969e9698cc5SSrivatsa S. Bhat err_free_cpumask: 970e9698cc5SSrivatsa S. Bhat free_cpumask_var(policy->cpus); 971e9698cc5SSrivatsa S. Bhat err_free_policy: 972e9698cc5SSrivatsa S. Bhat kfree(policy); 973e9698cc5SSrivatsa S. Bhat 974e9698cc5SSrivatsa S. Bhat return NULL; 975e9698cc5SSrivatsa S. Bhat } 976e9698cc5SSrivatsa S. Bhat 977e9698cc5SSrivatsa S. Bhat static void cpufreq_policy_free(struct cpufreq_policy *policy) 978e9698cc5SSrivatsa S. Bhat { 979e9698cc5SSrivatsa S. Bhat free_cpumask_var(policy->related_cpus); 980e9698cc5SSrivatsa S. Bhat free_cpumask_var(policy->cpus); 981e9698cc5SSrivatsa S. Bhat kfree(policy); 982e9698cc5SSrivatsa S. Bhat } 983e9698cc5SSrivatsa S. Bhat 984a82fab29SSrivatsa S. Bhat static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, 985a82fab29SSrivatsa S. Bhat bool frozen) 9861da177e4SLinus Torvalds { 987fcf80582SViresh Kumar unsigned int j, cpu = dev->id; 98865922465SViresh Kumar int ret = -ENOMEM; 9891da177e4SLinus Torvalds struct cpufreq_policy *policy; 9901da177e4SLinus Torvalds unsigned long flags; 99190e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 992fcf80582SViresh Kumar struct cpufreq_governor *gov; 99390e41bacSPrarit Bhargava int sibling; 99490e41bacSPrarit Bhargava #endif 9951da177e4SLinus Torvalds 996c32b6b8eSAshok Raj if (cpu_is_offline(cpu)) 997c32b6b8eSAshok Raj return 0; 998c32b6b8eSAshok Raj 9992d06d8c4SDominik Brodowski pr_debug("adding CPU %u\n", cpu); 10001da177e4SLinus Torvalds 10011da177e4SLinus Torvalds #ifdef CONFIG_SMP 10021da177e4SLinus Torvalds /* check whether a different CPU already registered this 10031da177e4SLinus Torvalds * CPU because it is in the same boat. */ 10041da177e4SLinus Torvalds policy = cpufreq_cpu_get(cpu); 10051da177e4SLinus Torvalds if (unlikely(policy)) { 10068ff69732SDave Jones cpufreq_cpu_put(policy); 10071da177e4SLinus Torvalds return 0; 10081da177e4SLinus Torvalds } 1009fcf80582SViresh Kumar 1010fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 1011fcf80582SViresh Kumar /* Check if this cpu was hot-unplugged earlier and has siblings */ 10120d1857a1SNathan Zimmer read_lock_irqsave(&cpufreq_driver_lock, flags); 1013fcf80582SViresh Kumar for_each_online_cpu(sibling) { 1014fcf80582SViresh Kumar struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling); 10152eaa3e2dSViresh Kumar if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) { 10160d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1017a82fab29SSrivatsa S. Bhat return cpufreq_add_policy_cpu(cpu, sibling, dev, 1018a82fab29SSrivatsa S. Bhat frozen); 1019fcf80582SViresh Kumar } 10202eaa3e2dSViresh Kumar } 10210d1857a1SNathan Zimmer read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1022fcf80582SViresh Kumar #endif 10231da177e4SLinus Torvalds #endif 10241da177e4SLinus Torvalds 10251c3d85ddSRafael J. Wysocki if (!try_module_get(cpufreq_driver->owner)) { 10261da177e4SLinus Torvalds ret = -EINVAL; 10271da177e4SLinus Torvalds goto module_out; 10281da177e4SLinus Torvalds } 10291da177e4SLinus Torvalds 10308414809cSSrivatsa S. Bhat if (frozen) 10318414809cSSrivatsa S. Bhat /* Restore the saved policy when doing light-weight init */ 10328414809cSSrivatsa S. Bhat policy = cpufreq_policy_restore(cpu); 10338414809cSSrivatsa S. Bhat else 1034e9698cc5SSrivatsa S. Bhat policy = cpufreq_policy_alloc(); 10358414809cSSrivatsa S. Bhat 1036059019a3SDave Jones if (!policy) 10371da177e4SLinus Torvalds goto nomem_out; 1038059019a3SDave Jones 10391da177e4SLinus Torvalds policy->cpu = cpu; 104065922465SViresh Kumar policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 1041835481d9SRusty Russell cpumask_copy(policy->cpus, cpumask_of(cpu)); 10421da177e4SLinus Torvalds 10435a01f2e8SVenkatesh Pallipadi /* Initially set CPU itself as the policy_cpu */ 1044f1625066STejun Heo per_cpu(cpufreq_policy_cpu, cpu) = cpu; 10455a01f2e8SVenkatesh Pallipadi 10461da177e4SLinus Torvalds init_completion(&policy->kobj_unregister); 104765f27f38SDavid Howells INIT_WORK(&policy->update, handle_update); 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds /* call driver. From then on the cpufreq must be able 10501da177e4SLinus Torvalds * to accept all calls to ->verify and ->setpolicy for this CPU 10511da177e4SLinus Torvalds */ 10521c3d85ddSRafael J. Wysocki ret = cpufreq_driver->init(policy); 10531da177e4SLinus Torvalds if (ret) { 10542d06d8c4SDominik Brodowski pr_debug("initialization failed\n"); 10552eaa3e2dSViresh Kumar goto err_set_policy_cpu; 10561da177e4SLinus Torvalds } 1057643ae6e8SViresh Kumar 1058fcf80582SViresh Kumar /* related cpus should atleast have policy->cpus */ 1059fcf80582SViresh Kumar cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); 1060fcf80582SViresh Kumar 1061643ae6e8SViresh Kumar /* 1062643ae6e8SViresh Kumar * affected cpus must always be the one, which are online. We aren't 1063643ae6e8SViresh Kumar * managing offline cpus here. 1064643ae6e8SViresh Kumar */ 1065643ae6e8SViresh Kumar cpumask_and(policy->cpus, policy->cpus, cpu_online_mask); 1066643ae6e8SViresh Kumar 1067187d9f4eSMike Chan policy->user_policy.min = policy->min; 1068187d9f4eSMike Chan policy->user_policy.max = policy->max; 10691da177e4SLinus Torvalds 1070a1531acdSThomas Renninger blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1071a1531acdSThomas Renninger CPUFREQ_START, policy); 1072a1531acdSThomas Renninger 1073fcf80582SViresh Kumar #ifdef CONFIG_HOTPLUG_CPU 1074fcf80582SViresh Kumar gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu)); 1075fcf80582SViresh Kumar if (gov) { 1076fcf80582SViresh Kumar policy->governor = gov; 1077fcf80582SViresh Kumar pr_debug("Restoring governor %s for cpu %d\n", 1078fcf80582SViresh Kumar policy->governor->name, cpu); 10794bfa042cSThomas Renninger } 1080fcf80582SViresh Kumar #endif 10811da177e4SLinus Torvalds 1082e18f1682SSrivatsa S. Bhat write_lock_irqsave(&cpufreq_driver_lock, flags); 1083e18f1682SSrivatsa S. Bhat for_each_cpu(j, policy->cpus) { 1084e18f1682SSrivatsa S. Bhat per_cpu(cpufreq_cpu_data, j) = policy; 1085e18f1682SSrivatsa S. Bhat per_cpu(cpufreq_policy_cpu, j) = policy->cpu; 1086e18f1682SSrivatsa S. Bhat } 1087e18f1682SSrivatsa S. Bhat write_unlock_irqrestore(&cpufreq_driver_lock, flags); 1088e18f1682SSrivatsa S. Bhat 1089a82fab29SSrivatsa S. Bhat if (!frozen) { 1090308b60e7SViresh Kumar ret = cpufreq_add_dev_interface(policy, dev); 109119d6f7ecSDave Jones if (ret) 10920142f9dcSAhmed S. Darwish goto err_out_unregister; 1093a82fab29SSrivatsa S. Bhat } 10948ff69732SDave Jones 1095e18f1682SSrivatsa S. Bhat cpufreq_init_policy(policy); 1096e18f1682SSrivatsa S. Bhat 1097038c5b3eSGreg Kroah-Hartman kobject_uevent(&policy->kobj, KOBJ_ADD); 10981c3d85ddSRafael J. Wysocki module_put(cpufreq_driver->owner); 10992d06d8c4SDominik Brodowski pr_debug("initialization complete\n"); 11001da177e4SLinus Torvalds 11011da177e4SLinus Torvalds return 0; 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds err_out_unregister: 11040d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 1105e18f1682SSrivatsa S. Bhat for_each_cpu(j, policy->cpus) { 11067a6aedfaSMike Travis per_cpu(cpufreq_cpu_data, j) = NULL; 1107e18f1682SSrivatsa S. Bhat if (j != cpu) 1108e18f1682SSrivatsa S. Bhat per_cpu(cpufreq_policy_cpu, j) = -1; 1109e18f1682SSrivatsa S. Bhat } 11100d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 11111da177e4SLinus Torvalds 1112c10997f6SGreg Kroah-Hartman kobject_put(&policy->kobj); 11131da177e4SLinus Torvalds wait_for_completion(&policy->kobj_unregister); 11141da177e4SLinus Torvalds 11152eaa3e2dSViresh Kumar err_set_policy_cpu: 11162eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = -1; 1117e9698cc5SSrivatsa S. Bhat cpufreq_policy_free(policy); 11181da177e4SLinus Torvalds nomem_out: 11191c3d85ddSRafael J. Wysocki module_put(cpufreq_driver->owner); 11201da177e4SLinus Torvalds module_out: 11211da177e4SLinus Torvalds return ret; 11221da177e4SLinus Torvalds } 11231da177e4SLinus Torvalds 1124a82fab29SSrivatsa S. Bhat /** 1125a82fab29SSrivatsa S. Bhat * cpufreq_add_dev - add a CPU device 1126a82fab29SSrivatsa S. Bhat * 1127a82fab29SSrivatsa S. Bhat * Adds the cpufreq interface for a CPU device. 1128a82fab29SSrivatsa S. Bhat * 1129a82fab29SSrivatsa S. Bhat * The Oracle says: try running cpufreq registration/unregistration concurrently 1130a82fab29SSrivatsa S. Bhat * with with cpu hotplugging and all hell will break loose. Tried to clean this 1131a82fab29SSrivatsa S. Bhat * mess up, but more thorough testing is needed. - Mathieu 1132a82fab29SSrivatsa S. Bhat */ 1133a82fab29SSrivatsa S. Bhat static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) 1134a82fab29SSrivatsa S. Bhat { 1135a82fab29SSrivatsa S. Bhat return __cpufreq_add_dev(dev, sif, false); 1136a82fab29SSrivatsa S. Bhat } 1137a82fab29SSrivatsa S. Bhat 1138b8eed8afSViresh Kumar static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) 1139b8eed8afSViresh Kumar { 1140b8eed8afSViresh Kumar int j; 1141b8eed8afSViresh Kumar 1142b8eed8afSViresh Kumar policy->last_cpu = policy->cpu; 1143b8eed8afSViresh Kumar policy->cpu = cpu; 1144b8eed8afSViresh Kumar 11453361b7b1SViresh Kumar for_each_cpu(j, policy->cpus) 1146b8eed8afSViresh Kumar per_cpu(cpufreq_policy_cpu, j) = cpu; 1147b8eed8afSViresh Kumar 1148b8eed8afSViresh Kumar #ifdef CONFIG_CPU_FREQ_TABLE 1149b8eed8afSViresh Kumar cpufreq_frequency_table_update_policy_cpu(policy); 1150b8eed8afSViresh Kumar #endif 1151b8eed8afSViresh Kumar blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1152b8eed8afSViresh Kumar CPUFREQ_UPDATE_POLICY_CPU, policy); 1153b8eed8afSViresh Kumar } 11541da177e4SLinus Torvalds 1155f9ba680dSSrivatsa S. Bhat static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data, 1156a82fab29SSrivatsa S. Bhat unsigned int old_cpu, bool frozen) 1157f9ba680dSSrivatsa S. Bhat { 1158f9ba680dSSrivatsa S. Bhat struct device *cpu_dev; 1159f9ba680dSSrivatsa S. Bhat unsigned long flags; 1160f9ba680dSSrivatsa S. Bhat int ret; 1161f9ba680dSSrivatsa S. Bhat 1162f9ba680dSSrivatsa S. Bhat /* first sibling now owns the new sysfs dir */ 1163f9ba680dSSrivatsa S. Bhat cpu_dev = get_cpu_device(cpumask_first(data->cpus)); 1164a82fab29SSrivatsa S. Bhat 1165a82fab29SSrivatsa S. Bhat /* Don't touch sysfs files during light-weight tear-down */ 1166a82fab29SSrivatsa S. Bhat if (frozen) 1167a82fab29SSrivatsa S. Bhat return cpu_dev->id; 1168a82fab29SSrivatsa S. Bhat 1169f9ba680dSSrivatsa S. Bhat sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); 1170f9ba680dSSrivatsa S. Bhat ret = kobject_move(&data->kobj, &cpu_dev->kobj); 1171f9ba680dSSrivatsa S. Bhat if (ret) { 1172f9ba680dSSrivatsa S. Bhat pr_err("%s: Failed to move kobj: %d", __func__, ret); 1173f9ba680dSSrivatsa S. Bhat 1174f9ba680dSSrivatsa S. Bhat WARN_ON(lock_policy_rwsem_write(old_cpu)); 1175f9ba680dSSrivatsa S. Bhat cpumask_set_cpu(old_cpu, data->cpus); 1176f9ba680dSSrivatsa S. Bhat 1177f9ba680dSSrivatsa S. Bhat write_lock_irqsave(&cpufreq_driver_lock, flags); 1178f9ba680dSSrivatsa S. Bhat per_cpu(cpufreq_cpu_data, old_cpu) = data; 1179f9ba680dSSrivatsa S. Bhat write_unlock_irqrestore(&cpufreq_driver_lock, flags); 1180f9ba680dSSrivatsa S. Bhat 1181f9ba680dSSrivatsa S. Bhat unlock_policy_rwsem_write(old_cpu); 1182f9ba680dSSrivatsa S. Bhat 1183f9ba680dSSrivatsa S. Bhat ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj, 1184f9ba680dSSrivatsa S. Bhat "cpufreq"); 1185f9ba680dSSrivatsa S. Bhat 1186f9ba680dSSrivatsa S. Bhat return -EINVAL; 1187f9ba680dSSrivatsa S. Bhat } 1188f9ba680dSSrivatsa S. Bhat 1189f9ba680dSSrivatsa S. Bhat return cpu_dev->id; 1190f9ba680dSSrivatsa S. Bhat } 1191f9ba680dSSrivatsa S. Bhat 11921da177e4SLinus Torvalds /** 11935a01f2e8SVenkatesh Pallipadi * __cpufreq_remove_dev - remove a CPU device 11941da177e4SLinus Torvalds * 11951da177e4SLinus Torvalds * Removes the cpufreq interface for a CPU device. 11965a01f2e8SVenkatesh Pallipadi * Caller should already have policy_rwsem in write mode for this CPU. 11975a01f2e8SVenkatesh Pallipadi * This routine frees the rwsem before returning. 11981da177e4SLinus Torvalds */ 1199bb176f7dSViresh Kumar static int __cpufreq_remove_dev(struct device *dev, 1200a82fab29SSrivatsa S. Bhat struct subsys_interface *sif, bool frozen) 12011da177e4SLinus Torvalds { 1202f9ba680dSSrivatsa S. Bhat unsigned int cpu = dev->id, cpus; 1203f9ba680dSSrivatsa S. Bhat int new_cpu; 12041da177e4SLinus Torvalds unsigned long flags; 12051da177e4SLinus Torvalds struct cpufreq_policy *data; 1206499bca9bSAmerigo Wang struct kobject *kobj; 1207499bca9bSAmerigo Wang struct completion *cmp; 12081da177e4SLinus Torvalds 1209b8eed8afSViresh Kumar pr_debug("%s: unregistering CPU %u\n", __func__, cpu); 12101da177e4SLinus Torvalds 12110d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds data = per_cpu(cpufreq_cpu_data, cpu); 12147a6aedfaSMike Travis per_cpu(cpufreq_cpu_data, cpu) = NULL; 12151da177e4SLinus Torvalds 12168414809cSSrivatsa S. Bhat /* Save the policy somewhere when doing a light-weight tear-down */ 12178414809cSSrivatsa S. Bhat if (frozen) 12188414809cSSrivatsa S. Bhat per_cpu(cpufreq_cpu_data_fallback, cpu) = data; 12198414809cSSrivatsa S. Bhat 12200d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds if (!data) { 1223b8eed8afSViresh Kumar pr_debug("%s: No cpu_data found\n", __func__); 12241da177e4SLinus Torvalds return -EINVAL; 12251da177e4SLinus Torvalds } 12261da177e4SLinus Torvalds 12271c3d85ddSRafael J. Wysocki if (cpufreq_driver->target) 12281da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_STOP); 12295a01f2e8SVenkatesh Pallipadi 12301da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG_CPU 12311c3d85ddSRafael J. Wysocki if (!cpufreq_driver->setpolicy) 1232fa69e33fSDirk Brandewie strncpy(per_cpu(cpufreq_cpu_governor, cpu), 1233fa69e33fSDirk Brandewie data->governor->name, CPUFREQ_NAME_LEN); 12341da177e4SLinus Torvalds #endif 12351da177e4SLinus Torvalds 12362eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1237b8eed8afSViresh Kumar cpus = cpumask_weight(data->cpus); 1238e4969ebaSViresh Kumar 1239e4969ebaSViresh Kumar if (cpus > 1) 1240b8eed8afSViresh Kumar cpumask_clear_cpu(cpu, data->cpus); 12412eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 12421da177e4SLinus Torvalds 1243a82fab29SSrivatsa S. Bhat if (cpu != data->cpu && !frozen) { 124473bf0fc2SViresh Kumar sysfs_remove_link(&dev->kobj, "cpufreq"); 124573bf0fc2SViresh Kumar } else if (cpus > 1) { 12462eaa3e2dSViresh Kumar 1247a82fab29SSrivatsa S. Bhat new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu, frozen); 1248f9ba680dSSrivatsa S. Bhat if (new_cpu >= 0) { 12492eaa3e2dSViresh Kumar WARN_ON(lock_policy_rwsem_write(cpu)); 1250f9ba680dSSrivatsa S. Bhat update_policy_cpu(data, new_cpu); 12512eaa3e2dSViresh Kumar unlock_policy_rwsem_write(cpu); 1252a82fab29SSrivatsa S. Bhat 1253a82fab29SSrivatsa S. Bhat if (!frozen) { 1254f9ba680dSSrivatsa S. Bhat pr_debug("%s: policy Kobject moved to cpu: %d " 1255f9ba680dSSrivatsa S. Bhat "from: %d\n",__func__, new_cpu, cpu); 12561da177e4SLinus Torvalds } 12571da177e4SLinus Torvalds } 1258a82fab29SSrivatsa S. Bhat } 1259b8eed8afSViresh Kumar 1260b8eed8afSViresh Kumar /* If cpu is last user of policy, free policy */ 1261b8eed8afSViresh Kumar if (cpus == 1) { 12622a998599SRafael J. Wysocki if (cpufreq_driver->target) 12632a998599SRafael J. Wysocki __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); 12642a998599SRafael J. Wysocki 12658414809cSSrivatsa S. Bhat if (!frozen) { 12662eaa3e2dSViresh Kumar lock_policy_rwsem_read(cpu); 1267499bca9bSAmerigo Wang kobj = &data->kobj; 1268499bca9bSAmerigo Wang cmp = &data->kobj_unregister; 12692eaa3e2dSViresh Kumar unlock_policy_rwsem_read(cpu); 1270499bca9bSAmerigo Wang kobject_put(kobj); 12711da177e4SLinus Torvalds 12728414809cSSrivatsa S. Bhat /* 12738414809cSSrivatsa S. Bhat * We need to make sure that the underlying kobj is 12748414809cSSrivatsa S. Bhat * actually not referenced anymore by anybody before we 12758414809cSSrivatsa S. Bhat * proceed with unloading. 12761da177e4SLinus Torvalds */ 12772d06d8c4SDominik Brodowski pr_debug("waiting for dropping of refcount\n"); 1278499bca9bSAmerigo Wang wait_for_completion(cmp); 12792d06d8c4SDominik Brodowski pr_debug("wait complete\n"); 12808414809cSSrivatsa S. Bhat } 12811da177e4SLinus Torvalds 12828414809cSSrivatsa S. Bhat /* 12838414809cSSrivatsa S. Bhat * Perform the ->exit() even during light-weight tear-down, 12848414809cSSrivatsa S. Bhat * since this is a core component, and is essential for the 12858414809cSSrivatsa S. Bhat * subsequent light-weight ->init() to succeed. 12868414809cSSrivatsa S. Bhat */ 12871c3d85ddSRafael J. Wysocki if (cpufreq_driver->exit) 12881c3d85ddSRafael J. Wysocki cpufreq_driver->exit(data); 128927ecddc2SJacob Shin 12908414809cSSrivatsa S. Bhat if (!frozen) 1291e9698cc5SSrivatsa S. Bhat cpufreq_policy_free(data); 12922a998599SRafael J. Wysocki } else { 12932a998599SRafael J. Wysocki if (cpufreq_driver->target) { 1294b8eed8afSViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_START); 1295b8eed8afSViresh Kumar __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); 1296b8eed8afSViresh Kumar } 12972a998599SRafael J. Wysocki } 12981da177e4SLinus Torvalds 12992eaa3e2dSViresh Kumar per_cpu(cpufreq_policy_cpu, cpu) = -1; 13001da177e4SLinus Torvalds return 0; 13011da177e4SLinus Torvalds } 13021da177e4SLinus Torvalds 13038a25a2fdSKay Sievers static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) 13045a01f2e8SVenkatesh Pallipadi { 13058a25a2fdSKay Sievers unsigned int cpu = dev->id; 13065a01f2e8SVenkatesh Pallipadi int retval; 1307ec28297aSVenki Pallipadi 1308ec28297aSVenki Pallipadi if (cpu_is_offline(cpu)) 1309ec28297aSVenki Pallipadi return 0; 1310ec28297aSVenki Pallipadi 1311a82fab29SSrivatsa S. Bhat retval = __cpufreq_remove_dev(dev, sif, false); 13125a01f2e8SVenkatesh Pallipadi return retval; 13135a01f2e8SVenkatesh Pallipadi } 13145a01f2e8SVenkatesh Pallipadi 131565f27f38SDavid Howells static void handle_update(struct work_struct *work) 13161da177e4SLinus Torvalds { 131765f27f38SDavid Howells struct cpufreq_policy *policy = 131865f27f38SDavid Howells container_of(work, struct cpufreq_policy, update); 131965f27f38SDavid Howells unsigned int cpu = policy->cpu; 13202d06d8c4SDominik Brodowski pr_debug("handle_update for cpu %u called\n", cpu); 13211da177e4SLinus Torvalds cpufreq_update_policy(cpu); 13221da177e4SLinus Torvalds } 13231da177e4SLinus Torvalds 13241da177e4SLinus Torvalds /** 1325bb176f7dSViresh Kumar * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're 1326bb176f7dSViresh Kumar * in deep trouble. 13271da177e4SLinus Torvalds * @cpu: cpu number 13281da177e4SLinus Torvalds * @old_freq: CPU frequency the kernel thinks the CPU runs at 13291da177e4SLinus Torvalds * @new_freq: CPU frequency the CPU actually runs at 13301da177e4SLinus Torvalds * 133129464f28SDave Jones * We adjust to current frequency first, and need to clean up later. 133229464f28SDave Jones * So either call to cpufreq_update_policy() or schedule handle_update()). 13331da177e4SLinus Torvalds */ 1334e08f5f5bSGautham R Shenoy static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, 1335e08f5f5bSGautham R Shenoy unsigned int new_freq) 13361da177e4SLinus Torvalds { 1337b43a7ffbSViresh Kumar struct cpufreq_policy *policy; 13381da177e4SLinus Torvalds struct cpufreq_freqs freqs; 1339b43a7ffbSViresh Kumar unsigned long flags; 1340b43a7ffbSViresh Kumar 13412d06d8c4SDominik Brodowski pr_debug("Warning: CPU frequency out of sync: cpufreq and timing " 13421da177e4SLinus Torvalds "core thinks of %u, is %u kHz.\n", old_freq, new_freq); 13431da177e4SLinus Torvalds 13441da177e4SLinus Torvalds freqs.old = old_freq; 13451da177e4SLinus Torvalds freqs.new = new_freq; 1346b43a7ffbSViresh Kumar 1347b43a7ffbSViresh Kumar read_lock_irqsave(&cpufreq_driver_lock, flags); 1348b43a7ffbSViresh Kumar policy = per_cpu(cpufreq_cpu_data, cpu); 1349b43a7ffbSViresh Kumar read_unlock_irqrestore(&cpufreq_driver_lock, flags); 1350b43a7ffbSViresh Kumar 1351b43a7ffbSViresh Kumar cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); 1352b43a7ffbSViresh Kumar cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); 13531da177e4SLinus Torvalds } 13541da177e4SLinus Torvalds 13551da177e4SLinus Torvalds /** 13564ab70df4SDhaval Giani * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur 135795235ca2SVenkatesh Pallipadi * @cpu: CPU number 135895235ca2SVenkatesh Pallipadi * 135995235ca2SVenkatesh Pallipadi * This is the last known freq, without actually getting it from the driver. 136095235ca2SVenkatesh Pallipadi * Return value will be same as what is shown in scaling_cur_freq in sysfs. 136195235ca2SVenkatesh Pallipadi */ 136295235ca2SVenkatesh Pallipadi unsigned int cpufreq_quick_get(unsigned int cpu) 136395235ca2SVenkatesh Pallipadi { 13649e21ba8bSDirk Brandewie struct cpufreq_policy *policy; 1365e08f5f5bSGautham R Shenoy unsigned int ret_freq = 0; 136695235ca2SVenkatesh Pallipadi 13671c3d85ddSRafael J. Wysocki if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get) 13681c3d85ddSRafael J. Wysocki return cpufreq_driver->get(cpu); 13699e21ba8bSDirk Brandewie 13709e21ba8bSDirk Brandewie policy = cpufreq_cpu_get(cpu); 137195235ca2SVenkatesh Pallipadi if (policy) { 1372e08f5f5bSGautham R Shenoy ret_freq = policy->cur; 137395235ca2SVenkatesh Pallipadi cpufreq_cpu_put(policy); 137495235ca2SVenkatesh Pallipadi } 137595235ca2SVenkatesh Pallipadi 13764d34a67dSDave Jones return ret_freq; 137795235ca2SVenkatesh Pallipadi } 137895235ca2SVenkatesh Pallipadi EXPORT_SYMBOL(cpufreq_quick_get); 137995235ca2SVenkatesh Pallipadi 13803d737108SJesse Barnes /** 13813d737108SJesse Barnes * cpufreq_quick_get_max - get the max reported CPU frequency for this CPU 13823d737108SJesse Barnes * @cpu: CPU number 13833d737108SJesse Barnes * 13843d737108SJesse Barnes * Just return the max possible frequency for a given CPU. 13853d737108SJesse Barnes */ 13863d737108SJesse Barnes unsigned int cpufreq_quick_get_max(unsigned int cpu) 13873d737108SJesse Barnes { 13883d737108SJesse Barnes struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 13893d737108SJesse Barnes unsigned int ret_freq = 0; 13903d737108SJesse Barnes 13913d737108SJesse Barnes if (policy) { 13923d737108SJesse Barnes ret_freq = policy->max; 13933d737108SJesse Barnes cpufreq_cpu_put(policy); 13943d737108SJesse Barnes } 13953d737108SJesse Barnes 13963d737108SJesse Barnes return ret_freq; 13973d737108SJesse Barnes } 13983d737108SJesse Barnes EXPORT_SYMBOL(cpufreq_quick_get_max); 13993d737108SJesse Barnes 14005a01f2e8SVenkatesh Pallipadi static unsigned int __cpufreq_get(unsigned int cpu) 14011da177e4SLinus Torvalds { 14027a6aedfaSMike Travis struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); 1403e08f5f5bSGautham R Shenoy unsigned int ret_freq = 0; 14041da177e4SLinus Torvalds 14051c3d85ddSRafael J. Wysocki if (!cpufreq_driver->get) 14064d34a67dSDave Jones return ret_freq; 14071da177e4SLinus Torvalds 14081c3d85ddSRafael J. Wysocki ret_freq = cpufreq_driver->get(cpu); 14091da177e4SLinus Torvalds 1410e08f5f5bSGautham R Shenoy if (ret_freq && policy->cur && 14111c3d85ddSRafael J. Wysocki !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { 1412e08f5f5bSGautham R Shenoy /* verify no discrepancy between actual and 1413e08f5f5bSGautham R Shenoy saved value exists */ 1414e08f5f5bSGautham R Shenoy if (unlikely(ret_freq != policy->cur)) { 1415e08f5f5bSGautham R Shenoy cpufreq_out_of_sync(cpu, policy->cur, ret_freq); 14161da177e4SLinus Torvalds schedule_work(&policy->update); 14171da177e4SLinus Torvalds } 14181da177e4SLinus Torvalds } 14191da177e4SLinus Torvalds 14204d34a67dSDave Jones return ret_freq; 14215a01f2e8SVenkatesh Pallipadi } 14221da177e4SLinus Torvalds 14235a01f2e8SVenkatesh Pallipadi /** 14245a01f2e8SVenkatesh Pallipadi * cpufreq_get - get the current CPU frequency (in kHz) 14255a01f2e8SVenkatesh Pallipadi * @cpu: CPU number 14265a01f2e8SVenkatesh Pallipadi * 14275a01f2e8SVenkatesh Pallipadi * Get the CPU current (static) CPU frequency 14285a01f2e8SVenkatesh Pallipadi */ 14295a01f2e8SVenkatesh Pallipadi unsigned int cpufreq_get(unsigned int cpu) 14305a01f2e8SVenkatesh Pallipadi { 14315a01f2e8SVenkatesh Pallipadi unsigned int ret_freq = 0; 14325a01f2e8SVenkatesh Pallipadi struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); 14335a01f2e8SVenkatesh Pallipadi 14345a01f2e8SVenkatesh Pallipadi if (!policy) 14355a01f2e8SVenkatesh Pallipadi goto out; 14365a01f2e8SVenkatesh Pallipadi 14375a01f2e8SVenkatesh Pallipadi if (unlikely(lock_policy_rwsem_read(cpu))) 14385a01f2e8SVenkatesh Pallipadi goto out_policy; 14395a01f2e8SVenkatesh Pallipadi 14405a01f2e8SVenkatesh Pallipadi ret_freq = __cpufreq_get(cpu); 14415a01f2e8SVenkatesh Pallipadi 14425a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_read(cpu); 14435a01f2e8SVenkatesh Pallipadi 14445a01f2e8SVenkatesh Pallipadi out_policy: 14451da177e4SLinus Torvalds cpufreq_cpu_put(policy); 14465a01f2e8SVenkatesh Pallipadi out: 14474d34a67dSDave Jones return ret_freq; 14481da177e4SLinus Torvalds } 14491da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_get); 14501da177e4SLinus Torvalds 14518a25a2fdSKay Sievers static struct subsys_interface cpufreq_interface = { 14528a25a2fdSKay Sievers .name = "cpufreq", 14538a25a2fdSKay Sievers .subsys = &cpu_subsys, 14548a25a2fdSKay Sievers .add_dev = cpufreq_add_dev, 14558a25a2fdSKay Sievers .remove_dev = cpufreq_remove_dev, 1456e00e56dfSRafael J. Wysocki }; 1457e00e56dfSRafael J. Wysocki 14581da177e4SLinus Torvalds /** 1459e00e56dfSRafael J. Wysocki * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. 1460e00e56dfSRafael J. Wysocki * 1461e00e56dfSRafael J. Wysocki * This function is only executed for the boot processor. The other CPUs 1462e00e56dfSRafael J. Wysocki * have been put offline by means of CPU hotplug. 146342d4dc3fSBenjamin Herrenschmidt */ 1464e00e56dfSRafael J. Wysocki static int cpufreq_bp_suspend(void) 146542d4dc3fSBenjamin Herrenschmidt { 1466e08f5f5bSGautham R Shenoy int ret = 0; 14674bc5d341SDave Jones 1468e00e56dfSRafael J. Wysocki int cpu = smp_processor_id(); 146942d4dc3fSBenjamin Herrenschmidt struct cpufreq_policy *cpu_policy; 147042d4dc3fSBenjamin Herrenschmidt 14712d06d8c4SDominik Brodowski pr_debug("suspending cpu %u\n", cpu); 147242d4dc3fSBenjamin Herrenschmidt 1473e00e56dfSRafael J. Wysocki /* If there's no policy for the boot CPU, we have nothing to do. */ 147442d4dc3fSBenjamin Herrenschmidt cpu_policy = cpufreq_cpu_get(cpu); 147542d4dc3fSBenjamin Herrenschmidt if (!cpu_policy) 1476e00e56dfSRafael J. Wysocki return 0; 147742d4dc3fSBenjamin Herrenschmidt 14781c3d85ddSRafael J. Wysocki if (cpufreq_driver->suspend) { 14791c3d85ddSRafael J. Wysocki ret = cpufreq_driver->suspend(cpu_policy); 1480ce6c3997SDominik Brodowski if (ret) 148142d4dc3fSBenjamin Herrenschmidt printk(KERN_ERR "cpufreq: suspend failed in ->suspend " 148242d4dc3fSBenjamin Herrenschmidt "step on CPU %u\n", cpu_policy->cpu); 148342d4dc3fSBenjamin Herrenschmidt } 148442d4dc3fSBenjamin Herrenschmidt 148542d4dc3fSBenjamin Herrenschmidt cpufreq_cpu_put(cpu_policy); 1486c9060494SDave Jones return ret; 148742d4dc3fSBenjamin Herrenschmidt } 148842d4dc3fSBenjamin Herrenschmidt 148942d4dc3fSBenjamin Herrenschmidt /** 1490e00e56dfSRafael J. Wysocki * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU. 14911da177e4SLinus Torvalds * 14921da177e4SLinus Torvalds * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) 1493ce6c3997SDominik Brodowski * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are 1494ce6c3997SDominik Brodowski * restored. It will verify that the current freq is in sync with 1495ce6c3997SDominik Brodowski * what we believe it to be. This is a bit later than when it 1496ce6c3997SDominik Brodowski * should be, but nonethteless it's better than calling 1497ce6c3997SDominik Brodowski * cpufreq_driver->get() here which might re-enable interrupts... 1498e00e56dfSRafael J. Wysocki * 1499e00e56dfSRafael J. Wysocki * This function is only executed for the boot CPU. The other CPUs have not 1500e00e56dfSRafael J. Wysocki * been turned on yet. 15011da177e4SLinus Torvalds */ 1502e00e56dfSRafael J. Wysocki static void cpufreq_bp_resume(void) 15031da177e4SLinus Torvalds { 1504e08f5f5bSGautham R Shenoy int ret = 0; 15054bc5d341SDave Jones 1506e00e56dfSRafael J. Wysocki int cpu = smp_processor_id(); 15071da177e4SLinus Torvalds struct cpufreq_policy *cpu_policy; 15081da177e4SLinus Torvalds 15092d06d8c4SDominik Brodowski pr_debug("resuming cpu %u\n", cpu); 15101da177e4SLinus Torvalds 1511e00e56dfSRafael J. Wysocki /* If there's no policy for the boot CPU, we have nothing to do. */ 15121da177e4SLinus Torvalds cpu_policy = cpufreq_cpu_get(cpu); 15131da177e4SLinus Torvalds if (!cpu_policy) 1514e00e56dfSRafael J. Wysocki return; 15151da177e4SLinus Torvalds 15161c3d85ddSRafael J. Wysocki if (cpufreq_driver->resume) { 15171c3d85ddSRafael J. Wysocki ret = cpufreq_driver->resume(cpu_policy); 15181da177e4SLinus Torvalds if (ret) { 15191da177e4SLinus Torvalds printk(KERN_ERR "cpufreq: resume failed in ->resume " 15201da177e4SLinus Torvalds "step on CPU %u\n", cpu_policy->cpu); 1521c9060494SDave Jones goto fail; 15221da177e4SLinus Torvalds } 15231da177e4SLinus Torvalds } 15241da177e4SLinus Torvalds 15251da177e4SLinus Torvalds schedule_work(&cpu_policy->update); 1526ce6c3997SDominik Brodowski 1527c9060494SDave Jones fail: 15281da177e4SLinus Torvalds cpufreq_cpu_put(cpu_policy); 15291da177e4SLinus Torvalds } 15301da177e4SLinus Torvalds 1531e00e56dfSRafael J. Wysocki static struct syscore_ops cpufreq_syscore_ops = { 1532e00e56dfSRafael J. Wysocki .suspend = cpufreq_bp_suspend, 1533e00e56dfSRafael J. Wysocki .resume = cpufreq_bp_resume, 15341da177e4SLinus Torvalds }; 15351da177e4SLinus Torvalds 15369d95046eSBorislav Petkov /** 15379d95046eSBorislav Petkov * cpufreq_get_current_driver - return current driver's name 15389d95046eSBorislav Petkov * 15399d95046eSBorislav Petkov * Return the name string of the currently loaded cpufreq driver 15409d95046eSBorislav Petkov * or NULL, if none. 15419d95046eSBorislav Petkov */ 15429d95046eSBorislav Petkov const char *cpufreq_get_current_driver(void) 15439d95046eSBorislav Petkov { 15441c3d85ddSRafael J. Wysocki if (cpufreq_driver) 15451c3d85ddSRafael J. Wysocki return cpufreq_driver->name; 15461c3d85ddSRafael J. Wysocki 15471c3d85ddSRafael J. Wysocki return NULL; 15489d95046eSBorislav Petkov } 15499d95046eSBorislav Petkov EXPORT_SYMBOL_GPL(cpufreq_get_current_driver); 15501da177e4SLinus Torvalds 15511da177e4SLinus Torvalds /********************************************************************* 15521da177e4SLinus Torvalds * NOTIFIER LISTS INTERFACE * 15531da177e4SLinus Torvalds *********************************************************************/ 15541da177e4SLinus Torvalds 15551da177e4SLinus Torvalds /** 15561da177e4SLinus Torvalds * cpufreq_register_notifier - register a driver with cpufreq 15571da177e4SLinus Torvalds * @nb: notifier function to register 15581da177e4SLinus Torvalds * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER 15591da177e4SLinus Torvalds * 15601da177e4SLinus Torvalds * Add a driver to one of two lists: either a list of drivers that 15611da177e4SLinus Torvalds * are notified about clock rate changes (once before and once after 15621da177e4SLinus Torvalds * the transition), or a list of drivers that are notified about 15631da177e4SLinus Torvalds * changes in cpufreq policy. 15641da177e4SLinus Torvalds * 15651da177e4SLinus Torvalds * This function may sleep, and has the same return conditions as 1566e041c683SAlan Stern * blocking_notifier_chain_register. 15671da177e4SLinus Torvalds */ 15681da177e4SLinus Torvalds int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) 15691da177e4SLinus Torvalds { 15701da177e4SLinus Torvalds int ret; 15711da177e4SLinus Torvalds 1572d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1573d5aaffa9SDirk Brandewie return -EINVAL; 1574d5aaffa9SDirk Brandewie 157574212ca4SCesar Eduardo Barros WARN_ON(!init_cpufreq_transition_notifier_list_called); 157674212ca4SCesar Eduardo Barros 15771da177e4SLinus Torvalds switch (list) { 15781da177e4SLinus Torvalds case CPUFREQ_TRANSITION_NOTIFIER: 1579b4dfdbb3SAlan Stern ret = srcu_notifier_chain_register( 1580e041c683SAlan Stern &cpufreq_transition_notifier_list, nb); 15811da177e4SLinus Torvalds break; 15821da177e4SLinus Torvalds case CPUFREQ_POLICY_NOTIFIER: 1583e041c683SAlan Stern ret = blocking_notifier_chain_register( 1584e041c683SAlan Stern &cpufreq_policy_notifier_list, nb); 15851da177e4SLinus Torvalds break; 15861da177e4SLinus Torvalds default: 15871da177e4SLinus Torvalds ret = -EINVAL; 15881da177e4SLinus Torvalds } 15891da177e4SLinus Torvalds 15901da177e4SLinus Torvalds return ret; 15911da177e4SLinus Torvalds } 15921da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_register_notifier); 15931da177e4SLinus Torvalds 15941da177e4SLinus Torvalds /** 15951da177e4SLinus Torvalds * cpufreq_unregister_notifier - unregister a driver with cpufreq 15961da177e4SLinus Torvalds * @nb: notifier block to be unregistered 15971da177e4SLinus Torvalds * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER 15981da177e4SLinus Torvalds * 15991da177e4SLinus Torvalds * Remove a driver from the CPU frequency notifier list. 16001da177e4SLinus Torvalds * 16011da177e4SLinus Torvalds * This function may sleep, and has the same return conditions as 1602e041c683SAlan Stern * blocking_notifier_chain_unregister. 16031da177e4SLinus Torvalds */ 16041da177e4SLinus Torvalds int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) 16051da177e4SLinus Torvalds { 16061da177e4SLinus Torvalds int ret; 16071da177e4SLinus Torvalds 1608d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1609d5aaffa9SDirk Brandewie return -EINVAL; 1610d5aaffa9SDirk Brandewie 16111da177e4SLinus Torvalds switch (list) { 16121da177e4SLinus Torvalds case CPUFREQ_TRANSITION_NOTIFIER: 1613b4dfdbb3SAlan Stern ret = srcu_notifier_chain_unregister( 1614e041c683SAlan Stern &cpufreq_transition_notifier_list, nb); 16151da177e4SLinus Torvalds break; 16161da177e4SLinus Torvalds case CPUFREQ_POLICY_NOTIFIER: 1617e041c683SAlan Stern ret = blocking_notifier_chain_unregister( 1618e041c683SAlan Stern &cpufreq_policy_notifier_list, nb); 16191da177e4SLinus Torvalds break; 16201da177e4SLinus Torvalds default: 16211da177e4SLinus Torvalds ret = -EINVAL; 16221da177e4SLinus Torvalds } 16231da177e4SLinus Torvalds 16241da177e4SLinus Torvalds return ret; 16251da177e4SLinus Torvalds } 16261da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_unregister_notifier); 16271da177e4SLinus Torvalds 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds /********************************************************************* 16301da177e4SLinus Torvalds * GOVERNORS * 16311da177e4SLinus Torvalds *********************************************************************/ 16321da177e4SLinus Torvalds 16331da177e4SLinus Torvalds int __cpufreq_driver_target(struct cpufreq_policy *policy, 16341da177e4SLinus Torvalds unsigned int target_freq, 16351da177e4SLinus Torvalds unsigned int relation) 16361da177e4SLinus Torvalds { 16371da177e4SLinus Torvalds int retval = -EINVAL; 16387249924eSViresh Kumar unsigned int old_target_freq = target_freq; 1639c32b6b8eSAshok Raj 1640a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1641a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 16427c30ed53SViresh Kumar if (policy->transition_ongoing) 16437c30ed53SViresh Kumar return -EBUSY; 1644a7b422cdSKonrad Rzeszutek Wilk 16457249924eSViresh Kumar /* Make sure that target_freq is within supported range */ 16467249924eSViresh Kumar if (target_freq > policy->max) 16477249924eSViresh Kumar target_freq = policy->max; 16487249924eSViresh Kumar if (target_freq < policy->min) 16497249924eSViresh Kumar target_freq = policy->min; 16507249924eSViresh Kumar 16517249924eSViresh Kumar pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", 16527249924eSViresh Kumar policy->cpu, target_freq, relation, old_target_freq); 16535a1c0228SViresh Kumar 16545a1c0228SViresh Kumar if (target_freq == policy->cur) 16555a1c0228SViresh Kumar return 0; 16565a1c0228SViresh Kumar 16571c3d85ddSRafael J. Wysocki if (cpufreq_driver->target) 16581c3d85ddSRafael J. Wysocki retval = cpufreq_driver->target(policy, target_freq, relation); 165990d45d17SAshok Raj 16601da177e4SLinus Torvalds return retval; 16611da177e4SLinus Torvalds } 16621da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(__cpufreq_driver_target); 16631da177e4SLinus Torvalds 16641da177e4SLinus Torvalds int cpufreq_driver_target(struct cpufreq_policy *policy, 16651da177e4SLinus Torvalds unsigned int target_freq, 16661da177e4SLinus Torvalds unsigned int relation) 16671da177e4SLinus Torvalds { 1668f1829e4aSJulia Lawall int ret = -EINVAL; 16691da177e4SLinus Torvalds 16705a01f2e8SVenkatesh Pallipadi if (unlikely(lock_policy_rwsem_write(policy->cpu))) 1671f1829e4aSJulia Lawall goto fail; 16721da177e4SLinus Torvalds 16731da177e4SLinus Torvalds ret = __cpufreq_driver_target(policy, target_freq, relation); 16741da177e4SLinus Torvalds 16755a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(policy->cpu); 16761da177e4SLinus Torvalds 1677f1829e4aSJulia Lawall fail: 16781da177e4SLinus Torvalds return ret; 16791da177e4SLinus Torvalds } 16801da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_driver_target); 16811da177e4SLinus Torvalds 1682bf0b90e3Svenkatesh.pallipadi@intel.com int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) 1683dfde5d62SVenkatesh Pallipadi { 1684d5aaffa9SDirk Brandewie if (cpufreq_disabled()) 1685a262e94cSViresh Kumar return 0; 1686d5aaffa9SDirk Brandewie 16871c3d85ddSRafael J. Wysocki if (!cpufreq_driver->getavg) 16880676f7f2SViresh Kumar return 0; 16890676f7f2SViresh Kumar 1690a262e94cSViresh Kumar return cpufreq_driver->getavg(policy, cpu); 1691dfde5d62SVenkatesh Pallipadi } 16925a01f2e8SVenkatesh Pallipadi EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg); 1693dfde5d62SVenkatesh Pallipadi 1694153d7f3fSArjan van de Ven /* 1695153d7f3fSArjan van de Ven * when "event" is CPUFREQ_GOV_LIMITS 1696153d7f3fSArjan van de Ven */ 16971da177e4SLinus Torvalds 1698e08f5f5bSGautham R Shenoy static int __cpufreq_governor(struct cpufreq_policy *policy, 1699e08f5f5bSGautham R Shenoy unsigned int event) 17001da177e4SLinus Torvalds { 1701cc993cabSDave Jones int ret; 17026afde10cSThomas Renninger 17036afde10cSThomas Renninger /* Only must be defined when default governor is known to have latency 17046afde10cSThomas Renninger restrictions, like e.g. conservative or ondemand. 17056afde10cSThomas Renninger That this is the case is already ensured in Kconfig 17066afde10cSThomas Renninger */ 17076afde10cSThomas Renninger #ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE 17086afde10cSThomas Renninger struct cpufreq_governor *gov = &cpufreq_gov_performance; 17096afde10cSThomas Renninger #else 17106afde10cSThomas Renninger struct cpufreq_governor *gov = NULL; 17116afde10cSThomas Renninger #endif 17121c256245SThomas Renninger 17131c256245SThomas Renninger if (policy->governor->max_transition_latency && 17141c256245SThomas Renninger policy->cpuinfo.transition_latency > 17151c256245SThomas Renninger policy->governor->max_transition_latency) { 17166afde10cSThomas Renninger if (!gov) 17176afde10cSThomas Renninger return -EINVAL; 17186afde10cSThomas Renninger else { 17191c256245SThomas Renninger printk(KERN_WARNING "%s governor failed, too long" 17201c256245SThomas Renninger " transition latency of HW, fallback" 17211c256245SThomas Renninger " to %s governor\n", 17221c256245SThomas Renninger policy->governor->name, 17231c256245SThomas Renninger gov->name); 17241c256245SThomas Renninger policy->governor = gov; 17251c256245SThomas Renninger } 17266afde10cSThomas Renninger } 17271da177e4SLinus Torvalds 17281da177e4SLinus Torvalds if (!try_module_get(policy->governor->owner)) 17291da177e4SLinus Torvalds return -EINVAL; 17301da177e4SLinus Torvalds 17312d06d8c4SDominik Brodowski pr_debug("__cpufreq_governor for CPU %u, event %u\n", 1732e08f5f5bSGautham R Shenoy policy->cpu, event); 173395731ebbSXiaoguang Chen 173495731ebbSXiaoguang Chen mutex_lock(&cpufreq_governor_lock); 173595731ebbSXiaoguang Chen if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) || 173695731ebbSXiaoguang Chen (policy->governor_enabled && (event == CPUFREQ_GOV_START))) { 173795731ebbSXiaoguang Chen mutex_unlock(&cpufreq_governor_lock); 173895731ebbSXiaoguang Chen return -EBUSY; 173995731ebbSXiaoguang Chen } 174095731ebbSXiaoguang Chen 174195731ebbSXiaoguang Chen if (event == CPUFREQ_GOV_STOP) 174295731ebbSXiaoguang Chen policy->governor_enabled = false; 174395731ebbSXiaoguang Chen else if (event == CPUFREQ_GOV_START) 174495731ebbSXiaoguang Chen policy->governor_enabled = true; 174595731ebbSXiaoguang Chen 174695731ebbSXiaoguang Chen mutex_unlock(&cpufreq_governor_lock); 174795731ebbSXiaoguang Chen 17481da177e4SLinus Torvalds ret = policy->governor->governor(policy, event); 17491da177e4SLinus Torvalds 17504d5dcc42SViresh Kumar if (!ret) { 17514d5dcc42SViresh Kumar if (event == CPUFREQ_GOV_POLICY_INIT) 17528e53695fSViresh Kumar policy->governor->initialized++; 17534d5dcc42SViresh Kumar else if (event == CPUFREQ_GOV_POLICY_EXIT) 17548e53695fSViresh Kumar policy->governor->initialized--; 175595731ebbSXiaoguang Chen } else { 175695731ebbSXiaoguang Chen /* Restore original values */ 175795731ebbSXiaoguang Chen mutex_lock(&cpufreq_governor_lock); 175895731ebbSXiaoguang Chen if (event == CPUFREQ_GOV_STOP) 175995731ebbSXiaoguang Chen policy->governor_enabled = true; 176095731ebbSXiaoguang Chen else if (event == CPUFREQ_GOV_START) 176195731ebbSXiaoguang Chen policy->governor_enabled = false; 176295731ebbSXiaoguang Chen mutex_unlock(&cpufreq_governor_lock); 17634d5dcc42SViresh Kumar } 1764b394058fSViresh Kumar 1765e08f5f5bSGautham R Shenoy /* we keep one module reference alive for 1766e08f5f5bSGautham R Shenoy each CPU governed by this CPU */ 17671da177e4SLinus Torvalds if ((event != CPUFREQ_GOV_START) || ret) 17681da177e4SLinus Torvalds module_put(policy->governor->owner); 17691da177e4SLinus Torvalds if ((event == CPUFREQ_GOV_STOP) && !ret) 17701da177e4SLinus Torvalds module_put(policy->governor->owner); 17711da177e4SLinus Torvalds 17721da177e4SLinus Torvalds return ret; 17731da177e4SLinus Torvalds } 17741da177e4SLinus Torvalds 17751da177e4SLinus Torvalds int cpufreq_register_governor(struct cpufreq_governor *governor) 17761da177e4SLinus Torvalds { 17773bcb09a3SJeremy Fitzhardinge int err; 17781da177e4SLinus Torvalds 17791da177e4SLinus Torvalds if (!governor) 17801da177e4SLinus Torvalds return -EINVAL; 17811da177e4SLinus Torvalds 1782a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1783a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 1784a7b422cdSKonrad Rzeszutek Wilk 17853fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 17861da177e4SLinus Torvalds 1787b394058fSViresh Kumar governor->initialized = 0; 17883bcb09a3SJeremy Fitzhardinge err = -EBUSY; 17893bcb09a3SJeremy Fitzhardinge if (__find_governor(governor->name) == NULL) { 17903bcb09a3SJeremy Fitzhardinge err = 0; 17911da177e4SLinus Torvalds list_add(&governor->governor_list, &cpufreq_governor_list); 17923bcb09a3SJeremy Fitzhardinge } 17931da177e4SLinus Torvalds 17943fc54d37Sakpm@osdl.org mutex_unlock(&cpufreq_governor_mutex); 17953bcb09a3SJeremy Fitzhardinge return err; 17961da177e4SLinus Torvalds } 17971da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_register_governor); 17981da177e4SLinus Torvalds 17991da177e4SLinus Torvalds void cpufreq_unregister_governor(struct cpufreq_governor *governor) 18001da177e4SLinus Torvalds { 180190e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 180290e41bacSPrarit Bhargava int cpu; 180390e41bacSPrarit Bhargava #endif 180490e41bacSPrarit Bhargava 18051da177e4SLinus Torvalds if (!governor) 18061da177e4SLinus Torvalds return; 18071da177e4SLinus Torvalds 1808a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 1809a7b422cdSKonrad Rzeszutek Wilk return; 1810a7b422cdSKonrad Rzeszutek Wilk 181190e41bacSPrarit Bhargava #ifdef CONFIG_HOTPLUG_CPU 181290e41bacSPrarit Bhargava for_each_present_cpu(cpu) { 181390e41bacSPrarit Bhargava if (cpu_online(cpu)) 181490e41bacSPrarit Bhargava continue; 181590e41bacSPrarit Bhargava if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name)) 181690e41bacSPrarit Bhargava strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0"); 181790e41bacSPrarit Bhargava } 181890e41bacSPrarit Bhargava #endif 181990e41bacSPrarit Bhargava 18203fc54d37Sakpm@osdl.org mutex_lock(&cpufreq_governor_mutex); 18211da177e4SLinus Torvalds list_del(&governor->governor_list); 18223fc54d37Sakpm@osdl.org mutex_unlock(&cpufreq_governor_mutex); 18231da177e4SLinus Torvalds return; 18241da177e4SLinus Torvalds } 18251da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_unregister_governor); 18261da177e4SLinus Torvalds 18271da177e4SLinus Torvalds 18281da177e4SLinus Torvalds /********************************************************************* 18291da177e4SLinus Torvalds * POLICY INTERFACE * 18301da177e4SLinus Torvalds *********************************************************************/ 18311da177e4SLinus Torvalds 18321da177e4SLinus Torvalds /** 18331da177e4SLinus Torvalds * cpufreq_get_policy - get the current cpufreq_policy 183429464f28SDave Jones * @policy: struct cpufreq_policy into which the current cpufreq_policy 183529464f28SDave Jones * is written 18361da177e4SLinus Torvalds * 18371da177e4SLinus Torvalds * Reads the current cpufreq policy. 18381da177e4SLinus Torvalds */ 18391da177e4SLinus Torvalds int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) 18401da177e4SLinus Torvalds { 18411da177e4SLinus Torvalds struct cpufreq_policy *cpu_policy; 18421da177e4SLinus Torvalds if (!policy) 18431da177e4SLinus Torvalds return -EINVAL; 18441da177e4SLinus Torvalds 18451da177e4SLinus Torvalds cpu_policy = cpufreq_cpu_get(cpu); 18461da177e4SLinus Torvalds if (!cpu_policy) 18471da177e4SLinus Torvalds return -EINVAL; 18481da177e4SLinus Torvalds 18491da177e4SLinus Torvalds memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy)); 18501da177e4SLinus Torvalds 18511da177e4SLinus Torvalds cpufreq_cpu_put(cpu_policy); 18521da177e4SLinus Torvalds return 0; 18531da177e4SLinus Torvalds } 18541da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_get_policy); 18551da177e4SLinus Torvalds 1856153d7f3fSArjan van de Ven /* 1857e08f5f5bSGautham R Shenoy * data : current policy. 1858e08f5f5bSGautham R Shenoy * policy : policy to be set. 1859153d7f3fSArjan van de Ven */ 1860e08f5f5bSGautham R Shenoy static int __cpufreq_set_policy(struct cpufreq_policy *data, 1861e08f5f5bSGautham R Shenoy struct cpufreq_policy *policy) 18621da177e4SLinus Torvalds { 18637bd353a9SViresh Kumar int ret = 0, failed = 1; 18641da177e4SLinus Torvalds 18652d06d8c4SDominik Brodowski pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, 18661da177e4SLinus Torvalds policy->min, policy->max); 18671da177e4SLinus Torvalds 1868e08f5f5bSGautham R Shenoy memcpy(&policy->cpuinfo, &data->cpuinfo, 1869e08f5f5bSGautham R Shenoy sizeof(struct cpufreq_cpuinfo)); 18701da177e4SLinus Torvalds 187153391fa2SYi Yang if (policy->min > data->max || policy->max < data->min) { 18729c9a43edSMattia Dongili ret = -EINVAL; 18739c9a43edSMattia Dongili goto error_out; 18749c9a43edSMattia Dongili } 18759c9a43edSMattia Dongili 18761da177e4SLinus Torvalds /* verify the cpu speed can be set within this limit */ 18771c3d85ddSRafael J. Wysocki ret = cpufreq_driver->verify(policy); 18781da177e4SLinus Torvalds if (ret) 18791da177e4SLinus Torvalds goto error_out; 18801da177e4SLinus Torvalds 18811da177e4SLinus Torvalds /* adjust if necessary - all reasons */ 1882e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1883e041c683SAlan Stern CPUFREQ_ADJUST, policy); 18841da177e4SLinus Torvalds 18851da177e4SLinus Torvalds /* adjust if necessary - hardware incompatibility*/ 1886e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1887e041c683SAlan Stern CPUFREQ_INCOMPATIBLE, policy); 18881da177e4SLinus Torvalds 1889bb176f7dSViresh Kumar /* 1890bb176f7dSViresh Kumar * verify the cpu speed can be set within this limit, which might be 1891bb176f7dSViresh Kumar * different to the first one 1892bb176f7dSViresh Kumar */ 18931c3d85ddSRafael J. Wysocki ret = cpufreq_driver->verify(policy); 1894e041c683SAlan Stern if (ret) 18951da177e4SLinus Torvalds goto error_out; 18961da177e4SLinus Torvalds 18971da177e4SLinus Torvalds /* notification of the new policy */ 1898e041c683SAlan Stern blocking_notifier_call_chain(&cpufreq_policy_notifier_list, 1899e041c683SAlan Stern CPUFREQ_NOTIFY, policy); 19001da177e4SLinus Torvalds 19011da177e4SLinus Torvalds data->min = policy->min; 19021da177e4SLinus Torvalds data->max = policy->max; 19031da177e4SLinus Torvalds 19042d06d8c4SDominik Brodowski pr_debug("new min and max freqs are %u - %u kHz\n", 1905e08f5f5bSGautham R Shenoy data->min, data->max); 19061da177e4SLinus Torvalds 19071c3d85ddSRafael J. Wysocki if (cpufreq_driver->setpolicy) { 19081da177e4SLinus Torvalds data->policy = policy->policy; 19092d06d8c4SDominik Brodowski pr_debug("setting range\n"); 19101c3d85ddSRafael J. Wysocki ret = cpufreq_driver->setpolicy(policy); 19111da177e4SLinus Torvalds } else { 19121da177e4SLinus Torvalds if (policy->governor != data->governor) { 19131da177e4SLinus Torvalds /* save old, working values */ 19141da177e4SLinus Torvalds struct cpufreq_governor *old_gov = data->governor; 19151da177e4SLinus Torvalds 19162d06d8c4SDominik Brodowski pr_debug("governor switch\n"); 19171da177e4SLinus Torvalds 19181da177e4SLinus Torvalds /* end old governor */ 19197bd353a9SViresh Kumar if (data->governor) { 19201da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_STOP); 1921955ef483SViresh Kumar unlock_policy_rwsem_write(policy->cpu); 19227bd353a9SViresh Kumar __cpufreq_governor(data, 19237bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 1924955ef483SViresh Kumar lock_policy_rwsem_write(policy->cpu); 19257bd353a9SViresh Kumar } 19261da177e4SLinus Torvalds 19271da177e4SLinus Torvalds /* start new governor */ 19281da177e4SLinus Torvalds data->governor = policy->governor; 19297bd353a9SViresh Kumar if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) { 1930955ef483SViresh Kumar if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) { 19317bd353a9SViresh Kumar failed = 0; 1932955ef483SViresh Kumar } else { 1933955ef483SViresh Kumar unlock_policy_rwsem_write(policy->cpu); 19347bd353a9SViresh Kumar __cpufreq_governor(data, 19357bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_EXIT); 1936955ef483SViresh Kumar lock_policy_rwsem_write(policy->cpu); 1937955ef483SViresh Kumar } 19387bd353a9SViresh Kumar } 19397bd353a9SViresh Kumar 19407bd353a9SViresh Kumar if (failed) { 19411da177e4SLinus Torvalds /* new governor failed, so re-start old one */ 19422d06d8c4SDominik Brodowski pr_debug("starting governor %s failed\n", 1943e08f5f5bSGautham R Shenoy data->governor->name); 19441da177e4SLinus Torvalds if (old_gov) { 19451da177e4SLinus Torvalds data->governor = old_gov; 1946e08f5f5bSGautham R Shenoy __cpufreq_governor(data, 19477bd353a9SViresh Kumar CPUFREQ_GOV_POLICY_INIT); 19487bd353a9SViresh Kumar __cpufreq_governor(data, 1949e08f5f5bSGautham R Shenoy CPUFREQ_GOV_START); 19501da177e4SLinus Torvalds } 19511da177e4SLinus Torvalds ret = -EINVAL; 19521da177e4SLinus Torvalds goto error_out; 19531da177e4SLinus Torvalds } 19541da177e4SLinus Torvalds /* might be a policy change, too, so fall through */ 19551da177e4SLinus Torvalds } 19562d06d8c4SDominik Brodowski pr_debug("governor: change or update limits\n"); 19571da177e4SLinus Torvalds __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); 19581da177e4SLinus Torvalds } 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvalds error_out: 19611da177e4SLinus Torvalds return ret; 19621da177e4SLinus Torvalds } 19631da177e4SLinus Torvalds 19641da177e4SLinus Torvalds /** 19651da177e4SLinus Torvalds * cpufreq_update_policy - re-evaluate an existing cpufreq policy 19661da177e4SLinus Torvalds * @cpu: CPU which shall be re-evaluated 19671da177e4SLinus Torvalds * 196825985edcSLucas De Marchi * Useful for policy notifiers which have different necessities 19691da177e4SLinus Torvalds * at different times. 19701da177e4SLinus Torvalds */ 19711da177e4SLinus Torvalds int cpufreq_update_policy(unsigned int cpu) 19721da177e4SLinus Torvalds { 19731da177e4SLinus Torvalds struct cpufreq_policy *data = cpufreq_cpu_get(cpu); 19741da177e4SLinus Torvalds struct cpufreq_policy policy; 1975f1829e4aSJulia Lawall int ret; 19761da177e4SLinus Torvalds 1977f1829e4aSJulia Lawall if (!data) { 1978f1829e4aSJulia Lawall ret = -ENODEV; 1979f1829e4aSJulia Lawall goto no_policy; 1980f1829e4aSJulia Lawall } 19811da177e4SLinus Torvalds 1982f1829e4aSJulia Lawall if (unlikely(lock_policy_rwsem_write(cpu))) { 1983f1829e4aSJulia Lawall ret = -EINVAL; 1984f1829e4aSJulia Lawall goto fail; 1985f1829e4aSJulia Lawall } 19861da177e4SLinus Torvalds 19872d06d8c4SDominik Brodowski pr_debug("updating policy for CPU %u\n", cpu); 19887d5e350fSDave Jones memcpy(&policy, data, sizeof(struct cpufreq_policy)); 19891da177e4SLinus Torvalds policy.min = data->user_policy.min; 19901da177e4SLinus Torvalds policy.max = data->user_policy.max; 19911da177e4SLinus Torvalds policy.policy = data->user_policy.policy; 19921da177e4SLinus Torvalds policy.governor = data->user_policy.governor; 19931da177e4SLinus Torvalds 1994bb176f7dSViresh Kumar /* 1995bb176f7dSViresh Kumar * BIOS might change freq behind our back 1996bb176f7dSViresh Kumar * -> ask driver for current freq and notify governors about a change 1997bb176f7dSViresh Kumar */ 19981c3d85ddSRafael J. Wysocki if (cpufreq_driver->get) { 19991c3d85ddSRafael J. Wysocki policy.cur = cpufreq_driver->get(cpu); 2000a85f7bd3SThomas Renninger if (!data->cur) { 20012d06d8c4SDominik Brodowski pr_debug("Driver did not initialize current freq"); 2002a85f7bd3SThomas Renninger data->cur = policy.cur; 2003a85f7bd3SThomas Renninger } else { 20041c3d85ddSRafael J. Wysocki if (data->cur != policy.cur && cpufreq_driver->target) 2005e08f5f5bSGautham R Shenoy cpufreq_out_of_sync(cpu, data->cur, 2006e08f5f5bSGautham R Shenoy policy.cur); 20070961dd0dSThomas Renninger } 2008a85f7bd3SThomas Renninger } 20090961dd0dSThomas Renninger 20101da177e4SLinus Torvalds ret = __cpufreq_set_policy(data, &policy); 20111da177e4SLinus Torvalds 20125a01f2e8SVenkatesh Pallipadi unlock_policy_rwsem_write(cpu); 20135a01f2e8SVenkatesh Pallipadi 2014f1829e4aSJulia Lawall fail: 20151da177e4SLinus Torvalds cpufreq_cpu_put(data); 2016f1829e4aSJulia Lawall no_policy: 20171da177e4SLinus Torvalds return ret; 20181da177e4SLinus Torvalds } 20191da177e4SLinus Torvalds EXPORT_SYMBOL(cpufreq_update_policy); 20201da177e4SLinus Torvalds 20212760984fSPaul Gortmaker static int cpufreq_cpu_callback(struct notifier_block *nfb, 2022c32b6b8eSAshok Raj unsigned long action, void *hcpu) 2023c32b6b8eSAshok Raj { 2024c32b6b8eSAshok Raj unsigned int cpu = (unsigned long)hcpu; 20258a25a2fdSKay Sievers struct device *dev; 20265302c3fbSSrivatsa S. Bhat bool frozen = false; 2027c32b6b8eSAshok Raj 20288a25a2fdSKay Sievers dev = get_cpu_device(cpu); 20298a25a2fdSKay Sievers if (dev) { 20305302c3fbSSrivatsa S. Bhat 20315302c3fbSSrivatsa S. Bhat if (action & CPU_TASKS_FROZEN) 20325302c3fbSSrivatsa S. Bhat frozen = true; 20335302c3fbSSrivatsa S. Bhat 20345302c3fbSSrivatsa S. Bhat switch (action & ~CPU_TASKS_FROZEN) { 2035c32b6b8eSAshok Raj case CPU_ONLINE: 20365302c3fbSSrivatsa S. Bhat __cpufreq_add_dev(dev, NULL, frozen); 203723d32899SSrivatsa S. Bhat cpufreq_update_policy(cpu); 2038c32b6b8eSAshok Raj break; 20395302c3fbSSrivatsa S. Bhat 2040c32b6b8eSAshok Raj case CPU_DOWN_PREPARE: 20415302c3fbSSrivatsa S. Bhat __cpufreq_remove_dev(dev, NULL, frozen); 2042c32b6b8eSAshok Raj break; 20435302c3fbSSrivatsa S. Bhat 20445a01f2e8SVenkatesh Pallipadi case CPU_DOWN_FAILED: 20455302c3fbSSrivatsa S. Bhat __cpufreq_add_dev(dev, NULL, frozen); 2046c32b6b8eSAshok Raj break; 2047c32b6b8eSAshok Raj } 2048c32b6b8eSAshok Raj } 2049c32b6b8eSAshok Raj return NOTIFY_OK; 2050c32b6b8eSAshok Raj } 2051c32b6b8eSAshok Raj 20529c36f746SNeal Buckendahl static struct notifier_block __refdata cpufreq_cpu_notifier = { 2053c32b6b8eSAshok Raj .notifier_call = cpufreq_cpu_callback, 2054c32b6b8eSAshok Raj }; 20551da177e4SLinus Torvalds 20561da177e4SLinus Torvalds /********************************************************************* 20571da177e4SLinus Torvalds * REGISTER / UNREGISTER CPUFREQ DRIVER * 20581da177e4SLinus Torvalds *********************************************************************/ 20591da177e4SLinus Torvalds 20601da177e4SLinus Torvalds /** 20611da177e4SLinus Torvalds * cpufreq_register_driver - register a CPU Frequency driver 20621da177e4SLinus Torvalds * @driver_data: A struct cpufreq_driver containing the values# 20631da177e4SLinus Torvalds * submitted by the CPU Frequency driver. 20641da177e4SLinus Torvalds * 20651da177e4SLinus Torvalds * Registers a CPU Frequency driver to this core code. This code 20661da177e4SLinus Torvalds * returns zero on success, -EBUSY when another driver got here first 20671da177e4SLinus Torvalds * (and isn't unregistered in the meantime). 20681da177e4SLinus Torvalds * 20691da177e4SLinus Torvalds */ 2070221dee28SLinus Torvalds int cpufreq_register_driver(struct cpufreq_driver *driver_data) 20711da177e4SLinus Torvalds { 20721da177e4SLinus Torvalds unsigned long flags; 20731da177e4SLinus Torvalds int ret; 20741da177e4SLinus Torvalds 2075a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 2076a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 2077a7b422cdSKonrad Rzeszutek Wilk 20781da177e4SLinus Torvalds if (!driver_data || !driver_data->verify || !driver_data->init || 20791da177e4SLinus Torvalds ((!driver_data->setpolicy) && (!driver_data->target))) 20801da177e4SLinus Torvalds return -EINVAL; 20811da177e4SLinus Torvalds 20822d06d8c4SDominik Brodowski pr_debug("trying to register driver %s\n", driver_data->name); 20831da177e4SLinus Torvalds 20841da177e4SLinus Torvalds if (driver_data->setpolicy) 20851da177e4SLinus Torvalds driver_data->flags |= CPUFREQ_CONST_LOOPS; 20861da177e4SLinus Torvalds 20870d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 20881c3d85ddSRafael J. Wysocki if (cpufreq_driver) { 20890d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20901da177e4SLinus Torvalds return -EBUSY; 20911da177e4SLinus Torvalds } 20921c3d85ddSRafael J. Wysocki cpufreq_driver = driver_data; 20930d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 20941da177e4SLinus Torvalds 20958a25a2fdSKay Sievers ret = subsys_interface_register(&cpufreq_interface); 20968f5bc2abSJiri Slaby if (ret) 20978f5bc2abSJiri Slaby goto err_null_driver; 20981da177e4SLinus Torvalds 20991c3d85ddSRafael J. Wysocki if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) { 21001da177e4SLinus Torvalds int i; 21011da177e4SLinus Torvalds ret = -ENODEV; 21021da177e4SLinus Torvalds 21031da177e4SLinus Torvalds /* check for at least one working CPU */ 21047a6aedfaSMike Travis for (i = 0; i < nr_cpu_ids; i++) 21057a6aedfaSMike Travis if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) { 21061da177e4SLinus Torvalds ret = 0; 21077a6aedfaSMike Travis break; 21087a6aedfaSMike Travis } 21091da177e4SLinus Torvalds 21101da177e4SLinus Torvalds /* if all ->init() calls failed, unregister */ 21111da177e4SLinus Torvalds if (ret) { 21122d06d8c4SDominik Brodowski pr_debug("no CPU initialized for driver %s\n", 2113e08f5f5bSGautham R Shenoy driver_data->name); 21148a25a2fdSKay Sievers goto err_if_unreg; 21151da177e4SLinus Torvalds } 21161da177e4SLinus Torvalds } 21171da177e4SLinus Torvalds 211865edc68cSChandra Seetharaman register_hotcpu_notifier(&cpufreq_cpu_notifier); 21192d06d8c4SDominik Brodowski pr_debug("driver %s up and running\n", driver_data->name); 21201da177e4SLinus Torvalds 21218f5bc2abSJiri Slaby return 0; 21228a25a2fdSKay Sievers err_if_unreg: 21238a25a2fdSKay Sievers subsys_interface_unregister(&cpufreq_interface); 21248f5bc2abSJiri Slaby err_null_driver: 21250d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 21261c3d85ddSRafael J. Wysocki cpufreq_driver = NULL; 21270d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 21284d34a67dSDave Jones return ret; 21291da177e4SLinus Torvalds } 21301da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_register_driver); 21311da177e4SLinus Torvalds 21321da177e4SLinus Torvalds /** 21331da177e4SLinus Torvalds * cpufreq_unregister_driver - unregister the current CPUFreq driver 21341da177e4SLinus Torvalds * 21351da177e4SLinus Torvalds * Unregister the current CPUFreq driver. Only call this if you have 21361da177e4SLinus Torvalds * the right to do so, i.e. if you have succeeded in initialising before! 21371da177e4SLinus Torvalds * Returns zero if successful, and -EINVAL if the cpufreq_driver is 21381da177e4SLinus Torvalds * currently not initialised. 21391da177e4SLinus Torvalds */ 2140221dee28SLinus Torvalds int cpufreq_unregister_driver(struct cpufreq_driver *driver) 21411da177e4SLinus Torvalds { 21421da177e4SLinus Torvalds unsigned long flags; 21431da177e4SLinus Torvalds 21441c3d85ddSRafael J. Wysocki if (!cpufreq_driver || (driver != cpufreq_driver)) 21451da177e4SLinus Torvalds return -EINVAL; 21461da177e4SLinus Torvalds 21472d06d8c4SDominik Brodowski pr_debug("unregistering driver %s\n", driver->name); 21481da177e4SLinus Torvalds 21498a25a2fdSKay Sievers subsys_interface_unregister(&cpufreq_interface); 215065edc68cSChandra Seetharaman unregister_hotcpu_notifier(&cpufreq_cpu_notifier); 21511da177e4SLinus Torvalds 21520d1857a1SNathan Zimmer write_lock_irqsave(&cpufreq_driver_lock, flags); 21531c3d85ddSRafael J. Wysocki cpufreq_driver = NULL; 21540d1857a1SNathan Zimmer write_unlock_irqrestore(&cpufreq_driver_lock, flags); 21551da177e4SLinus Torvalds 21561da177e4SLinus Torvalds return 0; 21571da177e4SLinus Torvalds } 21581da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); 21595a01f2e8SVenkatesh Pallipadi 21605a01f2e8SVenkatesh Pallipadi static int __init cpufreq_core_init(void) 21615a01f2e8SVenkatesh Pallipadi { 21625a01f2e8SVenkatesh Pallipadi int cpu; 21635a01f2e8SVenkatesh Pallipadi 2164a7b422cdSKonrad Rzeszutek Wilk if (cpufreq_disabled()) 2165a7b422cdSKonrad Rzeszutek Wilk return -ENODEV; 2166a7b422cdSKonrad Rzeszutek Wilk 21675a01f2e8SVenkatesh Pallipadi for_each_possible_cpu(cpu) { 2168f1625066STejun Heo per_cpu(cpufreq_policy_cpu, cpu) = -1; 21695a01f2e8SVenkatesh Pallipadi init_rwsem(&per_cpu(cpu_policy_rwsem, cpu)); 21705a01f2e8SVenkatesh Pallipadi } 21718aa84ad8SThomas Renninger 21722361be23SViresh Kumar cpufreq_global_kobject = kobject_create(); 21738aa84ad8SThomas Renninger BUG_ON(!cpufreq_global_kobject); 2174e00e56dfSRafael J. Wysocki register_syscore_ops(&cpufreq_syscore_ops); 21758aa84ad8SThomas Renninger 21765a01f2e8SVenkatesh Pallipadi return 0; 21775a01f2e8SVenkatesh Pallipadi } 21785a01f2e8SVenkatesh Pallipadi core_initcall(cpufreq_core_init); 2179