2 * spu aware cpufreq governor for the cell processor
4 * © Copyright IBM Corporation 2006-2008
6 * Author: Christian Krafft <krafft@de.ibm.com>
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)
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.
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.
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>
32 #define POLL_TIME 100000 /* in µs */
33 #define EXP 753 /* exp(-1) in fixed-point */
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 */
41 static DEFINE_PER_CPU(struct spu_gov_info_struct
, spu_gov_info
);
43 static int calc_freq(struct spu_gov_info_struct
*info
)
48 cpu
= info
->policy
->cpu
;
49 busy_spus
= atomic_read(&cbe_spu_info
[cpu_to_node(cpu
)].busy_spus
);
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
);
55 return info
->policy
->max
* info
->busy_spus
/ FIXED_1
;
58 static void spu_gov_work(struct work_struct
*work
)
60 struct spu_gov_info_struct
*info
;
62 unsigned long target_freq
;
64 info
= container_of(work
, struct spu_gov_info_struct
, work
.work
);
66 /* after cancel_delayed_work_sync we unset info->policy */
67 BUG_ON(info
->policy
== NULL
);
69 target_freq
= calc_freq(info
);
70 __cpufreq_driver_target(info
->policy
, target_freq
, CPUFREQ_RELATION_H
);
72 delay
= usecs_to_jiffies(info
->poll_int
);
73 schedule_delayed_work_on(info
->policy
->cpu
, &info
->work
, delay
);
76 static void spu_gov_init_work(struct spu_gov_info_struct
*info
)
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
);
83 static void spu_gov_cancel_work(struct spu_gov_info_struct
*info
)
85 cancel_delayed_work_sync(&info
->work
);
88 static int spu_gov_start(struct cpufreq_policy
*policy
)
90 unsigned int cpu
= policy
->cpu
;
91 struct spu_gov_info_struct
*info
= &per_cpu(spu_gov_info
, cpu
);
92 struct spu_gov_info_struct
*affected_info
;
95 if (!cpu_online(cpu
)) {
96 printk(KERN_ERR
"cpu %d is not online\n", cpu
);
101 printk(KERN_ERR
"no cpu specified in policy\n");
105 /* initialize spu_gov_info for all affected cpus */
106 for_each_cpu(i
, policy
->cpus
) {
107 affected_info
= &per_cpu(spu_gov_info
, i
);
108 affected_info
->policy
= policy
;
111 info
->poll_int
= POLL_TIME
;
114 spu_gov_init_work(info
);
119 static void spu_gov_stop(struct cpufreq_policy
*policy
)
121 unsigned int cpu
= policy
->cpu
;
122 struct spu_gov_info_struct
*info
= &per_cpu(spu_gov_info
, cpu
);
126 spu_gov_cancel_work(info
);
128 /* clean spu_gov_info for all affected cpus */
129 for_each_cpu (i
, policy
->cpus
) {
130 info
= &per_cpu(spu_gov_info
, i
);
135 static struct cpufreq_governor spu_governor
= {
137 .start
= spu_gov_start
,
138 .stop
= spu_gov_stop
,
139 .owner
= THIS_MODULE
,
143 * module init and destoy
146 static int __init
spu_gov_init(void)
150 ret
= cpufreq_register_governor(&spu_governor
);
152 printk(KERN_ERR
"registration of governor failed\n");
156 static void __exit
spu_gov_exit(void)
158 cpufreq_unregister_governor(&spu_governor
);
162 module_init(spu_gov_init
);
163 module_exit(spu_gov_exit
);
165 MODULE_LICENSE("GPL");
166 MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");