Blame view

drivers/cpufreq/e_powersaver.c 12.3 KB
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   *  Based on documentation provided by Dave Jones. Thanks!
   *
   *  Licensed under the terms of the GNU GPL License version 2.
   *
   *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/cpufreq.h>
  #include <linux/ioport.h>
  #include <linux/slab.h>
c9b8c8715   Dave Jones   [CPUFREQ] checkpa...
15
16
17
  #include <linux/timex.h>
  #include <linux/io.h>
  #include <linux/delay.h>
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
18
19
20
  
  #include <asm/msr.h>
  #include <asm/tsc.h>
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
21

27e954c24   Rafał Bilski   [CPUFREQ] e_power...
22
23
24
25
  #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
  #include <linux/acpi.h>
  #include <acpi/processor.h>
  #endif
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
26
27
28
29
  #define EPS_BRAND_C7M	0
  #define EPS_BRAND_C7	1
  #define EPS_BRAND_EDEN	2
  #define EPS_BRAND_C3	3
535ae38c9   Jesse Ahrens   [CPUFREQ] Support...
30
  #define EPS_BRAND_C7D	4
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
31
32
33
  
  struct eps_cpu_data {
  	u32 fsb;
27e954c24   Rafał Bilski   [CPUFREQ] e_power...
34
35
36
  #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
  	u32 bios_limit;
  #endif
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
37
38
39
40
  	struct cpufreq_frequency_table freq_table[];
  };
  
  static struct eps_cpu_data *eps_cpu[NR_CPUS];
ed361bf08   Rafał Bilski   [CPUFREQ] e_power...
41
42
43
  /* Module parameters */
  static int freq_failsafe_off;
  static int voltage_failsafe_off;
826e570bb   Rafał Bilski   [CPUFREQ] e_power...
44
  static int set_max_voltage;
ed361bf08   Rafał Bilski   [CPUFREQ] e_power...
45

