Blame view

drivers/cpufreq/powernow-k8.c 40.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
b2bd68e1d   Andreas Herrmann   [CPUFREQ] powerno...
2
   *   (c) 2003-2012 Advanced Micro Devices, Inc.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
   *  Your use of this code is subject to the terms and conditions of the
   *  GNU general public license version 2. See "COPYING" or
   *  http://www.gnu.org/licenses/gpl.html
   *
b2bd68e1d   Andreas Herrmann   [CPUFREQ] powerno...
7
8
   *  Maintainer:
   *  Andreas Herrmann <andreas.herrmann3@amd.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
   *
   *  Based on the powernow-k7.c module written by Dave Jones.
f4432c5ca   Dave Jones   Update email addr...
11
   *  (C) 2003 Dave Jones on behalf of SuSE Labs
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
   *  (C) 2004 Dominik Brodowski <linux@brodo.de>
a2531293d   Pavel Machek   update email address
13
   *  (C) 2004 Pavel Machek <pavel@ucw.cz>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
   *  Licensed under the terms of the GNU GPL License version 2.
   *  Based upon datasheets & sample CPUs kindly provided by AMD.
   *
   *  Valuable input gratefully received from Dave Jones, Pavel Machek,
1f729e066   Dave Jones   [CPUFREQ] Prepare...
18
   *  Dominik Brodowski, Jacob Shin, and others.
065b807ca   Dave Jones   [CPUFREQ] dual-co...
19
   *  Originally developed by Paul Devriendt.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
   *
