Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
powerpc
platforms
cell
cpufreq_spudemand.c
Go to the documentation of this file.
1
/*
2
* spu aware cpufreq governor for the cell processor
3
*
4
* © Copyright IBM Corporation 2006-2008
5
*
6
* Author: Christian Krafft <
[email protected]
>
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2, or (at your option)
11
* any later version.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
*/
22
23
#include <
linux/cpufreq.h
>
24
#include <linux/sched.h>
25
#include <linux/module.h>
26
#include <
linux/timer.h
>
27
#include <
linux/workqueue.h
>
28
#include <
linux/atomic.h
>
29
#include <asm/machdep.h>
30
#include <
asm/spu.h
>
31
32
#define POLL_TIME 100000
/* in µs */
33
#define EXP 753
/* exp(-1) in fixed-point */
34
35
struct
spu_gov_info_struct
{
36
unsigned
long
busy_spus
;
/* fixed-point */
37
struct
cpufreq_policy
*
policy
;
38
struct
delayed_work
work
;
39
unsigned
int
poll_int
;
/* µs */
40
};
41
static
DEFINE_PER_CPU
(
struct
spu_gov_info_struct
, spu_gov_info);
42
43
static
int
calc_freq(
struct
spu_gov_info_struct
*
info
)
44
{
45
int
cpu
;
46
int
busy_spus;
47
48
cpu = info->
policy
->cpu;
49
busy_spus =
atomic_read
(&
cbe_spu_info
[
cpu_to_node
(cpu)].busy_spus);
50
51
CALC_LOAD
(info->
busy_spus
,
EXP
, busy_spus *
FIXED_1
);
52
pr_debug
(
"cpu %d: busy_spus=%d, info->busy_spus=%ld\n"
,
53
cpu, busy_spus, info->
busy_spus
);
54
55
return
info->
policy
->max * info->
busy_spus
/
FIXED_1
;
56
}
57
58
static
void
spu_gov_work(
struct
work_struct
*
work
)
59
{
60
struct
spu_gov_info_struct
*
info
;
61
int
delay
;
62
unsigned
long
target_freq;
63
64
info =
container_of
(work,
struct
spu_gov_info_struct
, work.work);
65
66
/* after cancel_delayed_work_sync we unset info->policy */
67
BUG_ON
(info->
policy
==
NULL
);
68
69
target_freq = calc_freq(info);
70
__cpufreq_driver_target
(info->
policy
, target_freq,
CPUFREQ_RELATION_H
);
71
72
delay =
usecs_to_jiffies
(info->
poll_int
);
73
schedule_delayed_work_on
(info->
policy
->cpu, &info->
work
, delay);
74
}
75
76
static
void
spu_gov_init_work(
struct
spu_gov_info_struct
*info)
77
{
78
int
delay
=
usecs_to_jiffies
(info->
poll_int
);
79
INIT_DEFERRABLE_WORK
(&info->
work
, spu_gov_work);
80
schedule_delayed_work_on
(info->
policy
->cpu, &info->
work
, delay);
81
}
82
83
static
void
spu_gov_cancel_work(
struct
spu_gov_info_struct
*info)
84
{
85
cancel_delayed_work_sync
(&info->
work
);
86
}
87
88
static
int
spu_gov_govern(
struct
cpufreq_policy
*
policy
,
unsigned
int
event
)
89
{
90
unsigned
int
cpu = policy->
cpu
;
91
struct
spu_gov_info_struct
*
info
, *affected_info;
92
int
i
;
93
int
ret
= 0;
94
95
info = &
per_cpu
(spu_gov_info, cpu);
96
97
switch
(event) {
98
case
CPUFREQ_GOV_START
:
99
if
(!
cpu_online
(cpu)) {
100
printk
(
KERN_ERR
"cpu %d is not online\n"
, cpu);
101
ret = -
EINVAL
;
102
break
;
103
}
104
105
if
(!policy->
cur
) {
106
printk
(
KERN_ERR
"no cpu specified in policy\n"
);
107
ret = -
EINVAL
;
108
break
;
109
}
110
111
/* initialize spu_gov_info for all affected cpus */
112
for_each_cpu
(i, policy->
cpus
) {
113
affected_info = &
per_cpu
(spu_gov_info, i);
114
affected_info->
policy
=
policy
;
115
}
116
117
info->
poll_int
=
POLL_TIME
;
118
119
/* setup timer */
120
spu_gov_init_work(info);
121
122
break
;
123
124
case
CPUFREQ_GOV_STOP
:
125
/* cancel timer */
126
spu_gov_cancel_work(info);
127
128
/* clean spu_gov_info for all affected cpus */
129
for_each_cpu
(i, policy->
cpus
) {
130
info = &
per_cpu
(spu_gov_info, i);
131
info->
policy
=
NULL
;
132
}
133
134
break
;
135
}
136
137
return
ret
;
138
}
139
140
static
struct
cpufreq_governor
spu_governor = {
141
.name =
"spudemand"
,
142
.governor = spu_gov_govern,
143
.owner =
THIS_MODULE
,
144
};
145
146
/*
147
* module init and destoy
148
*/
149
150
static
int
__init
spu_gov_init(
void
)
151
{
152
int
ret
;
153
154
ret =
cpufreq_register_governor
(&spu_governor);
155
if
(ret)
156
printk
(
KERN_ERR
"registration of governor failed\n"
);
157
return
ret
;
158
}
159
160
static
void
__exit
spu_gov_exit(
void
)
161
{
162
cpufreq_unregister_governor
(&spu_governor);
163
}
164
165
166
module_init
(spu_gov_init);
167
module_exit
(spu_gov_exit);
168
169
MODULE_LICENSE
(
"GPL"
);
170
MODULE_AUTHOR
(
"Christian Krafft <
[email protected]
>"
);
171
Generated on Thu Jan 10 2013 13:14:52 for Linux Kernel by
1.8.2