27e954c24   Rafał Bilski   [CPUFREQ] e_power...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
  static int ignore_acpi_limit;
  
  static struct acpi_processor_performance *eps_acpi_cpu_perf;
  
  /* Minimum necessary to get acpi_processor_get_bios_limit() working */
  static int eps_acpi_init(void)
  {
  	eps_acpi_cpu_perf = kzalloc(sizeof(struct acpi_processor_performance),
  				      GFP_KERNEL);
  	if (!eps_acpi_cpu_perf)
  		return -ENOMEM;
  
  	if (!zalloc_cpumask_var(&eps_acpi_cpu_perf->shared_cpu_map,
  								GFP_KERNEL)) {
  		kfree(eps_acpi_cpu_perf);
  		eps_acpi_cpu_perf = NULL;
  		return -ENOMEM;
  	}
  
  	if (acpi_processor_register_performance(eps_acpi_cpu_perf, 0)) {
  		free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map);
  		kfree(eps_acpi_cpu_perf);
  		eps_acpi_cpu_perf = NULL;
  		return -EIO;
  	}
  	return 0;
  }
  
  static int eps_acpi_exit(struct cpufreq_policy *policy)
  {
  	if (eps_acpi_cpu_perf) {
  		acpi_processor_unregister_performance(eps_acpi_cpu_perf, 0);
  		free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map);
  		kfree(eps_acpi_cpu_perf);
  		eps_acpi_cpu_perf = NULL;
  	}
  	return 0;
  }
  #endif
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  
  static unsigned int eps_get(unsigned int cpu)
  {
  	struct eps_cpu_data *centaur;
  	u32 lo, hi;
  
  	if (cpu)
  		return 0;
  	centaur = eps_cpu[cpu];
  	if (centaur == NULL)
  		return 0;
  
  	/* Return current frequency */
  	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
  	return centaur->fsb * ((lo >> 8) & 0xff);
  }
  
  static int eps_set_state(struct eps_cpu_data *centaur,
  			 unsigned int cpu,
  			 u32 dest_state)
  {
  	struct cpufreq_freqs freqs;
  	u32 lo, hi;
  	int err = 0;
  	int i;
  
  	freqs.old = eps_get(cpu);
  	freqs.new = centaur->fsb * ((dest_state >> 8) & 0xff);
  	freqs.cpu = cpu;
  	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
  
  	/* Wait while CPU is busy */
  	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
  	i = 0;
  	while (lo & ((1 << 16) | (1 << 17))) {
  		udelay(16);
  		rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
  		i++;
  		if (unlikely(i > 64)) {
  			err = -ENODEV;
  			goto postchange;
  		}
  	}
  	/* Set new multiplier and voltage */
  	wrmsr(MSR_IA32_PERF_CTL, dest_state & 0xffff, 0);
  	/* Wait until transition end */
  	i = 0;
  	do {
  		udelay(16);
  		rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
  		i++;
  		if (unlikely(i > 64)) {
  			err = -ENODEV;
  			goto postchange;
  		}
  	} while (lo & ((1 << 16) | (1 << 17)));
  
  	/* Return current frequency */
  postchange:
  	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
  	freqs.new = centaur->fsb * ((lo >> 8) & 0xff);
0e5aa8d62   Dave Jones   [CPUFREQ] Remove ...
147
148
149
  #ifdef DEBUG
  	{
  	u8 current_multiplier, current_voltage;
535ae38c9   Jesse Ahrens   [CPUFREQ] Support...
150
151
152
153
154
155
156
157
158
159
  	/* Print voltage and multiplier */
  	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
  	current_voltage = lo & 0xff;
  	printk(KERN_INFO "eps: Current voltage = %dmV
  ",
  		current_voltage * 16 + 700);
  	current_multiplier = (lo >> 8) & 0xff;
  	printk(KERN_INFO "eps: Current multiplier = %d
  ",
  		current_multiplier);
0e5aa8d62   Dave Jones   [CPUFREQ] Remove ...
160
161
  	}
  #endif
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
  	return err;
  }
  
  static int eps_target(struct cpufreq_policy *policy,
  			       unsigned int target_freq,
  			       unsigned int relation)
  {
  	struct eps_cpu_data *centaur;
  	unsigned int newstate = 0;
  	unsigned int cpu = policy->cpu;
  	unsigned int dest_state;
  	int ret;
  
  	if (unlikely(eps_cpu[cpu] == NULL))
  		return -ENODEV;
  	centaur = eps_cpu[cpu];
  
  	if (unlikely(cpufreq_frequency_table_target(policy,
  			&eps_cpu[cpu]->freq_table[0],
  			target_freq,
  			relation,
  			&newstate))) {
  		return -EINVAL;
  	}
  
  	/* Make frequency transition */
  	dest_state = centaur->freq_table[newstate].index & 0xffff;
  	ret = eps_set_state(centaur, cpu, dest_state);
  	if (ret)
  		printk(KERN_ERR "eps: Timeout!
  ");
  	return ret;
  }
  
  static int eps_verify(struct cpufreq_policy *policy)
  {
  	return cpufreq_frequency_table_verify(policy,
  			&eps_cpu[policy->cpu]->freq_table[0]);
  }
  
  static int eps_cpu_init(struct cpufreq_policy *policy)
  {
  	unsigned int i;
  	u32 lo, hi;
  	u64 val;
  	u8 current_multiplier, current_voltage;
  	u8 max_multiplier, max_voltage;
  	u8 min_multiplier, min_voltage;
535ae38c9   Jesse Ahrens   [CPUFREQ] Support...
211
  	u8 brand = 0;
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
212
213
  	u32 fsb;
  	struct eps_cpu_data *centaur;
535ae38c9   Jesse Ahrens   [CPUFREQ] Support...
214
  	struct cpuinfo_x86 *c = &cpu_data(0);
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
215
216
217
218
  	struct cpufreq_frequency_table *f_table;
  	int k, step, voltage;
  	int ret;
  	int states;
27e954c24   Rafał Bilski   [CPUFREQ] e_power...
219
220
221
  #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
  	unsigned int limit;
  #endif
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
222
223
224
225
226
  
  	if (policy->cpu != 0)
  		return -ENODEV;
  
  	/* Check brand */
e19717fe2   Dave Jones   [CPUFREQ] Add mis...
227
  	printk(KERN_INFO "eps: Detected VIA ");
535ae38c9   Jesse Ahrens   [CPUFREQ] Support...
228
229
230
231
232
233
234
235
236
237
238
239
240
  
  	switch (c->x86_model) {
  	case 10:
  		rdmsr(0x1153, lo, hi);
  		brand = (((lo >> 2) ^ lo) >> 18) & 3;
  		printk(KERN_CONT "Model A ");
  		break;
  	case 13:
  		rdmsr(0x1154, lo, hi);
  		brand = (((lo >> 4) ^ (lo >> 2))) & 0x000000ff;
  		printk(KERN_CONT "Model D ");
  		break;
  	}
c9b8c8715   Dave Jones   [CPUFREQ] checkpa...
241
  	switch (brand) {
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
242
  	case EPS_BRAND_C7M:
e19717fe2   Dave Jones   [CPUFREQ] Add mis...
243
244
  		printk(KERN_CONT "C7-M
  ");
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
245
246
  		break;
  	case EPS_BRAND_C7:
e19717fe2   Dave Jones   [CPUFREQ] Add mis...
247
248
  		printk(KERN_CONT "C7
  ");
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
249
250
  		break;
  	case EPS_BRAND_EDEN:
e19717fe2   Dave Jones   [CPUFREQ] Add mis...
251
252
  		printk(KERN_CONT "Eden
  ");
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
253
  		break;
535ae38c9   Jesse Ahrens   [CPUFREQ] Support...
254
255
256
257
  	case EPS_BRAND_C7D:
  		printk(KERN_CONT "C7-D
  ");
  		break;
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
258
  	case EPS_BRAND_C3:
e19717fe2   Dave Jones   [CPUFREQ] Add mis...
259
260
  		printk(KERN_CONT "C3
  ");
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
261
262
263
264
265
  		return -ENODEV;
  		break;
  	}
  	/* Enable Enhanced PowerSaver */
  	rdmsrl(MSR_IA32_MISC_ENABLE, val);
ecab22aa6   Vegard Nossum   x86: use symbolic...
266
267
  	if (!(val & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) {
  		val |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP;
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
268
269
270
  		wrmsrl(MSR_IA32_MISC_ENABLE, val);
  		/* Can be locked at 0 */
  		rdmsrl(MSR_IA32_MISC_ENABLE, val);
ecab22aa6   Vegard Nossum   x86: use symbolic...
271
  		if (!(val & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) {
e19717fe2   Dave Jones   [CPUFREQ] Add mis...
272
273
  			printk(KERN_INFO "eps: Can't enable Enhanced PowerSaver
  ");
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
274
275
276
277
278
279
280
  			return -ENODEV;
  		}
  	}
  
  	/* Print voltage and multiplier */
  	rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
  	current_voltage = lo & 0xff;
c9b8c8715   Dave Jones   [CPUFREQ] checkpa...
281
282
283
  	printk(KERN_INFO "eps: Current voltage = %dmV
  ",
  			current_voltage * 16 + 700);
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
284
  	current_multiplier = (lo >> 8) & 0xff;
e19717fe2   Dave Jones   [CPUFREQ] Add mis...
285
286
  	printk(KERN_INFO "eps: Current multiplier = %d
  ", current_multiplier);
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
287
288
289
  
  	/* Print limits */
  	max_voltage = hi & 0xff;
c9b8c8715   Dave Jones   [CPUFREQ] checkpa...
290
291
292
  	printk(KERN_INFO "eps: Highest voltage = %dmV
  ",
  			max_voltage * 16 + 700);
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
293
  	max_multiplier = (hi >> 8) & 0xff;
e19717fe2   Dave Jones   [CPUFREQ] Add mis...
294
295
  	printk(KERN_INFO "eps: Highest multiplier = %d
  ", max_multiplier);
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
296
  	min_voltage = (hi >> 16) & 0xff;
c9b8c8715   Dave Jones   [CPUFREQ] checkpa...
297
298
299
  	printk(KERN_INFO "eps: Lowest voltage = %dmV
  ",
  			min_voltage * 16 + 700);
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
300
  	min_multiplier = (hi >> 24) & 0xff;
e19717fe2   Dave Jones   [CPUFREQ] Add mis...
301
302
  	printk(KERN_INFO "eps: Lowest multiplier = %d
  ", min_multiplier);
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
303
304
305
306
307
308
309
310
  
  	/* Sanity checks */
  	if (current_multiplier == 0 || max_multiplier == 0
  	    || min_multiplier == 0)
  		return -EINVAL;
  	if (current_multiplier > max_multiplier
  	    || max_multiplier <= min_multiplier)
  		return -EINVAL;
535ae38c9   Jesse Ahrens   [CPUFREQ] Support...
311
  	if (current_voltage > 0x1f || max_voltage > 0x1f)
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
312
  		return -EINVAL;
ed361bf08   Rafał Bilski   [CPUFREQ] e_power...
313
314
315
  	if (max_voltage < min_voltage
  	    || current_voltage < min_voltage
  	    || current_voltage > max_voltage)
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
316
  		return -EINVAL;
ed361bf08   Rafał Bilski   [CPUFREQ] e_power...
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  	/* Check for systems using underclocked CPU */
  	if (!freq_failsafe_off && max_multiplier != current_multiplier) {
  		printk(KERN_INFO "eps: Your processor is running at different "
  			"frequency then its maximum. Aborting.
  ");
  		printk(KERN_INFO "eps: You can use freq_failsafe_off option "
  			"to disable this check.
  ");
  		return -EINVAL;
  	}
  	if (!voltage_failsafe_off && max_voltage != current_voltage) {
  		printk(KERN_INFO "eps: Your processor is running at different "
  			"voltage then its maximum. Aborting.
  ");
  		printk(KERN_INFO "eps: You can use voltage_failsafe_off "
  			"option to disable this check.
  ");
  		return -EINVAL;
  	}
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
336
337
  	/* Calc FSB speed */
  	fsb = cpu_khz / current_multiplier;
27e954c24   Rafał Bilski   [CPUFREQ] e_power...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
  
  #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
  	/* Check for ACPI processor speed limit */
  	if (!ignore_acpi_limit && !eps_acpi_init()) {
  		if (!acpi_processor_get_bios_limit(policy->cpu, &limit)) {
  			printk(KERN_INFO "eps: ACPI limit %u.%uGHz
  ",
  				limit/1000000,
  				(limit%1000000)/10000);
  			eps_acpi_exit(policy);
  			/* Check if max_multiplier is in BIOS limits */
  			if (limit && max_multiplier * fsb > limit) {
  				printk(KERN_INFO "eps: Aborting.
  ");
  				return -EINVAL;
  			}
  		}
  	}
  #endif
826e570bb   Rafał Bilski   [CPUFREQ] e_power...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
  	/* Allow user to set lower maximum voltage then that reported
  	 * by processor */
  	if (brand == EPS_BRAND_C7M && set_max_voltage) {
  		u32 v;
  
  		/* Change mV to something hardware can use */
  		v = (set_max_voltage - 700) / 16;
  		/* Check if voltage is within limits */
  		if (v >= min_voltage && v <= max_voltage) {
  			printk(KERN_INFO "eps: Setting %dmV as maximum.
  ",
  				v * 16 + 700);
  			max_voltage = v;
  		}
  	}
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  	/* Calc number of p-states supported */
  	if (brand == EPS_BRAND_C7M)
  		states = max_multiplier - min_multiplier + 1;
  	else
  		states = 2;
  
  	/* Allocate private data and frequency table for current cpu */
  	centaur = kzalloc(sizeof(struct eps_cpu_data)
  		    + (states + 1) * sizeof(struct cpufreq_frequency_table),
  		    GFP_KERNEL);
  	if (!centaur)
  		return -ENOMEM;
  	eps_cpu[0] = centaur;
  
  	/* Copy basic values */
  	centaur->fsb = fsb;
27e954c24   Rafał Bilski   [CPUFREQ] e_power...
388
389
390
  #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
  	centaur->bios_limit = limit;
  #endif
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
391
392
393
  
  	/* Fill frequency and MSR value table */
  	f_table = &centaur->freq_table[0];
b6f45a4b0   Rafa³ Bilski   [CPUFREQ] EPS - C...
394
  	if (brand != EPS_BRAND_C7M) {
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
  		f_table[0].frequency = fsb * min_multiplier;
  		f_table[0].index = (min_multiplier << 8) | min_voltage;
  		f_table[1].frequency = fsb * max_multiplier;
  		f_table[1].index = (max_multiplier << 8) | max_voltage;
  		f_table[2].frequency = CPUFREQ_TABLE_END;
  	} else {
  		k = 0;
  		step = ((max_voltage - min_voltage) * 256)
  			/ (max_multiplier - min_multiplier);
  		for (i = min_multiplier; i <= max_multiplier; i++) {
  			voltage = (k * step) / 256 + min_voltage;
  			f_table[k].frequency = fsb * i;
  			f_table[k].index = (i << 8) | voltage;
  			k++;
  		}
  		f_table[k].frequency = CPUFREQ_TABLE_END;
  	}
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  	policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */
  	policy->cur = fsb * current_multiplier;
  
  	ret = cpufreq_frequency_table_cpuinfo(policy, &centaur->freq_table[0]);
  	if (ret) {
  		kfree(centaur);
  		return ret;
  	}
  
  	cpufreq_frequency_table_get_attr(&centaur->freq_table[0], policy->cpu);
  	return 0;
  }
  
  static int eps_cpu_exit(struct cpufreq_policy *policy)
  {
  	unsigned int cpu = policy->cpu;
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
428

86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
429
430
431
432
433
434
  	/* Bye */
  	cpufreq_frequency_table_put_attr(policy->cpu);
  	kfree(eps_cpu[cpu]);
  	eps_cpu[cpu] = NULL;
  	return 0;
  }
c9b8c8715   Dave Jones   [CPUFREQ] checkpa...
435
  static struct freq_attr *eps_attr[] = {
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
436
437
438
  	&cpufreq_freq_attr_scaling_available_freqs,
  	NULL,
  };
221dee285   Linus Torvalds   Revert "[CPUFREQ]...
439
  static struct cpufreq_driver eps_driver = {
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
440
441
442
443
444
445
446
447
448
449
450
451
  	.verify		= eps_verify,
  	.target		= eps_target,
  	.init		= eps_cpu_init,
  	.exit		= eps_cpu_exit,
  	.get		= eps_get,
  	.name		= "e_powersaver",
  	.owner		= THIS_MODULE,
  	.attr		= eps_attr,
  };
  
  static int __init eps_init(void)
  {
92cb7612a   Mike Travis   x86: convert cpui...
452
  	struct cpuinfo_x86 *c = &cpu_data(0);
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
453
454
455
456
  
  	/* This driver will work only on Centaur C7 processors with
  	 * Enhanced SpeedStep/PowerSaver registers */
  	if (c->x86_vendor != X86_VENDOR_CENTAUR
535ae38c9   Jesse Ahrens   [CPUFREQ] Support...
457
  	    || c->x86 != 6 || c->x86_model < 10)
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
458
459
460
461
462
463
464
465
466
467
468
469
470
  		return -ENODEV;
  	if (!cpu_has(c, X86_FEATURE_EST))
  		return -ENODEV;
  
  	if (cpufreq_register_driver(&eps_driver))
  		return -EINVAL;
  	return 0;
  }
  
  static void __exit eps_exit(void)
  {
  	cpufreq_unregister_driver(&eps_driver);
  }
ed361bf08   Rafał Bilski   [CPUFREQ] e_power...
471
472
473
474
475
476
  /* Allow user to overclock his machine or to change frequency to higher after
   * unloading module */
  module_param(freq_failsafe_off, int, 0644);
  MODULE_PARM_DESC(freq_failsafe_off, "Disable current vs max frequency check");
  module_param(voltage_failsafe_off, int, 0644);
  MODULE_PARM_DESC(voltage_failsafe_off, "Disable current vs max voltage check");
27e954c24   Rafał Bilski   [CPUFREQ] e_power...
477
478
479
480
  #if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
  module_param(ignore_acpi_limit, int, 0644);
  MODULE_PARM_DESC(ignore_acpi_limit, "Don't check ACPI's processor speed limit");
  #endif
826e570bb   Rafał Bilski   [CPUFREQ] e_power...
481
482
  module_param(set_max_voltage, int, 0644);
  MODULE_PARM_DESC(set_max_voltage, "Set maximum CPU voltage (mV) C7-M only");
ed361bf08   Rafał Bilski   [CPUFREQ] e_power...
483

c9b8c8715   Dave Jones   [CPUFREQ] checkpa...
484
  MODULE_AUTHOR("Rafal Bilski <rafalbilski@interia.pl>");
86acd49aa   Rafa³ Bilski   [CPUFREQ] Enhance...
485
486
487
488
489
  MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's.");
  MODULE_LICENSE("GPL");
  
  module_init(eps_init);
  module_exit(eps_exit);