Blame view

drivers/cpufreq/speedstep-smi.c 11.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * Intel SpeedStep SMI driver.
   *
   * (C) 2003  Hiroshi Miura <miura@da-cha.org>
   *
   *  Licensed under the terms of the GNU GPL License version 2.
   *
   */
  
  
  /*********************************************************************
   *                        SPEEDSTEP - DEFINITIONS                    *
   *********************************************************************/
  
  #include <linux/kernel.h>
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
16
17
  #include <linux/module.h>
  #include <linux/moduleparam.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  #include <linux/init.h>
  #include <linux/cpufreq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/delay.h>
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
21
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
  #include <asm/ist.h>
  
  #include "speedstep-lib.h"
  
  /* speedstep system management interface port/command.
   *
   * These parameters are got from IST-SMI BIOS call.
   * If user gives it, these are used.
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
30
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
   */
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
32
33
34
  static int smi_port;
  static int smi_cmd;
  static unsigned int smi_sig;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  
  /* info about the processor */
1cce76c2a   Rusty Russell   [CPUFREQ] use an ...
37
  static enum speedstep_processor speedstep_processor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38

32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
39
40
  /*
   * There are only two frequency states for each processor. Values
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
   * are in kHz for the time being.
   */
  static struct cpufreq_frequency_table speedstep_freqs[] = {
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
44
  	{SPEEDSTEP_HIGH,	0},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
52
53
54
55
56
  	{SPEEDSTEP_LOW,		0},
  	{0,			CPUFREQ_TABLE_END},
  };
  
  #define GET_SPEEDSTEP_OWNER 0
  #define GET_SPEEDSTEP_STATE 1
  #define SET_SPEEDSTEP_STATE 2
  #define GET_SPEEDSTEP_FREQS 4
  
  /* how often shall the SMI call be tried if it failed, e.g. because
   * of DMA activity going on? */
  #define SMI_TRIES 5
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
  /**
   * speedstep_smi_ownership
   */
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
60
  static int speedstep_smi_ownership(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  {
c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
62
  	u32 command, result, magic, dummy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
  	u32 function = GET_SPEEDSTEP_OWNER;
  	unsigned char magic_data[] = "Copyright (c) 1999 Intel Corporation";
  
  	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
  	magic = virt_to_phys(magic_data);
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
68
69
  	pr_debug("trying to obtain ownership with command %x at port %x
  ",
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
70
  			command, smi_port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
  
  	__asm__ __volatile__(
c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
73
74
  		"push %%ebp
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
  		"out %%al, (%%dx)
  "
c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
77
78
  		"pop %%ebp
  "
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
79
80
81
  		: "=D" (result),
  		  "=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy),
  		  "=S" (dummy)
f081a529f   Andrew Morton   [PATCH] cpufreq: ...
82
  		: "a" (command), "b" (function), "c" (0), "d" (smi_port),
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
83
  		  "D" (0), "S" (magic)
f081a529f   Andrew Morton   [PATCH] cpufreq: ...
84
  		: "memory"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  	);
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
86
87
  	pr_debug("result is %x
  ", result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
92
93
94
95
96
97
98
99
100
  
  	return result;
  }
  
  /**
   * speedstep_smi_get_freqs - get SpeedStep preferred & current freq.
   * @low: the low frequency value is placed here
   * @high: the high frequency value is placed here
   *
   * Only available on later SpeedStep-enabled systems, returns false results or
   * even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing
   * shows that the latter occurs if !(ist_info.event & 0xFFFF).
   */
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
101
  static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  {
c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
103
  	u32 command, result = 0, edi, high_mhz, low_mhz, dummy;
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
104
  	u32 state = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
  	u32 function = GET_SPEEDSTEP_FREQS;
  
  	if (!(ist_info.event & 0xFFFF)) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
108
109
  		pr_debug("bug #1422 -- can't read freqs from BIOS
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
  		return -ENODEV;
  	}
  
  	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
114
115
  	pr_debug("trying to determine frequencies with command %x at port %x
  ",
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
116
  			command, smi_port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117

c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
118
119
120
  	__asm__ __volatile__(
  		"push %%ebp
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
  		"out %%al, (%%dx)
  "
c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
123
  		"pop %%ebp"
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
124
125
126
127
128
129
130
131
  		: "=a" (result),
  		  "=b" (high_mhz),
  		  "=c" (low_mhz),
  		  "=d" (state), "=D" (edi), "=S" (dummy)
  		: "a" (command),
  		  "b" (function),
  		  "c" (state),
  		  "d" (smi_port), "S" (0), "D" (0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  	);
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
133
134
  	pr_debug("result %x, low_freq %u, high_freq %u
  ",
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
135
  			result, low_mhz, high_mhz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
140
141
142
143
144
  
  	/* abort if results are obviously incorrect... */
  	if ((high_mhz + low_mhz) < 600)
  		return -EINVAL;
  
  	*high = high_mhz * 1000;
  	*low  = low_mhz  * 1000;
  
  	return result;
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
145
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
151
  
  /**
   * speedstep_get_state - set the SpeedStep state
   * @state: processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
   *
   */
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
152
  static int speedstep_get_state(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  {
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
154
  	u32 function = GET_SPEEDSTEP_STATE;
c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
155
  	u32 result, state, edi, command, dummy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
  
  	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
158
  	pr_debug("trying to determine current setting with command %x "
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
159
160
  		"at port %x
  ", command, smi_port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161

c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
162
163
164
  	__asm__ __volatile__(
  		"push %%ebp
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
  		"out %%al, (%%dx)
  "
c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
167
168
  		"pop %%ebp
  "
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
169
170
171
172
173
  		: "=a" (result),
  		  "=b" (state), "=D" (edi),
  		  "=c" (dummy), "=d" (dummy), "=S" (dummy)
  		: "a" (command), "b" (function), "c" (0),
  		  "d" (smi_port), "S" (0), "D" (0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  	);
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
175
176
  	pr_debug("state is %x, result is %x
  ", state, result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177

bbfebd665   Dave Jones   [CPUFREQ] checkpa...
178
  	return state & 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
  }
  
  
  /**
   * speedstep_set_state - set the SpeedStep state
   * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
   *
   */
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
187
  static void speedstep_set_state(unsigned int state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  {
c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
189
  	unsigned int result = 0, command, new_state, dummy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  	unsigned long flags;
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
191
  	unsigned int function = SET_SPEEDSTEP_STATE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
196
197
198
199
200
  	unsigned int retry = 0;
  
  	if (state > 0x1)
  		return;
  
  	/* Disable IRQs */
  	local_irq_save(flags);
  
  	command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
201
  	pr_debug("trying to set frequency to state %u "
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
202
203
204
  		"with command %x at port %x
  ",
  		state, command, smi_port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
  
  	do {
  		if (retry) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
208
209
  			pr_debug("retry %u, previous result %u, waiting...
  ",
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
210
  					retry, result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
  			mdelay(retry * 50);
  		}
  		retry++;
  		__asm__ __volatile__(
c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
215
216
  			"push %%ebp
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
  			"out %%al, (%%dx)
  "
c6e8256a7   Stephan Diestelhorst   x86, cpufreq: fix...
219
  			"pop %%ebp"
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
220
221
222
223
224
  			: "=b" (new_state), "=D" (result),
  			  "=c" (dummy), "=a" (dummy),
  			  "=d" (dummy), "=S" (dummy)
  			: "a" (command), "b" (function), "c" (state),
  			  "d" (smi_port), "S" (0), "D" (0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
228
229
  			);
  	} while ((new_state != state) && (retry <= SMI_TRIES));
  
  	/* enable IRQs */
  	local_irq_restore(flags);
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
230
  	if (new_state == state)
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
231
  		pr_debug("change to %u MHz succeeded after %u tries "
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
232
233
234
235
236
237
238
239
240
  			"with result %u
  ",
  			(speedstep_freqs[new_state].frequency / 1000),
  			retry, result);
  	else
  		printk(KERN_ERR "cpufreq: change to state %u "
  			"failed with new_state %u and result %u
  ",
  			state, new_state, result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
245
246
247
248
249
  
  	return;
  }
  
  
  /**
   * speedstep_target - set a new CPUFreq policy
   * @policy: new policy
   * @target_freq: new freq
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
250
   * @relation:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
   *
   * Sets a new CPUFreq policy/freq.
   */
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
254
  static int speedstep_target(struct cpufreq_policy *policy,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
  			unsigned int target_freq, unsigned int relation)
  {
  	unsigned int newstate = 0;
  	struct cpufreq_freqs freqs;
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
259
260
  	if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0],
  				target_freq, relation, &newstate))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  		return -EINVAL;
  
  	freqs.old = speedstep_freqs[speedstep_get_state()].frequency;
  	freqs.new = speedstep_freqs[newstate].frequency;
  	freqs.cpu = 0; /* speedstep.c is UP only driver */
  
  	if (freqs.old == freqs.new)
  		return 0;
  
  	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
  	speedstep_set_state(newstate);
  	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
  
  	return 0;
  }
  
  
  /**
   * speedstep_verify - verifies a new CPUFreq policy
   * @policy: new policy
   *
   * Limit must be within speedstep_low_freq and speedstep_high_freq, with
   * at least one border included.
   */
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
285
  static int speedstep_verify(struct cpufreq_policy *policy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
291
292
293
  {
  	return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
  }
  
  
  static int speedstep_cpu_init(struct cpufreq_policy *policy)
  {
  	int result;
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
294
295
  	unsigned int speed, state;
  	unsigned int *low, *high;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
301
302
  
  	/* capability check */
  	if (policy->cpu != 0)
  		return -ENODEV;
  
  	result = speedstep_smi_ownership();
  	if (result) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
303
304
  		pr_debug("fails in acquiring ownership of a SMI interface.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
  		return -EINVAL;
  	}
  
  	/* detect low and high frequency */
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
309
310
311
312
  	low = &speedstep_freqs[SPEEDSTEP_LOW].frequency;
  	high = &speedstep_freqs[SPEEDSTEP_HIGH].frequency;
  
  	result = speedstep_smi_get_freqs(low, high);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  	if (result) {
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
314
315
  		/* fall back to speedstep_lib.c dection mechanism:
  		 * try both states out */
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
316
  		pr_debug("could not detect low and high frequencies "
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
317
318
  				"by SMI call.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  		result = speedstep_get_freqs(speedstep_processor,
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
320
  				low, high,
1a10760c9   Mattia Dongili   [CPUFREQ] Measure...
321
  				NULL,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
  				&speedstep_set_state);
  
  		if (result) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
325
  			pr_debug("could not detect two different speeds"
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
326
327
  					" -- aborting.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
  			return result;
  		} else
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
330
331
  			pr_debug("workaround worked.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
336
  	}
  
  	/* get current speed setting */
  	state = speedstep_get_state();
  	speed = speedstep_freqs[state].frequency;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
337
338
  	pr_debug("currently at %s speed setting - %i MHz
  ",
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
339
340
  		(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency)
  		? "low" : "high",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
  		(speed / 1000));
  
  	/* cpuinfo and default policy values */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
  	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
  	policy->cur = speed;
  
  	result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
  	if (result)
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
349
  		return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350

32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
351
  	cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  
  	return 0;
  }
  
  static int speedstep_cpu_exit(struct cpufreq_policy *policy)
  {
  	cpufreq_frequency_table_put_attr(policy->cpu);
  	return 0;
  }
  
  static unsigned int speedstep_get(unsigned int cpu)
  {
  	if (cpu)
  		return -ENODEV;
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
366
  	return speedstep_get_frequency(speedstep_processor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
373
374
  }
  
  
  static int speedstep_resume(struct cpufreq_policy *policy)
  {
  	int result = speedstep_smi_ownership();
  
  	if (result)
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
375
376
  		pr_debug("fails in re-acquiring ownership of a SMI interface.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
  
  	return result;
  }
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
380
  static struct freq_attr *speedstep_attr[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
  	&cpufreq_freq_attr_scaling_available_freqs,
  	NULL,
  };
221dee285   Linus Torvalds   Revert "[CPUFREQ]...
384
  static struct cpufreq_driver speedstep_driver = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  	.name		= "speedstep-smi",
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
386
387
  	.verify		= speedstep_verify,
  	.target		= speedstep_target,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  	.init		= speedstep_cpu_init,
  	.exit		= speedstep_cpu_exit,
  	.get		= speedstep_get,
  	.resume		= speedstep_resume,
  	.owner		= THIS_MODULE,
  	.attr		= speedstep_attr,
  };
  
  /**
   * speedstep_init - initializes the SpeedStep CPUFreq driver
   *
   *   Initializes the SpeedStep support. Returns -ENODEV on unsupported
   * BIOS, -EINVAL on problems during initiatization, and zero on
   * success.
   */
  static int __init speedstep_init(void)
  {
  	speedstep_processor = speedstep_detect_processor();
  
  	switch (speedstep_processor) {
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
408
409
410
  	case SPEEDSTEP_CPU_PIII_T:
  	case SPEEDSTEP_CPU_PIII_C:
  	case SPEEDSTEP_CPU_PIII_C_EARLY:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
  		break;
  	default:
  		speedstep_processor = 0;
  	}
  
  	if (!speedstep_processor) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
417
418
  		pr_debug("No supported Intel CPU detected.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
  		return -ENODEV;
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
421
422
423
  	pr_debug("signature:0x%.8ulx, command:0x%.8ulx, "
  		"event:0x%.8ulx, perf_level:0x%.8ulx.
  ",
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
424
425
  		ist_info.signature, ist_info.command,
  		ist_info.event, ist_info.perf_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426

32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
427
  	/* Error if no IST-SMI BIOS or no PARM
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  		 sig= 'ISGE' aka 'Intel Speedstep Gate E' */
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
429
  	if ((ist_info.signature !=  0x47534943) && (
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
434
435
436
437
438
  	    (smi_port == 0) || (smi_cmd == 0)))
  		return -ENODEV;
  
  	if (smi_sig == 1)
  		smi_sig = 0x47534943;
  	else
  		smi_sig = ist_info.signature;
  
  	/* setup smi_port from MODLULE_PARM or BIOS */
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
439
  	if ((smi_port > 0xff) || (smi_port < 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  		return -EINVAL;
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
441
  	else if (smi_port == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  		smi_port = ist_info.command & 0xff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443

32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
444
  	if ((smi_cmd > 0xff) || (smi_cmd < 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  		return -EINVAL;
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
446
  	else if (smi_cmd == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
  		smi_cmd = (ist_info.command >> 16) & 0xff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
454
455
456
457
458
459
460
461
  
  	return cpufreq_register_driver(&speedstep_driver);
  }
  
  
  /**
   * speedstep_exit - unregisters SpeedStep support
   *
   *   Unregisters SpeedStep support.
   */
  static void __exit speedstep_exit(void)
  {
  	cpufreq_unregister_driver(&speedstep_driver);
  }
bbfebd665   Dave Jones   [CPUFREQ] checkpa...
462
463
464
  module_param(smi_port, int, 0444);
  module_param(smi_cmd,  int, 0444);
  module_param(smi_sig, uint, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465

bbfebd665   Dave Jones   [CPUFREQ] checkpa...
466
467
468
469
470
471
  MODULE_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value "
  		"-- Intel's default setting is 0xb2");
  MODULE_PARM_DESC(smi_cmd, "Override the BIOS-given IST command with this value "
  		"-- Intel's default setting is 0x82");
  MODULE_PARM_DESC(smi_sig, "Set to 1 to fake the IST signature when using the "
  		"SMI interface.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

bbfebd665   Dave Jones   [CPUFREQ] checkpa...
473
474
475
  MODULE_AUTHOR("Hiroshi Miura");
  MODULE_DESCRIPTION("Speedstep driver for IST applet SMI interface.");
  MODULE_LICENSE("GPL");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
  
  module_init(speedstep_init);
  module_exit(speedstep_exit);