Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
3ee1e204
Commit
3ee1e204
authored
Aug 01, 2003
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://linux-dj.bkbits.net/cpufreq
into home.osdl.org:/home/torvalds/v2.5/linux
parents
6fd6bef3
b9ecdfd3
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
459 additions
and
329 deletions
+459
-329
CREDITS
CREDITS
+1
-6
Documentation/cpu-freq/core.txt
Documentation/cpu-freq/core.txt
+4
-4
Documentation/cpu-freq/cpu-drivers.txt
Documentation/cpu-freq/cpu-drivers.txt
+7
-7
Documentation/cpu-freq/governors.txt
Documentation/cpu-freq/governors.txt
+7
-7
Documentation/cpu-freq/user-guide.txt
Documentation/cpu-freq/user-guide.txt
+1
-1
MAINTAINERS
MAINTAINERS
+6
-4
arch/i386/kernel/cpu/common.c
arch/i386/kernel/cpu/common.c
+17
-4
arch/i386/kernel/cpu/cpufreq/acpi.c
arch/i386/kernel/cpu/cpufreq/acpi.c
+1
-1
arch/i386/kernel/cpu/cpufreq/longhaul.c
arch/i386/kernel/cpu/cpufreq/longhaul.c
+109
-97
arch/i386/kernel/cpu/cpufreq/longhaul.h
arch/i386/kernel/cpu/cpufreq/longhaul.h
+49
-0
arch/i386/kernel/cpu/cpufreq/longrun.c
arch/i386/kernel/cpu/cpufreq/longrun.c
+1
-3
arch/i386/kernel/cpu/cpufreq/powernow-k6.c
arch/i386/kernel/cpu/cpufreq/powernow-k6.c
+2
-5
arch/i386/kernel/cpu/cpufreq/powernow-k7.c
arch/i386/kernel/cpu/cpufreq/powernow-k7.c
+6
-26
arch/i386/kernel/cpu/cpufreq/powernow-k7.h
arch/i386/kernel/cpu/cpufreq/powernow-k7.h
+0
-8
arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
+4
-4
drivers/cpufreq/userspace.c
drivers/cpufreq/userspace.c
+6
-6
include/asm-i386/msr.h
include/asm-i386/msr.h
+18
-3
include/linux/cpufreq.h
include/linux/cpufreq.h
+5
-3
kernel/cpufreq.c
kernel/cpufreq.c
+215
-140
No files found.
CREDITS
View file @
3ee1e204
...
...
@@ -1522,17 +1522,12 @@ S: USA
N: Dave Jones
E: davej@codemonkey.org.uk
E: davej@suse.de
W: http://www.codemonkey.org.uk
D: x86 errata/setup maintenance.
D: AGPGART driver.
D: CPUFREQ maintenance.
D: Backport/Forwardport merge monkey.
D: Various Janitor work.
S: c/o SuSE Linux UK Ltd
S: Appleton House
S: 139 King Street
S: Hammersmith
S: W6 9JG
S: United Kingdom
N: Ani Joshi
...
...
Documentation/cpu-freq/core.txt
View file @
3ee1e204
...
...
@@ -73,9 +73,9 @@ The phase is specified in the second argument to the notifier.
The third argument, a void *pointer, points to a struct cpufreq_policy
consisting of five values: cpu, min, max, policy and max_cpu_freq. min
and max are the lower and upper frequencies (in kHz) of the new
policy, policy the new policy, cpu the number of the affected CPU
or
CPUFREQ_ALL_CPUS for all CPUs; and max_cpu_freq the maximum supported
CPU frequency. This value is given
for informational purposes only.
policy, policy the new policy, cpu the number of the affected CPU
; and
max_cpu_freq the maximum supported CPU frequency. This value is given
for informational purposes only.
2.2 CPUFreq transition notifiers
...
...
@@ -89,6 +89,6 @@ CPUFREQ_POSTCHANGE.
The third argument is a struct cpufreq_freqs with the following
values:
cpu - number of the affected CPU
or CPUFREQ_ALL_CPUS
cpu - number of the affected CPU
old - old frequency
new - new frequency
Documentation/cpu-freq/cpu-drivers.txt
View file @
3ee1e204
...
...
@@ -41,16 +41,17 @@ on what is necessary:
1.1 Initialization
------------------
First of all, in an __initcall level 7 or later (preferrably
module_init() so that your driver is modularized) function check
whether this kernel runs on the right CPU and the right chipset. If
so, register a struct cpufreq_driver with the CPUfreq core using
cpufreq_register_driver()
First of all, in an __initcall level 7 (module_init()) or later
function check whether this kernel runs on the right CPU and the right
chipset. If so, register a struct cpufreq_driver with the CPUfreq core
using cpufreq_register_driver()
What shall this struct cpufreq_driver contain?
cpufreq_driver.name - The name of this driver.
cpufreq_driver.owner - THIS_MODULE;
cpufreq_driver.init - A pointer to the per-CPU initialization
function.
...
...
@@ -76,8 +77,7 @@ cpufreq driver registers itself, the per-CPU initialization function
cpufreq_driver.init is called. It takes a struct cpufreq_policy
*policy as argument. What to do now?
If necessary, activate the CPUfreq support on your CPU (unlock that
register etc.).
If necessary, activate the CPUfreq support on your CPU.
Then, the driver must fill in the following values:
...
...
Documentation/cpu-freq/governors.txt
View file @
3ee1e204
...
...
@@ -135,21 +135,21 @@ CPUfreq core to ensure proper locking.
The CPUfreq governor may call the CPU processor driver using one of
these two functions:
in
line in
t cpufreq_driver_target(struct cpufreq_policy *policy,
int cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
in
line int cpufreq_driver_target_l
(struct cpufreq_policy *policy,
in
t __cpufreq_driver_target
(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
target_freq must be within policy->min and policy->max, of course.
What's the difference between these two functions? When your governor
still is in a direct code path of a call to governor->governor, the
cpufreq_driver_sem
lock is still held in the cpufreq core, and there's
per-CPU cpufreq
lock is still held in the cpufreq core, and there's
no need to lock it again (in fact, this would cause a deadlock). So
use
cpufreq_driver_target only in these cases. In all other cases (for
example, when there's a "daemonized" function that wakes up every
second), use cpufreq_driver_target_l to lock the cpufreq_driver_sem
before the command is passed to the cpufreq processor driver.
use
__cpufreq_driver_target only in these cases. In all other cases
(for example, when there's a "daemonized" function that wakes up
every second), use cpufreq_driver_target to lock the cpufreq per-CPU
lock
before the command is passed to the cpufreq processor driver.
Documentation/cpu-freq/user-guide.txt
View file @
3ee1e204
...
...
@@ -132,7 +132,7 @@ the processor shall run at.
The preferred interface is located in the sysfs filesystem. If you
mounted it at /sys, the cpufreq interface is located in a subdirectory
"cpufreq" within the cpu-device directory
(e.g. /sys/
class
/cpu/cpu0/cpufreq/ for the first CPU).
(e.g. /sys/
devices/system
/cpu/cpu0/cpufreq/ for the first CPU).
cpuinfo_min_freq : this file shows the minimum operating
frequency the processor can run at(in kHz)
...
...
MAINTAINERS
View file @
3ee1e204
...
...
@@ -431,8 +431,10 @@ W: http://www.fi.muni.cz/~kas/cosa/
S: Maintained
CPU FREQUENCY DRIVERS
P: Dave Jones
M: davej@codemonkey.org.uk
L: cpufreq@www.linux.org.uk
W:
http://www.brodo.de
/cpufreq/
W:
http://www.codemonkey.org.uk
/cpufreq/
S: Maintained
CPUID/MSR DRIVER
...
...
@@ -840,7 +842,7 @@ S: Maintained
i386 SETUP CODE / CPU ERRATA WORKAROUNDS
P: Dave Jones
M: davej@
suse.de
M: davej@
codemonkey.org.uk
P: H. Peter Anvin
M: hpa@zytor.com
S: Maintained
...
...
arch/i386/kernel/cpu/common.c
View file @
3ee1e204
...
...
@@ -288,11 +288,24 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
c
->
x86
=
3
;
}
if
(
this_cpu
->
c_identify
)
this_cpu
->
c_identify
(
c
);
else
generic_identify
(
c
);
printk
(
KERN_DEBUG
"CPU: After generic identify, caps: %08lx %08lx %08lx %08lx
\n
"
,
c
->
x86_capability
[
0
],
c
->
x86_capability
[
1
],
c
->
x86_capability
[
2
],
c
->
x86_capability
[
3
]);
if
(
this_cpu
->
c_identify
)
{
this_cpu
->
c_identify
(
c
);
printk
(
KERN_DEBUG
"CPU: After vendor identify, caps: %08lx %08lx %08lx %08lx
\n
"
,
c
->
x86_capability
[
0
],
c
->
x86_capability
[
1
],
c
->
x86_capability
[
2
],
c
->
x86_capability
[
3
]);
}
/*
* Vendor-specific initialization. In this section we
* canonicalize the feature flags, meaning if there are
...
...
@@ -341,7 +354,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
/* Now the feature flags better reflect actual CPU features! */
printk
(
KERN_DEBUG
"CPU: After
generic
, caps: %08lx %08lx %08lx %08lx
\n
"
,
printk
(
KERN_DEBUG
"CPU: After
all inits
, caps: %08lx %08lx %08lx %08lx
\n
"
,
c
->
x86_capability
[
0
],
c
->
x86_capability
[
1
],
c
->
x86_capability
[
2
],
...
...
arch/i386/kernel/cpu/cpufreq/acpi.c
View file @
3ee1e204
...
...
@@ -380,7 +380,7 @@ static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file)
static
int
acpi_processor_write_performance
(
struct
file
*
file
,
const
char
*
buffer
,
const
char
__user
*
buffer
,
size_t
count
,
loff_t
*
data
)
{
...
...
arch/i386/kernel/cpu/cpufreq/longhaul.c
View file @
3ee1e204
/*
* $Id: longhaul.c,v 1.87 2003/02/22 10:23:46 db Exp $
*
* (C) 2001 Dave Jones. <davej@suse.de>
* (C) 2001-2003 Dave Jones. <davej@codemonkey.org.uk>
* (C) 2002 Padraig Brady. <padraig@antefacto.com>
*
* Licensed under the terms of the GNU GPL License version 2.
...
...
@@ -32,6 +30,8 @@
#include <asm/timex.h>
#include <asm/io.h>
#include "longhaul.h"
#define DEBUG
#ifdef DEBUG
...
...
@@ -40,6 +40,8 @@
#define dprintk(msg...) do { } while(0)
#endif
#define PFX "longhaul: "
static
unsigned
int
numscales
=
16
,
numvscales
;
static
int
minvid
,
maxvid
;
static
int
can_scale_voltage
;
...
...
@@ -248,7 +250,7 @@ static int clock_ratio[32];
static
int
eblcr_table
[
32
];
static
int
voltage_table
[
32
];
static
unsigned
int
highest_speed
,
lowest_speed
;
/* kHz */
static
int
longhaul
;
/* version. */
static
int
longhaul
_version
;
static
struct
cpufreq_frequency_table
*
longhaul_table
;
...
...
@@ -273,7 +275,7 @@ static int longhaul_get_cpu_mult (void)
rdmsr
(
MSR_IA32_EBL_CR_POWERON
,
lo
,
hi
);
invalue
=
(
lo
&
(
1
<<
22
|
1
<<
23
|
1
<<
24
|
1
<<
25
))
>>
22
;
if
(
longhaul
==
3
)
{
if
(
longhaul
_version
==
3
)
{
if
(
lo
&
(
1
<<
27
))
invalue
+=
16
;
}
...
...
@@ -283,18 +285,17 @@ static int longhaul_get_cpu_mult (void)
/**
* longhaul_set_cpu_frequency()
* @clock_ratio_index :
index of clock_ratio[] for new frequency
* @clock_ratio_index :
bitpattern of the new multiplier.
*
* Sets a new clock ratio, and -if applicable- a new Front Side Bus
*/
static
void
longhaul_setstate
(
unsigned
int
clock_ratio_index
)
{
unsigned
long
lo
,
hi
;
unsigned
int
bits
;
int
revkey
;
int
vidindex
,
i
;
struct
cpufreq_freqs
freqs
;
union
msr_longhaul
longhaul
;
union
msr_bcr2
bcr2
;
if
(
clock_ratio
[
clock_ratio_index
]
==
-
1
)
return
;
...
...
@@ -309,39 +310,33 @@ static void longhaul_setstate (unsigned int clock_ratio_index)
cpufreq_notify_transition
(
&
freqs
,
CPUFREQ_PRECHANGE
);
dprintk
(
KERN_INFO
"longhaul:
FSB:%d Mult(x10):%d
\n
"
,
dprintk
(
KERN_INFO
PFX
"
FSB:%d Mult(x10):%d
\n
"
,
fsb
*
100
,
clock_ratio
[
clock_ratio_index
]);
bits
=
clock_ratio_index
;
/* "bits" contains the bitpattern of the new multiplier.
we now need to transform it to the desired format. */
switch
(
longhaul
)
{
switch
(
longhaul_version
)
{
case
1
:
rdmsr
(
MSR_VIA_BCR2
,
lo
,
hi
);
revkey
=
(
lo
&
0xf
)
<<
4
;
/* Rev key. */
lo
&=
~
(
1
<<
23
|
1
<<
24
|
1
<<
25
|
1
<<
26
);
lo
|=
(
1
<<
19
);
/* Enable software clock multiplier */
lo
|=
(
bits
<<
23
);
/* desired multiplier */
lo
|=
revkey
;
wrmsr
(
MSR_VIA_BCR2
,
lo
,
hi
);
rdmsrl
(
MSR_VIA_BCR2
,
bcr2
.
val
);
/* Enable software clock multiplier */
bcr2
.
bits
.
ESOFTBF
=
1
;
bcr2
.
bits
.
CLOCKMUL
=
clock_ratio_index
;
wrmsrl
(
MSR_VIA_BCR2
,
bcr2
.
val
);
__hlt
();
/* Disable software clock multiplier */
rdmsr
(
MSR_VIA_BCR2
,
lo
,
hi
);
lo
&=
~
(
1
<<
19
);
lo
|=
revkey
;
wrmsr
(
MSR_VIA_BCR2
,
lo
,
hi
);
rdmsrl
(
MSR_VIA_BCR2
,
bcr2
.
val
);
bcr2
.
bits
.
ESOFTBF
=
0
;
wrmsrl
(
MSR_VIA_BCR2
,
bcr2
.
val
);
break
;
case
2
:
rdmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
revkey
=
(
lo
&
0xf
)
<<
4
;
/* Rev key. */
lo
&=
0xfff0bf0f
;
/* reset [19:16,14](bus ratio) and [7:4](rev key) to 0 */
lo
|=
(
bits
<<
16
);
lo
|=
(
1
<<
8
);
/* EnableSoftBusRatio */
lo
|=
revkey
;
rdmsrl
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
longhaul
.
bits
.
SoftBusRatio
=
clock_ratio_index
&
0xf
;
longhaul
.
bits
.
SoftBusRatio4
=
(
clock_ratio_index
&
0x10
)
>>
4
;
longhaul
.
bits
.
EnableSoftBusRatio
=
1
;
/* We must program the revision key only with values we
* know about, not blindly copy it from 0:3 */
longhaul
.
bits
.
RevisionKey
=
1
;
if
(
can_scale_voltage
)
{
/* PB: TODO fix this up */
...
...
@@ -356,41 +351,41 @@ static void longhaul_setstate (unsigned int clock_ratio_index)
if
(
i
==
32
)
goto
bad_voltage
;
dprintk
(
KERN_INFO
"longhaul:
Desired vid index=%d
\n
"
,
i
);
dprintk
(
KERN_INFO
PFX
"
Desired vid index=%d
\n
"
,
i
);
#if 0
lo &= 0xfe0fffff;/* reset [24:20](voltage) to 0 */
lo |= (i<<20); /* set voltage */
lo |= (1<<9); /* EnableSoftVID */
longhaul.bits.SoftVID = i;
longhaul.bits.EnableSoftVID = 1;
#endif
}
/* FIXME: Do voltage and freq seperatly like we do in powernow-k7 */
bad_voltage:
wrmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
wrmsr
l
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
__hlt
();
rdmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
lo
&=
~
(
1
<<
8
)
;
rdmsr
l
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
lo
nghaul
.
bits
.
EnableSoftBusRatio
=
0
;
if
(
can_scale_voltage
)
lo
&=
~
(
1
<<
9
)
;
lo
|=
revkey
;
wrmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
lo
nghaul
.
bits
.
EnableSoftVID
=
0
;
lo
nghaul
.
bits
.
RevisionKey
=
1
;
wrmsr
l
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
break
;
case
3
:
rdmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
revkey
=
(
lo
&
0xf
)
<<
4
;
/* Rev key. */
lo
&=
0xfff0bf0f
;
/* reset longhaul[19:16,14] to 0 */
lo
|=
(
bits
<<
16
);
lo
|=
(
1
<<
8
);
/* EnableSoftBusRatio */
lo
|=
revkey
;
wrmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
rdmsrl
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
longhaul
.
bits
.
SoftBusRatio
=
clock_ratio_index
&
0xf
;
longhaul
.
bits
.
SoftBusRatio4
=
(
clock_ratio_index
&
0x10
)
>>
4
;
longhaul
.
bits
.
EnableSoftBusRatio
=
1
;
/* We must program the revision key only with values we
* know about, not blindly copy it from 0:3 */
longhaul
.
bits
.
RevisionKey
=
3
;
/* SoftVID & SoftBSEL */
wrmsrl
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
__hlt
();
rdmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
lo
&=
~
(
1
<<
8
)
;
lo
|=
revkey
;
wrmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
rdmsr
l
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
lo
nghaul
.
bits
.
EnableSoftBusRatio
=
0
;
lo
nghaul
.
bits
.
RevisionKey
=
3
;
wrmsr
l
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
break
;
}
...
...
@@ -400,14 +395,15 @@ static void longhaul_setstate (unsigned int clock_ratio_index)
static
int
__init
longhaul_get_ranges
(
void
)
{
unsigned
long
lo
,
hi
,
invalue
;
unsigned
long
invalue
;
unsigned
int
minmult
=
0
,
maxmult
=
0
;
unsigned
int
multipliers
[
32
]
=
{
50
,
30
,
40
,
100
,
55
,
35
,
45
,
95
,
90
,
70
,
80
,
60
,
120
,
75
,
85
,
65
,
-
1
,
110
,
120
,
-
1
,
135
,
115
,
125
,
105
,
130
,
150
,
160
,
140
,
-
1
,
155
,
-
1
,
145
};
unsigned
int
j
,
k
=
0
;
union
msr_longhaul
longhaul
;
switch
(
longhaul
)
{
switch
(
longhaul
_version
)
{
case
1
:
/* Ugh, Longhaul v1 didn't have the min/max MSRs.
Assume min=3.0x & max = whatever we booted at. */
...
...
@@ -416,16 +412,16 @@ static int __init longhaul_get_ranges (void)
break
;
case
2
...
3
:
rdmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
rdmsr
l
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
invalue
=
(
hi
&
(
1
<<
0
|
1
<<
1
|
1
<<
2
|
1
<<
3
))
;
if
(
hi
&
(
1
<<
11
)
)
invalue
=
longhaul
.
bits
.
MaxMHzBR
;
if
(
longhaul
.
bits
.
MaxMHzBR4
)
invalue
+=
16
;
maxmult
=
multipliers
[
invalue
];
#if 0
/* This is MaxMhz @ Min Voltage. Ignore for now */
invalue =
(hi & (1<<16|1<<17|1<<18|1<<19)) >> 16
;
if (
hi & (1<<27))
#if 0
invalue =
longhaul.bits.MinMHzBR
;
if (
longhaul.bits.MinMHzBR4);
invalue += 16;
minmult = multipliers[invalue];
#else
...
...
@@ -436,9 +432,9 @@ static int __init longhaul_get_ranges (void)
highest_speed
=
maxmult
*
fsb
*
100
;
lowest_speed
=
minmult
*
fsb
*
100
;
dprintk
(
KERN_INFO
"longhaul:
MinMult(x10)=%d MaxMult(x10)=%d
\n
"
,
dprintk
(
KERN_INFO
PFX
"
MinMult(x10)=%d MaxMult(x10)=%d
\n
"
,
minmult
,
maxmult
);
dprintk
(
KERN_INFO
"longhaul:
Lowestspeed=%d Highestspeed=%d
\n
"
,
dprintk
(
KERN_INFO
PFX
"
Lowestspeed=%d Highestspeed=%d
\n
"
,
lowest_speed
,
highest_speed
);
longhaul_table
=
kmalloc
((
numscales
+
1
)
*
sizeof
(
struct
cpufreq_frequency_table
),
GFP_KERNEL
);
...
...
@@ -465,38 +461,57 @@ static int __init longhaul_get_ranges (void)
}
static
void
__init
longhaul_setup_voltagescaling
(
unsigned
long
lo
,
unsigned
long
hi
)
static
void
__init
longhaul_setup_voltagescaling
(
void
)
{
int
revkey
;
union
msr_longhaul
longhaul
;
can_scale_voltage
=
1
;
rdmsrl
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
if
(
!
(
longhaul
.
bits
.
RevisionID
&
1
))
return
;
minvid
=
longhaul
.
bits
.
MinimumVID
;
maxvid
=
longhaul
.
bits
.
MaximumVID
;
vrmrev
=
longhaul
.
bits
.
VRMRev
;
minvid
=
(
hi
&
(
1
<<
20
|
1
<<
21
|
1
<<
22
|
1
<<
23
|
1
<<
24
))
>>
20
;
/* 56:52 */
maxvid
=
(
hi
&
(
1
<<
4
|
1
<<
5
|
1
<<
6
|
1
<<
7
|
1
<<
8
))
>>
4
;
/* 40:36 */
vrmrev
=
(
lo
&
(
1
<<
15
))
>>
15
;
if
(
minvid
==
0
||
maxvid
==
0
)
{
printk
(
KERN_INFO
PFX
"Bogus values Min:%d.%03d Max:%d.%03d. "
"Voltage scaling disabled.
\n
"
,
minvid
/
1000
,
minvid
%
1000
,
maxvid
/
1000
,
maxvid
%
1000
);
return
;
}
if
(
minvid
==
maxvid
)
{
printk
(
KERN_INFO
PFX
"Claims to support voltage scaling but min & max are "
"both %d.%03d. Voltage scaling disabled
\n
"
,
maxvid
/
1000
,
maxvid
%
1000
);
return
;
}
if
(
vrmrev
==
0
)
{
dprintk
(
KERN_INFO
"longhaul:
VRM 8.5 : "
);
dprintk
(
KERN_INFO
PFX
"
VRM 8.5 : "
);
memcpy
(
voltage_table
,
vrm85scales
,
sizeof
(
voltage_table
));
numvscales
=
(
voltage_table
[
maxvid
]
-
voltage_table
[
minvid
])
/
25
;
}
else
{
dprintk
(
KERN_INFO
"longhaul:
Mobile VRM : "
);
dprintk
(
KERN_INFO
PFX
"
Mobile VRM : "
);
memcpy
(
voltage_table
,
mobilevrmscales
,
sizeof
(
voltage_table
));
numvscales
=
(
voltage_table
[
maxvid
]
-
voltage_table
[
minvid
])
/
5
;
}
/* Current voltage isn't readable at first, so we need to
set it to a known value. The spec says to use maxvid */
revkey
=
(
lo
&
0xf
)
<<
4
;
/* Rev key. */
lo
&=
0xfe0fff0f
;
/* Mask unneeded bits */
lo
|=
(
1
<<
9
);
/* EnableSoftVID */
lo
|=
revkey
;
/* Reinsert key */
lo
|=
maxvid
<<
20
;
wrmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
longhaul
.
bits
.
RevisionKey
=
longhaul
.
bits
.
RevisionID
;
/* FIXME: This is bad. */
longhaul
.
bits
.
EnableSoftVID
=
1
;
longhaul
.
bits
.
SoftVID
=
maxvid
;
wrmsrl
(
MSR_VIA_LONGHAUL
,
longhaul
.
val
);
minvid
=
voltage_table
[
minvid
];
maxvid
=
voltage_table
[
maxvid
];
dprintk
(
"Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales
\n
"
,
maxvid
/
1000
,
maxvid
%
1000
,
minvid
/
1000
,
minvid
%
1000
,
numvscales
);
can_scale_voltage
=
1
;
}
...
...
@@ -530,7 +545,7 @@ static int longhaul_cpu_init (struct cpufreq_policy *policy)
switch
(
c
->
x86_model
)
{
case
6
:
/* VIA C3 Samuel C5A */
longhaul
=
1
;
longhaul
_version
=
1
;
memcpy
(
clock_ratio
,
longhaul1_clock_ratio
,
sizeof
(
longhaul1_clock_ratio
));
memcpy
(
eblcr_table
,
samuel1_eblcr
,
sizeof
(
samuel1_eblcr
));
break
;
...
...
@@ -538,12 +553,12 @@ static int longhaul_cpu_init (struct cpufreq_policy *policy)
case
7
:
/* C5B / C5C */
switch
(
c
->
x86_mask
)
{
case
0
:
longhaul
=
1
;
longhaul
_version
=
1
;
memcpy
(
clock_ratio
,
longhaul1_clock_ratio
,
sizeof
(
longhaul1_clock_ratio
));
memcpy
(
eblcr_table
,
samuel2_eblcr
,
sizeof
(
samuel2_eblcr
));
break
;
case
1
...
15
:
longhaul
=
2
;
longhaul
_version
=
2
;
memcpy
(
clock_ratio
,
longhaul2_clock_ratio
,
sizeof
(
longhaul2_clock_ratio
));
memcpy
(
eblcr_table
,
ezra_eblcr
,
sizeof
(
ezra_eblcr
));
break
;
...
...
@@ -552,21 +567,18 @@ static int longhaul_cpu_init (struct cpufreq_policy *policy)
case
8
:
/* C5M/C5N */
return
-
ENODEV
;
// Waiting on updated docs from VIA before this is usable
longhaul
=
3
;
longhaul
_version
=
3
;
numscales
=
32
;
memcpy
(
clock_ratio
,
longhaul3_clock_ratio
,
sizeof
(
longhaul3_clock_ratio
));
memcpy
(
eblcr_table
,
c5m_eblcr
,
sizeof
(
c5m_eblcr
));
break
;
}
printk
(
KERN_INFO
"longhaul: VIA CPU detected. Longhaul version %d supported
\n
"
,
longhaul
);
printk
(
KERN_INFO
PFX
"VIA CPU detected. Longhaul version %d supported
\n
"
,
longhaul_version
);
if
(
longhaul
==
2
||
longhaul
==
3
)
{
unsigned
long
lo
,
hi
;
rdmsr
(
MSR_VIA_LONGHAUL
,
lo
,
hi
);
if
((
lo
&
(
1
<<
0
))
&&
(
dont_scale_voltage
==
0
))
longhaul_setup_voltagescaling
(
lo
,
hi
);
}
if
((
longhaul_version
==
2
||
longhaul_version
==
3
)
&&
(
dont_scale_voltage
==
0
))
longhaul_setup_voltagescaling
();
ret
=
longhaul_get_ranges
();
if
(
ret
!=
0
)
...
...
@@ -601,7 +613,7 @@ static int __init longhaul_init (void)
case
8
:
return
-
ENODEV
;
default:
printk
(
KERN_INFO
"longhaul: Unknown VIA CPU. Contact davej@suse.de
\n
"
);
printk
(
KERN_INFO
PFX
"Unknown VIA CPU. Contact davej@codemonkey.org.uk
\n
"
);
}
return
-
ENODEV
;
...
...
@@ -615,7 +627,7 @@ static void __exit longhaul_exit (void)
MODULE_PARM
(
dont_scale_voltage
,
"i"
);
MODULE_AUTHOR
(
"Dave Jones <davej@
suse.de
>"
);
MODULE_AUTHOR
(
"Dave Jones <davej@
codemonkey.org.uk
>"
);
MODULE_DESCRIPTION
(
"Longhaul driver for VIA Cyrix processors."
);
MODULE_LICENSE
(
"GPL"
);
...
...
arch/i386/kernel/cpu/cpufreq/longhaul.h
0 → 100644
View file @
3ee1e204
/*
* longhaul.h
* (C) 2003 Dave Jones.
*
* Licensed under the terms of the GNU GPL License version 2.
*
* VIA-specific information
*/
union
msr_bcr2
{
struct
{
unsigned
Reseved
:
19
,
// 18:0
ESOFTBF:
1
,
// 19
Reserved2:
3
,
// 22:20
CLOCKMUL:
4
,
// 26:23
Reserved3:
5
;
// 31:27
}
bits
;
unsigned
long
val
;
};
union
msr_longhaul
{
struct
{
unsigned
RevisionID
:
4
,
// 3:0
RevisionKey:
4
,
// 7:4
EnableSoftBusRatio:
1
,
// 8
EnableSoftVID:
1
,
// 9
EnableSoftBSEL:
1
,
// 10
Reserved:
3
,
// 11:13
SoftBusRatio4:
1
,
// 14
VRMRev:
1
,
// 15
SoftBusRatio:
4
,
// 19:16
SoftVID:
5
,
// 24:20
Reserved2:
3
,
// 27:25
SoftBSEL:
2
,
// 29:28
Reserved3:
2
,
// 31:30
MaxMHzBR:
4
,
// 35:32
MaximumVID:
5
,
// 40:36
MaxMHzFSB:
2
,
// 42:41
MaxMHzBR4:
1
,
// 43
Reserved4:
4
,
// 47:44
MinMHzBR:
4
,
// 51:48
MinimumVID:
5
,
// 56:52
MinMHzFSB:
2
,
// 58:57
MinMHzBR4:
1
,
// 59
Reserved5:
4
;
// 63:60
}
bits
;
unsigned
long
long
val
;
};
arch/i386/kernel/cpu/cpufreq/longrun.c
View file @
3ee1e204
/*
* $Id: longrun.c,v 1.25 2003/02/28 16:03:50 db Exp $
*
* (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
*
* Licensed under the terms of the GNU GPL License version 2.
...
...
@@ -123,7 +121,7 @@ static int longrun_verify_policy(struct cpufreq_policy *policy)
policy
->
cpuinfo
.
max_freq
);
if
(
policy
->
policy
==
CPUFREQ_POLICY_GOVERNOR
)
policy
->
policy
=
longrun_driver
.
policy
[
0
].
policy
;
return
-
EINVAL
;
return
0
;
}
...
...
arch/i386/kernel/cpu/cpufreq/powernow-k6.c
View file @
3ee1e204
/*
* $Id: powernow-k6.c,v 1.48 2003/02/22 10:23:46 db Exp $
* This file was part of Powertweak Linux (http://powertweak.sf.net)
* and is shared with the Linux Kernel module.
*
* This file was based upon code in Powertweak Linux (http://powertweak.sf.net)
* (C) 2000-2003 Dave Jones, Arjan van de Ven, Janne Pnkl, Dominik Brodowski.
*
* Licensed under the terms of the GNU GPL License version 2.
...
...
@@ -230,7 +227,7 @@ static void __exit powernow_k6_exit(void)
}
MODULE_AUTHOR
(
"Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@
suse.de
>, Dominik Brodowski <linux@brodo.de>"
);
MODULE_AUTHOR
(
"Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@
codemonkey.org.uk
>, Dominik Brodowski <linux@brodo.de>"
);
MODULE_DESCRIPTION
(
"PowerNow! driver for AMD K6-2+ / K6-3+ processors."
);
MODULE_LICENSE
(
"GPL"
);
...
...
arch/i386/kernel/cpu/cpufreq/powernow-k7.c
View file @
3ee1e204
/*
* $Id: powernow-k7.c,v 1.34 2003/02/22 10:23:46 db Exp $
*
* (C) 2003 Dave Jones <davej@suse.de>
* AMD K7 Powernow driver.
* (C) 2003 Dave Jones <davej@codemonkey.org.uk> on behalf of SuSE Labs.
*
* Licensed under the terms of the GNU GPL License version 2.
* Based upon datasheets & sample CPUs kindly provided by AMD.
...
...
@@ -85,27 +84,6 @@ static unsigned int latency;
static
char
have_a0
;
#ifndef rdmsrl
#define rdmsrl(msr,val) do {unsigned long l__,h__; \
rdmsr (msr, l__, h__); \
val = l__; \
val |= ((u64)h__<<32); \
} while(0)
#endif
#ifndef wrmsrl
static
void
wrmsrl
(
u32
msr
,
u64
val
)
{
u32
lo
,
hi
;
lo
=
(
u32
)
val
;
hi
=
val
>>
32
;
wrmsr
(
msr
,
lo
,
hi
);
}
#endif
static
int
check_powernow
(
void
)
{
struct
cpuinfo_x86
*
c
=
cpu_data
;
...
...
@@ -240,6 +218,7 @@ static void change_speed (unsigned int index)
u8
fid
,
vid
;
struct
cpufreq_freqs
freqs
;
union
msr_fidvidstatus
fidvidstatus
;
int
cfid
;
/* fid are the lower 8 bits of the index we stored into
* the cpufreq frequency table in powernow_decode_bios,
...
...
@@ -251,8 +230,9 @@ static void change_speed (unsigned int index)
freqs
.
cpu
=
0
;
cfid
=
fidvidstatus
.
bits
.
CFID
;
rdmsrl
(
MSR_K7_FID_VID_STATUS
,
fidvidstatus
.
val
);
freqs
.
old
=
fsb
*
fid_codes
[
fidvidstatus
.
bits
.
CFID
]
*
100
;
freqs
.
old
=
fsb
*
fid_codes
[
cfid
]
*
100
;
freqs
.
new
=
powernow_table
[
index
].
frequency
;
cpufreq_notify_transition
(
&
freqs
,
CPUFREQ_PRECHANGE
);
...
...
@@ -426,7 +406,7 @@ static void __exit powernow_exit (void)
kfree
(
powernow_table
);
}
MODULE_AUTHOR
(
"Dave Jones <davej@
suse.de
>"
);
MODULE_AUTHOR
(
"Dave Jones <davej@
codemonkey.org.uk
>"
);
MODULE_DESCRIPTION
(
"Powernow driver for AMD K7 processors."
);
MODULE_LICENSE
(
"GPL"
);
...
...
arch/i386/kernel/cpu/cpufreq/powernow-k7.h
View file @
3ee1e204
...
...
@@ -8,14 +8,6 @@
*
*/
#ifndef MSR_K7_FID_VID_CTL
#define MSR_K7_FID_VID_CTL 0xc0010041
#endif
#ifndef MSR_K7_FID_VID_STATUS
#define MSR_K7_FID_VID_STATUS 0xc0010042
#endif
union
msr_fidvidctl
{
struct
{
unsigned
FID
:
5
,
// 4:0
...
...
arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
View file @
3ee1e204
...
...
@@ -82,7 +82,7 @@ static void speedstep_set_state (unsigned int state, unsigned int notify)
return
;
freqs
.
old
=
speedstep_get_processor_frequency
(
speedstep_processor
);
freqs
.
new
=
speedstep_freqs
[
SPEEDSTEP_LOW
].
frequency
;
freqs
.
new
=
speedstep_freqs
[
state
].
frequency
;
freqs
.
cpu
=
0
;
/* speedstep.c is UP only driver */
if
(
notify
)
...
...
@@ -137,7 +137,7 @@ static void speedstep_set_state (unsigned int state, unsigned int notify)
dprintk
(
KERN_DEBUG
"cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x
\n
"
,
pmbase
,
value
);
if
(
state
==
(
value
&
0x1
))
{
dprintk
(
KERN_INFO
"cpufreq: change to %u MHz succeeded
\n
"
,
(
freqs
.
new
/
1000
));
dprintk
(
KERN_INFO
"cpufreq: change to %u MHz succeeded
\n
"
,
(
speedstep_get_processor_frequency
(
speedstep_processor
)
/
1000
));
}
else
{
printk
(
KERN_ERR
"cpufreq: change failed - I/O error
\n
"
);
}
...
...
@@ -295,7 +295,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
return
-
EIO
;
dprintk
(
KERN_INFO
"cpufreq: currently at %s speed setting - %i MHz
\n
"
,
(
speed
==
speedstep_
low_freq
)
?
"low"
:
"high"
,
(
speed
==
speedstep_
freqs
[
SPEEDSTEP_LOW
].
frequency
)
?
"low"
:
"high"
,
(
speed
/
1000
));
/* cpuinfo and default policy values */
...
...
@@ -356,7 +356,7 @@ static void __exit speedstep_exit(void)
}
MODULE_AUTHOR
(
"Dave Jones <davej@
suse.de
>, Dominik Brodowski <linux@brodo.de>"
);
MODULE_AUTHOR
(
"Dave Jones <davej@
codemonkey.org.uk
>, Dominik Brodowski <linux@brodo.de>"
);
MODULE_DESCRIPTION
(
"Speedstep driver for Intel mobile processors on chipsets with ICH-M southbridges."
);
MODULE_LICENSE
(
"GPL"
);
...
...
drivers/cpufreq/userspace.c
View file @
3ee1e204
...
...
@@ -158,7 +158,7 @@ EXPORT_SYMBOL(cpufreq_get);
/*********************** cpufreq_sysctl interface ********************/
static
int
cpufreq_procctl
(
ctl_table
*
ctl
,
int
write
,
struct
file
*
filp
,
void
*
buffer
,
size_t
*
lenp
)
void
__user
*
buffer
,
size_t
*
lenp
)
{
char
buf
[
16
],
*
p
;
int
cpu
=
(
int
)
ctl
->
extra1
;
...
...
@@ -195,9 +195,9 @@ cpufreq_procctl(ctl_table *ctl, int write, struct file *filp,
}
static
int
cpufreq_sysctl
(
ctl_table
*
table
,
int
*
name
,
int
nlen
,
void
*
oldval
,
size_t
*
oldlenp
,
void
*
newval
,
size_t
newlen
,
void
**
context
)
cpufreq_sysctl
(
ctl_table
*
table
,
int
__user
*
name
,
int
nlen
,
void
__user
*
oldval
,
size_t
__user
*
oldlenp
,
void
__user
*
newval
,
size_t
newlen
,
void
**
context
)
{
int
cpu
=
(
int
)
table
->
extra1
;
...
...
@@ -524,10 +524,10 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
cpu_min_freq
[
cpu
]
=
policy
->
min
;
cpu_max_freq
[
cpu
]
=
policy
->
max
;
if
(
policy
->
max
<
cpu_cur_freq
[
cpu
])
cpufreq_driver_target
(
&
current_policy
[
cpu
],
policy
->
max
,
__
cpufreq_driver_target
(
&
current_policy
[
cpu
],
policy
->
max
,
CPUFREQ_RELATION_H
);
else
if
(
policy
->
min
>
cpu_cur_freq
[
cpu
])
cpufreq_driver_target
(
&
current_policy
[
cpu
],
policy
->
min
,
__
cpufreq_driver_target
(
&
current_policy
[
cpu
],
policy
->
min
,
CPUFREQ_RELATION_L
);
memcpy
(
&
current_policy
[
cpu
],
policy
,
sizeof
(
struct
cpufreq_policy
));
up
(
&
userspace_sem
);
...
...
include/asm-i386/msr.h
View file @
3ee1e204
...
...
@@ -17,6 +17,21 @@
:
/* no outputs */
\
: "c" (msr), "a" (val1), "d" (val2))
#define rdmsrl(msr,val) do { \
unsigned long l__,h__; \
rdmsr (msr, l__, h__); \
val = l__; \
val |= ((u64)h__<<32); \
} while(0)
static
inline
void
wrmsrl
(
unsigned
long
msr
,
unsigned
long
long
val
)
{
unsigned
long
lo
,
hi
;
lo
=
(
unsigned
long
)
val
;
hi
=
val
>>
32
;
wrmsr
(
msr
,
lo
,
hi
);
}
#define rdtsc(low,high) \
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
...
...
@@ -200,7 +215,7 @@
#define MSR_K7_HWCR 0xC0010015
#define MSR_K7_CLK_CTL 0xC001001b
#define MSR_K7_FID_VID_CTL 0xC0010041
#define MSR_K7_VID_STATUS 0xC0010042
#define MSR_K7_
FID_
VID_STATUS 0xC0010042
/* Centaur-Hauls/IDT defined MSRs. */
#define MSR_IDT_FCR1 0x107
...
...
include/linux/cpufreq.h
View file @
3ee1e204
...
...
@@ -137,10 +137,14 @@ struct cpufreq_governor {
/* pass a target to the cpufreq driver
*/
inline
int
cpufreq_driver_target
(
struct
cpufreq_policy
*
policy
,
extern
int
cpufreq_driver_target
(
struct
cpufreq_policy
*
policy
,
unsigned
int
target_freq
,
unsigned
int
relation
);
extern
int
__cpufreq_driver_target
(
struct
cpufreq_policy
*
policy
,
unsigned
int
target_freq
,
unsigned
int
relation
);
/* pass an event to the cpufreq governor */
int
cpufreq_governor
(
unsigned
int
cpu
,
unsigned
int
event
);
...
...
@@ -160,8 +164,6 @@ struct cpufreq_driver {
struct
module
*
owner
;
char
name
[
CPUFREQ_NAME_LEN
];
struct
cpufreq_policy
*
policy
;
/* needed by all drivers */
int
(
*
init
)
(
struct
cpufreq_policy
*
policy
);
int
(
*
verify
)
(
struct
cpufreq_policy
*
policy
);
...
...
kernel/cpufreq.c
View file @
3ee1e204
...
...
@@ -27,20 +27,23 @@
/**
* The "cpufreq driver" - the arch- or hardware-dependend low
* level driver of CPUFreq support, and its
locking mutex.
*
cpu_max_freq is in kHz
.
* level driver of CPUFreq support, and its
spinlock. This lock
*
also protects the cpufreq_cpu_data array
.
*/
static
struct
cpufreq_driver
*
cpufreq_driver
;
static
DECLARE_MUTEX
(
cpufreq_driver_sem
);
static
struct
cpufreq_policy
*
cpufreq_cpu_data
[
NR_CPUS
];
static
spinlock_t
cpufreq_driver_lock
=
SPIN_LOCK_UNLOCKED
;
/* internal prototype */
static
int
__cpufreq_governor
(
struct
cpufreq_policy
*
policy
,
unsigned
int
event
);
/**
* Two notifier lists: the "policy" list is involved in the
* validation process for a new CPU frequency policy; the
* "transition" list for kernel code that needs to handle
* changes to devices when the CPU clock speed changes.
* The mutex locks both lists. If both cpufreq_driver_sem
* and cpufreq_notifier_sem need to be hold, get cpufreq_driver_sem
* first.
* The mutex locks both lists.
*/
static
struct
notifier_block
*
cpufreq_policy_notifier_list
;
static
struct
notifier_block
*
cpufreq_transition_notifier_list
;
...
...
@@ -50,28 +53,49 @@ static DECLARE_RWSEM (cpufreq_notifier_rwsem);
static
LIST_HEAD
(
cpufreq_governor_list
);
static
DECLARE_MUTEX
(
cpufreq_governor_sem
);
static
int
cpufreq_cpu_get
(
unsigned
int
cpu
)
static
struct
cpufreq_policy
*
cpufreq_cpu_get
(
unsigned
int
cpu
)
{
struct
cpufreq_policy
*
data
;
unsigned
long
flags
;
if
(
cpu
>=
NR_CPUS
)
return
0
;
goto
err_out
;
/* get the cpufreq driver */
spin_lock_irqsave
(
&
cpufreq_driver_lock
,
flags
);
if
(
!
cpufreq_driver
)
return
0
;
goto
err_out_unlock
;
if
(
!
try_module_get
(
cpufreq_driver
->
owner
))
return
0
;
goto
err_out_unlock
;
if
(
!
kobject_get
(
&
cpufreq_driver
->
policy
[
cpu
].
kobj
))
{
module_put
(
cpufreq_driver
->
owner
);
return
0
;
}
return
1
;
/* get the CPU */
data
=
cpufreq_cpu_data
[
cpu
];
if
(
!
data
)
goto
err_out_put_module
;
if
(
!
kobject_get
(
&
data
->
kobj
))
goto
err_out_put_module
;
spin_unlock_irqrestore
(
&
cpufreq_driver_lock
,
flags
);
return
data
;
err_out_put_module:
module_put
(
cpufreq_driver
->
owner
);
err_out_unlock:
spin_unlock_irqrestore
(
&
cpufreq_driver_lock
,
flags
);
err_out:
return
NULL
;
}
static
void
cpufreq_cpu_put
(
unsigned
int
cpu
)
static
void
cpufreq_cpu_put
(
struct
cpufreq_policy
*
data
)
{
kobject_put
(
&
cpufreq_driver
->
policy
[
cpu
].
kobj
);
kobject_put
(
&
data
->
kobj
);
module_put
(
cpufreq_driver
->
owner
);
}
...
...
@@ -278,10 +302,11 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf)
struct
cpufreq_policy
*
policy
=
to_policy
(
kobj
);
struct
freq_attr
*
fattr
=
to_attr
(
attr
);
ssize_t
ret
;
if
(
!
cpufreq_cpu_get
(
policy
->
cpu
))
policy
=
cpufreq_cpu_get
(
policy
->
cpu
);
if
(
!
policy
)
return
-
EINVAL
;
ret
=
fattr
->
show
?
fattr
->
show
(
policy
,
buf
)
:
0
;
cpufreq_cpu_put
(
policy
->
cpu
);
cpufreq_cpu_put
(
policy
);
return
ret
;
}
...
...
@@ -291,10 +316,11 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr,
struct
cpufreq_policy
*
policy
=
to_policy
(
kobj
);
struct
freq_attr
*
fattr
=
to_attr
(
attr
);
ssize_t
ret
;
if
(
!
cpufreq_cpu_get
(
policy
->
cpu
))
policy
=
cpufreq_cpu_get
(
policy
->
cpu
);
if
(
!
policy
)
return
-
EINVAL
;
ret
=
fattr
->
store
?
fattr
->
store
(
policy
,
buf
,
count
)
:
0
;
cpufreq_cpu_put
(
policy
->
cpu
);
cpufreq_cpu_put
(
policy
);
return
ret
;
}
...
...
@@ -328,28 +354,28 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
struct
cpufreq_policy
new_policy
;
struct
cpufreq_policy
*
policy
;
struct
freq_attr
**
drv_attr
;
unsigned
long
flags
;
if
(
!
try_module_get
(
cpufreq_driver
->
owner
))
return
-
EINVAL
;
policy
=
kmalloc
(
sizeof
(
struct
cpufreq_policy
),
GFP_KERNEL
);
if
(
!
policy
)
return
-
ENOMEM
;
memset
(
policy
,
0
,
sizeof
(
struct
cpufreq_policy
));
policy
->
cpu
=
cpu
;
init_MUTEX_LOCKED
(
&
policy
->
lock
);
init_completion
(
&
policy
->
kobj_unregister
);
/* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU
*/
policy
=
&
cpufreq_driver
->
policy
[
cpu
];
policy
->
cpu
=
cpu
;
ret
=
cpufreq_driver
->
init
(
policy
);
if
(
ret
)
goto
out
;
/* set default policy on this CPU */
down
(
&
cpufreq_driver_sem
);
memcpy
(
&
new_policy
,
policy
,
sizeof
(
struct
cpufreq_policy
));
up
(
&
cpufreq_driver_sem
);
goto
err_out
;
init_MUTEX
(
&
policy
->
lock
);
init_completion
(
&
policy
->
kobj_unregister
);
memcpy
(
&
new_policy
,
policy
,
sizeof
(
struct
cpufreq_policy
));
/* prepare interface data */
policy
->
kobj
.
parent
=
&
sys_dev
->
kobj
;
...
...
@@ -358,7 +384,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
ret
=
kobject_register
(
&
policy
->
kobj
);
if
(
ret
)
goto
out
;
goto
err_
out
;
/* set up files for this cpu device */
drv_attr
=
cpufreq_driver
->
attr
;
...
...
@@ -367,14 +393,31 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
drv_attr
++
;
}
spin_lock_irqsave
(
&
cpufreq_driver_lock
,
flags
);
cpufreq_cpu_data
[
cpu
]
=
policy
;
spin_unlock_irqrestore
(
&
cpufreq_driver_lock
,
flags
);
up
(
&
policy
->
lock
);
/* set default policy */
ret
=
cpufreq_set_policy
(
&
new_policy
);
if
(
ret
)
{
if
(
ret
)
goto
err_out_unregister
;
module_put
(
cpufreq_driver
->
owner
);
return
0
;
err_out_unregister:
spin_lock_irqsave
(
&
cpufreq_driver_lock
,
flags
);
cpufreq_cpu_data
[
cpu
]
=
NULL
;
spin_unlock_irqrestore
(
&
cpufreq_driver_lock
,
flags
);
kobject_unregister
(
&
policy
->
kobj
);
wait_for_completion
(
&
policy
->
kobj_unregister
);
}
out:
err_out:
kfree
(
policy
);
module_put
(
cpufreq_driver
->
owner
);
return
ret
;
}
...
...
@@ -388,34 +431,39 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
static
int
cpufreq_remove_dev
(
struct
sys_device
*
sys_dev
)
{
unsigned
int
cpu
=
sys_dev
->
id
;
unsigned
long
flags
;
struct
cpufreq_policy
*
data
;
if
(
!
kobject_get
(
&
cpufreq_driver
->
policy
[
cpu
].
kobj
))
return
-
EFAULT
;
spin_lock_irqsave
(
&
cpufreq_driver_lock
,
flags
);
data
=
cpufreq_cpu_data
[
cpu
]
;
down
(
&
cpufreq_driver_sem
);
if
((
cpufreq_driver
->
target
)
&&
(
cpufreq_driver
->
policy
[
cpu
].
policy
==
CPUFREQ_POLICY_GOVERNOR
))
{
cpufreq_driver
->
policy
[
cpu
].
governor
->
governor
(
&
cpufreq_driver
->
policy
[
cpu
],
CPUFREQ_GOV_STOP
);
module_put
(
cpufreq_driver
->
policy
[
cpu
].
governor
->
owner
);
if
(
!
data
)
{
spin_unlock_irqrestore
(
&
cpufreq_driver_lock
,
flags
);
return
-
EINVAL
;
}
cpufreq_cpu_data
[
cpu
]
=
NULL
;
spin_unlock_irqrestore
(
&
cpufreq_driver_lock
,
flags
);
/* we may call driver->exit here without checking for try_module_exit
* as it's either the driver which wants to unload or we have a CPU
* removal AND driver removal at the same time...
*/
if
(
cpufreq_driver
->
exit
)
cpufreq_driver
->
exit
(
&
cpufreq_driver
->
policy
[
cpu
]);
if
(
!
kobject_get
(
&
data
->
kobj
))
return
-
EFAULT
;
kobject_unregister
(
&
cpufreq_driver
->
policy
[
cpu
].
kobj
);
kobject_unregister
(
&
data
->
kobj
);
up
(
&
cpufreq_driver_sem
);
kobject_put
(
&
cpufreq_driver
->
policy
[
cpu
].
kobj
);
kobject_put
(
&
data
->
kobj
);
/* we need to make sure that the underlying kobj is actually
*
destroyed before we proceed e.g. with cpufreq driver module
* unloading
*
not referenced anymore by anybody before we proceed with
* unloading
.
*/
wait_for_completion
(
&
cpufreq_driver
->
policy
[
cpu
].
kobj_unregister
);
wait_for_completion
(
&
data
->
kobj_unregister
);
if
(
cpufreq_driver
->
target
)
__cpufreq_governor
(
data
,
CPUFREQ_GOV_STOP
);
if
(
cpufreq_driver
->
exit
)
cpufreq_driver
->
exit
(
data
);
kfree
(
data
);
return
0
;
}
...
...
@@ -431,15 +479,20 @@ static int cpufreq_restore(struct sys_device * sysdev)
int
cpu
=
sysdev
->
id
;
unsigned
int
ret
=
0
;
struct
cpufreq_policy
policy
;
struct
cpufreq_policy
*
cpu_policy
;
if
(
!
cpu_online
(
cpu
))
return
0
;
cpu_policy
=
cpufreq_cpu_get
(
cpu
);
down
(
&
cpu_policy
->
lock
);
memcpy
(
&
policy
,
cpu_policy
,
sizeof
(
struct
cpufreq_policy
));
up
(
&
cpu_policy
->
lock
);
if
(
cpu_online
(
cpu
)
&&
cpufreq_cpu_get
(
cpu
))
{
down
(
&
cpufreq_driver_sem
);
memcpy
(
&
policy
,
&
cpufreq_driver
->
policy
[
cpu
],
sizeof
(
struct
cpufreq_policy
));
up
(
&
cpufreq_driver_sem
);
ret
=
cpufreq_set_policy
(
&
policy
);
cpufreq_cpu_put
(
cpu
);
}
cpufreq_cpu_put
(
cpu_policy
);
return
ret
;
}
...
...
@@ -526,68 +579,86 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
* GOVERNORS *
*********************************************************************/
inline
int
cpufreq_driver_target
(
struct
cpufreq_policy
*
policy
,
int
__cpufreq_driver_target
(
struct
cpufreq_policy
*
policy
,
unsigned
int
target_freq
,
unsigned
int
relation
)
{
return
cpufreq_driver
->
target
(
policy
,
target_freq
,
relation
);
}
EXPORT_SYMBOL_GPL
(
__cpufreq_driver_target
);
int
cpufreq_driver_target
(
struct
cpufreq_policy
*
policy
,
unsigned
int
target_freq
,
unsigned
int
relation
)
{
unsigned
int
ret
;
unsigned
int
cpu
=
policy
->
cpu
;
if
(
!
cpufreq_cpu_get
(
cpu
))
policy
=
cpufreq_cpu_get
(
policy
->
cpu
);
if
(
!
policy
)
return
-
EINVAL
;
down
(
&
cpufreq_driver
->
policy
[
cpu
].
lock
);
down
(
&
policy
->
lock
);
ret
=
cpufreq_driver
->
target
(
policy
,
target_freq
,
relation
);
ret
=
__cpufreq_driver_
target
(
policy
,
target_freq
,
relation
);
up
(
&
cpufreq_driver
->
policy
[
cpu
].
lock
);
up
(
&
policy
->
lock
);
cpufreq_cpu_put
(
cpu
);
cpufreq_cpu_put
(
policy
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
cpufreq_driver_target
);
int
cpufreq_governor
(
unsigned
int
cpu
,
unsigned
int
event
)
static
int
__cpufreq_governor
(
struct
cpufreq_policy
*
policy
,
unsigned
int
event
)
{
int
ret
=
0
;
struct
cpufreq_policy
*
policy
=
&
cpufreq_driver
->
policy
[
cpu
];
if
(
!
cpufreq_cpu_get
(
cpu
))
return
-
EINVAL
;
switch
(
policy
->
policy
)
{
case
CPUFREQ_POLICY_POWERSAVE
:
if
((
event
==
CPUFREQ_GOV_LIMITS
)
||
(
event
==
CPUFREQ_GOV_START
))
{
down
(
&
cpufreq_driver
->
policy
[
cpu
].
lock
);
ret
=
cpufreq_driver
->
target
(
policy
,
policy
->
min
,
CPUFREQ_RELATION_L
);
up
(
&
cpufreq_driver
->
policy
[
cpu
].
lock
);
ret
=
__cpufreq_driver_target
(
policy
,
policy
->
min
,
CPUFREQ_RELATION_L
);
}
break
;
case
CPUFREQ_POLICY_PERFORMANCE
:
if
((
event
==
CPUFREQ_GOV_LIMITS
)
||
(
event
==
CPUFREQ_GOV_START
))
{
down
(
&
cpufreq_driver
->
policy
[
cpu
].
lock
);
ret
=
cpufreq_driver
->
target
(
policy
,
policy
->
max
,
CPUFREQ_RELATION_H
);
up
(
&
cpufreq_driver
->
policy
[
cpu
].
lock
);
ret
=
__cpufreq_driver_target
(
policy
,
policy
->
max
,
CPUFREQ_RELATION_H
);
}
break
;
case
CPUFREQ_POLICY_GOVERNOR
:
ret
=
-
EINVAL
;
if
(
!
try_module_get
(
cpufreq_driver
->
policy
[
cpu
].
governor
->
owner
))
if
(
!
try_module_get
(
policy
->
governor
->
owner
))
break
;
ret
=
cpufreq_driver
->
policy
[
cpu
].
governor
->
governor
(
policy
,
event
);
ret
=
policy
->
governor
->
governor
(
policy
,
event
);
/* we keep one module reference alive for each CPU governed by this CPU */
if
((
event
!=
CPUFREQ_GOV_START
)
||
ret
)
module_put
(
cpufreq_driver
->
policy
[
cpu
].
governor
->
owner
);
module_put
(
policy
->
governor
->
owner
);
if
((
event
==
CPUFREQ_GOV_STOP
)
&&
!
ret
)
module_put
(
cpufreq_driver
->
policy
[
cpu
].
governor
->
owner
);
module_put
(
policy
->
governor
->
owner
);
break
;
default:
ret
=
-
EINVAL
;
}
cpufreq_cpu_put
(
cpu
);
return
ret
;
}
int
cpufreq_governor
(
unsigned
int
cpu
,
unsigned
int
event
)
{
int
ret
=
0
;
struct
cpufreq_policy
*
policy
=
cpufreq_cpu_get
(
cpu
);
if
(
!
policy
)
return
-
EINVAL
;
down
(
&
policy
->
lock
);
ret
=
__cpufreq_governor
(
policy
,
event
);
up
(
&
policy
->
lock
);
cpufreq_cpu_put
(
policy
);
return
ret
;
}
...
...
@@ -649,16 +720,19 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
*/
int
cpufreq_get_policy
(
struct
cpufreq_policy
*
policy
,
unsigned
int
cpu
)
{
if
(
!
policy
||
!
cpufreq_cpu_get
(
cpu
))
struct
cpufreq_policy
*
cpu_policy
;
if
(
!
policy
)
return
-
EINVAL
;
cpu_policy
=
cpufreq_cpu_get
(
cpu
);
if
(
!
cpu_policy
)
return
-
EINVAL
;
down
(
&
cpufreq_driver_sem
);
memcpy
(
policy
,
&
cpufreq_driver
->
policy
[
cpu
],
sizeof
(
struct
cpufreq_policy
));
up
(
&
cpufreq_driver_sem
);
down
(
&
cpu_policy
->
lock
);
memcpy
(
policy
,
cpu_policy
,
sizeof
(
struct
cpufreq_policy
));
up
(
&
cpu_policy
->
lock
);
cpufreq_cpu_put
(
cpu
);
cpufreq_cpu_put
(
cpu
_policy
);
return
0
;
}
...
...
@@ -674,15 +748,21 @@ EXPORT_SYMBOL(cpufreq_get_policy);
int
cpufreq_set_policy
(
struct
cpufreq_policy
*
policy
)
{
int
ret
=
0
;
struct
cpufreq_policy
*
data
;
if
(
!
policy
)
return
-
EINVAL
;
if
(
!
policy
||
!
cpufreq_cpu_get
(
policy
->
cpu
))
data
=
cpufreq_cpu_get
(
policy
->
cpu
);
if
(
!
data
)
return
-
EINVAL
;
down
(
&
cpufreq_driver_sem
);
/* lock this CPU */
down
(
&
data
->
lock
);
memcpy
(
&
policy
->
cpuinfo
,
&
cpufreq_driver
->
policy
[
policy
->
cpu
].
cpuinfo
,
&
data
->
cpuinfo
,
sizeof
(
struct
cpufreq_cpuinfo
));
up
(
&
cpufreq_driver_sem
);
/* verify the cpu speed can be set within this limit */
ret
=
cpufreq_driver
->
verify
(
policy
);
...
...
@@ -713,39 +793,39 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
up_read
(
&
cpufreq_notifier_rwsem
);
/* from here on we limit it to one limit and/or governor change running at the moment */
down
(
&
cpufreq_driver_sem
);
cpufreq_driver
->
policy
[
policy
->
cpu
].
min
=
policy
->
min
;
cpufreq_driver
->
policy
[
policy
->
cpu
].
max
=
policy
->
max
;
data
->
min
=
policy
->
min
;
data
->
max
=
policy
->
max
;
if
(
cpufreq_driver
->
setpolicy
)
{
cpufreq_driver
->
policy
[
policy
->
cpu
].
policy
=
policy
->
policy
;
data
->
policy
=
policy
->
policy
;
ret
=
cpufreq_driver
->
setpolicy
(
policy
);
}
else
{
if
((
policy
->
policy
!=
cpufreq_driver
->
policy
[
policy
->
cpu
].
policy
)
||
((
policy
->
policy
==
CPUFREQ_POLICY_GOVERNOR
)
&&
(
policy
->
governor
!=
cpufreq_driver
->
policy
[
policy
->
cpu
].
governor
)))
{
unsigned
int
old_pol
=
cpufreq_driver
->
policy
[
policy
->
cpu
].
policy
;
struct
cpufreq_governor
*
old_gov
=
cpufreq_driver
->
policy
[
policy
->
cpu
].
governor
;
if
((
policy
->
policy
!=
data
->
policy
)
||
((
policy
->
policy
==
CPUFREQ_POLICY_GOVERNOR
)
&&
(
policy
->
governor
!=
data
->
governor
)))
{
/* save old, working values */
unsigned
int
old_pol
=
data
->
policy
;
struct
cpufreq_governor
*
old_gov
=
data
->
governor
;
/* end old governor */
cpufreq_governor
(
policy
->
cpu
,
CPUFREQ_GOV_STOP
);
cpufreq_driver
->
policy
[
policy
->
cpu
].
policy
=
policy
->
policy
;
cpufreq_driver
->
policy
[
policy
->
cpu
].
governor
=
policy
->
governor
;
__cpufreq_governor
(
data
,
CPUFREQ_GOV_STOP
);
/* start new governor */
if
(
cpufreq_governor
(
policy
->
cpu
,
CPUFREQ_GOV_START
))
{
cpufreq_driver
->
policy
[
policy
->
cpu
].
policy
=
old_pol
;
cpufreq_driver
->
policy
[
policy
->
cpu
].
governor
=
old_gov
;
cpufreq_governor
(
policy
->
cpu
,
CPUFREQ_GOV_START
);
data
->
policy
=
policy
->
policy
;
data
->
governor
=
policy
->
governor
;
if
(
__cpufreq_governor
(
data
,
CPUFREQ_GOV_START
))
{
/* new governor failed, so re-start old one */
data
->
policy
=
old_pol
;
data
->
governor
=
old_gov
;
__cpufreq_governor
(
data
,
CPUFREQ_GOV_START
);
}
/* might be a policy change, too */
cpufreq_governor
(
policy
->
cpu
,
CPUFREQ_GOV_LIMITS
);
}
else
{
cpufreq_governor
(
policy
->
cpu
,
CPUFREQ_GOV_LIMITS
);
/* might be a policy change, too, so fall through */
}
__cpufreq_governor
(
data
,
CPUFREQ_GOV_LIMITS
);
}
up
(
&
cpufreq_driver_sem
);
error_out:
cpufreq_cpu_put
(
policy
->
cpu
);
up
(
&
data
->
lock
);
cpufreq_cpu_put
(
data
);
return
ret
;
}
...
...
@@ -801,7 +881,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
case
CPUFREQ_POSTCHANGE
:
adjust_jiffies
(
CPUFREQ_POSTCHANGE
,
freqs
);
notifier_call_chain
(
&
cpufreq_transition_notifier_list
,
CPUFREQ_POSTCHANGE
,
freqs
);
cpufreq_
driver
->
policy
[
freqs
->
cpu
].
cur
=
freqs
->
new
;
cpufreq_
cpu_data
[
freqs
->
cpu
]
->
cur
=
freqs
->
new
;
break
;
}
up_read
(
&
cpufreq_notifier_rwsem
);
...
...
@@ -826,25 +906,19 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
*/
int
cpufreq_register_driver
(
struct
cpufreq_driver
*
driver_data
)
{
unsigned
long
flags
;
if
(
!
driver_data
||
!
driver_data
->
verify
||
!
driver_data
->
init
||
((
!
driver_data
->
setpolicy
)
&&
(
!
driver_data
->
target
)))
return
-
EINVAL
;
down
(
&
cpufreq_driver_sem
);
spin_lock_irqsave
(
&
cpufreq_driver_lock
,
flags
);
if
(
cpufreq_driver
)
{
up
(
&
cpufreq_driver_sem
);
spin_unlock_irqrestore
(
&
cpufreq_driver_lock
,
flags
);
return
-
EBUSY
;
}
cpufreq_driver
=
driver_data
;
up
(
&
cpufreq_driver_sem
);
cpufreq_driver
->
policy
=
kmalloc
(
NR_CPUS
*
sizeof
(
struct
cpufreq_policy
),
GFP_KERNEL
);
if
(
!
cpufreq_driver
->
policy
)
{
cpufreq_driver
=
NULL
;
return
-
ENOMEM
;
}
memset
(
cpufreq_driver
->
policy
,
0
,
NR_CPUS
*
sizeof
(
struct
cpufreq_policy
));
spin_unlock_irqrestore
(
&
cpufreq_driver_lock
,
flags
);
return
sysdev_driver_register
(
&
cpu_sysdev_class
,
&
cpufreq_sysdev_driver
);
}
...
...
@@ -861,15 +935,16 @@ EXPORT_SYMBOL_GPL(cpufreq_register_driver);
*/
int
cpufreq_unregister_driver
(
struct
cpufreq_driver
*
driver
)
{
unsigned
long
flags
;
if
(
!
cpufreq_driver
||
(
driver
!=
cpufreq_driver
))
return
-
EINVAL
;
sysdev_driver_unregister
(
&
cpu_sysdev_class
,
&
cpufreq_sysdev_driver
);
down
(
&
cpufreq_driver_sem
);
kfree
(
cpufreq_driver
->
policy
);
spin_lock_irqsave
(
&
cpufreq_driver_lock
,
flags
);
cpufreq_driver
=
NULL
;
up
(
&
cpufreq_driver_sem
);
spin_unlock_irqrestore
(
&
cpufreq_driver_lock
,
flags
);
return
0
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment