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/timer.h>
26 #include <linux/workqueue.h>
27 #include <asm/atomic.h>
28 #include <asm/machdep.h>
31 #define POLL_TIME 100000 /* in µs */
32 #define EXP 753 /* exp(-1) in fixed-point */
34 struct spu_gov_info_struct
{
35 unsigned long busy_spus
; /* fixed-point */
36 struct cpufreq_policy
*policy
;
37 struct delayed_work work
;
38 unsigned int poll_int
; /* µs */
40 static DEFINE_PER_CPU(struct spu_gov_info_struct
, spu_gov_info
);
42 static struct workqueue_struct
*kspugov_wq
;
44 static int calc_freq(struct spu_gov_info_struct
*info
)
49 cpu
= info
->policy
->cpu
;
50 busy_spus
= atomic_read(&cbe_spu_info
[cpu_to_node(cpu
)].busy_spus
);
52 CALC_LOAD(info
->busy_spus
, EXP
, busy_spus
* FIXED_1
);
53 pr_debug("cpu %d: busy_spus=%d, info->busy_spus=%ld\n",
54 cpu
, busy_spus
, info
->busy_spus
);
56 return info
->policy
->max
* info
->busy_spus
/ FIXED_1
;
59 static void spu_gov_work(struct work_struct
*work
)
61 struct spu_gov_info_struct
*info
;
63 unsigned long target_freq
;
65 info
= container_of(work
, struct spu_gov_info_struct
, work
.work
);
67 /* after cancel_delayed_work_sync we unset info->policy */
68 BUG_ON(info
->policy
== NULL
);
70 target_freq
= calc_freq(info
);
71 __cpufreq_driver_target(info
->policy
, target_freq
, CPUFREQ_RELATION_H
);
73 delay
= usecs_to_jiffies(info
->poll_int
);
74 queue_delayed_work_on(info
->policy
->cpu
, kspugov_wq
, &info
->work
, delay
);
77 static void spu_gov_init_work(struct spu_gov_info_struct
*info
)
79 int delay
= usecs_to_jiffies(info
->poll_int
);
80 INIT_DELAYED_WORK_DEFERRABLE(&info
->work
, spu_gov_work
);
81 queue_delayed_work_on(info
->policy
->cpu
, kspugov_wq
, &info
->work
, delay
);
84 static void spu_gov_cancel_work(struct spu_gov_info_struct
*info
)
86 cancel_delayed_work_sync(&info
->work
);
89 static int spu_gov_govern(struct cpufreq_policy
*policy
, unsigned int event
)
91 unsigned int cpu
= policy
->cpu
;
92 struct spu_gov_info_struct
*info
, *affected_info
;
96 info
= &per_cpu(spu_gov_info
, cpu
);
99 case CPUFREQ_GOV_START
:
100 if (!cpu_online(cpu
)) {
101 printk(KERN_ERR
"cpu %d is not online\n", cpu
);
107 printk(KERN_ERR
"no cpu specified in policy\n");
112 /* initialize spu_gov_info for all affected cpus */
113 for_each_cpu(i
, policy
->cpus
) {
114 affected_info
= &per_cpu(spu_gov_info
, i
);
115 affected_info
->policy
= policy
;
118 info
->poll_int
= POLL_TIME
;
121 spu_gov_init_work(info
);
125 case CPUFREQ_GOV_STOP
:
127 spu_gov_cancel_work(info
);
129 /* clean spu_gov_info for all affected cpus */
130 for_each_cpu (i
, policy
->cpus
) {
131 info
= &per_cpu(spu_gov_info
, i
);
141 static struct cpufreq_governor spu_governor
= {
143 .governor
= spu_gov_govern
,
144 .owner
= THIS_MODULE
,
148 * module init and destoy
151 static int __init
spu_gov_init(void)
155 kspugov_wq
= create_workqueue("kspugov");
157 printk(KERN_ERR
"creation of kspugov failed\n");
162 ret
= cpufreq_register_governor(&spu_governor
);
164 printk(KERN_ERR
"registration of governor failed\n");
165 destroy_workqueue(kspugov_wq
);
172 static void __exit
spu_gov_exit(void)
174 cpufreq_unregister_governor(&spu_governor
);
175 destroy_workqueue(kspugov_wq
);
179 module_init(spu_gov_init
);
180 module_exit(spu_gov_exit
);
182 MODULE_LICENSE("GPL");
183 MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");