b2bd68e1d   Andreas Herrmann   [CPUFREQ] powerno...
21
22
23
24
25
26
27
   *  Processor information obtained from Chapter 9 (Power and Thermal
   *  Management) of the "BIOS and Kernel Developer's Guide (BKDG) for
   *  the AMD Athlon 64 and AMD Opteron Processors" and section "2.x
   *  Power Management" in BKDGs for newer AMD CPU families.
   *
   *  Tables for specific CPUs can be inferred from AMD's processor
   *  power and thermal data sheets, (e.g. 30417.pdf, 30430.pdf, 43375.pdf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
33
34
35
36
   */
  
  #include <linux/kernel.h>
  #include <linux/smp.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/cpufreq.h>
  #include <linux/slab.h>
  #include <linux/string.h>
065b807ca   Dave Jones   [CPUFREQ] dual-co...
37
  #include <linux/cpumask.h>
4e57b6817   Tim Schmielau   [PATCH] fix missi...
38
  #include <linux/sched.h>	/* for current / set_cpus_allowed() */
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
39
40
  #include <linux/io.h>
  #include <linux/delay.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  
  #include <asm/msr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  #include <linux/acpi.h>
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
45
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  #include <acpi/processor.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
  
  #define PFX "powernow-k8: "
c5829cd07   Mark Langsdorf   [CPUFREQ] archite...
49
  #define VERSION "version 2.20.00"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  #include "powernow-k8.h"
a2fed573f   Mark Langsdorf   x86, cpufreq: Add...
51
  #include "mperf.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
  
  /* serialize freq changes  */
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
54
  static DEFINE_MUTEX(fidvid_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55

2c6b8c030   travis@sgi.com   x86: change NR_CP...
56
  static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

1f729e066   Dave Jones   [CPUFREQ] Prepare...
58
  static int cpu_family = CPU_OPTERON;
a8eb28480   Andreas Herrmann   [CPUFREQ] powerno...
59
60
  /* array to map SW pstate number to acpi state */
  static u32 ps_to_as[8];
73860c6b2   Borislav Petkov   powernow-k8: Add ...
61
62
63
  /* core performance boost */
  static bool cpb_capable, cpb_enabled;
  static struct msr __percpu *msrs;
a2fed573f   Mark Langsdorf   x86, cpufreq: Add...
64
  static struct cpufreq_driver cpufreq_amd64_driver;
065b807ca   Dave Jones   [CPUFREQ] dual-co...
65
  #ifndef CONFIG_SMP
7ad728f98   Rusty Russell   cpumask: x86: con...
66
67
68
69
  static inline const struct cpumask *cpu_core_mask(int cpu)
  {
  	return cpumask_of(0);
  }
065b807ca   Dave Jones   [CPUFREQ] dual-co...
70
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
76
77
78
79
80
81
  /* Return a frequency in MHz, given an input fid */
  static u32 find_freq_from_fid(u32 fid)
  {
  	return 800 + (fid * 100);
  }
  
  /* Return a frequency in KHz, given an input fid */
  static u32 find_khz_freq_from_fid(u32 fid)
  {
  	return 1000 * find_freq_from_fid(fid);
  }
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
82
  static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data,
a8eb28480   Andreas Herrmann   [CPUFREQ] powerno...
83
  				     u32 pstate)
1f729e066   Dave Jones   [CPUFREQ] Prepare...
84
  {
a8eb28480   Andreas Herrmann   [CPUFREQ] powerno...
85
  	return data[ps_to_as[pstate]].frequency;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
86
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
92
93
94
  /* Return the vco fid for an input fid
   *
   * Each "low" fid has corresponding "high" fid, and you can get to "low" fids
   * only from corresponding high fids. This returns "high" fid corresponding to
   * "low" one.
   */
  static u32 convert_fid_to_vco_fid(u32 fid)
  {
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
95
  	if (fid < HI_FID_TABLE_BOTTOM)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  		return 8 + (2 * fid);
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
97
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  		return fid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
104
105
106
107
  }
  
  /*
   * Return 1 if the pending bit is set. Unless we just instructed the processor
   * to transition to a new state, seeing this bit set is really bad news.
   */
  static int pending_bit_stuck(void)
  {
  	u32 lo, hi;
e7bdd7a53   Langsdorf, Mark   [CPUFREQ] Clarify...
108
  	if (cpu_family == CPU_HW_PSTATE)
1f729e066   Dave Jones   [CPUFREQ] Prepare...
109
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
115
116
117
118
119
120
121
  	rdmsr(MSR_FIDVID_STATUS, lo, hi);
  	return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0;
  }
  
  /*
   * Update the global current fid / vid values from the status msr.
   * Returns 1 on error.
   */
  static int query_current_values_with_pending_wait(struct powernow_k8_data *data)
  {
  	u32 lo, hi;
  	u32 i = 0;
e7bdd7a53   Langsdorf, Mark   [CPUFREQ] Clarify...
122
  	if (cpu_family == CPU_HW_PSTATE) {
532cfee6b   Naga Chumbalkar   [CPUFREQ] powerno...
123
124
125
126
127
128
129
130
131
132
  		rdmsr(MSR_PSTATE_STATUS, lo, hi);
  		i = lo & HW_PSTATE_MASK;
  		data->currpstate = i;
  
  		/*
  		 * a workaround for family 11h erratum 311 might cause
  		 * an "out-of-range Pstate if the core is in Pstate-0
  		 */
  		if ((boot_cpu_data.x86 == 0x11) && (i >= data->numps))
  			data->currpstate = HW_PSTATE_0;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
133
134
  		return 0;
  	}
7153d9612   Dave Jones   powernow-k8.c: In...
135
  	do {
0213df743   Dave Jones   [PATCH] cpufreq: ...
136
  		if (i++ > 10000) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
137
138
  			pr_debug("detected change pending stuck
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
  			return 1;
  		}
  		rdmsr(MSR_FIDVID_STATUS, lo, hi);
7153d9612   Dave Jones   powernow-k8.c: In...
142
  	} while (lo & MSR_S_LO_CHANGE_PENDING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
148
149
150
151
152
153
154
155
  
  	data->currvid = hi & MSR_S_HI_CURRENT_VID;
  	data->currfid = lo & MSR_S_LO_CURRENT_FID;
  
  	return 0;
  }
  
  /* the isochronous relief time */
  static void count_off_irt(struct powernow_k8_data *data)
  {
  	udelay((1 << data->irt) * 10);
  	return;
  }
27b46d766   Simon Arlott   spelling fixes: a...
156
  /* the voltage stabilization time */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  static void count_off_vst(struct powernow_k8_data *data)
  {
  	udelay(data->vstable * VST_UNITS_20US);
  	return;
  }
  
  /* need to init the control msr to a safe value (for each cpu) */
  static void fidvid_msr_init(void)
  {
  	u32 lo, hi;
  	u8 fid, vid;
  
  	rdmsr(MSR_FIDVID_STATUS, lo, hi);
  	vid = hi & MSR_S_HI_CURRENT_VID;
  	fid = lo & MSR_S_LO_CURRENT_FID;
  	lo = fid | (vid << MSR_C_LO_VID_SHIFT);
  	hi = MSR_C_HI_STP_GNT_BENIGN;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
174
175
  	pr_debug("cpu%d, init lo 0x%x, hi 0x%x
  ", smp_processor_id(), lo, hi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
  	wrmsr(MSR_FIDVID_CTL, lo, hi);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
181
182
  /* write the new fid value along with the other control fields to the msr */
  static int write_new_fid(struct powernow_k8_data *data, u32 fid)
  {
  	u32 lo;
  	u32 savevid = data->currvid;
0213df743   Dave Jones   [PATCH] cpufreq: ...
183
  	u32 i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
  
  	if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) {
  		printk(KERN_ERR PFX "internal error - overflow on fid write
  ");
  		return 1;
  	}
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
190
191
192
  	lo = fid;
  	lo |= (data->currvid << MSR_C_LO_VID_SHIFT);
  	lo |= MSR_C_LO_INIT_FID_VID;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
194
195
  	pr_debug("writing fid 0x%x, lo 0x%x, hi 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  		fid, lo, data->plllock * PLL_LOCK_CONVERSION);
0213df743   Dave Jones   [PATCH] cpufreq: ...
197
198
199
  	do {
  		wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
  		if (i++ > 100) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
200
201
202
203
  			printk(KERN_ERR PFX
  				"Hardware error - pending bit very stuck - "
  				"no further pstate changes possible
  ");
63172cb3d   Chris Wright   [PATCH] typo fix ...
204
  			return 1;
32ee8c3e4   Dave Jones   [CPUFREQ] Lots of...
205
  		}
0213df743   Dave Jones   [PATCH] cpufreq: ...
206
  	} while (query_current_values_with_pending_wait(data));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
  
  	count_off_irt(data);
  
  	if (savevid != data->currvid) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
211
212
213
214
  		printk(KERN_ERR PFX
  			"vid change on fid trans, old 0x%x, new 0x%x
  ",
  			savevid, data->currvid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
  		return 1;
  	}
  
  	if (fid != data->currfid) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
219
220
221
222
  		printk(KERN_ERR PFX
  			"fid trans failed, fid 0x%x, curr 0x%x
  ", fid,
  			data->currfid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
226
227
228
229
230
231
232
233
  		return 1;
  	}
  
  	return 0;
  }
  
  /* Write a new vid to the hardware */
  static int write_new_vid(struct powernow_k8_data *data, u32 vid)
  {
  	u32 lo;
  	u32 savefid = data->currfid;
0213df743   Dave Jones   [PATCH] cpufreq: ...
234
  	int i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
  
  	if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) {
  		printk(KERN_ERR PFX "internal error - overflow on vid write
  ");
  		return 1;
  	}
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
241
242
243
  	lo = data->currfid;
  	lo |= (vid << MSR_C_LO_VID_SHIFT);
  	lo |= MSR_C_LO_INIT_FID_VID;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
245
246
  	pr_debug("writing vid 0x%x, lo 0x%x, hi 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  		vid, lo, STOP_GRANT_5NS);
0213df743   Dave Jones   [PATCH] cpufreq: ...
248
249
  	do {
  		wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
6df890067   Dave Jones   [CPUFREQ] Fix ind...
250
  		if (i++ > 100) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
251
252
253
254
  			printk(KERN_ERR PFX "internal error - pending bit "
  					"very stuck - no further pstate "
  					"changes possible
  ");
6df890067   Dave Jones   [CPUFREQ] Fix ind...
255
256
  			return 1;
  		}
0213df743   Dave Jones   [PATCH] cpufreq: ...
257
  	} while (query_current_values_with_pending_wait(data));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
  
  	if (savefid != data->currfid) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
260
261
262
  		printk(KERN_ERR PFX "fid changed on vid trans, old "
  			"0x%x new 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
  		       savefid, data->currfid);
  		return 1;
  	}
  
  	if (vid != data->currvid) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
268
269
270
271
  		printk(KERN_ERR PFX "vid trans failed, vid 0x%x, "
  				"curr 0x%x
  ",
  				vid, data->currvid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
276
277
278
279
280
  		return 1;
  	}
  
  	return 0;
  }
  
  /*
   * Reduce the vid by the max of step or reqvid.
   * Decreasing vid codes represent increasing voltages:
841e40b38   Dave Jones   Opteron revision ...
281
   * vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of VID_OFF is off.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
   */
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
283
284
  static int decrease_vid_code_by_step(struct powernow_k8_data *data,
  		u32 reqvid, u32 step)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
289
290
291
292
293
294
295
  {
  	if ((data->currvid - reqvid) > step)
  		reqvid = data->currvid - step;
  
  	if (write_new_vid(data, reqvid))
  		return 1;
  
  	count_off_vst(data);
  
  	return 0;
  }
1f729e066   Dave Jones   [CPUFREQ] Prepare...
296
297
298
299
  /* Change hardware pstate by single MSR write */
  static int transition_pstate(struct powernow_k8_data *data, u32 pstate)
  {
  	wrmsr(MSR_PSTATE_CTRL, pstate, 0);
c5829cd07   Mark Langsdorf   [CPUFREQ] archite...
300
  	data->currpstate = pstate;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
301
302
303
304
  	return 0;
  }
  
  /* Change Opteron/Athlon64 fid and vid, by the 3 phases. */
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
305
306
  static int transition_fid_vid(struct powernow_k8_data *data,
  		u32 reqfid, u32 reqvid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  {
a2e1b4c31   Mark Langsdorf   [CPUFREQ] Powerno...
308
  	if (core_voltage_pre_transition(data, reqvid, reqfid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
312
313
314
315
316
317
318
319
320
  		return 1;
  
  	if (core_frequency_transition(data, reqfid))
  		return 1;
  
  	if (core_voltage_post_transition(data, reqvid))
  		return 1;
  
  	if (query_current_values_with_pending_wait(data))
  		return 1;
  
  	if ((reqfid != data->currfid) || (reqvid != data->currvid)) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
321
322
323
  		printk(KERN_ERR PFX "failed (cpu%d): req 0x%x 0x%x, "
  				"curr 0x%x 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
  				smp_processor_id(),
  				reqfid, reqvid, data->currfid, data->currvid);
  		return 1;
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
328
329
  	pr_debug("transitioned (cpu%d): new fid 0x%x, vid 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
333
334
335
  		smp_processor_id(), data->currfid, data->currvid);
  
  	return 0;
  }
  
  /* Phase 1 - core voltage transition ... setup voltage */
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
336
  static int core_voltage_pre_transition(struct powernow_k8_data *data,
a2e1b4c31   Mark Langsdorf   [CPUFREQ] Powerno...
337
  		u32 reqvid, u32 reqfid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
  {
  	u32 rvosteps = data->rvo;
  	u32 savefid = data->currfid;
a2e1b4c31   Mark Langsdorf   [CPUFREQ] Powerno...
341
  	u32 maxvid, lo, rvomult = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
343
  	pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, "
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
344
345
  		"reqvid 0x%x, rvo 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
  		smp_processor_id(),
  		data->currfid, data->currvid, reqvid, data->rvo);
a2e1b4c31   Mark Langsdorf   [CPUFREQ] Powerno...
348
349
350
  	if ((savefid < LO_FID_TABLE_TOP) && (reqfid < LO_FID_TABLE_TOP))
  		rvomult = 2;
  	rvosteps *= rvomult;
065b807ca   Dave Jones   [CPUFREQ] dual-co...
351
352
  	rdmsr(MSR_FIDVID_STATUS, lo, maxvid);
  	maxvid = 0x1f & (maxvid >> 16);
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
353
354
  	pr_debug("ph1 maxvid=0x%x
  ", maxvid);
065b807ca   Dave Jones   [CPUFREQ] dual-co...
355
356
  	if (reqvid < maxvid) /* lower numbers are higher voltages */
  		reqvid = maxvid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
  	while (data->currvid > reqvid) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
358
359
  		pr_debug("ph1: curr 0x%x, req vid 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
363
  			data->currvid, reqvid);
  		if (decrease_vid_code_by_step(data, reqvid, data->vidmvs))
  			return 1;
  	}
a2e1b4c31   Mark Langsdorf   [CPUFREQ] Powerno...
364
365
  	while ((rvosteps > 0) &&
  			((rvomult * data->rvo + data->currvid) > reqvid)) {
065b807ca   Dave Jones   [CPUFREQ] dual-co...
366
  		if (data->currvid == maxvid) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
  			rvosteps = 0;
  		} else {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
369
370
  			pr_debug("ph1: changing vid for rvo, req 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  				data->currvid - 1);
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
372
  			if (decrease_vid_code_by_step(data, data->currvid-1, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
377
378
379
380
381
  				return 1;
  			rvosteps--;
  		}
  	}
  
  	if (query_current_values_with_pending_wait(data))
  		return 1;
  
  	if (savefid != data->currfid) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
382
383
384
  		printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x
  ",
  				data->currfid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
  		return 1;
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
387
388
  	pr_debug("ph1 complete, currfid 0x%x, currvid 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
392
393
394
395
396
  		data->currfid, data->currvid);
  
  	return 0;
  }
  
  /* Phase 2 - core frequency transition */
  static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
  {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
397
398
  	u32 vcoreqfid, vcocurrfid, vcofiddiff;
  	u32 fid_interval, savevid = data->currvid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  	if (data->currfid == reqfid) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
401
402
403
  		printk(KERN_ERR PFX "ph2 null fid transition 0x%x
  ",
  				data->currfid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  		return 0;
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
406
  	pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, "
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
407
408
  		"reqfid 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
413
414
415
  		smp_processor_id(),
  		data->currfid, data->currvid, reqfid);
  
  	vcoreqfid = convert_fid_to_vco_fid(reqfid);
  	vcocurrfid = convert_fid_to_vco_fid(data->currfid);
  	vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
  	    : vcoreqfid - vcocurrfid;
a2e1b4c31   Mark Langsdorf   [CPUFREQ] Powerno...
416
417
  	if ((reqfid <= LO_FID_TABLE_TOP) && (data->currfid <= LO_FID_TABLE_TOP))
  		vcofiddiff = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  	while (vcofiddiff > 2) {
019a61b99   Langsdorf, Mark   [PATCH] Support 1...
419
  		(data->currfid & 1) ? (fid_interval = 1) : (fid_interval = 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  		if (reqfid > data->currfid) {
  			if (data->currfid > LO_FID_TABLE_TOP) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
422
423
  				if (write_new_fid(data,
  						data->currfid + fid_interval))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  					return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
  			} else {
  				if (write_new_fid
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
427
428
  				    (data,
  				     2 + convert_fid_to_vco_fid(data->currfid)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  					return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
  			}
  		} else {
019a61b99   Langsdorf, Mark   [PATCH] Support 1...
432
  			if (write_new_fid(data, data->currfid - fid_interval))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  				return 1;
  		}
  
  		vcocurrfid = convert_fid_to_vco_fid(data->currfid);
  		vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
  		    : vcoreqfid - vcocurrfid;
  	}
  
  	if (write_new_fid(data, reqfid))
  		return 1;
  
  	if (query_current_values_with_pending_wait(data))
  		return 1;
  
  	if (data->currfid != reqfid) {
  		printk(KERN_ERR PFX
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
449
450
451
  			"ph2: mismatch, failed fid transition, "
  			"curr 0x%x, req 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
455
456
457
458
459
460
461
  			data->currfid, reqfid);
  		return 1;
  	}
  
  	if (savevid != data->currvid) {
  		printk(KERN_ERR PFX "ph2: vid changed, save 0x%x, curr 0x%x
  ",
  			savevid, data->currvid);
  		return 1;
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
462
463
  	pr_debug("ph2 complete, currfid 0x%x, currvid 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
466
467
468
469
  		data->currfid, data->currvid);
  
  	return 0;
  }
  
  /* Phase 3 - core voltage transition flow ... jump to the final vid. */
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
470
471
  static int core_voltage_post_transition(struct powernow_k8_data *data,
  		u32 reqvid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
  {
  	u32 savefid = data->currfid;
  	u32 savereqvid = reqvid;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
475
476
  	pr_debug("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
  		smp_processor_id(),
  		data->currfid, data->currvid);
  
  	if (reqvid != data->currvid) {
  		if (write_new_vid(data, reqvid))
  			return 1;
  
  		if (savefid != data->currfid) {
  			printk(KERN_ERR PFX
  			       "ph3: bad fid change, save 0x%x, curr 0x%x
  ",
  			       savefid, data->currfid);
  			return 1;
  		}
  
  		if (data->currvid != reqvid) {
  			printk(KERN_ERR PFX
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
494
495
496
  			       "ph3: failed vid transition
  , "
  			       "req 0x%x, curr 0x%x",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
502
503
504
505
  			       reqvid, data->currvid);
  			return 1;
  		}
  	}
  
  	if (query_current_values_with_pending_wait(data))
  		return 1;
  
  	if (savereqvid != data->currvid) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
506
507
  		pr_debug("ph3 failed, currvid 0x%x
  ", data->currvid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
  		return 1;
  	}
  
  	if (savefid != data->currfid) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
512
513
  		pr_debug("ph3 failed, currfid changed 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
  			data->currfid);
  		return 1;
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
517
518
  	pr_debug("ph3 complete, currfid 0x%x, currvid 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
522
  		data->currfid, data->currvid);
  
  	return 0;
  }
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
523
  static void check_supported_cpu(void *_rc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  	u32 eax, ebx, ecx, edx;
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
526
  	int *rc = _rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527

1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
528
  	*rc = -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529

7b543a533   Tejun Heo   x86: Replace uses...
530
  	if (__this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_AMD)
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
531
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  
  	eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
534
535
  	if (((eax & CPUID_XFAM) != CPUID_XFAM_K8) &&
  	    ((eax & CPUID_XFAM) < CPUID_XFAM_10H))
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
536
  		return;
2c906ae67   Dave Jones   [CPUFREQ] Silence...
537

1f729e066   Dave Jones   [CPUFREQ] Prepare...
538
539
  	if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
  		if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
99fbe1ac2   Dave Jones   [CPUFREQ] Correct...
540
  		    ((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
541
542
543
  			printk(KERN_INFO PFX
  				"Processor cpuid %x not supported
  ", eax);
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
544
  			return;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
545
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546

1f729e066   Dave Jones   [CPUFREQ] Prepare...
547
548
549
550
551
  		eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
  		if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
  			printk(KERN_INFO PFX
  			       "No frequency change capabilities detected
  ");
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
552
  			return;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
553
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554

1f729e066   Dave Jones   [CPUFREQ] Prepare...
555
  		cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
556
557
558
559
560
  		if ((edx & P_STATE_TRANSITION_CAPABLE)
  			!= P_STATE_TRANSITION_CAPABLE) {
  			printk(KERN_INFO PFX
  				"Power state transitions not supported
  ");
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
561
  			return;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
562
563
564
565
566
567
  		}
  	} else { /* must be a HW Pstate capable processor */
  		cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
  		if ((edx & USE_HW_PSTATE) == USE_HW_PSTATE)
  			cpu_family = CPU_HW_PSTATE;
  		else
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
568
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
  	}
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
570
  	*rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
  }
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
572
573
  static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst,
  		u8 maxvid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
577
578
579
  {
  	unsigned int j;
  	u8 lastfid = 0xff;
  
  	for (j = 0; j < data->numps; j++) {
  		if (pst[j].vid > LEAST_VID) {
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
580
581
582
  			printk(KERN_ERR FW_BUG PFX "vid %d invalid : 0x%x
  ",
  			       j, pst[j].vid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
584
  			return -EINVAL;
  		}
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
585
586
  		if (pst[j].vid < data->rvo) {
  			/* vid + rvo >= 0 */
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
587
588
589
  			printk(KERN_ERR FW_BUG PFX "0 vid exceeded with pstate"
  			       " %d
  ", j);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
  			return -ENODEV;
  		}
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
592
593
  		if (pst[j].vid < maxvid + data->rvo) {
  			/* vid + rvo >= maxvid */
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
594
595
596
  			printk(KERN_ERR FW_BUG PFX "maxvid exceeded with pstate"
  			       " %d
  ", j);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
  			return -ENODEV;
  		}
8aae8284f   Jacob Shin   [CPUFREQ] Improve...
599
  		if (pst[j].fid > MAX_FID) {
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
600
601
602
  			printk(KERN_ERR FW_BUG PFX "maxfid exceeded with pstate"
  			       " %d
  ", j);
8aae8284f   Jacob Shin   [CPUFREQ] Improve...
603
604
  			return -ENODEV;
  		}
8aae8284f   Jacob Shin   [CPUFREQ] Improve...
605
  		if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
  			/* Only first fid is allowed to be in "low" range */
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
607
608
609
  			printk(KERN_ERR FW_BUG PFX "two low fids - %d : "
  			       "0x%x
  ", j, pst[j].fid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
613
614
615
  			return -EINVAL;
  		}
  		if (pst[j].fid < lastfid)
  			lastfid = pst[j].fid;
  	}
  	if (lastfid & 1) {
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
616
617
  		printk(KERN_ERR FW_BUG PFX "lastfid invalid
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
620
  		return -EINVAL;
  	}
  	if (lastfid > LO_FID_TABLE_TOP)
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
621
622
623
  		printk(KERN_INFO FW_BUG PFX
  			"first fid not from lo freq table
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
  
  	return 0;
  }
f0adb134d   Kurt Roeckx   [CPUFREQ] Fix NUL...
627
628
  static void invalidate_entry(struct cpufreq_frequency_table *powernow_table,
  		unsigned int entry)
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
629
  {
f0adb134d   Kurt Roeckx   [CPUFREQ] Fix NUL...
630
  	powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
631
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
635
  static void print_basics(struct powernow_k8_data *data)
  {
  	int j;
  	for (j = 0; j < data->numps; j++) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
636
637
  		if (data->powernow_table[j].frequency !=
  				CPUFREQ_ENTRY_INVALID) {
e7bdd7a53   Langsdorf, Mark   [CPUFREQ] Clarify...
638
  			if (cpu_family == CPU_HW_PSTATE) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
639
640
641
  				printk(KERN_INFO PFX
  					"   %d : pstate %d (%d MHz)
  ", j,
4ae5c49ff   Yinghai Lu   [CPUFREQ] powerno...
642
  					data->powernow_table[j].index,
9a60ddbcb   Dave Jones   [CPUFREQ] Fix typ...
643
  					data->powernow_table[j].frequency/1000);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
644
  			} else {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
645
  				printk(KERN_INFO PFX
9e9186954   Thomas Renninger   [CPUFREQ] powerno...
646
647
  					"fid 0x%x (%d MHz), vid 0x%x
  ",
9a60ddbcb   Dave Jones   [CPUFREQ] Fix typ...
648
649
650
  					data->powernow_table[j].index & 0xff,
  					data->powernow_table[j].frequency/1000,
  					data->powernow_table[j].index >> 8);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
651
652
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
654
  	}
  	if (data->batps)
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
655
656
657
  		printk(KERN_INFO PFX "Only %d pstates on battery
  ",
  				data->batps);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
  }
ca446d063   Andreas Herrmann   [CPUFREQ] powerno...
659
660
661
662
663
664
665
666
667
668
669
670
671
  static u32 freq_from_fid_did(u32 fid, u32 did)
  {
  	u32 mhz = 0;
  
  	if (boot_cpu_data.x86 == 0x10)
  		mhz = (100 * (fid + 0x10)) >> did;
  	else if (boot_cpu_data.x86 == 0x11)
  		mhz = (100 * (fid + 8)) >> did;
  	else
  		BUG();
  
  	return mhz * 1000;
  }
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
672
673
  static int fill_powernow_table(struct powernow_k8_data *data,
  		struct pst_s *pst, u8 maxvid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
  {
  	struct cpufreq_frequency_table *powernow_table;
  	unsigned int j;
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
677
678
679
680
681
682
  	if (data->batps) {
  		/* use ACPI support to get full speed on mains power */
  		printk(KERN_WARNING PFX
  			"Only %d pstates usable (use ACPI driver for full "
  			"range
  ", data->batps);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
  		data->numps = data->batps;
  	}
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
685
  	for (j = 1; j < data->numps; j++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
  		if (pst[j-1].fid >= pst[j].fid) {
  			printk(KERN_ERR PFX "PST out of sequence
  ");
  			return -EINVAL;
  		}
  	}
  
  	if (data->numps < 2) {
  		printk(KERN_ERR PFX "no p states to transition
  ");
  		return -ENODEV;
  	}
  
  	if (check_pst_table(data, pst, maxvid))
  		return -EINVAL;
  
  	powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
  		* (data->numps + 1)), GFP_KERNEL);
  	if (!powernow_table) {
  		printk(KERN_ERR PFX "powernow_table memory alloc failure
  ");
  		return -ENOMEM;
  	}
  
  	for (j = 0; j < data->numps; j++) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
711
  		int freq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
  		powernow_table[j].index = pst[j].fid; /* lower 8 bits */
  		powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
714
715
  		freq = find_khz_freq_from_fid(pst[j].fid);
  		powernow_table[j].frequency = freq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
719
720
721
722
723
  	}
  	powernow_table[data->numps].frequency = CPUFREQ_TABLE_END;
  	powernow_table[data->numps].index = 0;
  
  	if (query_current_values_with_pending_wait(data)) {
  		kfree(powernow_table);
  		return -EIO;
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
724
725
  	pr_debug("cfid 0x%x, cvid 0x%x
  ", data->currfid, data->currvid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
  	data->powernow_table = powernow_table;
7ad728f98   Rusty Russell   cpumask: x86: con...
727
  	if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu)
2e4976206   Mark Langsdorf   [CPUFREQ] Report ...
728
  		print_basics(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
730
  
  	for (j = 0; j < data->numps; j++)
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
731
732
  		if ((pst[j].fid == data->currfid) &&
  		    (pst[j].vid == data->currvid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
  			return 0;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
734
735
  	pr_debug("currfid/vid do not match PST, ignoring
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  	return 0;
  }
  
  /* Find and validate the PSB/PST table in BIOS. */
  static int find_psb_table(struct powernow_k8_data *data)
  {
  	struct psb_s *psb;
  	unsigned int i;
  	u32 mvs;
  	u8 maxvid;
  	u32 cpst = 0;
  	u32 thiscpuid;
  
  	for (i = 0xc0000; i < 0xffff0; i += 0x10) {
  		/* Scan BIOS looking for the signature. */
  		/* It can not be at ffff0 - it is too big. */
  
  		psb = phys_to_virt(i);
  		if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0)
  			continue;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
756
757
  		pr_debug("found PSB header at 0x%p
  ", psb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
759
760
  		pr_debug("table vers: 0x%x
  ", psb->tableversion);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
  		if (psb->tableversion != PSB_VERSION_1_4) {
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
762
763
  			printk(KERN_ERR FW_BUG PFX "PSB table is not v1.4
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
  			return -ENODEV;
  		}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
766
767
  		pr_debug("flags: 0x%x
  ", psb->flags1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  		if (psb->flags1) {
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
769
770
  			printk(KERN_ERR FW_BUG PFX "unknown flags
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
773
774
  			return -ENODEV;
  		}
  
  		data->vstable = psb->vstable;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
775
776
  		pr_debug("voltage stabilization time: %d(*20us)
  ",
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
777
  				data->vstable);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
779
780
  		pr_debug("flags2: 0x%x
  ", psb->flags2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
785
  		data->rvo = psb->flags2 & 3;
  		data->irt = ((psb->flags2) >> 2) & 3;
  		mvs = ((psb->flags2) >> 4) & 3;
  		data->vidmvs = 1 << mvs;
  		data->batps = ((psb->flags2) >> 6) & 3;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
786
787
788
789
790
791
  		pr_debug("ramp voltage offset: %d
  ", data->rvo);
  		pr_debug("isochronous relief time: %d
  ", data->irt);
  		pr_debug("maximum voltage step: %d - 0x%x
  ", mvs, data->vidmvs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
793
794
  		pr_debug("numpst: 0x%x
  ", psb->num_tables);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
  		cpst = psb->num_tables;
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
796
797
  		if ((psb->cpuid == 0x00000fc0) ||
  		    (psb->cpuid == 0x00000fe0)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  			thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
799
800
  			if ((thiscpuid == 0x00000fc0) ||
  			    (thiscpuid == 0x00000fe0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
  				cpst = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
  		}
  		if (cpst != 1) {
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
804
805
  			printk(KERN_ERR FW_BUG PFX "numpst must be 1
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
808
809
  			return -ENODEV;
  		}
  
  		data->plllock = psb->plllocktime;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
810
811
812
813
814
815
  		pr_debug("plllocktime: 0x%x (units 1us)
  ", psb->plllocktime);
  		pr_debug("maxfid: 0x%x
  ", psb->maxfid);
  		pr_debug("maxvid: 0x%x
  ", psb->maxvid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
  		maxvid = psb->maxvid;
  
  		data->numps = psb->numps;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
819
820
  		pr_debug("numpstates: 0x%x
  ", data->numps);
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
821
822
  		return fill_powernow_table(data,
  				(struct pst_s *)(psb+1), maxvid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
825
826
827
828
829
830
831
832
833
834
  	}
  	/*
  	 * If you see this message, complain to BIOS manufacturer. If
  	 * he tells you "we do not support Linux" or some similar
  	 * nonsense, remember that Windows 2000 uses the same legacy
  	 * mechanism that the old Linux PSB driver uses. Tell them it
  	 * is broken with Windows 2000.
  	 *
  	 * The reference to the AMD documentation is chapter 9 in the
  	 * BIOS and Kernel Developer's Guide, which is available on
  	 * www.amd.com
  	 */
79cc56af9   Thomas Renninger   [CPUFREQ] powerno...
835
836
  	printk(KERN_ERR FW_BUG PFX "No PSB or ACPI _PSS objects
  ");
298decfbc   Marti Raudsepp   [CPUFREQ] powerno...
837
838
839
  	printk(KERN_ERR PFX "Make sure that your BIOS is up to date"
  		" and Cool'N'Quiet support is enabled in BIOS setup
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
  	return -ENODEV;
  }
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
842
843
  static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data,
  		unsigned int index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  {
439913fff   Lin Ming   ACPI: replace acp...
845
  	u64 control;
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
846

f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
847
  	if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
  		return;
21335d021   Luis Henriques   [CPUFREQ] powerno...
849
850
851
852
853
854
855
856
  	control = data->acpi_data.states[index].control;
  	data->irt = (control >> IRT_SHIFT) & IRT_MASK;
  	data->rvo = (control >> RVO_SHIFT) & RVO_MASK;
  	data->exttype = (control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK;
  	data->plllock = (control >> PLL_L_SHIFT) & PLL_L_MASK;
  	data->vidmvs = 1 << ((control >> MVS_SHIFT) & MVS_MASK);
  	data->vstable = (control >> VST_SHIFT) & VST_MASK;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
858
859
  
  static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
  	struct cpufreq_frequency_table *powernow_table;
2fdf66b49   Rusty Russell   cpumask: convert ...
861
  	int ret_val = -ENODEV;
439913fff   Lin Ming   ACPI: replace acp...
862
  	u64 control, status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863

f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
864
  	if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
865
866
  		pr_debug("register performance failed: bad ACPI data
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
869
870
  		return -EIO;
  	}
  
  	/* verify the data contained in the ACPI structures */
f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
871
  	if (data->acpi_data.state_count <= 1) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
872
873
  		pr_debug("No ACPI P-States
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
  		goto err_out;
  	}
2c701b102   Dave Jones   [CPUFREQ] powerno...
876
877
878
879
880
  	control = data->acpi_data.control_register.space_id;
  	status = data->acpi_data.status_register.space_id;
  
  	if ((control != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
  	    (status != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
881
882
  		pr_debug("Invalid control/status registers (%llx - %llx)
  ",
2c701b102   Dave Jones   [CPUFREQ] powerno...
883
  			control, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
886
887
888
  		goto err_out;
  	}
  
  	/* fill in data->powernow_table */
  	powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
889
  		* (data->acpi_data.state_count + 1)), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
  	if (!powernow_table) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
891
892
  		pr_debug("powernow_table memory alloc failure
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
894
  		goto err_out;
  	}
db39d5529   Mark Langsdorf   [CPUFREQ] Powerno...
895
896
897
  	/* fill in data */
  	data->numps = data->acpi_data.state_count;
  	powernow_k8_acpi_pst_values(data, 0);
e7bdd7a53   Langsdorf, Mark   [CPUFREQ] Clarify...
898
  	if (cpu_family == CPU_HW_PSTATE)
1f729e066   Dave Jones   [CPUFREQ] Prepare...
899
900
901
902
903
  		ret_val = fill_powernow_table_pstate(data, powernow_table);
  	else
  		ret_val = fill_powernow_table_fidvid(data, powernow_table);
  	if (ret_val)
  		goto err_out_mem;
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
904
905
  	powernow_table[data->acpi_data.state_count].frequency =
  		CPUFREQ_TABLE_END;
f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
906
  	powernow_table[data->acpi_data.state_count].index = 0;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
907
  	data->powernow_table = powernow_table;
7ad728f98   Rusty Russell   cpumask: x86: con...
908
  	if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu)
2e4976206   Mark Langsdorf   [CPUFREQ] Report ...
909
  		print_basics(data);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
910
911
912
  
  	/* notify BIOS that we exist */
  	acpi_processor_notify_smm(THIS_MODULE);
eaa958402   Yinghai Lu   cpumask: alloc ze...
913
  	if (!zalloc_cpumask_var(&data->acpi_data.shared_cpu_map, GFP_KERNEL)) {
2fdf66b49   Rusty Russell   cpumask: convert ...
914
915
916
917
918
919
  		printk(KERN_ERR PFX
  				"unable to alloc powernow_k8_data cpumask
  ");
  		ret_val = -ENOMEM;
  		goto err_out_mem;
  	}
1f729e066   Dave Jones   [CPUFREQ] Prepare...
920
921
922
923
924
925
  	return 0;
  
  err_out_mem:
  	kfree(powernow_table);
  
  err_out:
f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
926
  	acpi_processor_unregister_performance(&data->acpi_data, data->cpu);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
927

0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
928
929
  	/* data->acpi_data.state_count informs us at ->exit()
  	 * whether ACPI was used */
f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
930
  	data->acpi_data.state_count = 0;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
931

2fdf66b49   Rusty Russell   cpumask: convert ...
932
  	return ret_val;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
933
  }
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
934
935
  static int fill_powernow_table_pstate(struct powernow_k8_data *data,
  		struct cpufreq_frequency_table *powernow_table)
1f729e066   Dave Jones   [CPUFREQ] Prepare...
936
937
  {
  	int i;
c5829cd07   Mark Langsdorf   [CPUFREQ] archite...
938
  	u32 hi = 0, lo = 0;
b30d3304c   Borislav Petkov   [CPUFREQ] powerno...
939
940
  	rdmsr(MSR_PSTATE_CUR_LIMIT, lo, hi);
  	data->max_hw_pstate = (lo & HW_PSTATE_MAX_MASK) >> HW_PSTATE_MAX_SHIFT;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
941

f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
942
  	for (i = 0; i < data->acpi_data.state_count; i++) {
1f729e066   Dave Jones   [CPUFREQ] Prepare...
943
  		u32 index;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
944

f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
945
  		index = data->acpi_data.states[i].control & HW_PSTATE_MASK;
c5829cd07   Mark Langsdorf   [CPUFREQ] archite...
946
  		if (index > data->max_hw_pstate) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
947
948
949
950
951
952
  			printk(KERN_ERR PFX "invalid pstate %d - "
  					"bad value %d.
  ", i, index);
  			printk(KERN_ERR PFX "Please report to BIOS "
  					"manufacturer
  ");
f0adb134d   Kurt Roeckx   [CPUFREQ] Fix NUL...
953
  			invalidate_entry(powernow_table, i);
c5829cd07   Mark Langsdorf   [CPUFREQ] archite...
954
  			continue;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
955
  		}
a8eb28480   Andreas Herrmann   [CPUFREQ] powerno...
956
957
  
  		ps_to_as[index] = i;
ca446d063   Andreas Herrmann   [CPUFREQ] powerno...
958
  		/* Frequency may be rounded for these */
679370641   Mark Langsdorf   powernow-k8: Fix ...
959
960
  		if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10)
  				 || boot_cpu_data.x86 == 0x11) {
201bf0f12   Andreas Herrmann   [CPUFREQ] powerno...
961
962
963
964
965
966
967
968
  
  			rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
  			if (!(hi & HW_PSTATE_VALID_MASK)) {
  				pr_debug("invalid pstate %d, ignoring
  ", index);
  				invalidate_entry(powernow_table, i);
  				continue;
  			}
ca446d063   Andreas Herrmann   [CPUFREQ] powerno...
969
970
971
972
973
  			powernow_table[i].frequency =
  				freq_from_fid_did(lo & 0x3f, (lo >> 6) & 7);
  		} else
  			powernow_table[i].frequency =
  				data->acpi_data.states[i].core_frequency * 1000;
201bf0f12   Andreas Herrmann   [CPUFREQ] powerno...
974
975
  
  		powernow_table[i].index = index;
1f729e066   Dave Jones   [CPUFREQ] Prepare...
976
977
978
  	}
  	return 0;
  }
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
979
980
  static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
  		struct cpufreq_frequency_table *powernow_table)
1f729e066   Dave Jones   [CPUFREQ] Prepare...
981
982
  {
  	int i;
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
983

f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
984
  	for (i = 0; i < data->acpi_data.state_count; i++) {
094ce7fde   Dave Jones   arch/i386/kernel/...
985
986
  		u32 fid;
  		u32 vid;
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
987
  		u32 freq, index;
439913fff   Lin Ming   ACPI: replace acp...
988
  		u64 status, control;
094ce7fde   Dave Jones   arch/i386/kernel/...
989
990
  
  		if (data->exttype) {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
991
992
993
  			status =  data->acpi_data.states[i].status;
  			fid = status & EXT_FID_MASK;
  			vid = (status >> VID_SHIFT) & EXT_VID_MASK;
841e40b38   Dave Jones   Opteron revision ...
994
  		} else {
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
995
996
997
  			control =  data->acpi_data.states[i].control;
  			fid = control & FID_MASK;
  			vid = (control >> VID_SHIFT) & VID_MASK;
841e40b38   Dave Jones   Opteron revision ...
998
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1000
1001
  		pr_debug("   %d : fid 0x%x, vid 0x%x
  ", i, fid, vid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002

0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1003
1004
1005
1006
1007
  		index = fid | (vid<<8);
  		powernow_table[i].index = index;
  
  		freq = find_khz_freq_from_fid(fid);
  		powernow_table[i].frequency = freq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
  
  		/* verify frequency is OK */
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1010
  		if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1011
1012
  			pr_debug("invalid freq %u kHz, ignoring
  ", freq);
f0adb134d   Kurt Roeckx   [CPUFREQ] Fix NUL...
1013
  			invalidate_entry(powernow_table, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
  			continue;
  		}
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1016
1017
  		/* verify voltage is OK -
  		 * BIOSs are using "off" to indicate invalid */
841e40b38   Dave Jones   Opteron revision ...
1018
  		if (vid == VID_OFF) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1019
1020
  			pr_debug("invalid vid %u, ignoring
  ", vid);
f0adb134d   Kurt Roeckx   [CPUFREQ] Fix NUL...
1021
  			invalidate_entry(powernow_table, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
1023
  			continue;
  		}
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1024
1025
1026
1027
1028
1029
1030
  		if (freq != (data->acpi_data.states[i].core_frequency * 1000)) {
  			printk(KERN_INFO PFX "invalid freq entries "
  				"%u kHz vs. %u kHz
  ", freq,
  				(unsigned int)
  				(data->acpi_data.states[i].core_frequency
  				 * 1000));
f0adb134d   Kurt Roeckx   [CPUFREQ] Fix NUL...
1031
  			invalidate_entry(powernow_table, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
1033
1034
  			continue;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036
1037
1038
1039
  }
  
  static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data)
  {
f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
1040
  	if (data->acpi_data.state_count)
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1041
1042
  		acpi_processor_unregister_performance(&data->acpi_data,
  				data->cpu);
2fdf66b49   Rusty Russell   cpumask: convert ...
1043
  	free_cpumask_var(data->acpi_data.shared_cpu_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
  }
732553e56   Mark Langsdorf   [CPUFREQ] powerno...
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
  static int get_transition_latency(struct powernow_k8_data *data)
  {
  	int max_latency = 0;
  	int i;
  	for (i = 0; i < data->acpi_data.state_count; i++) {
  		int cur_latency = data->acpi_data.states[i].transition_latency
  			+ data->acpi_data.states[i].bus_master_latency;
  		if (cur_latency > max_latency)
  			max_latency = cur_latency;
  	}
86e13684a   Thomas Renninger   [CPUFREQ] powerno...
1055
1056
  	if (max_latency == 0) {
  		/*
c2f4a2c6e   Borislav Petkov   [CPUFREQ] powerno...
1057
1058
1059
1060
  		 * Fam 11h and later may return 0 as transition latency. This
  		 * is intended and means "very fast". While cpufreq core and
  		 * governors currently can handle that gracefully, better set it
  		 * to 1 to avoid problems in the future.
86e13684a   Thomas Renninger   [CPUFREQ] powerno...
1061
  		 */
c2f4a2c6e   Borislav Petkov   [CPUFREQ] powerno...
1062
  		if (boot_cpu_data.x86 < 0x11)
86e13684a   Thomas Renninger   [CPUFREQ] powerno...
1063
1064
1065
1066
1067
  			printk(KERN_ERR FW_WARN PFX "Invalid zero transition "
  				"latency
  ");
  		max_latency = 1;
  	}
732553e56   Mark Langsdorf   [CPUFREQ] powerno...
1068
1069
1070
  	/* value in usecs, needs to be in nanoseconds */
  	return 1000 * max_latency;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1071
  /* Take a frequency, and issue the fid/vid transition command */
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1072
1073
  static int transition_frequency_fidvid(struct powernow_k8_data *data,
  		unsigned int index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074
  {
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1075
1076
  	u32 fid = 0;
  	u32 vid = 0;
065b807ca   Dave Jones   [CPUFREQ] dual-co...
1077
  	int res, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
  	struct cpufreq_freqs freqs;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1079
1080
  	pr_debug("cpu %d transition to index %u
  ", smp_processor_id(), index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081

1f729e066   Dave Jones   [CPUFREQ] Prepare...
1082
  	/* fid/vid correctness check for k8 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
  	/* fid are the lower 8 bits of the index we stored into
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1084
1085
  	 * the cpufreq frequency table in find_psb_table, vid
  	 * are the upper 8 bits.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
1088
  	fid = data->powernow_table[index].index & 0xFF;
  	vid = (data->powernow_table[index].index & 0xFF00) >> 8;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1089
1090
  	pr_debug("table matched fid 0x%x, giving vid 0x%x
  ", fid, vid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
1092
1093
1094
1095
  
  	if (query_current_values_with_pending_wait(data))
  		return 1;
  
  	if ((data->currvid == vid) && (data->currfid == fid)) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1096
1097
  		pr_debug("target matches current values (fid 0x%x, vid 0x%x)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
1099
1100
  			fid, vid);
  		return 0;
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1101
1102
  	pr_debug("cpu %d, changing to fid 0x%x, vid 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
  		smp_processor_id(), fid, vid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
1105
  	freqs.old = find_khz_freq_from_fid(data->currfid);
  	freqs.new = find_khz_freq_from_fid(fid);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1106

8e7c25971   Rusty Russell   [CPUFREQ] cpumask...
1107
  	for_each_cpu(i, data->available_cores) {
065b807ca   Dave Jones   [CPUFREQ] dual-co...
1108
1109
1110
  		freqs.cpu = i;
  		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1111

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
  	res = transition_fid_vid(data, fid, vid);
a9d3d2068   Konrad Rzeszutek Wilk   [CPUFREQ] powerno...
1113
1114
  	if (res)
  		return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
  	freqs.new = find_khz_freq_from_fid(data->currfid);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1116

8e7c25971   Rusty Russell   [CPUFREQ] cpumask...
1117
  	for_each_cpu(i, data->available_cores) {
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1118
1119
1120
1121
1122
1123
1124
  		freqs.cpu = i;
  		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
  	}
  	return res;
  }
  
  /* Take a frequency, and issue the hardware pstate transition command */
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1125
1126
  static int transition_frequency_pstate(struct powernow_k8_data *data,
  		unsigned int index)
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1127
  {
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1128
1129
1130
  	u32 pstate = 0;
  	int res, i;
  	struct cpufreq_freqs freqs;
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1131
1132
  	pr_debug("cpu %d transition to index %u
  ", smp_processor_id(), index);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1133

c5829cd07   Mark Langsdorf   [CPUFREQ] archite...
1134
  	/* get MSR index for hardware pstate transition */
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1135
  	pstate = index & HW_PSTATE_MASK;
c5829cd07   Mark Langsdorf   [CPUFREQ] archite...
1136
  	if (pstate > data->max_hw_pstate)
fbb5b89ea   Konrad Rzeszutek Wilk   [CPUFREQ] powerno...
1137
  		return -EINVAL;
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1138
1139
  	freqs.old = find_khz_freq_from_pstate(data->powernow_table,
  			data->currpstate);
c5829cd07   Mark Langsdorf   [CPUFREQ] archite...
1140
  	freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1141

8e7c25971   Rusty Russell   [CPUFREQ] cpumask...
1142
  	for_each_cpu(i, data->available_cores) {
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1143
1144
1145
1146
1147
  		freqs.cpu = i;
  		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
  	}
  
  	res = transition_pstate(data, pstate);
c5829cd07   Mark Langsdorf   [CPUFREQ] archite...
1148
  	freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1149

8e7c25971   Rusty Russell   [CPUFREQ] cpumask...
1150
  	for_each_cpu(i, data->available_cores) {
065b807ca   Dave Jones   [CPUFREQ] dual-co...
1151
1152
  		freqs.cpu = i;
  		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
2e3f8faaa   Dave Jones   [CPUFREQ] Typo in...
1153
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
1156
1157
  	return res;
  }
  
  /* Driver entry point to switch to the target frequency */
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1158
1159
  static int powernowk8_target(struct cpufreq_policy *pol,
  		unsigned targfreq, unsigned relation)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
  {
b8cbe7e82   Rusty Russell   [CPUFREQ] cpumask...
1161
  	cpumask_var_t oldmask;
2c6b8c030   travis@sgi.com   x86: change NR_CP...
1162
  	struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
9180053ca   Adrian Bunk   [CPUFREQ] powerno...
1163
1164
  	u32 checkfid;
  	u32 checkvid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
  	unsigned int newstate;
  	int ret = -EIO;
4211a3034   Jacob Shin   [PATCH] x86_64: P...
1167
1168
  	if (!data)
  		return -EINVAL;
9180053ca   Adrian Bunk   [CPUFREQ] powerno...
1169
1170
  	checkfid = data->currfid;
  	checkvid = data->currvid;
b8cbe7e82   Rusty Russell   [CPUFREQ] cpumask...
1171
1172
1173
1174
  	/* only run on specific CPU from here on. */
  	/* This is poor form: use a workqueue or smp_call_function_single */
  	if (!alloc_cpumask_var(&oldmask, GFP_KERNEL))
  		return -ENOMEM;
a4636818f   Rusty Russell   cpumask: rename t...
1175
  	cpumask_copy(oldmask, tsk_cpus_allowed(current));
b8cbe7e82   Rusty Russell   [CPUFREQ] cpumask...
1176
  	set_cpus_allowed_ptr(current, cpumask_of(pol->cpu));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177
1178
  
  	if (smp_processor_id() != pol->cpu) {
8aae8284f   Jacob Shin   [CPUFREQ] Improve...
1179
1180
  		printk(KERN_ERR PFX "limiting to cpu %u failed
  ", pol->cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
1182
1183
1184
1185
1186
1187
1188
  		goto err_out;
  	}
  
  	if (pending_bit_stuck()) {
  		printk(KERN_ERR PFX "failing targ, change pending bit set
  ");
  		goto err_out;
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1189
1190
  	pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191
  		pol->cpu, targfreq, pol->min, pol->max, relation);
83844510e   Dave Jones   [CPUFREQ] Remove ...
1192
  	if (query_current_values_with_pending_wait(data))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194

c5829cd07   Mark Langsdorf   [CPUFREQ] archite...
1195
  	if (cpu_family != CPU_HW_PSTATE) {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1196
1197
  		pr_debug("targ: curr fid 0x%x, vid 0x%x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
  		data->currfid, data->currvid);
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1199
1200
  		if ((checkvid != data->currvid) ||
  		    (checkfid != data->currfid)) {
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1201
  			printk(KERN_INFO PFX
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1202
1203
1204
1205
1206
  				"error - out of sync, fix 0x%x 0x%x, "
  				"vid 0x%x 0x%x
  ",
  				checkfid, data->currfid,
  				checkvid, data->currvid);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1207
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
  	}
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1209
1210
  	if (cpufreq_frequency_table_target(pol, data->powernow_table,
  				targfreq, relation, &newstate))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
  		goto err_out;
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
1212
  	mutex_lock(&fidvid_mutex);
065b807ca   Dave Jones   [CPUFREQ] dual-co...
1213

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
  	powernow_k8_acpi_pst_values(data, newstate);
e7bdd7a53   Langsdorf, Mark   [CPUFREQ] Clarify...
1215
  	if (cpu_family == CPU_HW_PSTATE)
a8eb28480   Andreas Herrmann   [CPUFREQ] powerno...
1216
1217
  		ret = transition_frequency_pstate(data,
  			data->powernow_table[newstate].index);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1218
1219
1220
  	else
  		ret = transition_frequency_fidvid(data, newstate);
  	if (ret) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
1222
1223
  		printk(KERN_ERR PFX "transition frequency failed
  ");
  		ret = 1;
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
1224
  		mutex_unlock(&fidvid_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
1226
  		goto err_out;
  	}
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
1227
  	mutex_unlock(&fidvid_mutex);
065b807ca   Dave Jones   [CPUFREQ] dual-co...
1228

e7bdd7a53   Langsdorf, Mark   [CPUFREQ] Clarify...
1229
  	if (cpu_family == CPU_HW_PSTATE)
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1230
  		pol->cur = find_khz_freq_from_pstate(data->powernow_table,
a8eb28480   Andreas Herrmann   [CPUFREQ] powerno...
1231
  				data->powernow_table[newstate].index);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1232
1233
  	else
  		pol->cur = find_khz_freq_from_fid(data->currfid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
1235
1236
  	ret = 0;
  
  err_out:
b8cbe7e82   Rusty Russell   [CPUFREQ] cpumask...
1237
1238
  	set_cpus_allowed_ptr(current, oldmask);
  	free_cpumask_var(oldmask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
1240
1241
1242
1243
1244
  	return ret;
  }
  
  /* Driver entry point to verify the policy and range of frequencies */
  static int powernowk8_verify(struct cpufreq_policy *pol)
  {
2c6b8c030   travis@sgi.com   x86: change NR_CP...
1245
  	struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246

4211a3034   Jacob Shin   [PATCH] x86_64: P...
1247
1248
  	if (!data)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
1250
  	return cpufreq_frequency_table_verify(pol, data->powernow_table);
  }
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
  struct init_on_cpu {
  	struct powernow_k8_data *data;
  	int rc;
  };
  
  static void __cpuinit powernowk8_cpu_init_on_cpu(void *_init_on_cpu)
  {
  	struct init_on_cpu *init_on_cpu = _init_on_cpu;
  
  	if (pending_bit_stuck()) {
  		printk(KERN_ERR PFX "failing init, change pending bit set
  ");
  		init_on_cpu->rc = -ENODEV;
  		return;
  	}
  
  	if (query_current_values_with_pending_wait(init_on_cpu->data)) {
  		init_on_cpu->rc = -ENODEV;
  		return;
  	}
  
  	if (cpu_family == CPU_OPTERON)
  		fidvid_msr_init();
  
  	init_on_cpu->rc = 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1277
  /* per CPU init entry point to the driver */
aa41eb991   Andi Kleen   [PATCH] x86_64: M...
1278
  static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1279
  {
b394f1dfc   Andrew Morton   [CPUFREQ] reduce ...
1280
1281
1282
  	static const char ACPI_PSS_BIOS_BUG_MSG[] =
  		KERN_ERR FW_BUG PFX "No compatible ACPI _PSS objects found.
  "
ad361c988   Joe Perches   Remove multiple K...
1283
1284
  		FW_BUG PFX "Try again with latest BIOS.
  ";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
  	struct powernow_k8_data *data;
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
1286
  	struct init_on_cpu init_on_cpu;
d7fa706ce   Andi Kleen   [PATCH] x86_64: R...
1287
  	int rc;
a2fed573f   Mark Langsdorf   x86, cpufreq: Add...
1288
  	struct cpuinfo_x86 *c = &cpu_data(pol->cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289

8aae8284f   Jacob Shin   [CPUFREQ] Improve...
1290
1291
  	if (!cpu_online(pol->cpu))
  		return -ENODEV;
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
1292
1293
  	smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1);
  	if (rc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
  		return -ENODEV;
bfdc708dc   Dave Jones   [CPUFREQ] kzalloc...
1295
  	data = kzalloc(sizeof(struct powernow_k8_data), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
1297
1298
1299
  	if (!data) {
  		printk(KERN_ERR PFX "unable to alloc powernow_k8_data");
  		return -ENOMEM;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1300
1301
  
  	data->cpu = pol->cpu;
a266d9f12   Andreas Herrmann   [CPUFREQ] powerno...
1302
  	data->currpstate = HW_PSTATE_INVALID;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303

a0abd520f   Rusty Russell   cpumask: fix powe...
1304
  	if (powernow_k8_cpu_init_acpi(data)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1305
  		/*
0d2eb44f6   Lucas De Marchi   x86: Fix common m...
1306
  		 * Use the PSB BIOS structure. This is only available on
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
1308
  		 * an UP version, and is deprecated by AMD.
  		 */
9ed059e15   Randy Dunlap   [CPUFREQ] Fix pow...
1309
  		if (num_online_cpus() != 1) {
df1829770   Thomas Renninger   [CPUFREQ] powerno...
1310
  			printk_once(ACPI_PSS_BIOS_BUG_MSG);
0cb8bc256   Dave Jones   [CPUFREQ] powerno...
1311
  			goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1312
1313
  		}
  		if (pol->cpu != 0) {
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
1314
1315
1316
1317
  			printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for "
  			       "CPU other than CPU0. Complain to your BIOS "
  			       "vendor.
  ");
0cb8bc256   Dave Jones   [CPUFREQ] powerno...
1318
  			goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
  		}
  		rc = find_psb_table(data);
0cb8bc256   Dave Jones   [CPUFREQ] powerno...
1321
1322
  		if (rc)
  			goto err_out;
732553e56   Mark Langsdorf   [CPUFREQ] powerno...
1323
1324
1325
1326
1327
1328
1329
  		/* Take a crude guess here.
  		 * That guess was in microseconds, so multiply with 1000 */
  		pol->cpuinfo.transition_latency = (
  			 ((data->rvo + 8) * data->vstable * VST_UNITS_20US) +
  			 ((1 << data->irt) * 30)) * 1000;
  	} else /* ACPI _PSS objects available */
  		pol->cpuinfo.transition_latency = get_transition_latency(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330
1331
  
  	/* only run on specific CPU from here on */
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
1332
1333
1334
1335
1336
1337
  	init_on_cpu.data = data;
  	smp_call_function_single(data->cpu, powernowk8_cpu_init_on_cpu,
  				 &init_on_cpu, 1);
  	rc = init_on_cpu.rc;
  	if (rc != 0)
  		goto err_out_exit_acpi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338

f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
1339
  	if (cpu_family == CPU_HW_PSTATE)
835481d9b   Rusty Russell   cpumask: convert ...
1340
  		cpumask_copy(pol->cpus, cpumask_of(pol->cpu));
f607e3a03   Linus Torvalds   Revert "[CPUFREQ]...
1341
  	else
7ad728f98   Rusty Russell   cpumask: x86: con...
1342
  		cpumask_copy(pol->cpus, cpu_core_mask(pol->cpu));
835481d9b   Rusty Russell   cpumask: convert ...
1343
  	data->available_cores = pol->cpus;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344

e7bdd7a53   Langsdorf, Mark   [CPUFREQ] Clarify...
1345
  	if (cpu_family == CPU_HW_PSTATE)
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1346
1347
  		pol->cur = find_khz_freq_from_pstate(data->powernow_table,
  				data->currpstate);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1348
1349
  	else
  		pol->cur = find_khz_freq_from_fid(data->currfid);
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1350
1351
  	pr_debug("policy current frequency %d kHz
  ", pol->cur);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
1353
1354
  
  	/* min/max the cpu is capable of */
  	if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) {
2fd47094f   Thomas Renninger   CPUFREQ: powernow...
1355
1356
  		printk(KERN_ERR FW_BUG PFX "invalid powernow_table
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1357
1358
1359
1360
1361
  		powernow_k8_cpu_exit_acpi(data);
  		kfree(data->powernow_table);
  		kfree(data);
  		return -EINVAL;
  	}
a2fed573f   Mark Langsdorf   x86, cpufreq: Add...
1362
1363
1364
  	/* Check for APERF/MPERF support in hardware */
  	if (cpu_has(c, X86_FEATURE_APERFMPERF))
  		cpufreq_amd64_driver.getavg = cpufreq_get_measured_perf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365
  	cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
e7bdd7a53   Langsdorf, Mark   [CPUFREQ] Clarify...
1366
  	if (cpu_family == CPU_HW_PSTATE)
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1367
1368
  		pr_debug("cpu_init done, current pstate 0x%x
  ",
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1369
  				data->currpstate);
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1370
  	else
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1371
1372
  		pr_debug("cpu_init done, current fid 0x%x, vid 0x%x
  ",
1f729e066   Dave Jones   [CPUFREQ] Prepare...
1373
  			data->currfid, data->currvid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374

2c6b8c030   travis@sgi.com   x86: change NR_CP...
1375
  	per_cpu(powernow_data, pol->cpu) = data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376
1377
  
  	return 0;
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
1378
  err_out_exit_acpi:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1379
  	powernow_k8_cpu_exit_acpi(data);
0cb8bc256   Dave Jones   [CPUFREQ] powerno...
1380
  err_out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1381
1382
1383
  	kfree(data);
  	return -ENODEV;
  }
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1384
  static int __devexit powernowk8_cpu_exit(struct cpufreq_policy *pol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
  {
2c6b8c030   travis@sgi.com   x86: change NR_CP...
1386
  	struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
  
  	if (!data)
  		return -EINVAL;
  
  	powernow_k8_cpu_exit_acpi(data);
  
  	cpufreq_frequency_table_put_attr(pol->cpu);
  
  	kfree(data->powernow_table);
  	kfree(data);
557a701c1   Thomas Renninger   [CPUFREQ] Fix use...
1397
  	per_cpu(powernow_data, pol->cpu) = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1398
1399
1400
  
  	return 0;
  }
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
1401
1402
1403
  static void query_values_on_cpu(void *_err)
  {
  	int *err = _err;
0a3aee0da   Tejun Heo   x86: Use this_cpu...
1404
  	struct powernow_k8_data *data = __this_cpu_read(powernow_data);
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
1405
1406
1407
  
  	*err = query_current_values_with_pending_wait(data);
  }
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1408
  static unsigned int powernowk8_get(unsigned int cpu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
  {
e15bc4559   Naga Chumbalkar   [CPUFREQ] powerno...
1410
  	struct powernow_k8_data *data = per_cpu(powernow_data, cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1411
  	unsigned int khz = 0;
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
1412
  	int err;
eef5167e5   Jacob Shin   [CPUFREQ] hotplug...
1413
1414
  
  	if (!data)
557a701c1   Thomas Renninger   [CPUFREQ] Fix use...
1415
  		return 0;
eef5167e5   Jacob Shin   [CPUFREQ] hotplug...
1416

1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
1417
1418
  	smp_call_function_single(cpu, query_values_on_cpu, &err, true);
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419
  		goto out;
58389a86d   Joachim Deguara   [CPUFREQ] fix cpu...
1420
  	if (cpu_family == CPU_HW_PSTATE)
fc0e47484   Mike Travis   x86: use new set_...
1421
1422
  		khz = find_khz_freq_from_pstate(data->powernow_table,
  						data->currpstate);
58389a86d   Joachim Deguara   [CPUFREQ] fix cpu...
1423
1424
  	else
  		khz = find_khz_freq_from_fid(data->currfid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1425

b9111b7b7   Dave Jones   [CPUFREQ] Remove ...
1426
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427
1428
  	return khz;
  }
73860c6b2   Borislav Petkov   powernow-k8: Add ...
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
  static void _cpb_toggle_msrs(bool t)
  {
  	int cpu;
  
  	get_online_cpus();
  
  	rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
  
  	for_each_cpu(cpu, cpu_online_mask) {
  		struct msr *reg = per_cpu_ptr(msrs, cpu);
  		if (t)
  			reg->l &= ~BIT(25);
  		else
  			reg->l |= BIT(25);
  	}
  	wrmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
  
  	put_online_cpus();
  }
  
  /*
   * Switch on/off core performance boosting.
   *
   * 0=disable
   * 1=enable.
   */
  static void cpb_toggle(bool t)
  {
  	if (!cpb_capable)
  		return;
  
  	if (t && !cpb_enabled) {
  		cpb_enabled = true;
  		_cpb_toggle_msrs(t);
  		printk(KERN_INFO PFX "Core Boosting enabled.
  ");
  	} else if (!t && cpb_enabled) {
  		cpb_enabled = false;
  		_cpb_toggle_msrs(t);
  		printk(KERN_INFO PFX "Core Boosting disabled.
  ");
  	}
  }
  
  static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
  				 size_t count)
  {
  	int ret = -EINVAL;
  	unsigned long val = 0;
  
  	ret = strict_strtoul(buf, 10, &val);
  	if (!ret && (val == 0 || val == 1) && cpb_capable)
  		cpb_toggle(val);
  	else
  		return -EINVAL;
  
  	return count;
  }
  
  static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
  {
  	return sprintf(buf, "%u
  ", cpb_enabled);
  }
  
  #define define_one_rw(_name) \
  static struct freq_attr _name = \
  __ATTR(_name, 0644, show_##_name, store_##_name)
  
  define_one_rw(cpb);
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1499
  static struct freq_attr *powernow_k8_attr[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1500
  	&cpufreq_freq_attr_scaling_available_freqs,
73860c6b2   Borislav Petkov   powernow-k8: Add ...
1501
  	&cpb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1502
1503
  	NULL,
  };
221dee285   Linus Torvalds   Revert "[CPUFREQ]...
1504
  static struct cpufreq_driver cpufreq_amd64_driver = {
e2f74f355   Thomas Renninger   [ACPI/CPUFREQ] In...
1505
1506
1507
1508
1509
1510
1511
1512
1513
  	.verify		= powernowk8_verify,
  	.target		= powernowk8_target,
  	.bios_limit	= acpi_processor_get_bios_limit,
  	.init		= powernowk8_cpu_init,
  	.exit		= __devexit_p(powernowk8_cpu_exit),
  	.get		= powernowk8_get,
  	.name		= "powernow-k8",
  	.owner		= THIS_MODULE,
  	.attr		= powernow_k8_attr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1514
  };
73860c6b2   Borislav Petkov   powernow-k8: Add ...
1515
1516
1517
1518
1519
1520
  /*
   * Clear the boost-disable flag on the CPU_DOWN path so that this cpu
   * cannot block the remaining ones from boosting. On the CPU_UP path we
   * simply keep the boost-disable flag in sync with the current global
   * state.
   */
fe501f1e8   Borislav Petkov   x86, k8: Fix sect...
1521
1522
  static int cpb_notify(struct notifier_block *nb, unsigned long action,
  		      void *hcpu)
73860c6b2   Borislav Petkov   powernow-k8: Add ...
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
  {
  	unsigned cpu = (long)hcpu;
  	u32 lo, hi;
  
  	switch (action) {
  	case CPU_UP_PREPARE:
  	case CPU_UP_PREPARE_FROZEN:
  
  		if (!cpb_enabled) {
  			rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi);
  			lo |= BIT(25);
  			wrmsr_on_cpu(cpu, MSR_K7_HWCR, lo, hi);
  		}
  		break;
  
  	case CPU_DOWN_PREPARE:
  	case CPU_DOWN_PREPARE_FROZEN:
  		rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi);
  		lo &= ~BIT(25);
  		wrmsr_on_cpu(cpu, MSR_K7_HWCR, lo, hi);
  		break;
  
  	default:
  		break;
  	}
  
  	return NOTIFY_OK;
  }
fe501f1e8   Borislav Petkov   x86, k8: Fix sect...
1551
  static struct notifier_block cpb_nb = {
73860c6b2   Borislav Petkov   powernow-k8: Add ...
1552
1553
  	.notifier_call		= cpb_notify,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1554
  /* driver entry point for init */
aa41eb991   Andi Kleen   [PATCH] x86_64: M...
1555
  static int __cpuinit powernowk8_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1556
  {
73860c6b2   Borislav Petkov   powernow-k8: Add ...
1557
  	unsigned int i, supported_cpus = 0, cpu;
ac8183144   Neil Brown   [CPUFREQ] Missing...
1558
  	int rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559

a72011567   Andrew Morton   [PATCH] more-for_...
1560
  	for_each_online_cpu(i) {
1ff6e97f1   Rusty Russell   [CPUFREQ] cpumask...
1561
1562
1563
  		int rc;
  		smp_call_function_single(i, check_supported_cpu, &rc, 1);
  		if (rc == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1564
1565
  			supported_cpus++;
  	}
73860c6b2   Borislav Petkov   powernow-k8: Add ...
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
  	if (supported_cpus != num_online_cpus())
  		return -ENODEV;
  
  	printk(KERN_INFO PFX "Found %d %s (%d cpu cores) (" VERSION ")
  ",
  		num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus);
  
  	if (boot_cpu_has(X86_FEATURE_CPB)) {
  
  		cpb_capable = true;
73860c6b2   Borislav Petkov   powernow-k8: Add ...
1576
1577
1578
1579
1580
1581
  		msrs = msrs_alloc();
  		if (!msrs) {
  			printk(KERN_ERR "%s: Error allocating msrs!
  ", __func__);
  			return -ENOMEM;
  		}
a536b126f   Dave Jones   [CPUFREQ] Fix ano...
1582
  		register_cpu_notifier(&cpb_nb);
73860c6b2   Borislav Petkov   powernow-k8: Add ...
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
  		rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
  
  		for_each_cpu(cpu, cpu_online_mask) {
  			struct msr *reg = per_cpu_ptr(msrs, cpu);
  			cpb_enabled |= !(!!(reg->l & BIT(25)));
  		}
  
  		printk(KERN_INFO PFX "Core Performance Boosting: %s.
  ",
  			(cpb_enabled ? "on" : "off"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1593
  	}
ac8183144   Neil Brown   [CPUFREQ] Missing...
1594
1595
1596
1597
1598
1599
1600
  	rv = cpufreq_register_driver(&cpufreq_amd64_driver);
  	if (rv < 0 && boot_cpu_has(X86_FEATURE_CPB)) {
  		unregister_cpu_notifier(&cpb_nb);
  		msrs_free(msrs);
  		msrs = NULL;
  	}
  	return rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
1602
1603
1604
1605
  }
  
  /* driver entry point for term */
  static void __exit powernowk8_exit(void)
  {
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
1606
1607
  	pr_debug("exit
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1608

73860c6b2   Borislav Petkov   powernow-k8: Add ...
1609
1610
1611
1612
1613
1614
  	if (boot_cpu_has(X86_FEATURE_CPB)) {
  		msrs_free(msrs);
  		msrs = NULL;
  
  		unregister_cpu_notifier(&cpb_nb);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615
1616
  	cpufreq_unregister_driver(&cpufreq_amd64_driver);
  }
0e64a0c98   Dave Jones   [CPUFREQ] checkpa...
1617
1618
  MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com> and "
  		"Mark Langsdorf <mark.langsdorf@amd.com>");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
1620
1621
1622
1623
  MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver.");
  MODULE_LICENSE("GPL");
  
  late_initcall(powernowk8_init);
  module_exit(powernowk8_exit);