1s1$J2LX *
>pn?~ * linux/drivers/cpufreq/cpufreq.c
^IC|3sr *
m@TU2 * Copyright (C) 2001 Russell King
!$&K~>` * (C) 2002 - 2003 Dominik Brodowski <
linux@brodo.de>
`+i<:,z-gs *
g.z/%LpK * Oct 2005 - Ashok Raj <
ashok.raj@intel.com>
AC
3 ;i * Added handling for CPU hotplug
m:K/)v* * Feb 2006 - Jacob Shin <
jacob.shin@amd.com>
h( Iti& * Fix handling for CPU hotplug -- affected CPUs
?_ p3^kl *
G0<m3 Up * This program is free software; you can redistribute it and/or modify
$ABW|r * it under the terms of the GNU General Public License version 2 as
?HU(0Vgn' * published by the Free Software Foundation.
M`S >Q2{ *
\GBv@ */
B(E+2;!QF ;B!&( 50e #include <linux/kernel.h>
0~"{z>s ' #include <linux/module.h>
7eZ,;
x #include <linux/init.h>
I)n%aT fo8 #include <linux/notifier.h>
-k!UcMWP #include <linux/cpufreq.h>
9D-PmSnv #include <linux/delay.h>
91[(K'=& #include <linux/interrupt.h>
_AK-AY #include <linux/spinlock.h>
&(irri_ #include <linux/device.h>
_PQQ&e)E #include <linux/slab.h>
7)<&,BWc #include <linux/cpu.h>
qJrK?:O; #include <linux/completion.h>
I+ydVj(Op #include <linux/mutex.h>
$Z$BF #include <linux/syscore_ops.h>
<Y<%=` UG 9uNgzQ/ #include <trace/events/power.h>
l2z@t3{ }zj_Pp /**
Un@d Wf6' * The "cpufreq driver" - the arch- or hardware-dependent low
@2Z{en? * level driver of CPUFreq support, and its spinlock. This lock
8,=,'gFO * also protects the cpufreq_cpu_data array.
,n^{!^JW */
V+-%$-w> static struct cpufreq_driver *cpufreq_driver;
f D2.Zh static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
8)/d8@ #ifdef CONFIG_HOTPLUG_CPU
f6u<.b /* This one keeps track of the previously set governor of a removed CPU */
9K~X}]u static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
"! m6U#^ #endif
GK~uoz:^O static DEFINE_SPINLOCK(cpufreq_driver_lock);
!CY:XQm 9J$N5 /*
_-$(=`8|<{ * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
<D%.'=%pZ * all cpufreq/hotplug/workqueue/etc related lock issues.
4ba[*R2 *
Y2W|b5 * The rules for this semaphore:
cY0NQKUk~ * - Any routine that wants to read from the policy structure will
\0).
ODA( * do a down_read on this semaphore.
o7;lR? * - Any routine that will write to the policy structure and/or may take away
~5q1zr)E * the policy altogether (eg. CPU hotplug), will hold this lock in write
ot($aY,t * mode before doing so.
:Ugf3%sQ *
_<qe= hie! * Additional rules:
l1l=52r * - All holders of the lock should check to make sure that the CPU they
+0_e a~{ * are concerned with are online after they get the lock.
C6Lc * - Governor routines that can be called in cpufreq hotplug path should not
)%dxfwd6 * take this sem as top level hotplug notifier handler takes this.
QV)>+6\ * - Lock should not be held across
_Dr9 w&;< * __cpufreq_governor(data, CPUFREQ_GOV_STOP);
u0zF:: */
I() =Ufs5z static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
k{d] static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
c#(Hh{0 X6*4IE #define lock_policy_rwsem(mode, cpu) \
X|y(B%: static int lock_policy_rwsem_##mode \
G5vp(%j
(int cpu) \
. |%n"{ { \
'
Dcj\=8 int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \
x{4{.s%+: BUG_ON(policy_cpu == -1); \
:y'EIf down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \
z?dd5.k if (unlikely(!cpu_online(cpu))) { \
GZH{"_$ up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \
hz:h>Hwy return -1; \
%e^GfZ } \
{ppzg`G\ \
K*I!:1;3N return 0; \
e`n+U-)z }
d^MRu#] ,_iq$I; lock_policy_rwsem(read, cpu);
aKjP{Z0k$ ttOk6- lock_policy_rwsem(write, cpu);
]-8WM5\qJM e[
yN static void unlock_policy_rwsem_read(int cpu)
`6$|d,m5 {
s@Dln
Du. int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
;3x*pjLG:Q BUG_ON(policy_cpu == -1);
{Y-~7@ up_read(&per_cpu(cpu_policy_rwsem, policy_cpu));
TZ&X0x8 }
qG@YNc 3ew4QPT' static void unlock_policy_rwsem_write(int cpu)
{ETM > {
HS[($ int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
]Hp>~Zvbb BUG_ON(policy_cpu == -1);
IjGPiC up_write(&per_cpu(cpu_policy_rwsem, policy_cpu));
@}=(4% }
G %'xEr0n H2H`7 +I, CYRZ2Yrk?" /* internal prototypes */
/~MH]Gh static int __cpufreq_governor(struct cpufreq_policy *policy,
1U%
/~ unsigned int event);
2n)?)w]!M static unsigned int __cpufreq_get(unsigned int cpu);
KL3Z( static void handle_update(struct work_struct *work);
h PL]B_<
C];P yQS /**
v3#,Z! * Two notifier lists: the "policy" list is involved in the
oNZ_7tU * validation process for a new CPU frequency policy; the
0:f]&Ng * "transition" list for kernel code that needs to handle
\?pyax8 * changes to devices when the CPU clock speed changes.
Y{D%v * The mutex locks both lists.
8[;vC$ */
_0(%^5Y static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
]}dQ~lOE static struct srcu_notifier_head cpufreq_transition_notifier_list;
!$A/.;0$ V"m S$MN static bool init_cpufreq_transition_notifier_list_called;
U.KQjBi static int __init init_cpufreq_transition_notifier_list(void)
MjU|XQS: {
As< B8e] srcu_init_notifier_head(&cpufreq_transition_notifier_list);
l|=4FIMD init_cpufreq_transition_notifier_list_called = true;
O&1qL) return 0;
RFMPh<Ac }
+? h}e pure_initcall(init_cpufreq_transition_notifier_list);
3w</B-|nQ s'h;a5Q1'Q static LIST_HEAD(cpufreq_governor_list);
qT48Y static DEFINE_MUTEX(cpufreq_governor_mutex);
8LbwEKl 8q@Z struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
!bP%\)5 {
5?lc%,-& struct cpufreq_policy *data;
[ n7>g unsigned long flags;
T1]?E]m{ L.Qz29\ if (cpu >= nr_cpu_ids)
IdQ./@? goto err_out;
=j62tDS HR}O:2' /* get the cpufreq driver */
27EK+$ spin_lock_irqsave(&cpufreq_driver_lock, flags);
f#=c=e-A ovdJ[bO if (!cpufreq_driver)
Iko]c_W0 goto err_out_unlock;
]K"&Vd h q)1YO if (!try_module_get(cpufreq_driver->owner))
{%f{U"m goto err_out_unlock;
/]_ t-> {drc}BL_ Ho>Np& /* get the CPU */
(k?HT'3) data = per_cpu(cpufreq_cpu_data, cpu);
TxX =(7V ){*+s RBW if (!data)
yO q@w!xz goto err_out_put_module;
K]hp-QK< T.4&P#a1 if (!kobject_get(&data->kobj))
7uF|Z( goto err_out_put_module;
Upe}9xf qhEv6Yxfw6 spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
`7CK;NeT return data;
;V
xRaj? >?, Zn err_out_put_module:
T3X'73M module_put(cpufreq_driver->owner);
j*jUcD* err_out_unlock:
rO'DT{Yt spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
#z|Q $ err_out:
WMSJU/-P return NULL;
l4OrlS/ 5 }
aQCu3T EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
uM-,}7f7 D|N4X`T` !+eH8
void cpufreq_cpu_put(struct cpufreq_policy *data)
A&Y5z[p {
qCV<-o kobject_put(&data->kobj);
qqrjI. module_put(cpufreq_driver->owner);
'<R>cN" }
[9 W@<p EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
eU[g@Pq:Y fpD$%.y'J "& ,ov# /*********************************************************************
JvpGxj * EXTERNALLY AFFECTING FREQUENCY CHANGES *
cHs3:F~~ *********************************************************************/
Ld4U i%hCV o /**
0l!#u`cCI * adjust_jiffies - adjust the system "loops_per_jiffy"
WYw#mSp *
gcJ!_KZK * This function alters the system "loops_per_jiffy" for the clock
C=:<[_m` * speed change. Note that loops_per_jiffy cannot be updated on SMP
&X=7b@r * systems as each CPU might be scaled differently. So, use the arch
szI7I$Qb * per-CPU loops_per_jiffy value wherever possible.
Dac)`/ */
XKoY!Y\ #ifndef CONFIG_SMP
A,}M ^$@ static unsigned long l_p_j_ref;
p3I"LY static unsigned int l_p_j_ref_freq;
]A*}Dem*5 v}G^+-? static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
i5 '&u: {
UUah5$Iy if (ci->flags & CPUFREQ_CONST_LOOPS)
!"rPSGK* return;
# B `?}a= =!q%
1 mP if (!l_p_j_ref_freq) {
w!.@64- l_p_j_ref = loops_per_jiffy;
wA)
Hot
l_p_j_ref_freq = ci->old;
bSB%hFp=Cp pr_debug("saving %lu as reference value for loops_per_jiffy; "
(WM3(US| "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
oBzl=N3< }
1F@k9[d~ if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
@~3-- (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
W(, j2pU (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
oQ!M+sRmF loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
%TB(E<p` ci->new);
K\Ea\b[ pr_debug("scaling loops_per_jiffy to %lu "
_?{7%(C "for frequency %u kHz\n", loops_per_jiffy, ci->new);
}A#IBqf5 }
_P>YG<*"kQ }
;_<R +w3- #else
K7
e~%mY static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
5xQ-f {
swKkY`g return;
*rxr:y#Ve }
+$2{u_m, #endif
Gw
M:f/eV $3-vW{< rP@#_(22 /**
sX>u. * cpufreq_notify_transition - call notifier chain and adjust_jiffies
D /eH~ * on frequency transition.
$|K
d<wv *
l$42MRi/ * This function calls the transition notifiers and the "adjust_jiffies"
v+c>iI * function. It is called twice on all CPU frequency changes that have
3EoCEPb# * external effects.
d*(aue= */
K,b
M9>} void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
YeH!v, > {
>I5:@6
Z struct cpufreq_policy *policy;
[$N_YcN? aSL`yuXu BUG_ON(irqs_disabled());
Q$jEmmm%V[ /d`"WK, freqs->flags = cpufreq_driver->flags;
rzjVUPdnh pr_debug("notification %u of frequency transition to %u kHz\n",
'ofj1%c state, freqs->new);
n3^(y"q Z8$}Rpo policy = per_cpu(cpufreq_cpu_data, freqs->cpu);
Q&9yrx. switch (state) {
7|rH9Bc{U 3h@]cWp case CPUFREQ_PRECHANGE:
RNg?o[S /* detect if the driver reported a value as "old frequency"
IqOg{#sm * which is not equal to what the cpufreq core thinks is
s**<=M GK * "old frequency".
G\.~/<Mg+ */
_)A|JC!jId if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
X{9^$/XsJ if ((policy) && (policy->cpu == freqs->cpu) &&
{#,<)wFV\ (policy->cur) && (policy->cur != freqs->old)) {
/{M<FVXK+| pr_debug("Warning: CPU frequency is"
rp Nb. " %u, cpufreq assumed %u kHz.\n",
6j#JhcS+ freqs->old, policy->cur);
,75) freqs->old = policy->cur;
KA3U W }
\pmS*Dt }
N Ob`)qb srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
J<)qw CPUFREQ_PRECHANGE, freqs);
}@DCc f$< adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
9&mSF0q break;
`lf_wB+I aDlp>p^E> case CPUFREQ_POSTCHANGE:
nt.LiM/L adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
8K%N7RL| pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
/l$x} (unsigned long)freqs->cpu);
Na\ZV|;*tu trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu);
b@CB +8$ trace_cpu_frequency(freqs->new, freqs->cpu);
[KDxB>R<{ srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
BN/4O?jD9 CPUFREQ_POSTCHANGE, freqs);
6FS%9.Ws if (likely(policy) && likely(policy->cpu == freqs->cpu))
(?FH`< policy->cur = freqs->new;
JsEJ6!1 break;
Q|y }mC/ }
~.a"jYb7A} }
Zxk~X}K\P EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
FO{=^I5YA C.j+Zb1Z( \#sD`O 2"/MM2s /*********************************************************************
OL'Ito * SYSFS INTERFACE *
G gO5=| *********************************************************************/
3?OQ-7, (d9~z static struct cpufreq_governor *__find_governor(const char *str_governor)
5LeZ?'"c {
q'3{M]Tk struct cpufreq_governor *t;
lu utyK! _&KqmQ8$7 list_for_each_entry(t, &cpufreq_governor_list, governor_list)
}F08o,`? if (!strnicmp(str_governor, t->name, CPUFREQ_NAME_LEN))
7iB!Uuc return t;
?hoOSur+ ,p2UshOmd return NULL;
\;;M")$ }
2+]5}'M 1{uxpYAP=
/**
4.A^5J'W * cpufreq_parse_governor - parse a governor string
#G9
W65 f */
1]xk:u4LA static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
3:nhZN/95T struct cpufreq_governor **governor)
?0qVyK_1 {
Iix,}kzss int err = -EINVAL;
S
?Zh#`(* <JPN<
Kv if (!cpufreq_driver)
.1QGNW goto out;
pn" !wqg q<RjAi if (cpufreq_driver->setpolicy) {
@2(u=E: ^ if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
G':3U *policy = CPUFREQ_POLICY_PERFORMANCE;
Ou[K7-m%& err = 0;
]4~Yi1] } else if (!strnicmp(str_governor, "powersave",
3@Ndn CPUFREQ_NAME_LEN)) {
>t+ ENYb *policy = CPUFREQ_POLICY_POWERSAVE;
]3r}>/2( err = 0;
V 6}5^W }
dCx63rF`G } else if (cpufreq_driver->target) {
d<c 29Y struct cpufreq_governor *t;
U1\EwBK8*T oXo>pl mutex_lock(&cpufreq_governor_mutex);
vG |!d+ GrF4*I`q t = __find_governor(str_governor);
=<\22d5L ,%!m%+K9a if (t == NULL) {
XG#?fr}L int ret;
w4
yrAj
2 H3wJ5-q( mutex_unlock(&cpufreq_governor_mutex);
Q:kg ret = request_module("cpufreq_%s", str_governor);
)x-b+SC mutex_lock(&cpufreq_governor_mutex);
\zd[A~! (l5p_x if (ret == 0)
(Jp~=6&lKf t = __find_governor(str_governor);
FDoPW~+[ }
#p+iwW- N^
+q^iW if (t != NULL) {
a\sK{`|X* *governor = t;
lpi"@3 err = 0;
Y S3~sA }
P"c@V,. kBP?_ O mutex_unlock(&cpufreq_governor_mutex);
.AN1Yt }
MqJTRBs% out:
^y,h0?Z9 return err;
^f[6NYS? }
eKLvBa-{@ xMbgBx4+ 4!sK>l! /**
$ (}rTm * cpufreq_per_cpu_attr_read() / show_##file_name() -
F:/x7]7??Z * print out cpufreq information
_'D(>e? *
`%YMUBaI * Write out information from cpufreq_driver->policy[cpu]; object must be
9hr7+fW]t * "unsigned int".
=r]l"T */
):N#X<b': Kebr>t8^ #define show_one(file_name, object) \
%g:Q? static ssize_t show_##file_name \
NQD5=/o (struct cpufreq_policy *policy, char *buf) \
%??v?M* { \
e5mu- return sprintf(buf, "%u\n", policy->object); \
y\v#qFVOZ }
R*GBxJaw NV5qF/<M show_one(cpuinfo_min_freq, cpuinfo.min_freq);
/? %V%
n show_one(cpuinfo_max_freq, cpuinfo.max_freq);
sOqFEvzo1% show_one(cpuinfo_transition_latency, cpuinfo.transition_latency);
)q x;/=D show_one(scaling_min_freq, min);
y)zZ:lyIq show_one(scaling_max_freq, max);
k A=5Kc show_one(scaling_cur_freq, cur);
97Dq; 2G.y.#W static int __cpufreq_set_policy(struct cpufreq_policy *data,
Z9: struct cpufreq_policy *policy);
{Q>OZm\+ L#SW! /**
k"#gSCW$ * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access
]9_gbQ */
=`x }9|[ #define store_one(file_name, object) \
F'M X9P static ssize_t store_##file_name \
zgY VB} (struct cpufreq_policy *policy, const char *buf, size_t count) \
rC@VMe|0 { \
=%8 yEb*5# unsigned int ret = -EINVAL; \
0SvPr[ > struct cpufreq_policy new_policy; \
G^B>C \
9(t(sP_ ret = cpufreq_get_policy(&new_policy, policy->cpu); \
_1[Wv? if (ret) \
I^EZ s6~ return -EINVAL; \
kq X=3Zo \
*=i&n> ret = sscanf(buf, "%u", &new_policy.object); \
'( I0VJJ if (ret != 1) \
Gd A!8 return -EINVAL; \
-]wEk%j \
xHt7/8wF ret = __cpufreq_set_policy(policy, &new_policy); \
Jqb~RP~ policy->user_policy.object = policy->object; \
0{vT`e' \
CHTK.%AQH! return ret ? ret : count; \
(F^R9G| }
/"J 6``MV =?$~=1SL+ store_one(scaling_min_freq, min);
U
2-{p store_one(scaling_max_freq, max);
xO_>%F^? JPF6zzl) /**
g8cBb5(L * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware
/4O))}TX */
wU|@fm" static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
~~Bks{"BS char *buf)
N!c FUZ5] {
R*vQvO%)h unsigned int cur_freq = __cpufreq_get(policy->cpu);
tAq0Z) if (!cur_freq)
=/K)hI!u return sprintf(buf, "<unknown>");
eP"B3Jw return sprintf(buf, "%u\n", cur_freq);
"dP-e }
S?CT6moXA *EGzFXa G@/iK/>5|` /**
O*v&CHd3 * show_scaling_governor - show the current policy for the specified CPU
`Pc6
G*p */
W8 Ssv static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
1J0gjO)AZ {
{U2AAQSa if (policy->policy == CPUFREQ_POLICY_POWERSAVE)
|kK5:\H return sprintf(buf, "powersave\n");
sJKr%2nVV else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE)
"a].v 8l! return sprintf(buf, "performance\n");
tx7 zG., else if (policy->governor)
Uj;JN}k return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n",
O)`L(
x policy->governor->name);
Xk.OyQ@ return -EINVAL;
ef^GJTv&k }
]7}!3 m UhqTn$=fb vYm-$KQ"o /**
y>}r * store_scaling_governor - store policy for the specified CPU
.^*;hZ~4% */
8!|vp7/ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
IQU1 JVkZ const char *buf, size_t count)
.O"a: ^i {
b9rQQS unsigned int ret = -EINVAL;
|;NfH|43; char str_governor[16];
-XXsob}/8 struct cpufreq_policy new_policy;
i=\)[;U C]2-V1,ZX ret = cpufreq_get_policy(&new_policy, policy->cpu);
g;=VuQuP| if (ret)
ic`BDkNO return ret;
%W9R08` )qb'tZz/g_ ret = sscanf(buf, "%15s", str_governor);
UstUPO if (ret != 1)
hy~[7:/<I& return -EINVAL;
<L8|Wz keLeD1 if (cpufreq_parse_governor(str_governor, &new_policy.policy,
{Vj&i.2, &new_policy.governor))
k*?T^<c3 return -EINVAL;
msgR"T3' p#jAEY p /* Do not use cpufreq_set_policy here or the user_policy.max
P}~MO)*1 will be wrongly overridden */
&u[{V R: ret = __cpufreq_set_policy(policy, &new_policy);
|hxiARr4 Fc@R,9 policy->user_policy.policy = policy->policy;
7:olStK policy->user_policy.governor = policy->governor;
=S{OzF mP\V.^ if (ret)
by'KJxl[ return ret;
Xi%Og\vm5 else
cy.r/Z} return count;
z(A[xN@/W< }
0zNbux_ 2|^@=.4\ /**
^O*-|ecA
* show_scaling_driver - show the cpufreq driver currently loaded
:pdX */
Y[f]L4,V static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf)
K7`6G[RMb {
F8Ety^9>9 return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name);
OJpfiZ@Q_ }
:wS&3:h pM@8T25= /**
N-QS/*C.~ * show_scaling_available_governors - show the available CPUfreq governors
pZ'q_Oux */
" Bx@( static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
fY9+m}$S$ char *buf)
'wEQvCS {
:W, S ssize_t i = 0;
FShjUl>mV struct cpufreq_governor *t;
y#B=9Ri=z `;Tf _6c if (!cpufreq_driver->target) {
6=]Gom&S i += sprintf(buf, "performance powersave");
N\*oL*[j goto out;
I`{*QU }
:41Y RJ@79L*# list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
@CzFzVmF" if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
0 YFXF - (CPUFREQ_NAME_LEN + 2)))
12U]= goto out;
O8.xt|
i += scnprintf(&buf
, CPUFREQ_NAME_LEN, "%s ", t->name); %urvX$r4K
} }R<t=):
out: Q&:)D7m\)S
i += sprintf(&buf, "\n"); :@i+yN cV
return i; IOZw[9](+
} 1<'z)r4
4,LS08&gh
static ssize_t show_cpus(const struct cpumask *mask, char *buf) FDD=I\Ic
{ A#cFO)"
ssize_t i = 0; */h(4Hz
unsigned int cpu; Oq~{HJ{
9Of;8R
for_each_cpu(cpu, mask) { |p[Mp:^^
if (i) _">F]ptI;
i += scnprintf(&buf, (PAGE_SIZE - i - 2), " "); Y"bm4&'
i += scnprintf(&buf, (PAGE_SIZE - i - 2), "%u", cpu); -:%QoRCy
if (i >= (PAGE_SIZE - 5)) Pv5S k8
break; [<@T%yq
} 'Hx#DhiFz
i += sprintf(&buf, "\n"); >`UqS`YQK
return i; e2c'Wab
} ]|g2V
a~-
6d]4
%Q T
/** k_]'?f7Z
* show_related_cpus - show the CPUs affected by each transition even if Pg T3E
* hw coordination is in use Dst;sLr[,
*/ wA$7SWC
static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf) "qq$i35x
{ 8*u'D@0
if (cpumask_empty(policy->related_cpus)) HjA~3l7
return show_cpus(policy->cpus, buf); g/.FJ-I*
return show_cpus(policy->related_cpus, buf); =F_uK7W
} n~6$CQ5dF(
DGGySO6=$e
/** 2x<BU3
* show_affected_cpus - show the CPUs affected by each transition HDKF>S_S
*/ Jn{)CZ
static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) Pr}
l
y
{ >P
j#?j*Y
return show_cpus(policy->cpus, buf); 1R8tR#l
} !QwB8yK@
V]--d33/a
static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy, >I@&"&d
const char *buf, size_t count) sZ=!*tb-
{ {2 q"9Ox"
unsigned int freq = 0; ?VotIruR
unsigned int ret; $O\m~r4
1oO(;--u_
if (!policy->governor || !policy->governor->store_setspeed) S*G^U1Sc+
return -EINVAL; D,.`mX
}Y7P2W+4?
ret = sscanf(buf, "%u", &freq); WVyDE1K<
if (ret != 1) Q<6* UUQm
return -EINVAL; QaO9-:]eN
&I-:=ir
policy->governor->store_setspeed(policy, freq); O<p=&=TD7
DtBvfYO8)>
return count; ).jQ+XE'>
} VvIUAn
%TI3Eb
static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf) fB<Qs.T
{ | t:UpP
if (!policy->governor || !policy->governor->show_setspeed) l\L71|3" g
return sprintf(buf, "<unsupported>\n"); Caj H;K\
tb?TPd-OY
return policy->governor->show_setspeed(policy, buf); ;V~x[J|x
} s2,6aW C
cu1!WD
/** p,z>:3M
* show_scaling_driver - show the current cpufreq HW/BIOS limitation VTL_I^p
*/ 2<UC^vZ
static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) 3.dSS
{ F6~
;f;
unsigned int limit; tOVTHx3E]
int ret; ;rL>{UhG
if (cpufreq_driver->bios_limit) { 1^]IuPxq
ret = cpufreq_driver->bios_limit(policy->cpu, &limit); "\Dqtr w
if (!ret) 1:<n(?5JI
return sprintf(buf, "%u\n", limit); uG'S&8i_
} J;XO1}9
return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); ='.b/]! _
} q<.k:v&
S@pdCH, n
cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400); #@YKNS[
cpufreq_freq_attr_ro(cpuinfo_min_freq); &&$*MHJ
cpufreq_freq_attr_ro(cpuinfo_max_freq); nT:<_'!
cpufreq_freq_attr_ro(cpuinfo_transition_latency); 9+*{3 t
cpufreq_freq_attr_ro(scaling_available_governors); 6miXaAA8
cpufreq_freq_attr_ro(scaling_driver); Tr>_R%b K
cpufreq_freq_attr_ro(scaling_cur_freq); <
`;Mf>V
cpufreq_freq_attr_ro(bios_limit); y)|d`qC\
cpufreq_freq_attr_ro(related_cpus); GBZ u<t/
cpufreq_freq_attr_ro(affected_cpus); j@nK6`d+1
cpufreq_freq_attr_rw(scaling_min_freq); jHT^I
as
cpufreq_freq_attr_rw(scaling_max_freq); =@O&$&
cpufreq_freq_attr_rw(scaling_governor); rg[#(
cpufreq_freq_attr_rw(scaling_setspeed); I3.JAoB>!
Edc3YSg%;
static struct attribute *default_attrs[] = { 3s]o~I 2x
&cpuinfo_min_freq.attr, }Uj-R3]}K
&cpuinfo_max_freq.attr, DJdhOLx
&cpuinfo_transition_latency.attr, A]QGaWK
&scaling_min_freq.attr, 21<Sfsc$
&scaling_max_freq.attr, SefF Ci%4
&affected_cpus.attr, -h|[8UG^b
&related_cpus.attr, g@O?0,+1
&scaling_governor.attr, WllQM,h
&scaling_driver.attr, ,^1 #Uz8
&scaling_available_governors.attr, 4VF]tX?o
&scaling_setspeed.attr, 1)}hzA
NULL "<egm^Yq
}; >G?*rg4
7^.g\Kt?
struct kobject *cpufreq_global_kobject; dw}ge,bBic
EXPORT_SYMBOL(cpufreq_global_kobject); 3LQu+EsS
&)q>Z!C-l
#define to_policy(k) container_of(k, struct cpufreq_policy, kobj) d+h~4'ebv
#define to_attr(a) container_of(a, struct freq_attr, attr)
m5J@kE%
r;(^]Soz
static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) ;x_T*} CH
{ ~|~ 2B$JeV
struct cpufreq_policy *policy = to_policy(kobj); u9q#L.Ij
struct freq_attr *fattr = to_attr(attr); 6e,IjocsB
ssize_t ret = -EINVAL; YJz06E1 -9
policy = cpufreq_cpu_get(policy->cpu); 7/]Ra
if (!policy) " 5Pqvi
goto no_policy; .pxUO3g
x^`P[>
if (lock_policy_rwsem_read(policy->cpu) < 0) V@G|2ZI
goto fail; {J)gS
rx#GrV*y
if (fattr->show) Wxj(3lg/
ret = fattr->show(policy, buf); 4%yeEc;z
else { O=_c|u{N
ret = -EIO; R SWw4}
~r})&`5
unlock_policy_rwsem_read(policy->cpu); W>CG;x{
fail: ;&w_.j*Is
cpufreq_cpu_put(policy); jX$U)O
no_policy: "_rpErm
}
return ret; 6m(+X
MS
} -idbR[1{?
LDo~
static ssize_t store(struct kobject *kobj, struct attribute *attr, g_Y$5ft`
const char *buf, size_t count) oO
&%&;[/A
{ w2!5TKZ`
struct cpufreq_policy *policy = to_policy(kobj); K.? S,qg
struct freq_attr *fattr = to_attr(attr); 04X/(74
ssize_t ret = -EINVAL; ~2Mcw`<
policy = cpufreq_cpu_get(policy->cpu); j=Q ?d]
if (!policy) D_z&G)
goto no_policy; F CfU=4O
L?(1
[jB4G
if (lock_policy_rwsem_write(policy->cpu) < 0) }p9#Bzc
goto fail; C91'dM
rc{F17~vX
if (fattr->store) KAT^v bR
ret = fattr->store(policy, buf, count); Z2]\k|%<Fa
else >I/~)B`jhE
ret = -EIO; 1OK~*=/4
S6yLq|W0
unlock_policy_rwsem_write(policy->cpu); L6=5]?B=
fail: ,I f9w$(z
cpufreq_cpu_put(policy); kQ6YQsJ.*
no_policy: :N4?W}r.
return ret; dlV HyCW
} P=4o)e7E!
<;Td8T;
static void cpufreq_sysfs_release(struct kobject *kobj) ~05(92bK
{ ~X) 1!Sr
struct cpufreq_policy *policy = to_policy(kobj); y
0fI7:e3
pr_debug("last reference is dropped\n"); 2:^
complete(&policy->kobj_unregister); Eo<N
} te3\MSv;O
GtqA@&5&
static const struct sysfs_ops sysfs_ops = { 0o?2Sf`L\*
.show = show, >$A, B
.store = store, &nn+X%m9g
}; [k,FJ5X
=:^f6"p&Z
static struct kobj_type ktype_cpufreq = { OimqP
.sysfs_ops = &sysfs_ops, .Dyxul
.default_attrs = default_attrs, "4QD\k5
.release = cpufreq_sysfs_release, G:PcV_ihx
}; +d8?=LX
d
a.6Z!a
/* c~Z\|Y`#B
* Returns: rx(z::
* Negative: Failure 3)~z~p7
* 0: Success [iG4qI
* Positive: When we have a managed CPU and the sysfs got symlinked lHoV>k
*/ 6Y=MW{=F
static int cpufreq_add_dev_policy(unsigned int cpu, MB(l*ju0
struct cpufreq_policy *policy, BIEeHN4
struct sys_device *sys_dev) @1peJJ{
{ naW!Mga
int ret = 0; .Aa(
#ifdef CONFIG_SMP rWzO>v
unsigned long flags; ( |Xc_nC
unsigned int j; bQ_N^[oxQ
#ifdef CONFIG_HOTPLUG_CPU i<uk}
struct cpufreq_governor *gov; JKYkS*.a}
zlN<yZB^
gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu)); 0VlB7oF
if (gov) { <nT).S>+
policy->governor = gov; .Vb\f
pr_debug("Restoring governor %s for cpu %d\n", 3ES3,uR
policy->governor->name, cpu); ]g0\3A
} "+ 8Y{T
#endif A^hFRAg4
9iQc\@eGd
for_each_cpu(j, policy->cpus) { Ft$tL;
struct cpufreq_policy *managed_policy; gJI(d6
Mhj.3nN
if (cpu == j) D4CiB"g3*
continue; x[H9<&)D
73d7'Fw
/* Check for existing affected CPUs. XnI)s^
* They may not be aware of it due to CPU Hotplug. O'<cEv'B*
* cpufreq_cpu_put is called when the device is removed M8'
GbF=1
* in __cpufreq_remove_dev() #1` lJ
*/ <gc\,P<ru
managed_policy = cpufreq_cpu_get(j); SPK%
' s
if (unlikely(managed_policy)) { bMpCQ
Oe*+pReSD
/* Set proper policy_cpu */ vT>ki0P_;
unlock_policy_rwsem_write(cpu); 6H_7M(f
per_cpu(cpufreq_policy_cpu, cpu) = managed_policy->cpu; /5c;,.hm1R
^(8(z@y
if (lock_policy_rwsem_write(cpu) < 0) { \a6knd
/* Should not go through policy unlock path */ ]@MBE1M
if (cpufreq_driver->exit) Ss~dK-{e7
cpufreq_driver->exit(policy); n9Xs sl0
cpufreq_cpu_put(managed_policy); v"dj%75O?e
return -EBUSY; 92HxZ*t7km
} _~b$6Nf!83
27!9LU
spin_lock_irqsave(&cpufreq_driver_lock, flags); &7\q1X&Rr
cpumask_copy(managed_policy->cpus, policy->cpus); zS##YR
per_cpu(cpufreq_cpu_data, cpu) = managed_policy; tv1Z%Mx?Cp
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); e+5]l>3)f
4 06.6jmv
pr_debug("CPU already managed, adding link\n"); tu6Q7CjW8
ret = sysfs_create_link(&sys_dev->kobj, z rV
&managed_policy->kobj, gqf*;Z eU
"cpufreq"); J~[A8o
if (ret) `II/nv0jn
cpufreq_cpu_put(managed_policy); U0kEhMIIf
/* s1eGItx[w
* Success. We only needed to be added to the mask. ~~_!&
* Call driver->exit() because only the cpu parent of ;w_f ^R #
* the kobj needed to call init(). ITu6m<V
*/ K;wd2/jmJ
if (cpufreq_driver->exit) _DK%-,Spu
cpufreq_driver->exit(policy); phA^ kdW
KF[P
/cFI
if (!ret) )./%/
_*K
return 1; FM3DJ?\L-
else `E),G;I
return ret; ]`2=<n;=
} )"IBw0]
} K9X0/
#endif +h$)l/>:
return ret; A:3:Cr
} '}D$"2I*
{T]^C
OBY
/* symlink affected CPUs */ tDl1UX
static int cpufreq_add_dev_symlink(unsigned int cpu, ;nPjyu'g
struct cpufreq_policy *policy)
5Y\wXqlY
{ 9*+%Qt,{B
unsigned int j;
De>'
int ret = 0; >~kSe=Hsb4
_[,oP s:+
for_each_cpu(j, policy->cpus) { NiwJ$Ah~X
struct cpufreq_policy *managed_policy; F~cvob{
struct sys_device *cpu_sys_dev; luyU!
Qifjv0&;u
if (j == cpu) "]dNN{Wka
continue; RQZ|:SvV
if (!cpu_online(j)) YJlpP0;++
continue; v}v! hs Q
pr2b<(Pm
pr_debug("CPU %u already managed, adding link\n", j); $ePBw~yu
managed_policy = cpufreq_cpu_get(cpu); >4A~?=
cpu_sys_dev = get_cpu_sysdev(j); Xi]WDH \
ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj, 0k?ph$
"cpufreq"); 9Se7
1
if (ret) { F
j_r
n
cpufreq_cpu_put(managed_policy); \(PC#H%
return ret; KB$s7S"=
} L- -
} 5YlY=J
return ret; qYHAXc}$
} qV%t[>
+X4O.6Mn
static int cpufreq_add_dev_interface(unsigned int cpu, km;M!}D
struct cpufreq_policy *policy, Zc"Vf]:
struct sys_device *sys_dev) .!ThqYo
{ 9{?L3V!+r
struct cpufreq_policy new_policy; >g%^hjJ
struct freq_attr **drv_attr; %rpJZ
t
unsigned long flags; fX,L;Se"
int ret = 0; @_tQ:U,v
unsigned int j; bqwQi>^Cw
E\V-<]o
/* prepare interface data */ e Ir|%
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, AnV\{A^
&sys_dev->kobj, "cpufreq"); "p43#
if (ret) K|-?1)Um
return ret; j +j2_\
!c`KzqP
/* set up files for this cpu device */ sN^3bfi!i
drv_attr = cpufreq_driver->attr; SMr
]Gf.
while ((drv_attr) && (*drv_attr)) { 289@O-
ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); M
<oy
if (ret) D"WqJcDt
goto err_out_kobj_put; B!|<<;Da6
drv_attr++; mC
P*v-
} ;}!hgyq
if (cpufreq_driver->get) { $M F
U9<O
ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); o2
=UUD&
if (ret) \#P>k;D
goto err_out_kobj_put; d,fX3
} 3PB#m.N<
if (cpufreq_driver->target) { >E;-asD
ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); |wASeZMO2
if (ret) \Kph?l9Ww
goto err_out_kobj_put; :` >|N|i
} (9_~R^='y
if (cpufreq_driver->bios_limit) { j';V(ZY&BB
ret = sysfs_create_file(&policy->kobj, &bios_limit.attr); D-8NDa(`
if (ret) C9-IJj
goto err_out_kobj_put; E5d?toZ,8"
} S^,1N4
$sDvE~f0n
spin_lock_irqsave(&cpufreq_driver_lock, flags); 'j84-U{&)
for_each_cpu(j, policy->cpus) { #}50oWE
if (!cpu_online(j)) usb.cE3z
continue; ;[*jLi,uc
per_cpu(cpufreq_cpu_data, j) = policy; }cK<2J#
per_cpu(cpufreq_policy_cpu, j) = policy->cpu; <eU28M?\
} 8}m bfuo1
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); +{V"a<D$m
]I9Hbw
ret = cpufreq_add_dev_symlink(cpu, policy); O$}p}%%y7
if (ret) 4q"x|}a
goto err_out_kobj_put; }`g:)gJ
>}#h
memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); d52l)8
/* assure that the starting sequence is run in __cpufreq_set_policy */ t+'|&b][Qi
policy->governor = NULL; @5n!t1(
{R[FwB^7wJ
/* set default policy */ n:zoN2lC
ret = __cpufreq_set_policy(policy, &new_policy); sY4sq5'!
policy->user_policy.policy = policy->policy; Ha l,%W~e
policy->user_policy.governor = policy->governor; a []Iz8*6e
cE}R7,y
if (ret) { pkjf5DWp
pr_debug("setting policy failed\n"); 82%~WQnS
if (cpufreq_driver->exit) FLI\SF<
cpufreq_driver->exit(policy); WVc3C-h,
} kTG4h@w
return ret; 3L$_OXx
(lwrk(
err_out_kobj_put: H`/QhE
kobject_put(&policy->kobj); rrK&XP&
wait_for_completion(&policy->kobj_unregister); 5y7rY!]Bf
return ret; =[8EQdR
} jU2Dpxkt
hC ^|
uU v yZ
/** BKDs3?&
* cpufreq_add_dev - add a CPU device +TW9BU'a^
* c$),/0td|
* Adds the cpufreq interface for a CPU device. E"l&<U
* Ad)Po
* The Oracle says: try running cpufreq registration/unregistration concurrently %4#,y(dO
* with with cpu hotplugging and all hell will break loose. Tried to clean this NvH9?Ek"
* mess up, but more thorough testing is needed. - Mathieu wjk-$p
*/ hzIP ?0^E
static int cpufreq_add_dev(struct sys_device *sys_dev) " , c1z\
{ >$,A [|R
unsigned int cpu = sys_dev->id; =a>a A Z
int ret = 0, found = 0; `YTagUq7
struct cpufreq_policy *policy; !@mV$nTA
unsigned long flags; "p>$^
unsigned int j; ,L#Qy>MOb
#ifdef CONFIG_HOTPLUG_CPU sBP.P7u
int sibling; 3V:{_~~
#endif ~_WsjD0O
GOJ*>GpS
if (cpu_is_offline(cpu)) v3|-eWet^
return 0; (9:MIP
3-cCdn
pr_debug("adding CPU %u\n", cpu); E"!I[
B6)d2O9C
#ifdef CONFIG_SMP 0yW#).D^b
/* check whether a different CPU already registered this w~J 7|8Y
* CPU because it is in the same boat. */ %bo0-lnp
policy = cpufreq_cpu_get(cpu); "&jA
CI
if (unlikely(policy)) { f8`K8Y]4
cpufreq_cpu_put(policy); ~l$u~:4Ob
return 0; bJc<FL<E
} n4Fh*d ixg
#endif IC&xL9
P3|_RHIb
if (!try_module_get(cpufreq_driver->owner)) { q{v:T}Q|A
ret = -EINVAL; zbH Nj(~
goto module_out; "Y(stRa
} lSv?!2
/DOV/>@5%
ret = -ENOMEM; S9~X#tpKe
policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); C^ngdba\
if (!policy) tL0<xGI5^
goto nomem_out; =zw=Jp
<<#-IsT
if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) 4W7
goto err_free_policy; H/8H`9S$
6&~8TH
if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) W}&[p=PAS
goto err_free_cpumask; Yud]s~N
JCoDe.
policy->cpu = cpu; *_G(*yAe(
cpumask_copy(policy->cpus, cpumask_of(cpu)); ]IbX<
Oax*3TD
/* Initially set CPU itself as the policy_cpu */ [J0f:&7\
per_cpu(cpufreq_policy_cpu, cpu) = cpu; L ]HtmI
ret = (lock_policy_rwsem_write(cpu) < 0); ovv<7`
WARN_ON(ret); l*^J}oY
hV5Aw;7C
init_completion(&policy->kobj_unregister); r{y&}gA
INIT_WORK(&policy->update, handle_update); N$1ZA)M
6H+'ezM
/* Set governor before ->init, so that driver could check it */ 9Q{-4yF9k
#ifdef CONFIG_HOTPLUG_CPU npsDy&