Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/platforms/cell/cpufreq_spudemand.c
10818 views
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/timer.h>
26
#include <linux/workqueue.h>
27
#include <asm/atomic.h>
28
#include <asm/machdep.h>
29
#include <asm/spu.h>
30
31
#define POLL_TIME 100000 /* in µs */
32
#define EXP 753 /* exp(-1) in fixed-point */
33
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 */
39
};
40
static DEFINE_PER_CPU(struct spu_gov_info_struct, spu_gov_info);
41
42
static int calc_freq(struct spu_gov_info_struct *info)
43
{
44
int cpu;
45
int busy_spus;
46
47
cpu = info->policy->cpu;
48
busy_spus = atomic_read(&cbe_spu_info[cpu_to_node(cpu)].busy_spus);
49
50
CALC_LOAD(info->busy_spus, EXP, busy_spus * FIXED_1);
51
pr_debug("cpu %d: busy_spus=%d, info->busy_spus=%ld\n",
52
cpu, busy_spus, info->busy_spus);
53
54
return info->policy->max * info->busy_spus / FIXED_1;
55
}
56
57
static void spu_gov_work(struct work_struct *work)
58
{
59
struct spu_gov_info_struct *info;
60
int delay;
61
unsigned long target_freq;
62
63
info = container_of(work, struct spu_gov_info_struct, work.work);
64
65
/* after cancel_delayed_work_sync we unset info->policy */
66
BUG_ON(info->policy == NULL);
67
68
target_freq = calc_freq(info);
69
__cpufreq_driver_target(info->policy, target_freq, CPUFREQ_RELATION_H);
70
71
delay = usecs_to_jiffies(info->poll_int);
72
schedule_delayed_work_on(info->policy->cpu, &info->work, delay);
73
}
74
75
static void spu_gov_init_work(struct spu_gov_info_struct *info)
76
{
77
int delay = usecs_to_jiffies(info->poll_int);
78
INIT_DELAYED_WORK_DEFERRABLE(&info->work, spu_gov_work);
79
schedule_delayed_work_on(info->policy->cpu, &info->work, delay);
80
}
81
82
static void spu_gov_cancel_work(struct spu_gov_info_struct *info)
83
{
84
cancel_delayed_work_sync(&info->work);
85
}
86
87
static int spu_gov_govern(struct cpufreq_policy *policy, unsigned int event)
88
{
89
unsigned int cpu = policy->cpu;
90
struct spu_gov_info_struct *info, *affected_info;
91
int i;
92
int ret = 0;
93
94
info = &per_cpu(spu_gov_info, cpu);
95
96
switch (event) {
97
case CPUFREQ_GOV_START:
98
if (!cpu_online(cpu)) {
99
printk(KERN_ERR "cpu %d is not online\n", cpu);
100
ret = -EINVAL;
101
break;
102
}
103
104
if (!policy->cur) {
105
printk(KERN_ERR "no cpu specified in policy\n");
106
ret = -EINVAL;
107
break;
108
}
109
110
/* initialize spu_gov_info for all affected cpus */
111
for_each_cpu(i, policy->cpus) {
112
affected_info = &per_cpu(spu_gov_info, i);
113
affected_info->policy = policy;
114
}
115
116
info->poll_int = POLL_TIME;
117
118
/* setup timer */
119
spu_gov_init_work(info);
120
121
break;
122
123
case CPUFREQ_GOV_STOP:
124
/* cancel timer */
125
spu_gov_cancel_work(info);
126
127
/* clean spu_gov_info for all affected cpus */
128
for_each_cpu (i, policy->cpus) {
129
info = &per_cpu(spu_gov_info, i);
130
info->policy = NULL;
131
}
132
133
break;
134
}
135
136
return ret;
137
}
138
139
static struct cpufreq_governor spu_governor = {
140
.name = "spudemand",
141
.governor = spu_gov_govern,
142
.owner = THIS_MODULE,
143
};
144
145
/*
146
* module init and destoy
147
*/
148
149
static int __init spu_gov_init(void)
150
{
151
int ret;
152
153
ret = cpufreq_register_governor(&spu_governor);
154
if (ret)
155
printk(KERN_ERR "registration of governor failed\n");
156
return ret;
157
}
158
159
static void __exit spu_gov_exit(void)
160
{
161
cpufreq_unregister_governor(&spu_governor);
162
}
163
164
165
module_init(spu_gov_init);
166
module_exit(spu_gov_exit);
167
168
MODULE_LICENSE("GPL");
169
MODULE_AUTHOR("Christian Krafft <[email protected]>");
170
171
172