Subversion Repositories shark

Rev

Rev 582 | Rev 770 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
582 mauro 1
/*
2
 * cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium
3
 * M (part of the Centrino chipset).
4
 *
5
 * Despite the "SpeedStep" in the name, this is almost entirely unlike
6
 * traditional SpeedStep.
7
 *
8
 * Modelled on speedstep.c
9
 *
10
 * Copyright (C) 2003 Jeremy Fitzhardinge <jeremy@goop.org>
11
 *
12
 * WARNING WARNING WARNING
13
 *
14
 * This driver manipulates the PERF_CTL MSR, which is only somewhat
15
 * documented.  While it seems to work on my laptop, it has not been
16
 * tested anywhere else, and it may not work for you, do strange
17
 * things or simply crash.
18
 */
19
 
20
#include <linuxcomp.h>
21
 
22
#include <linux/kernel.h>
23
#include <linux/module.h>
24
#include <linux/init.h>
25
#include <linux/cpufreq.h>
26
 
27
#include <asm/msr.h>
28
#include <asm/processor.h>
29
#include <asm/cpufeature.h>
30
 
31
#define PFX             "speedstep-centrino: "
32
#define MAINTAINER      "Jeremy Fitzhardinge <jeremy@goop.org>"
33
 
34
#define CENTRINO_DEBUG
35
 
36
#ifdef CENTRINO_DEBUG
37
#define dprintk(msg...) printk(msg)
38
#else
39
#define dprintk(msg...) do { } while(0)
40
#endif
41
 
42
struct cpu_model
43
{
44
        const char      *model_name;
45
        unsigned        max_freq; /* max clock in kHz */
46
 
47
        struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */
48
};
49
 
50
/* Operating points for current CPU */
51
static const struct cpu_model *centrino_model;
52
 
53
/* Computes the correct form for IA32_PERF_CTL MSR for a particular
54
   frequency/voltage operating point; frequency in MHz, volts in mV.
55
   This is stored as "index" in the structure. */
56
#define OP(mhz, mv)                                                     \
57
        {                                                               \
58
                .frequency = (mhz) * 1000,                              \
59
                .index = (((mhz)/100) << 8) | ((mv - 700) / 16)         \
60
        }
61
 
62
/*
63
 * These voltage tables were derived from the Intel Pentium M
64
 * datasheet, document 25261202.pdf, Table 5.  I have verified they
65
 * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium
66
 * M.
67
 */
68
 
69
/* Ultra Low Voltage Intel Pentium M processor 900MHz */
70
static struct cpufreq_frequency_table op_900[] =
71
{
72
        OP(600,  844),
73
        OP(800,  988),
74
        OP(900, 1004),
75
        { .frequency = CPUFREQ_TABLE_END }
76
};
77
 
78
/* Low Voltage Intel Pentium M processor 1.10GHz */
79
static struct cpufreq_frequency_table op_1100[] =
80
{
81
        OP( 600,  956),
82
        OP( 800, 1020),
83
        OP( 900, 1100),
84
        OP(1000, 1164),
85
        OP(1100, 1180),
86
        { .frequency = CPUFREQ_TABLE_END }
87
};
88
 
89
 
90
/* Low Voltage Intel Pentium M processor 1.20GHz */
91
static struct cpufreq_frequency_table op_1200[] =
92
{
93
        OP( 600,  956),
94
        OP( 800, 1004),
95
        OP( 900, 1020),
96
        OP(1000, 1100),
97
        OP(1100, 1164),
98
        OP(1200, 1180),
99
        { .frequency = CPUFREQ_TABLE_END }
100
};
101
 
102
/* Intel Pentium M processor 1.30GHz */
103
static struct cpufreq_frequency_table op_1300[] =
104
{
105
        OP( 600,  956),
106
        OP( 800, 1260),
107
        OP(1000, 1292),
108
        OP(1200, 1356),
109
        OP(1300, 1388),
110
        { .frequency = CPUFREQ_TABLE_END }
111
};
112
 
113
/* Intel Pentium M processor 1.40GHz */
114
static struct cpufreq_frequency_table op_1400[] =
115
{
116
        OP( 600,  956),
117
        OP( 800, 1180),
118
        OP(1000, 1308),
119
        OP(1200, 1436),
120
        OP(1400, 1484),
121
        { .frequency = CPUFREQ_TABLE_END }
122
};
123
 
