Blame view

drivers/cpufreq/longhaul.c 25.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
d5e80b4b1   Dave Jones   Update/Remove soo...
2
   *  (C) 2001-2004  Dave Jones.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
   *  (C) 2002  Padraig Brady. <padraig@antefacto.com>
   *
   *  Licensed under the terms of the GNU GPL License version 2.
   *  Based upon datasheets & sample CPUs kindly provided by VIA.
   *
   *  VIA have currently 3 different versions of Longhaul.
   *  Version 1 (Longhaul) uses the BCR2 MSR at 0x1147.
   *   It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0.
2b8c0e130   Rafa³ Bilski   [CPUFREQ] Longhau...
11
12
13
   *  Version 2 of longhaul is backward compatible with v1, but adds
   *   LONGHAUL MSR for purpose of both frequency and voltage scaling.
   *   Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
   *  Version 3 of longhaul got renamed to Powersaver and redesigned
2b8c0e130   Rafa³ Bilski   [CPUFREQ] Longhau...
15
   *   to use only the POWERSAVER MSR at 0x110a.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
21
22
   *   It is present in Ezra-T (C5M), Nehemiah (C5X) and above.
   *   It's pretty much the same feature wise to longhaul v2, though
   *   there is provision for scaling FSB too, but this doesn't work
   *   too well in practice so we don't even try to use this.
   *
   *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
   */
1c5864e26   Joe Perches   cpufreq: Use cons...
23
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/init.h>
  #include <linux/cpufreq.h>
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
29
  #include <linux/pci.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
  #include <linux/slab.h>
  #include <linux/string.h>
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
32
  #include <linux/delay.h>
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
33
34
35
  #include <linux/timex.h>
  #include <linux/io.h>
  #include <linux/acpi.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
  
  #include <asm/msr.h>
fa8031aef   Andi Kleen   cpufreq: Add supp...
38
  #include <asm/cpu_device_id.h>
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
39
  #include <acpi/processor.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
  
  #include "longhaul.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
  #define TYPE_LONGHAUL_V1	1
  #define TYPE_LONGHAUL_V2	2
  #define TYPE_POWERSAVER		3
  
  #define	CPU_SAMUEL	1
  #define	CPU_SAMUEL2	2
  #define	CPU_EZRA	3
  #define	CPU_EZRA_T	4
  #define	CPU_NEHEMIAH	5
980342a7e   Rafa³ Bilski   [CPUFREQ] Longhau...
51
  #define	CPU_NEHEMIAH_C	6
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
53
54
55
  /* Flags */
  #define USE_ACPI_C3		(1 << 1)
  #define USE_NORTHBRIDGE		(1 << 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  static int cpu_model;
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
57
  static unsigned int numscales = 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  static unsigned int fsb;
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
59

bd5ab26a7   Dave Jones   [CPUFREQ] constif...
60
61
  static const struct mV_pos *vrm_mV_table;
  static const unsigned char *mV_vrm_table;
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
62
63
  
  static unsigned int highest_speed, lowest_speed; /* kHz */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
  static unsigned int minmult, maxmult;
  static int can_scale_voltage;
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
66
67
  static struct acpi_processor *pr;
  static struct acpi_processor_cx *cx;
275bc6b7f   Rafał Bilski   [CPUFREQ] Longhau...
68
  static u32 acpi_regs_addr;
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
69
  static u8 longhaul_flags;
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
70
  static unsigned int longhaul_index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
  
  /* Module parameters */
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
73
  static int scale_voltage;
905497c4b   Rafał Bilski   [CPUFREQ] Longhau...
74
  static int disable_acpi_c3;
52a2638bf   Rafal Bilski   Longhaul: add aut...
75
  static int revid_errata;
