Subversion Repositories shark

Rev

Rev 770 | 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
 
775 mauro 34
//#define CENTRINO_DEBUG
582 mauro 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);
770 mauro 212
 
213
        /* Added by Nino */
214
        cpufreq_frequency_table_get_attr(centrino_model->op_points, policy->cpu);
215
 
582 mauro 216
        return cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points);
217
}
218
 
219
/**
220
 * centrino_verify - verifies a new CPUFreq policy
221
 * @freq: new policy
222
 *
223
 * Limit must be within this model's frequency range at least one
224
 * border included.
225
 */
226
static int centrino_verify (struct cpufreq_policy *policy)
227
{
228
        return cpufreq_frequency_table_verify(policy, centrino_model->op_points);
229
}
230
 
231
/**
232
 * centrino_setpolicy - set a new CPUFreq policy
233
 * @policy: new policy
234
 *
235
 * Sets a new CPUFreq policy.
236
 */
237
static int centrino_target (struct cpufreq_policy *policy,
238
                            unsigned int target_freq,
239
                            unsigned int relation)
240
{
241
        unsigned int    newstate = 0;
242
        unsigned int    msr, oldmsr, h;
243
        struct cpufreq_freqs    freqs;
244
 
245
        if (centrino_model == NULL)
246
                return -ENODEV;
247
 
248
        if (cpufreq_frequency_table_target(policy, centrino_model->op_points, target_freq,
249
                                           relation, &newstate))
250
                return -EINVAL;
251
 
252
        msr = centrino_model->op_points[newstate].index;
253
        rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
254
 
255
        if (msr == (oldmsr & 0xffff))
256
                return 0;
257
 
258
        /* Hm, old frequency can either be the last value we put in
259
           PERF_CTL, or whatever it is now. The trouble is that TM2
260
           can change it behind our back, which means we never get to
261
           see the speed change.  Reading back the current speed would
262
           tell us something happened, but it may leave the things on
263
           the notifier chain confused; we therefore stick to using
264
           the last programmed speed rather than the current speed for
265
           "old".
266
 
267
           TODO: work out how the TCC interrupts work, and try to
268
           catch the CPU changing things under us.
269
        */
270
        freqs.cpu = 0;
271
        freqs.old = extract_clock(oldmsr);
272
        freqs.new = extract_clock(msr);
273
 
274
        dprintk(KERN_INFO PFX "target=%dkHz old=%d new=%d msr=%04x\n",
275
                target_freq, freqs.old, freqs.new, msr);
276
 
600 mauro 277
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);  
582 mauro 278
 
279
        /* all but 16 LSB are "reserved", so treat them with
280
           care */
281
        oldmsr &= ~0xffff;
282
        msr &= 0xffff;
283
        oldmsr |= msr;
284
 
285
        wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
286
 
600 mauro 287
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
582 mauro 288
 
289
        return 0;
290
}
291
 
292
static struct cpufreq_driver centrino_driver = {
293
        .name           = "centrino", /* should be speedstep-centrino,
294
                                         but there's a 16 char limit */
295
        .init           = centrino_cpu_init,
296
        .verify         = centrino_verify,
297
        .target         = centrino_target,
298
        .owner          = THIS_MODULE,
299
};
300
 
301
 
302
/**
303
 * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver
304
 *
305
 * Initializes the Enhanced SpeedStep support. Returns -ENODEV on
306
 * unsupported devices, -ENOENT if there's no voltage table for this
307
 * particular CPU model, -EINVAL on problems during initiatization,
308
 * and zero on success.
309
 *
310
 * This is quite picky.  Not only does the CPU have to advertise the
311
 * "est" flag in the cpuid capability flags, we look for a specific
312
 * CPU model and stepping, and we need to have the exact model name in
313
 * our voltage tables.  That is, be paranoid about not releasing
314
 * someone's valuable magic smoke.
315
 */
316
/*static*/ int __init centrino_init(void)
317
{
318
        struct cpuinfo_x86 *cpu = &new_cpu_data;
319
        const struct cpu_model *model;
320
        unsigned l, h;
321
 
322
        if (!cpu_has(cpu, X86_FEATURE_EST))
323
                return -ENODEV;
324
 
325
        /* Only Intel Pentium M stepping 5 for now - add new CPUs as
326
           they appear after making sure they use PERF_CTL in the same
327
           way. */
328
        if (cpu->x86_vendor != X86_VENDOR_INTEL ||
329
            cpu->x86        != 6 ||
330
            cpu->x86_model  != 9 ||
331
            cpu->x86_mask   != 5) {
332
                printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
333
                       "send /proc/cpuinfo to " MAINTAINER "\n");
334
                return -ENODEV;
335
        }
336
 
337
        /* Check to see if Enhanced SpeedStep is enabled, and try to
338
           enable it if not. */
339
        rdmsr(MSR_IA32_MISC_ENABLE, l, h);
340
 
341
        if (!(l & (1<<16))) {
342
                l |= (1<<16);
343
                wrmsr(MSR_IA32_MISC_ENABLE, l, h);
344
 
345
                /* check to see if it stuck */
346
                rdmsr(MSR_IA32_MISC_ENABLE, l, h);
347
                if (!(l & (1<<16))) {
348
                        printk(KERN_INFO PFX "couldn't enable Enhanced SpeedStep\n");
349
                        return -ENODEV;
350
                }
351
        }
352
 
353
        for(model = models; model->model_name != NULL; model++)
354
                if (strcmp(cpu->x86_model_id, model->model_name) == 0)
355
                        break;
356
        if (model->model_name == NULL) {
357
                printk(KERN_INFO PFX "no support for CPU model \"%s\": "
358
                       "send /proc/cpuinfo to " MAINTAINER "\n",
359
                       cpu->x86_model_id);
360
                return -ENOENT;
361
        }
362
 
363
        centrino_model = model;
364
 
365
        printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n",
366
               model->model_name, model->max_freq);
367
 
368
        return cpufreq_register_driver(&centrino_driver);
369
}
370
 
371
/*static*/ void __exit centrino_exit(void)
372
{
373
        cpufreq_unregister_driver(&centrino_driver);
374
}
375
 
376
MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");
377
MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors.");
378
MODULE_LICENSE ("GPL");
379
 
380
module_init(centrino_init);
381
module_exit(centrino_exit);