124
/* Intel Pentium M processor 1.50GHz */
125
static struct cpufreq_frequency_table op_1500[] =
126
{
127
        OP( 600,  956),
128
        OP( 800, 1116),
129
        OP(1000, 1228),
130
        OP(1200, 1356),
131
        OP(1400, 1452),
132
        OP(1500, 1484),
133
        { .frequency = CPUFREQ_TABLE_END }
134
};
135
 
136
/* Intel Pentium M processor 1.60GHz */
137
static struct cpufreq_frequency_table op_1600[] =
138
{
139
        OP( 600,  956),
140
        OP( 800, 1036),
141
        OP(1000, 1164),
142
        OP(1200, 1276),
143
        OP(1400, 1420),
144
        OP(1600, 1484),
145
        { .frequency = CPUFREQ_TABLE_END }
146
};
147
 
148
/* Intel Pentium M processor 1.70GHz */
149
static struct cpufreq_frequency_table op_1700[] =
150
{
151
        OP( 600,  956),
152
        OP( 800, 1004),
153
        OP(1000, 1116),
154
        OP(1200, 1228),
155
        OP(1400, 1308),
156
        OP(1700, 1484),
157
        { .frequency = CPUFREQ_TABLE_END }
158
};
159
#undef OP
160
 
161
#define _CPU(max, name) \
162
        { "Intel(R) Pentium(R) M processor " name "MHz", (max)*1000, op_##max }
163
#define CPU(max)        _CPU(max, #max)
164
 
165
/* CPU models, their operating frequency range, and freq/voltage
166
   operating points */
167
static const struct cpu_model models[] =
168
{
169
       _CPU( 900, " 900"),
170
        CPU(1100),
171
        CPU(1200),
172
        CPU(1300),
173
        CPU(1400),
174
        CPU(1500),
175
        CPU(1600),
176
        CPU(1700),
177
        { 0, }
178
};
179
#undef CPU
180
 
181
/* Extract clock in kHz from PERF_CTL value */
182
static unsigned extract_clock(unsigned msr)
183
{
184
        msr = (msr >> 8) & 0xff;
185
        return msr * 100000;
186
}
187
 
188
/* Return the current CPU frequency in kHz */
189
static unsigned get_cur_freq(void)
190
{
191
        unsigned l, h;
192
 
193
        rdmsr(MSR_IA32_PERF_STATUS, l, h);
194
        return extract_clock(l);
195
}
196
 
197
static int centrino_cpu_init(struct cpufreq_policy *policy)
198
{
199
        unsigned freq;
200
 
201
        if (policy->cpu != 0 || centrino_model == NULL)
202
                return -ENODEV;
203
 
204
        freq = get_cur_freq();
205
 
206
        policy->governor = 0; //!!!CPUFREQ_DEFAULT_GOVERNOR;
207
        policy->cpuinfo.transition_latency = 10; /* 10uS transition latency */
208
        policy->cur = freq;
209
 
210
        dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n",
211
                policy->policy, policy->cur);
212
 
213
        return cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points);
214
}
215
 
216
/**
217
 * centrino_verify - verifies a new CPUFreq policy
218
 * @freq: new policy
219
 *
220
 * Limit must be within this model's frequency range at least one
221
 * border included.
222
 */
223
static int centrino_verify (struct cpufreq_policy *policy)
224
{
225
        return cpufreq_frequency_table_verify(policy, centrino_model->op_points);
226
}
227
 
228
/**
229
 * centrino_setpolicy - set a new CPUFreq policy
230
 * @policy: new policy
231
 *
232
 * Sets a new CPUFreq policy.
233
 */
234
static int centrino_target (struct cpufreq_policy *policy,
235
                            unsigned int target_freq,
236
                            unsigned int relation)
237
{
238
        unsigned int    newstate = 0;
239
        unsigned int    msr, oldmsr, h;
240
        struct cpufreq_freqs    freqs;
241
 
242
        if (centrino_model == NULL)
243
                return -ENODEV;
244
 
245
        if (cpufreq_frequency_table_target(policy, centrino_model->op_points, target_freq,
246
                                           relation, &newstate))
247
                return -EINVAL;
248
 
249
        msr = centrino_model->op_points[newstate].index;
250
        rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
251
 
252
        if (msr == (oldmsr & 0xffff))
253
                return 0;
254
 
255
        /* Hm, old frequency can either be the last value we put in
256
           PERF_CTL, or whatever it is now. The trouble is that TM2
257
           can change it behind our back, which means we never get to
258
           see the speed change.  Reading back the current speed would
259
           tell us something happened, but it may leave the things on
260
           the notifier chain confused; we therefore stick to using
261
           the last programmed speed rather than the current speed for
262
           "old".
263
 
264
           TODO: work out how the TCC interrupts work, and try to
265
           catch the CPU changing things under us.
266
        */
267
        freqs.cpu = 0;
268
        freqs.old = extract_clock(oldmsr);
269
        freqs.new = extract_clock(msr);
270
 
271
        dprintk(KERN_INFO PFX "target=%dkHz old=%d new=%d msr=%04x\n",
272
                target_freq, freqs.old, freqs.new, msr);
273
 
600 mauro 274
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);  
582 mauro 275
 