b5811bc46   Rafał Bilski   cpufreq / Longhau...
76
  static int enable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  /* Clock ratios multiplied by 10 */
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
79
80
  static int mults[32];
  static int eblcr[32];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
  static int longhaul_version;
  static struct cpufreq_frequency_table *longhaul_table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
  static char speedbuffer[8];
  
  static char *print_speed(int speed)
  {
e2aa8732a   Dave Jones   [CPUFREQ] Clean u...
87
  	if (speed < 1000) {
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
88
  		snprintf(speedbuffer, sizeof(speedbuffer), "%dMHz", speed);
e2aa8732a   Dave Jones   [CPUFREQ] Clean u...
89
90
91
92
93
94
95
96
97
  		return speedbuffer;
  	}
  
  	if (speed%1000 == 0)
  		snprintf(speedbuffer, sizeof(speedbuffer),
  			"%dGHz", speed/1000);
  	else
  		snprintf(speedbuffer, sizeof(speedbuffer),
  			"%d.%dGHz", speed/1000, (speed%1000)/100);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
  
  	return speedbuffer;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  
  
  static unsigned int calc_speed(int mult)
  {
  	int khz;
  	khz = (mult/10)*fsb;
  	if (mult%10)
  		khz += fsb/2;
  	khz *= 1000;
  	return khz;
  }
  
  
  static int longhaul_get_cpu_mult(void)
  {
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
116
  	unsigned long invalue = 0, lo, hi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117

ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
118
119
120
121
  	rdmsr(MSR_IA32_EBL_CR_POWERON, lo, hi);
  	invalue = (lo & (1<<22|1<<23|1<<24|1<<25))>>22;
  	if (longhaul_version == TYPE_LONGHAUL_V2 ||
  	    longhaul_version == TYPE_POWERSAVER) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  		if (lo & (1<<27))
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
123
  			invalue += 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  	}
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
125
  	return eblcr[invalue];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  }
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
127
  /* For processor with BCR2 MSR */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128

ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
129
  static void do_longhaul1(unsigned int mults_index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  {
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
131
  	union msr_bcr2 bcr2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132

dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
133
134
135
  	rdmsrl(MSR_VIA_BCR2, bcr2.val);
  	/* Enable software clock multiplier */
  	bcr2.bits.ESOFTBF = 1;
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
136
  	bcr2.bits.CLOCKMUL = mults_index & 0xff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137

dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
138
139
  	/* Sync to timer tick */
  	safe_halt();
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
140
141
  	/* Change frequency on next halt or sleep */
  	wrmsrl(MSR_VIA_BCR2, bcr2.val);
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
142
143
144
  	/* Invoke transition */
  	ACPI_FLUSH_CPU_CACHE();
  	halt();
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
145
146
147
148
149
150
151
  
  	/* Disable software clock multiplier */
  	local_irq_disable();
  	rdmsrl(MSR_VIA_BCR2, bcr2.val);
  	bcr2.bits.ESOFTBF = 0;
  	wrmsrl(MSR_VIA_BCR2, bcr2.val);
  }
3be6a48f3   Dave Jones   [CPUFREQ] longhau...
152

dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
153
  /* For processor with Longhaul MSR */
3be6a48f3   Dave Jones   [CPUFREQ] longhau...
154

ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
155
  static void do_powersaver(int cx_address, unsigned int mults_index,
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
156
  			  unsigned int dir)
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
157
158
159
  {
  	union msr_longhaul longhaul;
  	u32 t;
3be6a48f3   Dave Jones   [CPUFREQ] longhau...
160

dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
161
  	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
162
  	/* Setup new frequency */
52a2638bf   Rafal Bilski   Longhaul: add aut...
163
164
165
166
  	if (!revid_errata)
  		longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
  	else
  		longhaul.bits.RevisionKey = 0;
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
167
168
  	longhaul.bits.SoftBusRatio = mults_index & 0xf;
  	longhaul.bits.SoftBusRatio4 = (mults_index & 0x10) >> 4;
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
169
170
  	/* Setup new voltage */
  	if (can_scale_voltage)
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
171
  		longhaul.bits.SoftVID = (mults_index >> 8) & 0x1f;
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
172
173
174
  	/* Sync to timer tick */
  	safe_halt();
  	/* Raise voltage if necessary */
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
175
  	if (can_scale_voltage && dir) {
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
176
  		longhaul.bits.EnableSoftVID = 1;
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
177
178
179
180
181
182
183
184
185
186
187
  		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
  		/* Change voltage */
  		if (!cx_address) {
  			ACPI_FLUSH_CPU_CACHE();
  			halt();
  		} else {
  			ACPI_FLUSH_CPU_CACHE();
  			/* Invoke C3 */
  			inb(cx_address);
  			/* Dummy op - must do something useless after P_LVL3
  			 * read */
bd0561c9d   Dave Jones   [CPUFREQ] Fix up ...
188
  			t = inl(acpi_gbl_FADT.xpm_timer_block.address);
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
189
190
191
  		}
  		longhaul.bits.EnableSoftVID = 0;
  		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
192
  	}
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
193
  	/* Change frequency on next halt or sleep */
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
194
  	longhaul.bits.EnableSoftBusRatio = 1;
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
195
  	wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
196
  	if (!cx_address) {
7f1be8924   rafalbilski@interia.pl   [CPUFREQ] Longhau...
197
  		ACPI_FLUSH_CPU_CACHE();
7f1be8924   rafalbilski@interia.pl   [CPUFREQ] Longhau...
198
199
200
201
202
203
  		halt();
  	} else {
  		ACPI_FLUSH_CPU_CACHE();
  		/* Invoke C3 */
  		inb(cx_address);
  		/* Dummy op - must do something useless after P_LVL3 read */
cee324b14   Alexey Starikovskiy   ACPICA: use new A...
204
  		t = inl(acpi_gbl_FADT.xpm_timer_block.address);
7f1be8924   rafalbilski@interia.pl   [CPUFREQ] Longhau...
205
  	}
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
206
  	/* Disable bus ratio bit */
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
207
  	longhaul.bits.EnableSoftBusRatio = 0;
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
208
  	wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
209
210
  
  	/* Reduce voltage if necessary */
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
211
  	if (can_scale_voltage && !dir) {
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
212
213
214
215
216
217
218
219
220
221
222
223
  		longhaul.bits.EnableSoftVID = 1;
  		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
  		/* Change voltage */
  		if (!cx_address) {
  			ACPI_FLUSH_CPU_CACHE();
  			halt();
  		} else {
  			ACPI_FLUSH_CPU_CACHE();
  			/* Invoke C3 */
  			inb(cx_address);
  			/* Dummy op - must do something useless after P_LVL3
  			 * read */
bd0561c9d   Dave Jones   [CPUFREQ] Fix up ...
224
  			t = inl(acpi_gbl_FADT.xpm_timer_block.address);
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
225
226
227
  		}
  		longhaul.bits.EnableSoftVID = 0;
  		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
228
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
  }
  
  /**
   * longhaul_set_cpu_frequency()
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
233
   * @mults_index : bitpattern of the new multiplier.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
   *
   * Sets a new clock ratio.
   */
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
237
  static int longhaul_setstate(struct cpufreq_policy *policy,
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
238
  		unsigned int table_index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  {
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
240
  	unsigned int mults_index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
  	int speed, mult;
  	struct cpufreq_freqs freqs;
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
243
244
  	unsigned long flags;
  	unsigned int pic1_mask, pic2_mask;
689eba77c   Rafał Bilski   [CPUFREQ] Longhau...
245
  	u16 bm_status = 0;
275bc6b7f   Rafał Bilski   [CPUFREQ] Longhau...
246
  	u32 bm_timeout = 1000;
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
247
  	unsigned int dir = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248

507015880   Viresh Kumar   cpufreq: rename i...
249
  	mults_index = longhaul_table[table_index].driver_data;
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
250
  	/* Safety precautions */
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
251
  	mult = mults[mults_index & 0x1f];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  	if (mult == -1)
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
253
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
  	speed = calc_speed(mult);
  	if ((speed > highest_speed) || (speed < lowest_speed))
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
256
  		return -EINVAL;
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
257
258
259
  	/* Voltage transition before frequency transition? */
  	if (can_scale_voltage && longhaul_index < table_index)
  		dir = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
  
  	freqs.old = calc_speed(longhaul_get_cpu_mult());
  	freqs.new = speed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
264
265
  	pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  			fsb, mult/10, mult%10, print_speed(speed/1000));
52a2638bf   Rafal Bilski   Longhaul: add aut...
267
  retry_loop:
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
268
269
270
271
272
  	preempt_disable();
  	local_irq_save(flags);
  
  	pic2_mask = inb(0xA1);
  	pic1_mask = inb(0x21);	/* works on C3. save mask. */
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
273
274
  	outb(0xFF, 0xA1);	/* Overkill */
  	outb(0xFE, 0x21);	/* TMR0 only */
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
275

489dc5cb1   Rafał Bilski   [CPUFREQ] Longhau...
276
  	/* Wait while PCI bus is busy. */
689eba77c   Rafał Bilski   [CPUFREQ] Longhau...
277
278
279
  	if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE
  	    || ((pr != NULL) && pr->flags.bm_control))) {
  		bm_status = inw(acpi_regs_addr);
275bc6b7f   Rafał Bilski   [CPUFREQ] Longhau...
280
  		bm_status &= 1 << 4;
489dc5cb1   Rafał Bilski   [CPUFREQ] Longhau...
281
  		while (bm_status && bm_timeout) {
689eba77c   Rafał Bilski   [CPUFREQ] Longhau...
282
  			outw(1 << 4, acpi_regs_addr);
489dc5cb1   Rafał Bilski   [CPUFREQ] Longhau...
283
  			bm_timeout--;
689eba77c   Rafał Bilski   [CPUFREQ] Longhau...
284
  			bm_status = inw(acpi_regs_addr);
275bc6b7f   Rafał Bilski   [CPUFREQ] Longhau...
285
  			bm_status &= 1 << 4;
489dc5cb1   Rafał Bilski   [CPUFREQ] Longhau...
286
287
  		}
  	}
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
288
289
290
291
  	if (longhaul_flags & USE_NORTHBRIDGE) {
  		/* Disable AGP and PCI arbiters */
  		outb(3, 0x22);
  	} else if ((pr != NULL) && pr->flags.bm_control) {
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
292
  		/* Disable bus master arbitration */
fb318cbff   Lin Ming   ACPI: cpufreq: us...
293
  		acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
294
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
  	switch (longhaul_version) {
  
  	/*
  	 * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B])
  	 * Software controlled multipliers only.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  	 */
  	case TYPE_LONGHAUL_V1:
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
302
  		do_longhaul1(mults_index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
  		break;
  
  	/*
2b8c0e130   Rafa³ Bilski   [CPUFREQ] Longhau...
306
307
  	 * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5B] and Ezra [C5C]
  	 *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  	 * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
  	 * Nehemiah can do FSB scaling too, but this has never been proven
  	 * to work in practice.
  	 */
2b8c0e130   Rafa³ Bilski   [CPUFREQ] Longhau...
312
  	case TYPE_LONGHAUL_V2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  	case TYPE_POWERSAVER:
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
314
315
  		if (longhaul_flags & USE_ACPI_C3) {
  			/* Don't allow wakeup */
fb318cbff   Lin Ming   ACPI: cpufreq: us...
316
  			acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
317
  			do_powersaver(cx->address, mults_index, dir);
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
318
  		} else {
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
319
  			do_powersaver(0, mults_index, dir);
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
320
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
  		break;
  	}
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
323
324
325
326
  	if (longhaul_flags & USE_NORTHBRIDGE) {
  		/* Enable arbiters */
  		outb(0, 0x22);
  	} else if ((pr != NULL) && pr->flags.bm_control) {
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
327
  		/* Enable bus master arbitration */
fb318cbff   Lin Ming   ACPI: cpufreq: us...
328
  		acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
329
  	}
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
330
331
  	outb(pic2_mask, 0xA1);	/* restore mask */
  	outb(pic1_mask, 0x21);
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
332
333
334
  
  	local_irq_restore(flags);
  	preempt_enable();
2b8c0e130   Rafa³ Bilski   [CPUFREQ] Longhau...
335
  	freqs.new = calc_speed(longhaul_get_cpu_mult());
52a2638bf   Rafal Bilski   Longhaul: add aut...
336
337
  	/* Check if requested frequency is set. */
  	if (unlikely(freqs.new != speed)) {
1c5864e26   Joe Perches   cpufreq: Use cons...
338
339
  		pr_info("Failed to set requested frequency!
  ");
52a2638bf   Rafal Bilski   Longhaul: add aut...
340
341
342
343
344
  		/* Revision ID = 1 but processor is expecting revision key
  		 * equal to 0. Jumpers at the bottom of processor will change
  		 * multiplier and FSB, but will not change bits in Longhaul
  		 * MSR nor enable voltage scaling. */
  		if (!revid_errata) {
1c5864e26   Joe Perches   cpufreq: Use cons...
345
346
  			pr_info("Enabling \"Ignore Revision ID\" option
  ");
52a2638bf   Rafal Bilski   Longhaul: add aut...
347
348
349
350
351
352
353
354
355
  			revid_errata = 1;
  			msleep(200);
  			goto retry_loop;
  		}
  		/* Why ACPI C3 sometimes doesn't work is a mystery for me.
  		 * But it does happen. Processor is entering ACPI C3 state,
  		 * but it doesn't change frequency. I tried poking various
  		 * bits in northbridge registers, but without success. */
  		if (longhaul_flags & USE_ACPI_C3) {
1c5864e26   Joe Perches   cpufreq: Use cons...
356
357
  			pr_info("Disabling ACPI C3 support
  ");
52a2638bf   Rafal Bilski   Longhaul: add aut...
358
359
  			longhaul_flags &= ~USE_ACPI_C3;
  			if (revid_errata) {
1c5864e26   Joe Perches   cpufreq: Use cons...
360
361
  				pr_info("Disabling \"Ignore Revision ID\" option
  ");
52a2638bf   Rafal Bilski   Longhaul: add aut...
362
363
364
365
366
367
368
369
370
371
  				revid_errata = 0;
  			}
  			msleep(200);
  			goto retry_loop;
  		}
  		/* This shouldn't happen. Longhaul ver. 2 was reported not
  		 * working on processors without voltage scaling, but with
  		 * RevID = 1. RevID errata will make things right. Just
  		 * to be 100% sure. */
  		if (longhaul_version == TYPE_LONGHAUL_V2) {
1c5864e26   Joe Perches   cpufreq: Use cons...
372
373
  			pr_info("Switching to Longhaul ver. 1
  ");
52a2638bf   Rafal Bilski   Longhaul: add aut...
374
375
376
377
378
  			longhaul_version = TYPE_LONGHAUL_V1;
  			msleep(200);
  			goto retry_loop;
  		}
  	}
489dc5cb1   Rafał Bilski   [CPUFREQ] Longhau...
379

7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
380
  	if (!bm_timeout) {
1c5864e26   Joe Perches   cpufreq: Use cons...
381
382
  		pr_info("Warning: Timeout while waiting for idle PCI bus
  ");
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
383
384
385
386
  		return -EBUSY;
  	}
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
391
392
393
394
395
396
397
398
  }
  
  /*
   * Centaur decided to make life a little more tricky.
   * Only longhaul v1 is allowed to read EBLCR BSEL[0:1].
   * Samuel2 and above have to try and guess what the FSB is.
   * We do this by assuming we booted at maximum multiplier, and interpolate
   * between that value multiplied by possible FSBs and cpu_mhz which
   * was calculated at boot time. Really ugly, but no other way to do this.
   */
  
  #define ROUNDING	0xf
24ebead82   Rafa³ Bilski   [CPUFREQ] Longhau...
399
  static int guess_fsb(int mult)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  {
46ef955f5   Rafa³ Bilski   [CPUFREQ] Longhau...
401
  	int speed = cpu_khz / 1000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  	int i;
46ef955f5   Rafa³ Bilski   [CPUFREQ] Longhau...
403
404
405
406
407
408
409
410
411
  	int speeds[] = { 666, 1000, 1333, 2000 };
  	int f_max, f_min;
  
  	for (i = 0; i < 4; i++) {
  		f_max = ((speeds[i] * mult) + 50) / 100;
  		f_max += (ROUNDING / 2);
  		f_min = f_max - ROUNDING;
  		if ((speed <= f_max) && (speed >= f_min))
  			return speeds[i] / 10;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
  	}
  	return 0;
  }
2760984f6   Paul Gortmaker   cpufreq: delete _...
415
  static int longhaul_get_ranges(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  {
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
417
418
  	unsigned int i, j, k = 0;
  	unsigned int ratio;
980342a7e   Rafa³ Bilski   [CPUFREQ] Longhau...
419
  	int mult;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420

980342a7e   Rafa³ Bilski   [CPUFREQ] Longhau...
421
422
423
  	/* Get current frequency */
  	mult = longhaul_get_cpu_mult();
  	if (mult == -1) {
1c5864e26   Joe Perches   cpufreq: Use cons...
424
425
  		pr_info("Invalid (reserved) multiplier!
  ");
980342a7e   Rafa³ Bilski   [CPUFREQ] Longhau...
426
427
428
429
  		return -EINVAL;
  	}
  	fsb = guess_fsb(mult);
  	if (fsb == 0) {
1c5864e26   Joe Perches   cpufreq: Use cons...
430
431
  		pr_info("Invalid (reserved) FSB!
  ");
980342a7e   Rafa³ Bilski   [CPUFREQ] Longhau...
432
433
434
  		return -EINVAL;
  	}
  	/* Get max multiplier - as we always did.
0d2eb44f6   Lucas De Marchi   x86: Fix common m...
435
  	 * Longhaul MSR is useful only when voltage scaling is enabled.
980342a7e   Rafa³ Bilski   [CPUFREQ] Longhau...
436
437
438
  	 * C3 is booting at max anyway. */
  	maxmult = mult;
  	/* Get min multiplier */
9addf3b63   Rafa³ Bilski   [CPUFREQ] Longhau...
439
440
441
  	switch (cpu_model) {
  	case CPU_NEHEMIAH:
  		minmult = 50;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  		break;
9addf3b63   Rafa³ Bilski   [CPUFREQ] Longhau...
443
444
445
446
447
  	case CPU_NEHEMIAH_C:
  		minmult = 40;
  		break;
  	default:
  		minmult = 30;
980342a7e   Rafa³ Bilski   [CPUFREQ] Longhau...
448
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
450
451
  	pr_debug("MinMult:%d.%dx MaxMult:%d.%dx
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  		 minmult/10, minmult%10, maxmult/10, maxmult%10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
  	highest_speed = calc_speed(maxmult);
  	lowest_speed = calc_speed(minmult);
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
455
456
  	pr_debug("FSB:%dMHz  Lowest speed: %s   Highest speed:%s
  ", fsb,
cee324b14   Alexey Starikovskiy   ACPICA: use new A...
457
  		 print_speed(lowest_speed/1000),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
  		 print_speed(highest_speed/1000));
  
  	if (lowest_speed == highest_speed) {
1c5864e26   Joe Perches   cpufreq: Use cons...
461
462
  		pr_info("highestspeed == lowest, aborting
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
465
  		return -EINVAL;
  	}
  	if (lowest_speed > highest_speed) {
1c5864e26   Joe Perches   cpufreq: Use cons...
466
467
  		pr_info("nonsense! lowest (%d > %d) !
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
  			lowest_speed, highest_speed);
  		return -EINVAL;
  	}
71508a1f4   Viresh Kumar   cpufreq: use kzal...
471
  	longhaul_table = kzalloc((numscales + 1) * sizeof(*longhaul_table),
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
472
473
  			GFP_KERNEL);
  	if (!longhaul_table)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  		return -ENOMEM;
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
475
  	for (j = 0; j < numscales; j++) {
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
476
  		ratio = mults[j];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
  		if (ratio == -1)
  			continue;
  		if (ratio > maxmult || ratio < minmult)
  			continue;
  		longhaul_table[k].frequency = calc_speed(ratio);
507015880   Viresh Kumar   cpufreq: rename i...
482
  		longhaul_table[k].driver_data	= j;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
  		k++;
  	}
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
  	if (k <= 1) {
  		kfree(longhaul_table);
  		return -ENODEV;
  	}
  	/* Sort */
  	for (j = 0; j < k - 1; j++) {
  		unsigned int min_f, min_i;
  		min_f = longhaul_table[j].frequency;
  		min_i = j;
  		for (i = j + 1; i < k; i++) {
  			if (longhaul_table[i].frequency < min_f) {
  				min_f = longhaul_table[i].frequency;
  				min_i = i;
  			}
  		}
  		if (min_i != j) {
91420220d   Dave Jones   [CPUFREQ] Use swa...
501
502
  			swap(longhaul_table[j].frequency,
  			     longhaul_table[min_i].frequency);
507015880   Viresh Kumar   cpufreq: rename i...
503
504
  			swap(longhaul_table[j].driver_data,
  			     longhaul_table[min_i].driver_data);
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
505
506
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
  
  	longhaul_table[k].frequency = CPUFREQ_TABLE_END;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509

73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
510
511
  	/* Find index we are running on */
  	for (j = 0; j < k; j++) {
507015880   Viresh Kumar   cpufreq: rename i...
512
  		if (mults[longhaul_table[j].driver_data & 0x1f] == mult) {
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
513
514
515
516
  			longhaul_index = j;
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
  	return 0;
  }
2760984f6   Paul Gortmaker   cpufreq: delete _...
519
  static void longhaul_setup_voltagescaling(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  {
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
521
  	struct cpufreq_frequency_table *freq_pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  	union msr_longhaul longhaul;
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
523
  	struct mV_pos minvid, maxvid, vid;
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
524
  	unsigned int j, speed, pos, kHz_step, numvscales;
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
525
  	int min_vid_speed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526

db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
527
528
  	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
  	if (!(longhaul.bits.RevisionID & 1)) {
1c5864e26   Joe Perches   cpufreq: Use cons...
529
530
  		pr_info("Voltage scaling not supported by CPU
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  		return;
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
532
533
534
  	}
  
  	if (!longhaul.bits.VRMRev) {
1c5864e26   Joe Perches   cpufreq: Use cons...
535
536
  		pr_info("VRM 8.5
  ");
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
537
538
539
  		vrm_mV_table = &vrm85_mV[0];
  		mV_vrm_table = &mV_vrm85[0];
  	} else {
1c5864e26   Joe Perches   cpufreq: Use cons...
540
541
  		pr_info("Mobile VRM
  ");
2b8c0e130   Rafa³ Bilski   [CPUFREQ] Longhau...
542
543
  		if (cpu_model < CPU_NEHEMIAH)
  			return;
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
544
545
546
  		vrm_mV_table = &mobilevrm_mV[0];
  		mV_vrm_table = &mV_mobilevrm[0];
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547

db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
548
549
  	minvid = vrm_mV_table[longhaul.bits.MinimumVID];
  	maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550

db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
551
  	if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
1c5864e26   Joe Perches   cpufreq: Use cons...
552
553
  		pr_info("Bogus values Min:%d.%03d Max:%d.%03d - Voltage scaling disabled
  ",
b49c22a6c   Joe Perches   cpufreq: Convert ...
554
555
  			minvid.mV/1000, minvid.mV%1000,
  			maxvid.mV/1000, maxvid.mV%1000);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
  		return;
  	}
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
558
  	if (minvid.mV == maxvid.mV) {
1c5864e26   Joe Perches   cpufreq: Use cons...
559
560
  		pr_info("Claims to support voltage scaling but min & max are both %d.%03d - Voltage scaling disabled
  ",
b49c22a6c   Joe Perches   cpufreq: Convert ...
561
  			maxvid.mV/1000, maxvid.mV%1000);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
  		return;
  	}
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
564
  	/* How many voltage steps*/
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
565
  	numvscales = maxvid.pos - minvid.pos + 1;
1c5864e26   Joe Perches   cpufreq: Use cons...
566
567
  	pr_info("Max VID=%d.%03d  Min VID=%d.%03d, %d possible voltage scales
  ",
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
568
569
570
  		maxvid.mV/1000, maxvid.mV%1000,
  		minvid.mV/1000, minvid.mV%1000,
  		numvscales);
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
571
572
573
574
575
  
  	/* Calculate max frequency at min voltage */
  	j = longhaul.bits.MinMHzBR;
  	if (longhaul.bits.MinMHzBR4)
  		j += 16;
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
576
  	min_vid_speed = eblcr[j];
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
  	if (min_vid_speed == -1)
  		return;
  	switch (longhaul.bits.MinMHzFSB) {
  	case 0:
  		min_vid_speed *= 13333;
  		break;
  	case 1:
  		min_vid_speed *= 10000;
  		break;
  	case 3:
  		min_vid_speed *= 6666;
  		break;
  	default:
  		return;
  		break;
  	}
  	if (min_vid_speed >= highest_speed)
  		return;
  	/* Calculate kHz for one voltage step */
  	kHz_step = (highest_speed - min_vid_speed) / numvscales;
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
597
598
  	cpufreq_for_each_entry(freq_pos, longhaul_table) {
  		speed = freq_pos->frequency;
348f31ed2   Rafa³ Bilski   [CPUFREQ] Longhau...
599
600
601
602
  		if (speed > min_vid_speed)
  			pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
  		else
  			pos = minvid.pos;
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
603
  		freq_pos->driver_data |= mV_vrm_table[pos] << 8;
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
604
  		vid = vrm_mV_table[mV_vrm_table[pos]];
1c5864e26   Joe Perches   cpufreq: Use cons...
605
606
  		pr_info("f: %d kHz, index: %d, vid: %d mV
  ",
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
607
  			speed, (int)(freq_pos - longhaul_table), vid.mV);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  	can_scale_voltage = 1;
1c5864e26   Joe Perches   cpufreq: Use cons...
610
611
  	pr_info("Voltage scaling enabled
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  static int longhaul_target(struct cpufreq_policy *policy,
9c0ebcf78   Viresh Kumar   cpufreq: Implemen...
614
  			    unsigned int table_index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
  {
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
616
617
618
  	unsigned int i;
  	unsigned int dir = 0;
  	u8 vid, current_vid;
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
619
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620

73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
621
  	if (!can_scale_voltage)
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
622
  		retval = longhaul_setstate(policy, table_index);
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
623
624
625
626
627
628
629
  	else {
  		/* On test system voltage transitions exceeding single
  		 * step up or down were turning motherboard off. Both
  		 * "ondemand" and "userspace" are unsafe. C7 is doing
  		 * this in hardware, C3 is old and we need to do this
  		 * in software. */
  		i = longhaul_index;
507015880   Viresh Kumar   cpufreq: rename i...
630
  		current_vid = (longhaul_table[longhaul_index].driver_data >> 8);
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
631
  		current_vid &= 0x1f;
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
632
633
634
  		if (table_index > longhaul_index)
  			dir = 1;
  		while (i != table_index) {
507015880   Viresh Kumar   cpufreq: rename i...
635
  			vid = (longhaul_table[i].driver_data >> 8) & 0x1f;
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
636
  			if (vid != current_vid) {
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
637
  				retval = longhaul_setstate(policy, i);
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
638
639
640
641
642
643
644
645
  				current_vid = vid;
  				msleep(200);
  			}
  			if (dir)
  				i++;
  			else
  				i--;
  		}
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
646
  		retval = longhaul_setstate(policy, table_index);
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
647
  	}
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
648

73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
649
  	longhaul_index = table_index;
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
650
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
655
656
657
658
659
  }
  
  
  static unsigned int longhaul_get(unsigned int cpu)
  {
  	if (cpu)
  		return 0;
  	return calc_speed(longhaul_get_cpu_mult());
  }
c4a96c1eb   Adrian Bunk   [CPUFREQ] Make lo...
660
661
662
  static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
  					  u32 nesting_level,
  					  void *context, void **return_value)
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
663
664
  {
  	struct acpi_device *d;
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
665
  	if (acpi_bus_get_device(obj_handle, &d))
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
666
  		return 0;
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
667

ade1af771   Jan Engelhardt   x86: remove unned...
668
  	*return_value = acpi_driver_data(d);
dadb49d87   Rafa³ Bilski   [CPUFREQ] Longhau...
669
670
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671

179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
672
673
674
675
  /* VIA don't support PM2 reg, but have something similar */
  static int enable_arbiter_disable(void)
  {
  	struct pci_dev *dev;
73e107d4a   Rafał Bilski   [CPUFREQ] Longhau...
676
  	int status = 1;
7f1be8924   rafalbilski@interia.pl   [CPUFREQ] Longhau...
677
  	int reg;
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
678
679
680
  	u8 pci_cmd;
  
  	/* Find PLE133 host bridge */
7f1be8924   rafalbilski@interia.pl   [CPUFREQ] Longhau...
681
  	reg = 0x78;
fb48e1564   Rafał Bilski   [CPUFREQ] Longhau...
682
683
  	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
  			     NULL);
a09d60a62   Rafał Bilski   [CPUFREQ] Longhau...
684
685
686
687
  	/* Find PM133/VT8605 host bridge */
  	if (dev == NULL)
  		dev = pci_get_device(PCI_VENDOR_ID_VIA,
  				     PCI_DEVICE_ID_VIA_8605_0, NULL);
7f1be8924   rafalbilski@interia.pl   [CPUFREQ] Longhau...
688
689
  	/* Find CLE266 host bridge */
  	if (dev == NULL) {
7f1be8924   rafalbilski@interia.pl   [CPUFREQ] Longhau...
690
  		reg = 0x76;
fb48e1564   Rafał Bilski   [CPUFREQ] Longhau...
691
692
  		dev = pci_get_device(PCI_VENDOR_ID_VIA,
  				     PCI_DEVICE_ID_VIA_862X_0, NULL);
db2fb9db5   Rafa³ Bilski   [CPUFREQ] Longhau...
693
694
  		/* Find CN400 V-Link host bridge */
  		if (dev == NULL)
fb48e1564   Rafał Bilski   [CPUFREQ] Longhau...
695
  			dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);
7f1be8924   rafalbilski@interia.pl   [CPUFREQ] Longhau...
696
  	}
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
697
698
  	if (dev != NULL) {
  		/* Enable access to port 0x22 */
7f1be8924   rafalbilski@interia.pl   [CPUFREQ] Longhau...
699
  		pci_read_config_byte(dev, reg, &pci_cmd);
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
700
  		if (!(pci_cmd & 1<<7)) {
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
701
  			pci_cmd |= 1<<7;
7f1be8924   rafalbilski@interia.pl   [CPUFREQ] Longhau...
702
  			pci_write_config_byte(dev, reg, pci_cmd);
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
703
704
  			pci_read_config_byte(dev, reg, &pci_cmd);
  			if (!(pci_cmd & 1<<7)) {
1c5864e26   Joe Perches   cpufreq: Use cons...
705
706
  				pr_err("Can't enable access to port 0x22
  ");
fb48e1564   Rafał Bilski   [CPUFREQ] Longhau...
707
  				status = 0;
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
708
  			}
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
709
  		}
fb48e1564   Rafał Bilski   [CPUFREQ] Longhau...
710
711
  		pci_dev_put(dev);
  		return status;
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
712
713
714
  	}
  	return 0;
  }
7d5edcc02   Rafał Bilski   [CPUFREQ] Longhau...
715
  static int longhaul_setup_southbridge(void)
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
716
717
718
719
720
  {
  	struct pci_dev *dev;
  	u8 pci_cmd;
  
  	/* Find VT8235 southbridge */
fb48e1564   Rafał Bilski   [CPUFREQ] Longhau...
721
  	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
920dd0fbb   Rafał Bilski   [CPUFREQ] Longhau...
722
  	if (dev == NULL)
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
723
  		/* Find VT8237 southbridge */
920dd0fbb   Rafał Bilski   [CPUFREQ] Longhau...
724
725
  		dev = pci_get_device(PCI_VENDOR_ID_VIA,
  				     PCI_DEVICE_ID_VIA_8237, NULL);
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
726
727
728
729
730
731
732
733
734
735
736
  	if (dev != NULL) {
  		/* Set transition time to max */
  		pci_read_config_byte(dev, 0xec, &pci_cmd);
  		pci_cmd &= ~(1 << 2);
  		pci_write_config_byte(dev, 0xec, pci_cmd);
  		pci_read_config_byte(dev, 0xe4, &pci_cmd);
  		pci_cmd &= ~(1 << 7);
  		pci_write_config_byte(dev, 0xe4, pci_cmd);
  		pci_read_config_byte(dev, 0xe5, &pci_cmd);
  		pci_cmd |= 1 << 7;
  		pci_write_config_byte(dev, 0xe5, pci_cmd);
275bc6b7f   Rafał Bilski   [CPUFREQ] Longhau...
737
738
739
740
741
  		/* Get address of ACPI registers block*/
  		pci_read_config_byte(dev, 0x81, &pci_cmd);
  		if (pci_cmd & 1 << 7) {
  			pci_read_config_dword(dev, 0x88, &acpi_regs_addr);
  			acpi_regs_addr &= 0xff00;
1c5864e26   Joe Perches   cpufreq: Use cons...
742
743
  			pr_info("ACPI I/O at 0x%x
  ", acpi_regs_addr);
275bc6b7f   Rafał Bilski   [CPUFREQ] Longhau...
744
  		}
fb48e1564   Rafał Bilski   [CPUFREQ] Longhau...
745
  		pci_dev_put(dev);
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
746
747
748
749
  		return 1;
  	}
  	return 0;
  }
2760984f6   Paul Gortmaker   cpufreq: delete _...
750
  static int longhaul_cpu_init(struct cpufreq_policy *policy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  {
92cb7612a   Mike Travis   x86: convert cpui...
752
  	struct cpuinfo_x86 *c = &cpu_data(0);
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
753
  	char *cpuname = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
  	int ret;
2b8c0e130   Rafa³ Bilski   [CPUFREQ] Longhau...
755
  	u32 lo, hi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756

179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
757
  	/* Check what we have on this motherboard */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
761
762
  	switch (c->x86_model) {
  	case 6:
  		cpu_model = CPU_SAMUEL;
  		cpuname = "C3 'Samuel' [C5A]";
  		longhaul_version = TYPE_LONGHAUL_V1;
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
763
764
  		memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
  		memcpy(eblcr, samuel1_eblcr, sizeof(samuel1_eblcr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
  		break;
  
  	case 7:
325cbb04d   Jia Zhang   x86/cpu: Rename c...
768
  		switch (c->x86_stepping) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
  		case 0:
2b8c0e130   Rafa³ Bilski   [CPUFREQ] Longhau...
770
  			longhaul_version = TYPE_LONGHAUL_V1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
  			cpu_model = CPU_SAMUEL2;
  			cpuname = "C3 'Samuel 2' [C5B]";
2b8c0e130   Rafa³ Bilski   [CPUFREQ] Longhau...
773
774
  			/* Note, this is not a typo, early Samuel2's had
  			 * Samuel1 ratios. */
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
775
776
  			memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
  			memcpy(eblcr, samuel2_eblcr, sizeof(samuel2_eblcr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
  			break;
  		case 1 ... 15:
f7f3cad06   Krzysztof Helt   [CPUFREQ] longhau...
779
  			longhaul_version = TYPE_LONGHAUL_V2;
325cbb04d   Jia Zhang   x86/cpu: Rename c...
780
  			if (c->x86_stepping < 8) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
785
786
  				cpu_model = CPU_SAMUEL2;
  				cpuname = "C3 'Samuel 2' [C5B]";
  			} else {
  				cpu_model = CPU_EZRA;
  				cpuname = "C3 'Ezra' [C5C]";
  			}
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
787
788
  			memcpy(mults, ezra_mults, sizeof(ezra_mults));
  			memcpy(eblcr, ezra_eblcr, sizeof(ezra_eblcr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
791
792
793
794
795
796
  			break;
  		}
  		break;
  
  	case 8:
  		cpu_model = CPU_EZRA_T;
  		cpuname = "C3 'Ezra-T' [C5M]";
  		longhaul_version = TYPE_POWERSAVER;
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
797
798
799
  		numscales = 32;
  		memcpy(mults, ezrat_mults, sizeof(ezrat_mults));
  		memcpy(eblcr, ezrat_eblcr, sizeof(ezrat_eblcr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
802
  		break;
  
  	case 9:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
  		longhaul_version = TYPE_POWERSAVER;
0d44b2ba2   Rafa³ Bilski   [CPUFREQ] Longhau...
804
  		numscales = 32;
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
805
806
  		memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults));
  		memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr));
325cbb04d   Jia Zhang   x86/cpu: Rename c...
807
  		switch (c->x86_stepping) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  		case 0 ... 1:
980342a7e   Rafa³ Bilski   [CPUFREQ] Longhau...
809
  			cpu_model = CPU_NEHEMIAH;
e57501c15   Rafa³ Bilski   [CPUFREQ] Longhau...
810
  			cpuname = "C3 'Nehemiah A' [C5XLOE]";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
812
  			break;
  		case 2 ... 4:
980342a7e   Rafa³ Bilski   [CPUFREQ] Longhau...
813
  			cpu_model = CPU_NEHEMIAH;
e57501c15   Rafa³ Bilski   [CPUFREQ] Longhau...
814
  			cpuname = "C3 'Nehemiah B' [C5XLOH]";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
  			break;
  		case 5 ... 15:
980342a7e   Rafa³ Bilski   [CPUFREQ] Longhau...
817
  			cpu_model = CPU_NEHEMIAH_C;
e57501c15   Rafa³ Bilski   [CPUFREQ] Longhau...
818
  			cpuname = "C3 'Nehemiah C' [C5P]";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
822
823
824
825
826
  			break;
  		}
  		break;
  
  	default:
  		cpuname = "Unknown";
  		break;
  	}
2b8c0e130   Rafa³ Bilski   [CPUFREQ] Longhau...
827
828
829
830
831
832
833
  	/* Check Longhaul ver. 2 */
  	if (longhaul_version == TYPE_LONGHAUL_V2) {
  		rdmsr(MSR_VIA_LONGHAUL, lo, hi);
  		if (lo == 0 && hi == 0)
  			/* Looks like MSR isn't present */
  			longhaul_version = TYPE_LONGHAUL_V1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834

1c5864e26   Joe Perches   cpufreq: Use cons...
835
  	pr_info("VIA %s CPU detected.  ", cpuname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
  	switch (longhaul_version) {
  	case TYPE_LONGHAUL_V1:
  	case TYPE_LONGHAUL_V2:
b49c22a6c   Joe Perches   cpufreq: Convert ...
839
840
  		pr_cont("Longhaul v%d supported
  ", longhaul_version);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
  		break;
  	case TYPE_POWERSAVER:
b49c22a6c   Joe Perches   cpufreq: Convert ...
843
844
  		pr_cont("Powersaver supported
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
  		break;
  	};
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
847
  	/* Doesn't hurt */
7d5edcc02   Rafał Bilski   [CPUFREQ] Longhau...
848
  	longhaul_setup_southbridge();
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
849

179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
850
  	/* Find ACPI data for processor */
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
851
  	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
2263576cf   Lin Ming   ACPICA: Add post-...
852
  				ACPI_UINT32_MAX, &longhaul_walk_callback, NULL,
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
853
  				NULL, (void *)&pr);
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
854

264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
855
  	/* Check ACPI support for C3 state */
7ab77e03c   Dave Jones   Longhaul - Revert...
856
  	if (pr != NULL && longhaul_version == TYPE_POWERSAVER) {
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
857
  		cx = &pr->power.states[ACPI_STATE_C3];
7d5edcc02   Rafał Bilski   [CPUFREQ] Longhau...
858
  		if (cx->address > 0 && cx->latency <= 1000)
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
859
  			longhaul_flags |= USE_ACPI_C3;
eed7d4125   Rafa³ Bilski   [CPUFREQ] longhau...
860
  	}
905497c4b   Rafał Bilski   [CPUFREQ] Longhau...
861
862
863
  	/* Disable if it isn't working */
  	if (disable_acpi_c3)
  		longhaul_flags &= ~USE_ACPI_C3;
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
864
  	/* Check if northbridge is friendly */
7d5edcc02   Rafał Bilski   [CPUFREQ] Longhau...
865
  	if (enable_arbiter_disable())
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
866
  		longhaul_flags |= USE_NORTHBRIDGE;
7d5edcc02   Rafał Bilski   [CPUFREQ] Longhau...
867

eed7d4125   Rafa³ Bilski   [CPUFREQ] longhau...
868
  	/* Check ACPI support for bus master arbiter disable */
7d5edcc02   Rafał Bilski   [CPUFREQ] Longhau...
869
870
871
  	if (!(longhaul_flags & USE_ACPI_C3
  	     || longhaul_flags & USE_NORTHBRIDGE)
  	    && ((pr == NULL) || !(pr->flags.bm_control))) {
1c5864e26   Joe Perches   cpufreq: Use cons...
872
873
  		pr_err("No ACPI support: Unsupported northbridge
  ");
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
874
  		return -ENODEV;
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
875
  	}
264166e60   Rafa³ Bilski   [CPUFREQ] Longhau...
876

786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
877
  	if (longhaul_flags & USE_NORTHBRIDGE)
1c5864e26   Joe Perches   cpufreq: Use cons...
878
879
  		pr_info("Using northbridge support
  ");
7d5edcc02   Rafał Bilski   [CPUFREQ] Longhau...
880
  	if (longhaul_flags & USE_ACPI_C3)
1c5864e26   Joe Perches   cpufreq: Use cons...
881
882
  		pr_info("Using ACPI support
  ");
179da8e6e   Rafa³ Bilski   [CPUFREQ] Longhau...
883

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
886
  	ret = longhaul_get_ranges();
  	if (ret != 0)
  		return ret;
786f46b26   Rafa³ Bilski   [CPUFREQ] Longhau...
887
  	if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
  		longhaul_setup_voltagescaling();
b453f9d8c   Viresh Kumar   cpufreq: longhaul...
889
  	policy->transition_delay_us = 200000;	/* usec */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890

30aa53412   Viresh Kumar   cpufreq: longhaul...
891
  	return cpufreq_table_validate_and_show(policy, longhaul_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  }
221dee285   Linus Torvalds   Revert "[CPUFREQ]...
893
  static struct cpufreq_driver longhaul_driver = {
3a4d0342e   Viresh Kumar   cpufreq: longhaul...
894
  	.verify	= cpufreq_generic_frequency_table_verify,
9c0ebcf78   Viresh Kumar   cpufreq: Implemen...
895
  	.target_index = longhaul_target,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
  	.get	= longhaul_get,
  	.init	= longhaul_cpu_init,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
  	.name	= "longhaul",
3a4d0342e   Viresh Kumar   cpufreq: longhaul...
899
  	.attr	= cpufreq_generic_attr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900
  };
fa8031aef   Andi Kleen   cpufreq: Add supp...
901
902
903
904
905
  static const struct x86_cpu_id longhaul_id[] = {
  	{ X86_VENDOR_CENTAUR, 6 },
  	{}
  };
  MODULE_DEVICE_TABLE(x86cpu, longhaul_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
908
  
  static int __init longhaul_init(void)
  {
92cb7612a   Mike Travis   x86: convert cpui...
909
  	struct cpuinfo_x86 *c = &cpu_data(0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910

fa8031aef   Andi Kleen   cpufreq: Add supp...
911
  	if (!x86_match_cpu(longhaul_id))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  		return -ENODEV;
b5811bc46   Rafał Bilski   cpufreq / Longhau...
913
  	if (!enable) {
1c5864e26   Joe Perches   cpufreq: Use cons...
914
915
  		pr_err("Option \"enable\" not set - Aborting
  ");
b5811bc46   Rafał Bilski   cpufreq / Longhau...
916
917
  		return -ENODEV;
  	}
48b7bde0f   Rafa³ Bilski   [CPUFREQ] Longhau...
918
919
  #ifdef CONFIG_SMP
  	if (num_online_cpus() > 1) {
1c5864e26   Joe Perches   cpufreq: Use cons...
920
921
  		pr_err("More than 1 CPU detected, longhaul disabled
  ");
1cfe20142   Dave Jones   [CPUFREQ] longhau...
922
  		return -ENODEV;
48b7bde0f   Rafa³ Bilski   [CPUFREQ] Longhau...
923
924
925
  	}
  #endif
  #ifdef CONFIG_X86_IO_APIC
93984fbd4   Borislav Petkov   x86/cpufeature: R...
926
  	if (boot_cpu_has(X86_FEATURE_APIC)) {
1c5864e26   Joe Perches   cpufreq: Use cons...
927
928
  		pr_err("APIC detected. Longhaul is currently broken in this configuration.
  ");
48b7bde0f   Rafa³ Bilski   [CPUFREQ] Longhau...
929
930
931
  		return -ENODEV;
  	}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
  	switch (c->x86_model) {
  	case 6 ... 9:
  		return cpufreq_register_driver(&longhaul_driver);
8ec9822dd   Dave Jones   [CPUFREQ] Advise ...
935
  	case 10:
1c5864e26   Joe Perches   cpufreq: Use cons...
936
937
  		pr_err("Use acpi-cpufreq driver for VIA C7
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
  	default:
c19a28e11   Fernando Carrijo   remove lots of do...
939
  		;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
942
943
944
945
946
947
  	}
  
  	return -ENODEV;
  }
  
  
  static void __exit longhaul_exit(void)
  {
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
948
  	struct cpufreq_policy *policy = cpufreq_cpu_get(0);
8eebf1a4c   Dave Jones   [CPUFREQ] Remove ...
949
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950

ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
951
952
  	for (i = 0; i < numscales; i++) {
  		if (mults[i] == maxmult) {
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
953
954
955
956
957
958
959
  			struct cpufreq_freqs freqs;
  
  			freqs.old = policy->cur;
  			freqs.new = longhaul_table[i].frequency;
  			freqs.flags = 0;
  
  			cpufreq_freq_transition_begin(policy, &freqs);
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
960
  			longhaul_setstate(policy, i);
7aa0557fa   Srivatsa S. Bhat   cpufreq: longhaul...
961
  			cpufreq_freq_transition_end(policy, &freqs, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
964
  			break;
  		}
  	}
b43a7ffbf   Viresh Kumar   cpufreq: Notify a...
965
  	cpufreq_cpu_put(policy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
967
968
  	cpufreq_unregister_driver(&longhaul_driver);
  	kfree(longhaul_table);
  }
52a2638bf   Rafal Bilski   Longhaul: add aut...
969
970
971
  /* Even if BIOS is exporting ACPI C3 state, and it is used
   * with success when CPU is idle, this state doesn't
   * trigger frequency transition in some cases. */
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
972
  module_param(disable_acpi_c3, int, 0644);
905497c4b   Rafał Bilski   [CPUFREQ] Longhau...
973
  MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support");
0d2eb44f6   Lucas De Marchi   x86: Fix common m...
974
  /* Change CPU voltage with frequency. Very useful to save
52a2638bf   Rafal Bilski   Longhaul: add aut...
975
   * power, but most VIA C3 processors aren't supporting it. */
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
976
  module_param(scale_voltage, int, 0644);
db44aaf3a   Rafa³ Bilski   [CPUFREQ] Longhau...
977
  MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
52a2638bf   Rafal Bilski   Longhaul: add aut...
978
979
980
981
982
  /* Force revision key to 0 for processors which doesn't
   * support voltage scaling, but are introducing itself as
   * such. */
  module_param(revid_errata, int, 0644);
  MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID");
b5811bc46   Rafał Bilski   cpufreq / Longhau...
983
984
985
986
  /* By default driver is disabled to prevent incompatible
   * system freeze. */
  module_param(enable, int, 0644);
  MODULE_PARM_DESC(enable, "Enable driver");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987

d5e80b4b1   Dave Jones   Update/Remove soo...
988
  MODULE_AUTHOR("Dave Jones");
ac617bd0f   Dave Jones   [CPUFREQ] checkpa...
989
990
  MODULE_DESCRIPTION("Longhaul driver for VIA Cyrix processors.");
  MODULE_LICENSE("GPL");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991

0d6daba5f   Rafa³ Bilski   [CPUFREQ] Longhau...
992
  late_initcall(longhaul_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993
  module_exit(longhaul_exit);