276
        /* all but 16 LSB are "reserved", so treat them with
277
           care */
278
        oldmsr &= ~0xffff;
279
        msr &= 0xffff;
280
        oldmsr |= msr;
281
 
282
        wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
283
 
600 mauro 284
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
582 mauro 285
 
286
        return 0;
287
}
288
 
289
static struct cpufreq_driver centrino_driver = {
290
        .name           = "centrino", /* should be speedstep-centrino,
291
                                         but there's a 16 char limit */
292
        .init           = centrino_cpu_init,
293
        .verify         = centrino_verify,
294
        .target         = centrino_target,
295
        .owner          = THIS_MODULE,
296
};
297
 
298
 
299
/**
300
 * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver
301
 *
302
 * Initializes the Enhanced SpeedStep support. Returns -ENODEV on
303
 * unsupported devices, -ENOENT if there's no voltage table for this
304
 * particular CPU model, -EINVAL on problems during initiatization,
305
 * and zero on success.
306
 *
307
 * This is quite picky.  Not only does the CPU have to advertise the
308
 * "est" flag in the cpuid capability flags, we look for a specific
309
 * CPU model and stepping, and we need to have the exact model name in
310
 * our voltage tables.  That is, be paranoid about not releasing
311
 * someone's valuable magic smoke.
312
 */
313
/*static*/ int __init centrino_init(void)
314
{
315
        struct cpuinfo_x86 *cpu = &new_cpu_data;
316
        const struct cpu_model *model;
317
        unsigned l, h;
318
 
319
        if (!cpu_has(cpu, X86_FEATURE_EST))
320
                return -ENODEV;
321
 
322
        /* Only Intel Pentium M stepping 5 for now - add new CPUs as
323
           they appear after making sure they use PERF_CTL in the same
324
           way. */
325
        if (cpu->x86_vendor != X86_VENDOR_INTEL ||
326
            cpu->x86        != 6 ||
327
            cpu->x86_model  != 9 ||
328
            cpu->x86_mask   != 5) {
329
                printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
330
                       "send /proc/cpuinfo to " MAINTAINER "\n");
331
                return -ENODEV;
332
        }
333
 
334
        /* Check to see if Enhanced SpeedStep is enabled, and try to
335
           enable it if not. */
336
        rdmsr(MSR_IA32_MISC_ENABLE, l, h);
337
 
338
        if (!(l & (1<<16))) {
339
                l |= (1<<16);
340
                wrmsr(MSR_IA32_MISC_ENABLE, l, h);
341
 
342
                /* check to see if it stuck */
343
                rdmsr(MSR_IA32_MISC_ENABLE, l, h);
344
                if (!(l & (1<<16))) {
345
                        printk(KERN_INFO PFX "couldn't enable Enhanced SpeedStep\n");
346
                        return -ENODEV;
347
                }
348
        }
349
 
350
        for(model = models; model->model_name != NULL; model++)
351
                if (strcmp(cpu->x86_model_id, model->model_name) == 0)
352
                        break;
353
        if (model->model_name == NULL) {
354
                printk(KERN_INFO PFX "no support for CPU model \"%s\": "
355
                       "send /proc/cpuinfo to " MAINTAINER "\n",
356
                       cpu->x86_model_id);
357
                return -ENOENT;
358
        }
359
 
360
        centrino_model = model;
361
 
362
        printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n",
363
               model->model_name, model->max_freq);
364
 
365
        return cpufreq_register_driver(&centrino_driver);
366
}
367
 
368
/*static*/ void __exit centrino_exit(void)
369
{
370
        cpufreq_unregister_driver(&centrino_driver);
371
}
372
 
373
MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");
374
MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors.");
375
MODULE_LICENSE ("GPL");
376
 
377
module_init(centrino_init);
378
module_exit(centrino_exit);