Blame view
drivers/cpufreq/powernow-k8.c
30.4 KB
4f19048fd treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
1da177e4c Linux-2.6.12-rc2 |
2 |
/* |
b2bd68e1d [CPUFREQ] powerno... |
3 |
* (c) 2003-2012 Advanced Micro Devices, Inc. |
1da177e4c Linux-2.6.12-rc2 |
4 |
* |
b2bd68e1d [CPUFREQ] powerno... |
5 |
* Maintainer: |
29c4bcdda cpufreq / powerno... |
6 |
* Andreas Herrmann <herrmann.der.user@googlemail.com> |
1da177e4c Linux-2.6.12-rc2 |
7 8 |
* * Based on the powernow-k7.c module written by Dave Jones. |
f4432c5ca Update email addr... |
9 |
* (C) 2003 Dave Jones on behalf of SuSE Labs |
1da177e4c Linux-2.6.12-rc2 |
10 |
* (C) 2004 Dominik Brodowski <linux@brodo.de> |
a2531293d update email address |
11 |
* (C) 2004 Pavel Machek <pavel@ucw.cz> |
1da177e4c Linux-2.6.12-rc2 |
12 13 14 |
* Based upon datasheets & sample CPUs kindly provided by AMD. * * Valuable input gratefully received from Dave Jones, Pavel Machek, |
1f729e066 [CPUFREQ] Prepare... |
15 |
* Dominik Brodowski, Jacob Shin, and others. |
065b807ca [CPUFREQ] dual-co... |
16 |
* Originally developed by Paul Devriendt. |
1da177e4c Linux-2.6.12-rc2 |
17 |
* |
b2bd68e1d [CPUFREQ] powerno... |
18 19 20 21 22 23 24 |
* 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 Linux-2.6.12-rc2 |
25 |
*/ |
e54173b4e cpufreq: powernow... |
26 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
27 28 29 30 31 32 33 |
#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 [CPUFREQ] dual-co... |
34 |
#include <linux/cpumask.h> |
0e64a0c98 [CPUFREQ] checkpa... |
35 36 |
#include <linux/io.h> #include <linux/delay.h> |
1da177e4c Linux-2.6.12-rc2 |
37 38 |
#include <asm/msr.h> |
fa8031aef cpufreq: Add supp... |
39 |
#include <asm/cpu_device_id.h> |
1da177e4c Linux-2.6.12-rc2 |
40 |
|
1da177e4c Linux-2.6.12-rc2 |
41 |
#include <linux/acpi.h> |
14cc3e2b6 [PATCH] sem2mutex... |
42 |
#include <linux/mutex.h> |
1da177e4c Linux-2.6.12-rc2 |
43 |
#include <acpi/processor.h> |
1da177e4c Linux-2.6.12-rc2 |
44 |
|
c5829cd07 [CPUFREQ] archite... |
45 |
#define VERSION "version 2.20.00" |
1da177e4c Linux-2.6.12-rc2 |
46 47 48 |
#include "powernow-k8.h" /* serialize freq changes */ |
14cc3e2b6 [PATCH] sem2mutex... |
49 |
static DEFINE_MUTEX(fidvid_mutex); |
1da177e4c Linux-2.6.12-rc2 |
50 |
|
2c6b8c030 x86: change NR_CP... |
51 |
static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data); |
1da177e4c Linux-2.6.12-rc2 |
52 |
|
a2fed573f x86, cpufreq: Add... |
53 |
static struct cpufreq_driver cpufreq_amd64_driver; |
1da177e4c Linux-2.6.12-rc2 |
54 55 56 57 58 59 60 61 62 63 64 |
/* 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); } |
1da177e4c Linux-2.6.12-rc2 |
65 66 67 68 69 70 71 72 |
/* 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 [CPUFREQ] Lots of... |
73 |
if (fid < HI_FID_TABLE_BOTTOM) |
1da177e4c Linux-2.6.12-rc2 |
74 |
return 8 + (2 * fid); |
32ee8c3e4 [CPUFREQ] Lots of... |
75 |
else |
1da177e4c Linux-2.6.12-rc2 |
76 |
return fid; |
1da177e4c Linux-2.6.12-rc2 |
77 78 79 80 81 82 83 84 |
} /* * 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) { |
638b50979 cpufreq: powernow... |
85 |
u32 lo, hi __always_unused; |
1da177e4c Linux-2.6.12-rc2 |
86 87 88 89 90 91 92 93 94 95 96 97 98 |
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; |
7153d9612 powernow-k8.c: In... |
99 |
do { |
0213df743 [PATCH] cpufreq: ... |
100 |
if (i++ > 10000) { |
2d06d8c49 [CPUFREQ] use dyn... |
101 102 |
pr_debug("detected change pending stuck "); |
1da177e4c Linux-2.6.12-rc2 |
103 104 105 |
return 1; } rdmsr(MSR_FIDVID_STATUS, lo, hi); |
7153d9612 powernow-k8.c: In... |
106 |
} while (lo & MSR_S_LO_CHANGE_PENDING); |
1da177e4c Linux-2.6.12-rc2 |
107 108 109 110 111 112 113 114 115 116 117 |
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); |
1da177e4c Linux-2.6.12-rc2 |
118 |
} |
27b46d766 spelling fixes: a... |
119 |
/* the voltage stabilization time */ |
1da177e4c Linux-2.6.12-rc2 |
120 121 122 |
static void count_off_vst(struct powernow_k8_data *data) { udelay(data->vstable * VST_UNITS_20US); |
1da177e4c Linux-2.6.12-rc2 |
123 124 125 126 127 128 129 130 131 132 133 134 135 |
} /* 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 [CPUFREQ] use dyn... |
136 137 |
pr_debug("cpu%d, init lo 0x%x, hi 0x%x ", smp_processor_id(), lo, hi); |
1da177e4c Linux-2.6.12-rc2 |
138 139 |
wrmsr(MSR_FIDVID_CTL, lo, hi); } |
1da177e4c Linux-2.6.12-rc2 |
140 141 142 143 144 |
/* 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 [PATCH] cpufreq: ... |
145 |
u32 i = 0; |
1da177e4c Linux-2.6.12-rc2 |
146 147 |
if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) { |
e54173b4e cpufreq: powernow... |
148 149 |
pr_err("internal error - overflow on fid write "); |
1da177e4c Linux-2.6.12-rc2 |
150 151 |
return 1; } |
0e64a0c98 [CPUFREQ] checkpa... |
152 153 154 |
lo = fid; lo |= (data->currvid << MSR_C_LO_VID_SHIFT); lo |= MSR_C_LO_INIT_FID_VID; |
1da177e4c Linux-2.6.12-rc2 |
155 |
|
2d06d8c49 [CPUFREQ] use dyn... |
156 157 |
pr_debug("writing fid 0x%x, lo 0x%x, hi 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
158 |
fid, lo, data->plllock * PLL_LOCK_CONVERSION); |
0213df743 [PATCH] cpufreq: ... |
159 160 161 |
do { wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION); if (i++ > 100) { |
e54173b4e cpufreq: powernow... |
162 163 |
pr_err("Hardware error - pending bit very stuck - no further pstate changes possible "); |
63172cb3d [PATCH] typo fix ... |
164 |
return 1; |
32ee8c3e4 [CPUFREQ] Lots of... |
165 |
} |
0213df743 [PATCH] cpufreq: ... |
166 |
} while (query_current_values_with_pending_wait(data)); |
1da177e4c Linux-2.6.12-rc2 |
167 168 169 170 |
count_off_irt(data); if (savevid != data->currvid) { |
e54173b4e cpufreq: powernow... |
171 172 173 |
pr_err("vid change on fid trans, old 0x%x, new 0x%x ", savevid, data->currvid); |
1da177e4c Linux-2.6.12-rc2 |
174 175 176 177 |
return 1; } if (fid != data->currfid) { |
e54173b4e cpufreq: powernow... |
178 179 |
pr_err("fid trans failed, fid 0x%x, curr 0x%x ", fid, |
0e64a0c98 [CPUFREQ] checkpa... |
180 |
data->currfid); |
1da177e4c Linux-2.6.12-rc2 |
181 182 183 184 185 186 187 188 189 190 191 |
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 [PATCH] cpufreq: ... |
192 |
int i = 0; |
1da177e4c Linux-2.6.12-rc2 |
193 194 |
if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) { |
e54173b4e cpufreq: powernow... |
195 196 |
pr_err("internal error - overflow on vid write "); |
1da177e4c Linux-2.6.12-rc2 |
197 198 |
return 1; } |
0e64a0c98 [CPUFREQ] checkpa... |
199 200 201 |
lo = data->currfid; lo |= (vid << MSR_C_LO_VID_SHIFT); lo |= MSR_C_LO_INIT_FID_VID; |
1da177e4c Linux-2.6.12-rc2 |
202 |
|
2d06d8c49 [CPUFREQ] use dyn... |
203 204 |
pr_debug("writing vid 0x%x, lo 0x%x, hi 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
205 |
vid, lo, STOP_GRANT_5NS); |
0213df743 [PATCH] cpufreq: ... |
206 207 |
do { wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS); |
6df890067 [CPUFREQ] Fix ind... |
208 |
if (i++ > 100) { |
e54173b4e cpufreq: powernow... |
209 210 |
pr_err("internal error - pending bit very stuck - no further pstate changes possible "); |
6df890067 [CPUFREQ] Fix ind... |
211 212 |
return 1; } |
0213df743 [PATCH] cpufreq: ... |
213 |
} while (query_current_values_with_pending_wait(data)); |
1da177e4c Linux-2.6.12-rc2 |
214 215 |
if (savefid != data->currfid) { |
e54173b4e cpufreq: powernow... |
216 217 218 |
pr_err("fid changed on vid trans, old 0x%x new 0x%x ", savefid, data->currfid); |
1da177e4c Linux-2.6.12-rc2 |
219 220 221 222 |
return 1; } if (vid != data->currvid) { |
e54173b4e cpufreq: powernow... |
223 224 |
pr_err("vid trans failed, vid 0x%x, curr 0x%x ", |
0e64a0c98 [CPUFREQ] checkpa... |
225 |
vid, data->currvid); |
1da177e4c Linux-2.6.12-rc2 |
226 227 228 229 230 231 232 233 234 |
return 1; } return 0; } /* * Reduce the vid by the max of step or reqvid. * Decreasing vid codes represent increasing voltages: |
841e40b38 Opteron revision ... |
235 |
* vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of VID_OFF is off. |
1da177e4c Linux-2.6.12-rc2 |
236 |
*/ |
0e64a0c98 [CPUFREQ] checkpa... |
237 238 |
static int decrease_vid_code_by_step(struct powernow_k8_data *data, u32 reqvid, u32 step) |
1da177e4c Linux-2.6.12-rc2 |
239 240 241 242 243 244 245 246 247 248 249 |
{ if ((data->currvid - reqvid) > step) reqvid = data->currvid - step; if (write_new_vid(data, reqvid)) return 1; count_off_vst(data); return 0; } |
1f729e066 [CPUFREQ] Prepare... |
250 |
/* Change Opteron/Athlon64 fid and vid, by the 3 phases. */ |
0e64a0c98 [CPUFREQ] checkpa... |
251 252 |
static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 reqvid) |
1da177e4c Linux-2.6.12-rc2 |
253 |
{ |
a2e1b4c31 [CPUFREQ] Powerno... |
254 |
if (core_voltage_pre_transition(data, reqvid, reqfid)) |
1da177e4c Linux-2.6.12-rc2 |
255 256 257 258 259 260 261 262 263 264 265 266 |
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)) { |
e54173b4e cpufreq: powernow... |
267 268 |
pr_err("failed (cpu%d): req 0x%x 0x%x, curr 0x%x 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
269 270 271 272 |
smp_processor_id(), reqfid, reqvid, data->currfid, data->currvid); return 1; } |
2d06d8c49 [CPUFREQ] use dyn... |
273 274 |
pr_debug("transitioned (cpu%d): new fid 0x%x, vid 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
275 276 277 278 279 280 |
smp_processor_id(), data->currfid, data->currvid); return 0; } /* Phase 1 - core voltage transition ... setup voltage */ |
0e64a0c98 [CPUFREQ] checkpa... |
281 |
static int core_voltage_pre_transition(struct powernow_k8_data *data, |
a2e1b4c31 [CPUFREQ] Powerno... |
282 |
u32 reqvid, u32 reqfid) |
1da177e4c Linux-2.6.12-rc2 |
283 284 285 |
{ u32 rvosteps = data->rvo; u32 savefid = data->currfid; |
638b50979 cpufreq: powernow... |
286 |
u32 maxvid, lo __always_unused, rvomult = 1; |
1da177e4c Linux-2.6.12-rc2 |
287 |
|
e54173b4e cpufreq: powernow... |
288 289 |
pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
290 291 |
smp_processor_id(), data->currfid, data->currvid, reqvid, data->rvo); |
a2e1b4c31 [CPUFREQ] Powerno... |
292 293 294 |
if ((savefid < LO_FID_TABLE_TOP) && (reqfid < LO_FID_TABLE_TOP)) rvomult = 2; rvosteps *= rvomult; |
065b807ca [CPUFREQ] dual-co... |
295 296 |
rdmsr(MSR_FIDVID_STATUS, lo, maxvid); maxvid = 0x1f & (maxvid >> 16); |
2d06d8c49 [CPUFREQ] use dyn... |
297 298 |
pr_debug("ph1 maxvid=0x%x ", maxvid); |
065b807ca [CPUFREQ] dual-co... |
299 300 |
if (reqvid < maxvid) /* lower numbers are higher voltages */ reqvid = maxvid; |
1da177e4c Linux-2.6.12-rc2 |
301 |
while (data->currvid > reqvid) { |
2d06d8c49 [CPUFREQ] use dyn... |
302 303 |
pr_debug("ph1: curr 0x%x, req vid 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
304 305 306 307 |
data->currvid, reqvid); if (decrease_vid_code_by_step(data, reqvid, data->vidmvs)) return 1; } |
a2e1b4c31 [CPUFREQ] Powerno... |
308 309 |
while ((rvosteps > 0) && ((rvomult * data->rvo + data->currvid) > reqvid)) { |
065b807ca [CPUFREQ] dual-co... |
310 |
if (data->currvid == maxvid) { |
1da177e4c Linux-2.6.12-rc2 |
311 312 |
rvosteps = 0; } else { |
2d06d8c49 [CPUFREQ] use dyn... |
313 314 |
pr_debug("ph1: changing vid for rvo, req 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
315 |
data->currvid - 1); |
0e64a0c98 [CPUFREQ] checkpa... |
316 |
if (decrease_vid_code_by_step(data, data->currvid-1, 1)) |
1da177e4c Linux-2.6.12-rc2 |
317 318 319 320 321 322 323 324 325 |
return 1; rvosteps--; } } if (query_current_values_with_pending_wait(data)) return 1; if (savefid != data->currfid) { |
e54173b4e cpufreq: powernow... |
326 327 |
pr_err("ph1 err, currfid changed 0x%x ", data->currfid); |
1da177e4c Linux-2.6.12-rc2 |
328 329 |
return 1; } |
2d06d8c49 [CPUFREQ] use dyn... |
330 331 |
pr_debug("ph1 complete, currfid 0x%x, currvid 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
332 333 334 335 336 337 338 339 |
data->currfid, data->currvid); return 0; } /* Phase 2 - core frequency transition */ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) { |
0e64a0c98 [CPUFREQ] checkpa... |
340 341 |
u32 vcoreqfid, vcocurrfid, vcofiddiff; u32 fid_interval, savevid = data->currvid; |
1da177e4c Linux-2.6.12-rc2 |
342 |
|
1da177e4c Linux-2.6.12-rc2 |
343 |
if (data->currfid == reqfid) { |
e54173b4e cpufreq: powernow... |
344 345 |
pr_err("ph2 null fid transition 0x%x ", data->currfid); |
1da177e4c Linux-2.6.12-rc2 |
346 347 |
return 0; } |
e54173b4e cpufreq: powernow... |
348 349 |
pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
350 351 352 353 354 355 356 |
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 [CPUFREQ] Powerno... |
357 358 |
if ((reqfid <= LO_FID_TABLE_TOP) && (data->currfid <= LO_FID_TABLE_TOP)) vcofiddiff = 0; |
1da177e4c Linux-2.6.12-rc2 |
359 |
while (vcofiddiff > 2) { |
019a61b99 [PATCH] Support 1... |
360 |
(data->currfid & 1) ? (fid_interval = 1) : (fid_interval = 2); |
1da177e4c Linux-2.6.12-rc2 |
361 362 |
if (reqfid > data->currfid) { if (data->currfid > LO_FID_TABLE_TOP) { |
0e64a0c98 [CPUFREQ] checkpa... |
363 364 |
if (write_new_fid(data, data->currfid + fid_interval)) |
1da177e4c Linux-2.6.12-rc2 |
365 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
366 367 |
} else { if (write_new_fid |
0e64a0c98 [CPUFREQ] checkpa... |
368 369 |
(data, 2 + convert_fid_to_vco_fid(data->currfid))) |
1da177e4c Linux-2.6.12-rc2 |
370 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
371 372 |
} } else { |
019a61b99 [PATCH] Support 1... |
373 |
if (write_new_fid(data, data->currfid - fid_interval)) |
1da177e4c Linux-2.6.12-rc2 |
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 |
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) { |
e54173b4e cpufreq: powernow... |
389 390 |
pr_err("ph2: mismatch, failed fid transition, curr 0x%x, req 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
391 392 393 394 395 |
data->currfid, reqfid); return 1; } if (savevid != data->currvid) { |
e54173b4e cpufreq: powernow... |
396 397 |
pr_err("ph2: vid changed, save 0x%x, curr 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
398 399 400 |
savevid, data->currvid); return 1; } |
2d06d8c49 [CPUFREQ] use dyn... |
401 402 |
pr_debug("ph2 complete, currfid 0x%x, currvid 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
403 404 405 406 407 408 |
data->currfid, data->currvid); return 0; } /* Phase 3 - core voltage transition flow ... jump to the final vid. */ |
0e64a0c98 [CPUFREQ] checkpa... |
409 410 |
static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid) |
1da177e4c Linux-2.6.12-rc2 |
411 412 413 |
{ u32 savefid = data->currfid; u32 savereqvid = reqvid; |
2d06d8c49 [CPUFREQ] use dyn... |
414 415 |
pr_debug("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
416 417 418 419 420 421 422 423 |
smp_processor_id(), data->currfid, data->currvid); if (reqvid != data->currvid) { if (write_new_vid(data, reqvid)) return 1; if (savefid != data->currfid) { |
e54173b4e cpufreq: powernow... |
424 425 426 |
pr_err("ph3: bad fid change, save 0x%x, curr 0x%x ", savefid, data->currfid); |
1da177e4c Linux-2.6.12-rc2 |
427 428 429 430 |
return 1; } if (data->currvid != reqvid) { |
e54173b4e cpufreq: powernow... |
431 432 433 |
pr_err("ph3: failed vid transition , req 0x%x, curr 0x%x", reqvid, data->currvid); |
1da177e4c Linux-2.6.12-rc2 |
434 435 436 437 438 439 440 441 |
return 1; } } if (query_current_values_with_pending_wait(data)) return 1; if (savereqvid != data->currvid) { |
2d06d8c49 [CPUFREQ] use dyn... |
442 443 |
pr_debug("ph3 failed, currvid 0x%x ", data->currvid); |
1da177e4c Linux-2.6.12-rc2 |
444 445 446 447 |
return 1; } if (savefid != data->currfid) { |
2d06d8c49 [CPUFREQ] use dyn... |
448 449 |
pr_debug("ph3 failed, currfid changed 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
450 451 452 |
data->currfid); return 1; } |
2d06d8c49 [CPUFREQ] use dyn... |
453 454 |
pr_debug("ph3 complete, currfid 0x%x, currvid 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
455 456 457 458 |
data->currfid, data->currvid); return 0; } |
fa8031aef cpufreq: Add supp... |
459 460 |
static const struct x86_cpu_id powernow_k8_ids[] = { /* IO based frequency switching */ |
b11d77fa3 cpufreq: Convert ... |
461 |
X86_MATCH_VENDOR_FAM(AMD, 0xf, NULL), |
fa8031aef cpufreq: Add supp... |
462 463 464 |
{} }; MODULE_DEVICE_TABLE(x86cpu, powernow_k8_ids); |
1ff6e97f1 [CPUFREQ] cpumask... |
465 |
static void check_supported_cpu(void *_rc) |
1da177e4c Linux-2.6.12-rc2 |
466 |
{ |
1da177e4c Linux-2.6.12-rc2 |
467 |
u32 eax, ebx, ecx, edx; |
1ff6e97f1 [CPUFREQ] cpumask... |
468 |
int *rc = _rc; |
1da177e4c Linux-2.6.12-rc2 |
469 |
|
1ff6e97f1 [CPUFREQ] cpumask... |
470 |
*rc = -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
471 |
|
1da177e4c Linux-2.6.12-rc2 |
472 |
eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); |
2c906ae67 [CPUFREQ] Silence... |
473 |
|
1f729e066 [CPUFREQ] Prepare... |
474 475 |
if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) { if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) || |
99fbe1ac2 [CPUFREQ] Correct... |
476 |
((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) { |
e54173b4e cpufreq: powernow... |
477 478 |
pr_info("Processor cpuid %x not supported ", eax); |
1ff6e97f1 [CPUFREQ] cpumask... |
479 |
return; |
1f729e066 [CPUFREQ] Prepare... |
480 |
} |
1da177e4c Linux-2.6.12-rc2 |
481 |
|
1f729e066 [CPUFREQ] Prepare... |
482 483 |
eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES); if (eax < CPUID_FREQ_VOLT_CAPABILITIES) { |
e54173b4e cpufreq: powernow... |
484 485 |
pr_info("No frequency change capabilities detected "); |
1ff6e97f1 [CPUFREQ] cpumask... |
486 |
return; |
1f729e066 [CPUFREQ] Prepare... |
487 |
} |
1da177e4c Linux-2.6.12-rc2 |
488 |
|
1f729e066 [CPUFREQ] Prepare... |
489 |
cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); |
0e64a0c98 [CPUFREQ] checkpa... |
490 491 |
if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) { |
e54173b4e cpufreq: powernow... |
492 493 |
pr_info("Power state transitions not supported "); |
1ff6e97f1 [CPUFREQ] cpumask... |
494 |
return; |
1f729e066 [CPUFREQ] Prepare... |
495 |
} |
e1f0b8e9b cpufreq: Remove s... |
496 |
*rc = 0; |
1da177e4c Linux-2.6.12-rc2 |
497 |
} |
1da177e4c Linux-2.6.12-rc2 |
498 |
} |
0e64a0c98 [CPUFREQ] checkpa... |
499 500 |
static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid) |
1da177e4c Linux-2.6.12-rc2 |
501 502 503 504 505 506 |
{ unsigned int j; u8 lastfid = 0xff; for (j = 0; j < data->numps; j++) { if (pst[j].vid > LEAST_VID) { |
e54173b4e cpufreq: powernow... |
507 508 509 |
pr_err(FW_BUG "vid %d invalid : 0x%x ", j, pst[j].vid); |
1da177e4c Linux-2.6.12-rc2 |
510 511 |
return -EINVAL; } |
0e64a0c98 [CPUFREQ] checkpa... |
512 513 |
if (pst[j].vid < data->rvo) { /* vid + rvo >= 0 */ |
e54173b4e cpufreq: powernow... |
514 515 |
pr_err(FW_BUG "0 vid exceeded with pstate %d ", j); |
1da177e4c Linux-2.6.12-rc2 |
516 517 |
return -ENODEV; } |
0e64a0c98 [CPUFREQ] checkpa... |
518 519 |
if (pst[j].vid < maxvid + data->rvo) { /* vid + rvo >= maxvid */ |
e54173b4e cpufreq: powernow... |
520 521 |
pr_err(FW_BUG "maxvid exceeded with pstate %d ", j); |
1da177e4c Linux-2.6.12-rc2 |
522 523 |
return -ENODEV; } |
8aae8284f [CPUFREQ] Improve... |
524 |
if (pst[j].fid > MAX_FID) { |
e54173b4e cpufreq: powernow... |
525 526 |
pr_err(FW_BUG "maxfid exceeded with pstate %d ", j); |
8aae8284f [CPUFREQ] Improve... |
527 528 |
return -ENODEV; } |
8aae8284f [CPUFREQ] Improve... |
529 |
if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) { |
1da177e4c Linux-2.6.12-rc2 |
530 |
/* Only first fid is allowed to be in "low" range */ |
e54173b4e cpufreq: powernow... |
531 532 533 |
pr_err(FW_BUG "two low fids - %d : 0x%x ", j, pst[j].fid); |
1da177e4c Linux-2.6.12-rc2 |
534 535 536 537 538 539 |
return -EINVAL; } if (pst[j].fid < lastfid) lastfid = pst[j].fid; } if (lastfid & 1) { |
e54173b4e cpufreq: powernow... |
540 541 |
pr_err(FW_BUG "lastfid invalid "); |
1da177e4c Linux-2.6.12-rc2 |
542 543 544 |
return -EINVAL; } if (lastfid > LO_FID_TABLE_TOP) |
e54173b4e cpufreq: powernow... |
545 546 |
pr_info(FW_BUG "first fid not from lo freq table "); |
1da177e4c Linux-2.6.12-rc2 |
547 548 549 |
return 0; } |
f0adb134d [CPUFREQ] Fix NUL... |
550 551 |
static void invalidate_entry(struct cpufreq_frequency_table *powernow_table, unsigned int entry) |
0e64a0c98 [CPUFREQ] checkpa... |
552 |
{ |
f0adb134d [CPUFREQ] Fix NUL... |
553 |
powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID; |
0e64a0c98 [CPUFREQ] checkpa... |
554 |
} |
1da177e4c Linux-2.6.12-rc2 |
555 556 557 558 |
static void print_basics(struct powernow_k8_data *data) { int j; for (j = 0; j < data->numps; j++) { |
0e64a0c98 [CPUFREQ] checkpa... |
559 560 |
if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID) { |
e54173b4e cpufreq: powernow... |
561 562 563 564 565 |
pr_info("fid 0x%x (%d MHz), vid 0x%x ", data->powernow_table[j].driver_data & 0xff, data->powernow_table[j].frequency/1000, data->powernow_table[j].driver_data >> 8); |
1f729e066 [CPUFREQ] Prepare... |
566 |
} |
1da177e4c Linux-2.6.12-rc2 |
567 568 |
} if (data->batps) |
e54173b4e cpufreq: powernow... |
569 570 |
pr_info("Only %d pstates on battery ", data->batps); |
1da177e4c Linux-2.6.12-rc2 |
571 |
} |
0e64a0c98 [CPUFREQ] checkpa... |
572 573 |
static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid) |
1da177e4c Linux-2.6.12-rc2 |
574 575 576 |
{ struct cpufreq_frequency_table *powernow_table; unsigned int j; |
0e64a0c98 [CPUFREQ] checkpa... |
577 578 |
if (data->batps) { /* use ACPI support to get full speed on mains power */ |
e54173b4e cpufreq: powernow... |
579 580 581 |
pr_warn("Only %d pstates usable (use ACPI driver for full range ", data->batps); |
1da177e4c Linux-2.6.12-rc2 |
582 583 |
data->numps = data->batps; } |
0e64a0c98 [CPUFREQ] checkpa... |
584 |
for (j = 1; j < data->numps; j++) { |
1da177e4c Linux-2.6.12-rc2 |
585 |
if (pst[j-1].fid >= pst[j].fid) { |
e54173b4e cpufreq: powernow... |
586 587 |
pr_err("PST out of sequence "); |
1da177e4c Linux-2.6.12-rc2 |
588 589 590 591 592 |
return -EINVAL; } } if (data->numps < 2) { |
e54173b4e cpufreq: powernow... |
593 594 |
pr_err("no p states to transition "); |
1da177e4c Linux-2.6.12-rc2 |
595 596 597 598 599 |
return -ENODEV; } if (check_pst_table(data, pst, maxvid)) return -EINVAL; |
71508a1f4 cpufreq: use kzal... |
600 |
powernow_table = kzalloc((sizeof(*powernow_table) |
1da177e4c Linux-2.6.12-rc2 |
601 |
* (data->numps + 1)), GFP_KERNEL); |
7f3a1d66d cpufreq: powernow... |
602 |
if (!powernow_table) |
1da177e4c Linux-2.6.12-rc2 |
603 |
return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
604 605 |
for (j = 0; j < data->numps; j++) { |
0e64a0c98 [CPUFREQ] checkpa... |
606 |
int freq; |
507015880 cpufreq: rename i... |
607 608 |
powernow_table[j].driver_data = pst[j].fid; /* lower 8 bits */ powernow_table[j].driver_data |= (pst[j].vid << 8); /* upper 8 bits */ |
0e64a0c98 [CPUFREQ] checkpa... |
609 610 |
freq = find_khz_freq_from_fid(pst[j].fid); powernow_table[j].frequency = freq; |
1da177e4c Linux-2.6.12-rc2 |
611 612 |
} powernow_table[data->numps].frequency = CPUFREQ_TABLE_END; |
507015880 cpufreq: rename i... |
613 |
powernow_table[data->numps].driver_data = 0; |
1da177e4c Linux-2.6.12-rc2 |
614 615 616 617 618 |
if (query_current_values_with_pending_wait(data)) { kfree(powernow_table); return -EIO; } |
2d06d8c49 [CPUFREQ] use dyn... |
619 620 |
pr_debug("cfid 0x%x, cvid 0x%x ", data->currfid, data->currvid); |
1da177e4c Linux-2.6.12-rc2 |
621 |
data->powernow_table = powernow_table; |
38c52e634 powernow-k8: Repl... |
622 |
if (cpumask_first(topology_core_cpumask(data->cpu)) == data->cpu) |
2e4976206 [CPUFREQ] Report ... |
623 |
print_basics(data); |
1da177e4c Linux-2.6.12-rc2 |
624 625 |
for (j = 0; j < data->numps; j++) |
0e64a0c98 [CPUFREQ] checkpa... |
626 627 |
if ((pst[j].fid == data->currfid) && (pst[j].vid == data->currvid)) |
1da177e4c Linux-2.6.12-rc2 |
628 |
return 0; |
2d06d8c49 [CPUFREQ] use dyn... |
629 630 |
pr_debug("currfid/vid do not match PST, ignoring "); |
1da177e4c Linux-2.6.12-rc2 |
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 |
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 [CPUFREQ] use dyn... |
651 652 |
pr_debug("found PSB header at 0x%p ", psb); |
1da177e4c Linux-2.6.12-rc2 |
653 |
|
2d06d8c49 [CPUFREQ] use dyn... |
654 655 |
pr_debug("table vers: 0x%x ", psb->tableversion); |
1da177e4c Linux-2.6.12-rc2 |
656 |
if (psb->tableversion != PSB_VERSION_1_4) { |
e54173b4e cpufreq: powernow... |
657 658 |
pr_err(FW_BUG "PSB table is not v1.4 "); |
1da177e4c Linux-2.6.12-rc2 |
659 660 |
return -ENODEV; } |
2d06d8c49 [CPUFREQ] use dyn... |
661 662 |
pr_debug("flags: 0x%x ", psb->flags1); |
1da177e4c Linux-2.6.12-rc2 |
663 |
if (psb->flags1) { |
e54173b4e cpufreq: powernow... |
664 665 |
pr_err(FW_BUG "unknown flags "); |
1da177e4c Linux-2.6.12-rc2 |
666 667 668 669 |
return -ENODEV; } data->vstable = psb->vstable; |
2d06d8c49 [CPUFREQ] use dyn... |
670 671 |
pr_debug("voltage stabilization time: %d(*20us) ", |
0e64a0c98 [CPUFREQ] checkpa... |
672 |
data->vstable); |
1da177e4c Linux-2.6.12-rc2 |
673 |
|
2d06d8c49 [CPUFREQ] use dyn... |
674 675 |
pr_debug("flags2: 0x%x ", psb->flags2); |
1da177e4c Linux-2.6.12-rc2 |
676 677 678 679 680 |
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 [CPUFREQ] use dyn... |
681 682 683 684 685 686 |
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 Linux-2.6.12-rc2 |
687 |
|
2d06d8c49 [CPUFREQ] use dyn... |
688 689 |
pr_debug("numpst: 0x%x ", psb->num_tables); |
1da177e4c Linux-2.6.12-rc2 |
690 |
cpst = psb->num_tables; |
0e64a0c98 [CPUFREQ] checkpa... |
691 692 |
if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0)) { |
1da177e4c Linux-2.6.12-rc2 |
693 |
thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); |
0e64a0c98 [CPUFREQ] checkpa... |
694 695 |
if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0)) |
1da177e4c Linux-2.6.12-rc2 |
696 |
cpst = 1; |
1da177e4c Linux-2.6.12-rc2 |
697 698 |
} if (cpst != 1) { |
e54173b4e cpufreq: powernow... |
699 700 |
pr_err(FW_BUG "numpst must be 1 "); |
1da177e4c Linux-2.6.12-rc2 |
701 702 703 704 |
return -ENODEV; } data->plllock = psb->plllocktime; |
2d06d8c49 [CPUFREQ] use dyn... |
705 706 707 708 709 710 |
pr_debug("plllocktime: 0x%x (units 1us) ", psb->plllocktime); pr_debug("maxfid: 0x%x ", psb->maxfid); pr_debug("maxvid: 0x%x ", psb->maxvid); |
1da177e4c Linux-2.6.12-rc2 |
711 712 713 |
maxvid = psb->maxvid; data->numps = psb->numps; |
2d06d8c49 [CPUFREQ] use dyn... |
714 715 |
pr_debug("numpstates: 0x%x ", data->numps); |
0e64a0c98 [CPUFREQ] checkpa... |
716 717 |
return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid); |
1da177e4c Linux-2.6.12-rc2 |
718 719 720 721 722 723 724 725 726 727 728 729 |
} /* * 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 */ |
e54173b4e cpufreq: powernow... |
730 731 732 733 |
pr_err(FW_BUG "No PSB or ACPI _PSS objects "); pr_err("Make sure that your BIOS is up to date and Cool'N'Quiet support is enabled in BIOS setup "); |
1da177e4c Linux-2.6.12-rc2 |
734 735 |
return -ENODEV; } |
0e64a0c98 [CPUFREQ] checkpa... |
736 737 |
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) |
1da177e4c Linux-2.6.12-rc2 |
738 |
{ |
439913fff ACPI: replace acp... |
739 |
u64 control; |
0e64a0c98 [CPUFREQ] checkpa... |
740 |
|
e1f0b8e9b cpufreq: Remove s... |
741 |
if (!data->acpi_data.state_count) |
1da177e4c Linux-2.6.12-rc2 |
742 |
return; |
21335d021 [CPUFREQ] powerno... |
743 744 745 746 747 748 749 750 |
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 Linux-2.6.12-rc2 |
751 752 753 |
static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) { |
1da177e4c Linux-2.6.12-rc2 |
754 |
struct cpufreq_frequency_table *powernow_table; |
2fdf66b49 cpumask: convert ... |
755 |
int ret_val = -ENODEV; |
439913fff ACPI: replace acp... |
756 |
u64 control, status; |
1da177e4c Linux-2.6.12-rc2 |
757 |
|
f607e3a03 Revert "[CPUFREQ]... |
758 |
if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { |
2d06d8c49 [CPUFREQ] use dyn... |
759 760 |
pr_debug("register performance failed: bad ACPI data "); |
1da177e4c Linux-2.6.12-rc2 |
761 762 763 764 |
return -EIO; } /* verify the data contained in the ACPI structures */ |
f607e3a03 Revert "[CPUFREQ]... |
765 |
if (data->acpi_data.state_count <= 1) { |
2d06d8c49 [CPUFREQ] use dyn... |
766 767 |
pr_debug("No ACPI P-States "); |
1da177e4c Linux-2.6.12-rc2 |
768 769 |
goto err_out; } |
2c701b102 [CPUFREQ] powerno... |
770 771 772 773 774 |
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 [CPUFREQ] use dyn... |
775 776 |
pr_debug("Invalid control/status registers (%llx - %llx) ", |
2c701b102 [CPUFREQ] powerno... |
777 |
control, status); |
1da177e4c Linux-2.6.12-rc2 |
778 779 780 781 |
goto err_out; } /* fill in data->powernow_table */ |
71508a1f4 cpufreq: use kzal... |
782 |
powernow_table = kzalloc((sizeof(*powernow_table) |
f607e3a03 Revert "[CPUFREQ]... |
783 |
* (data->acpi_data.state_count + 1)), GFP_KERNEL); |
7f3a1d66d cpufreq: powernow... |
784 |
if (!powernow_table) |
1da177e4c Linux-2.6.12-rc2 |
785 |
goto err_out; |
1da177e4c Linux-2.6.12-rc2 |
786 |
|
db39d5529 [CPUFREQ] Powerno... |
787 788 789 |
/* fill in data */ data->numps = data->acpi_data.state_count; powernow_k8_acpi_pst_values(data, 0); |
e1f0b8e9b cpufreq: Remove s... |
790 |
ret_val = fill_powernow_table_fidvid(data, powernow_table); |
1f729e066 [CPUFREQ] Prepare... |
791 792 |
if (ret_val) goto err_out_mem; |
0e64a0c98 [CPUFREQ] checkpa... |
793 794 |
powernow_table[data->acpi_data.state_count].frequency = CPUFREQ_TABLE_END; |
1f729e066 [CPUFREQ] Prepare... |
795 |
data->powernow_table = powernow_table; |
38c52e634 powernow-k8: Repl... |
796 |
if (cpumask_first(topology_core_cpumask(data->cpu)) == data->cpu) |
2e4976206 [CPUFREQ] Report ... |
797 |
print_basics(data); |
1f729e066 [CPUFREQ] Prepare... |
798 799 800 |
/* notify BIOS that we exist */ acpi_processor_notify_smm(THIS_MODULE); |
eaa958402 cpumask: alloc ze... |
801 |
if (!zalloc_cpumask_var(&data->acpi_data.shared_cpu_map, GFP_KERNEL)) { |
e54173b4e cpufreq: powernow... |
802 803 |
pr_err("unable to alloc powernow_k8_data cpumask "); |
2fdf66b49 cpumask: convert ... |
804 805 806 |
ret_val = -ENOMEM; goto err_out_mem; } |
1f729e066 [CPUFREQ] Prepare... |
807 808 809 810 811 812 |
return 0; err_out_mem: kfree(powernow_table); err_out: |
b2f8dc4ce ACPI / processor:... |
813 |
acpi_processor_unregister_performance(data->cpu); |
1f729e066 [CPUFREQ] Prepare... |
814 |
|
0e64a0c98 [CPUFREQ] checkpa... |
815 816 |
/* data->acpi_data.state_count informs us at ->exit() * whether ACPI was used */ |
f607e3a03 Revert "[CPUFREQ]... |
817 |
data->acpi_data.state_count = 0; |
1f729e066 [CPUFREQ] Prepare... |
818 |
|
2fdf66b49 cpumask: convert ... |
819 |
return ret_val; |
1f729e066 [CPUFREQ] Prepare... |
820 |
} |
0e64a0c98 [CPUFREQ] checkpa... |
821 822 |
static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table) |
1f729e066 [CPUFREQ] Prepare... |
823 824 |
{ int i; |
0e64a0c98 [CPUFREQ] checkpa... |
825 |
|
f607e3a03 Revert "[CPUFREQ]... |
826 |
for (i = 0; i < data->acpi_data.state_count; i++) { |
094ce7fde arch/i386/kernel/... |
827 828 |
u32 fid; u32 vid; |
0e64a0c98 [CPUFREQ] checkpa... |
829 |
u32 freq, index; |
439913fff ACPI: replace acp... |
830 |
u64 status, control; |
094ce7fde arch/i386/kernel/... |
831 832 |
if (data->exttype) { |
0e64a0c98 [CPUFREQ] checkpa... |
833 834 835 |
status = data->acpi_data.states[i].status; fid = status & EXT_FID_MASK; vid = (status >> VID_SHIFT) & EXT_VID_MASK; |
841e40b38 Opteron revision ... |
836 |
} else { |
0e64a0c98 [CPUFREQ] checkpa... |
837 838 839 |
control = data->acpi_data.states[i].control; fid = control & FID_MASK; vid = (control >> VID_SHIFT) & VID_MASK; |
841e40b38 Opteron revision ... |
840 |
} |
1da177e4c Linux-2.6.12-rc2 |
841 |
|
2d06d8c49 [CPUFREQ] use dyn... |
842 843 |
pr_debug(" %d : fid 0x%x, vid 0x%x ", i, fid, vid); |
1da177e4c Linux-2.6.12-rc2 |
844 |
|
0e64a0c98 [CPUFREQ] checkpa... |
845 |
index = fid | (vid<<8); |
507015880 cpufreq: rename i... |
846 |
powernow_table[i].driver_data = index; |
0e64a0c98 [CPUFREQ] checkpa... |
847 848 849 |
freq = find_khz_freq_from_fid(fid); powernow_table[i].frequency = freq; |
1da177e4c Linux-2.6.12-rc2 |
850 851 |
/* verify frequency is OK */ |
0e64a0c98 [CPUFREQ] checkpa... |
852 |
if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) { |
2d06d8c49 [CPUFREQ] use dyn... |
853 854 |
pr_debug("invalid freq %u kHz, ignoring ", freq); |
f0adb134d [CPUFREQ] Fix NUL... |
855 |
invalidate_entry(powernow_table, i); |
1da177e4c Linux-2.6.12-rc2 |
856 857 |
continue; } |
0e64a0c98 [CPUFREQ] checkpa... |
858 859 |
/* verify voltage is OK - * BIOSs are using "off" to indicate invalid */ |
841e40b38 Opteron revision ... |
860 |
if (vid == VID_OFF) { |
2d06d8c49 [CPUFREQ] use dyn... |
861 862 |
pr_debug("invalid vid %u, ignoring ", vid); |
f0adb134d [CPUFREQ] Fix NUL... |
863 |
invalidate_entry(powernow_table, i); |
1da177e4c Linux-2.6.12-rc2 |
864 865 |
continue; } |
0e64a0c98 [CPUFREQ] checkpa... |
866 |
if (freq != (data->acpi_data.states[i].core_frequency * 1000)) { |
e54173b4e cpufreq: powernow... |
867 868 869 |
pr_info("invalid freq entries %u kHz vs. %u kHz ", freq, (unsigned int) |
0e64a0c98 [CPUFREQ] checkpa... |
870 871 |
(data->acpi_data.states[i].core_frequency * 1000)); |
f0adb134d [CPUFREQ] Fix NUL... |
872 |
invalidate_entry(powernow_table, i); |
1da177e4c Linux-2.6.12-rc2 |
873 874 875 |
continue; } } |
1da177e4c Linux-2.6.12-rc2 |
876 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
877 878 879 880 |
} static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) { |
f607e3a03 Revert "[CPUFREQ]... |
881 |
if (data->acpi_data.state_count) |
b2f8dc4ce ACPI / processor:... |
882 |
acpi_processor_unregister_performance(data->cpu); |
2fdf66b49 cpumask: convert ... |
883 |
free_cpumask_var(data->acpi_data.shared_cpu_map); |
1da177e4c Linux-2.6.12-rc2 |
884 |
} |
732553e56 [CPUFREQ] powerno... |
885 886 887 888 889 890 891 892 893 894 |
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 [CPUFREQ] powerno... |
895 |
if (max_latency == 0) { |
e54173b4e cpufreq: powernow... |
896 897 |
pr_err(FW_WARN "Invalid zero transition latency "); |
86e13684a [CPUFREQ] powerno... |
898 899 |
max_latency = 1; } |
732553e56 [CPUFREQ] powerno... |
900 901 902 |
/* value in usecs, needs to be in nanoseconds */ return 1000 * max_latency; } |
1da177e4c Linux-2.6.12-rc2 |
903 |
/* Take a frequency, and issue the fid/vid transition command */ |
0e64a0c98 [CPUFREQ] checkpa... |
904 |
static int transition_frequency_fidvid(struct powernow_k8_data *data, |
932e130e3 cpufreq: powernow... |
905 906 |
unsigned int index, struct cpufreq_policy *policy) |
1da177e4c Linux-2.6.12-rc2 |
907 |
{ |
1f729e066 [CPUFREQ] Prepare... |
908 909 |
u32 fid = 0; u32 vid = 0; |
b43a7ffbf cpufreq: Notify a... |
910 |
int res; |
1da177e4c Linux-2.6.12-rc2 |
911 |
struct cpufreq_freqs freqs; |
2d06d8c49 [CPUFREQ] use dyn... |
912 913 |
pr_debug("cpu %d transition to index %u ", smp_processor_id(), index); |
1da177e4c Linux-2.6.12-rc2 |
914 |
|
1f729e066 [CPUFREQ] Prepare... |
915 |
/* fid/vid correctness check for k8 */ |
1da177e4c Linux-2.6.12-rc2 |
916 |
/* fid are the lower 8 bits of the index we stored into |
1f729e066 [CPUFREQ] Prepare... |
917 918 |
* the cpufreq frequency table in find_psb_table, vid * are the upper 8 bits. |
1da177e4c Linux-2.6.12-rc2 |
919 |
*/ |
507015880 cpufreq: rename i... |
920 921 |
fid = data->powernow_table[index].driver_data & 0xFF; vid = (data->powernow_table[index].driver_data & 0xFF00) >> 8; |
1da177e4c Linux-2.6.12-rc2 |
922 |
|
2d06d8c49 [CPUFREQ] use dyn... |
923 924 |
pr_debug("table matched fid 0x%x, giving vid 0x%x ", fid, vid); |
1da177e4c Linux-2.6.12-rc2 |
925 926 927 928 929 |
if (query_current_values_with_pending_wait(data)) return 1; if ((data->currvid == vid) && (data->currfid == fid)) { |
2d06d8c49 [CPUFREQ] use dyn... |
930 931 |
pr_debug("target matches current values (fid 0x%x, vid 0x%x) ", |
1da177e4c Linux-2.6.12-rc2 |
932 933 934 |
fid, vid); return 0; } |
2d06d8c49 [CPUFREQ] use dyn... |
935 936 |
pr_debug("cpu %d, changing to fid 0x%x, vid 0x%x ", |
1da177e4c Linux-2.6.12-rc2 |
937 |
smp_processor_id(), fid, vid); |
1da177e4c Linux-2.6.12-rc2 |
938 939 |
freqs.old = find_khz_freq_from_fid(data->currfid); freqs.new = find_khz_freq_from_fid(fid); |
1f729e066 [CPUFREQ] Prepare... |
940 |
|
8fec051ee cpufreq: Convert ... |
941 |
cpufreq_freq_transition_begin(policy, &freqs); |
1da177e4c Linux-2.6.12-rc2 |
942 |
res = transition_fid_vid(data, fid, vid); |
8fec051ee cpufreq: Convert ... |
943 |
cpufreq_freq_transition_end(policy, &freqs, res); |
1f729e066 [CPUFREQ] Prepare... |
944 |
|
1f729e066 [CPUFREQ] Prepare... |
945 946 |
return res; } |
6889125b8 cpufreq/powernow-... |
947 948 |
struct powernowk8_target_arg { struct cpufreq_policy *pol; |
9c0ebcf78 cpufreq: Implemen... |
949 |
unsigned newstate; |
6889125b8 cpufreq/powernow-... |
950 951 952 |
}; static long powernowk8_target_fn(void *arg) |
1da177e4c Linux-2.6.12-rc2 |
953 |
{ |
6889125b8 cpufreq/powernow-... |
954 955 |
struct powernowk8_target_arg *pta = arg; struct cpufreq_policy *pol = pta->pol; |
9c0ebcf78 cpufreq: Implemen... |
956 |
unsigned newstate = pta->newstate; |
2c6b8c030 x86: change NR_CP... |
957 |
struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); |
9180053ca [CPUFREQ] powerno... |
958 959 |
u32 checkfid; u32 checkvid; |
6889125b8 cpufreq/powernow-... |
960 |
int ret; |
1da177e4c Linux-2.6.12-rc2 |
961 |
|
4211a3034 [PATCH] x86_64: P... |
962 963 |
if (!data) return -EINVAL; |
9180053ca [CPUFREQ] powerno... |
964 965 |
checkfid = data->currfid; checkvid = data->currvid; |
1da177e4c Linux-2.6.12-rc2 |
966 |
if (pending_bit_stuck()) { |
e54173b4e cpufreq: powernow... |
967 968 |
pr_err("failing targ, change pending bit set "); |
6889125b8 cpufreq/powernow-... |
969 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
970 |
} |
9c0ebcf78 cpufreq: Implemen... |
971 972 973 974 |
pr_debug("targ: cpu %d, %d kHz, min %d, max %d ", pol->cpu, data->powernow_table[newstate].frequency, pol->min, pol->max); |
1da177e4c Linux-2.6.12-rc2 |
975 |
|
83844510e [CPUFREQ] Remove ... |
976 |
if (query_current_values_with_pending_wait(data)) |
6889125b8 cpufreq/powernow-... |
977 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
978 |
|
e1f0b8e9b cpufreq: Remove s... |
979 980 |
pr_debug("targ: curr fid 0x%x, vid 0x%x ", |
e54173b4e cpufreq: powernow... |
981 |
data->currfid, data->currvid); |
1da177e4c Linux-2.6.12-rc2 |
982 |
|
e1f0b8e9b cpufreq: Remove s... |
983 984 |
if ((checkvid != data->currvid) || (checkfid != data->currfid)) { |
e54173b4e cpufreq: powernow... |
985 986 |
pr_info("error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x ", |
e1f0b8e9b cpufreq: Remove s... |
987 988 |
checkfid, data->currfid, checkvid, data->currvid); |
1da177e4c Linux-2.6.12-rc2 |
989 |
} |
14cc3e2b6 [PATCH] sem2mutex... |
990 |
mutex_lock(&fidvid_mutex); |
065b807ca [CPUFREQ] dual-co... |
991 |
|
1da177e4c Linux-2.6.12-rc2 |
992 |
powernow_k8_acpi_pst_values(data, newstate); |
932e130e3 cpufreq: powernow... |
993 |
ret = transition_frequency_fidvid(data, newstate, pol); |
e1f0b8e9b cpufreq: Remove s... |
994 |
|
1f729e066 [CPUFREQ] Prepare... |
995 |
if (ret) { |
e54173b4e cpufreq: powernow... |
996 997 |
pr_err("transition frequency failed "); |
14cc3e2b6 [PATCH] sem2mutex... |
998 |
mutex_unlock(&fidvid_mutex); |
6889125b8 cpufreq/powernow-... |
999 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
1000 |
} |
14cc3e2b6 [PATCH] sem2mutex... |
1001 |
mutex_unlock(&fidvid_mutex); |
065b807ca [CPUFREQ] dual-co... |
1002 |
|
e1f0b8e9b cpufreq: Remove s... |
1003 |
pol->cur = find_khz_freq_from_fid(data->currfid); |
1da177e4c Linux-2.6.12-rc2 |
1004 |
|
6889125b8 cpufreq/powernow-... |
1005 1006 1007 1008 |
return 0; } /* Driver entry point to switch to the target frequency */ |
9c0ebcf78 cpufreq: Implemen... |
1009 |
static int powernowk8_target(struct cpufreq_policy *pol, unsigned index) |
6889125b8 cpufreq/powernow-... |
1010 |
{ |
9c0ebcf78 cpufreq: Implemen... |
1011 |
struct powernowk8_target_arg pta = { .pol = pol, .newstate = index }; |
6889125b8 cpufreq/powernow-... |
1012 |
|
e4df1cbcc cpufreq / powerno... |
1013 |
return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta); |
1da177e4c Linux-2.6.12-rc2 |
1014 |
} |
1ff6e97f1 [CPUFREQ] cpumask... |
1015 1016 1017 1018 |
struct init_on_cpu { struct powernow_k8_data *data; int rc; }; |
2760984f6 cpufreq: delete _... |
1019 |
static void powernowk8_cpu_init_on_cpu(void *_init_on_cpu) |
1ff6e97f1 [CPUFREQ] cpumask... |
1020 1021 1022 1023 |
{ struct init_on_cpu *init_on_cpu = _init_on_cpu; if (pending_bit_stuck()) { |
e54173b4e cpufreq: powernow... |
1024 1025 |
pr_err("failing init, change pending bit set "); |
1ff6e97f1 [CPUFREQ] cpumask... |
1026 1027 1028 1029 1030 1031 1032 1033 |
init_on_cpu->rc = -ENODEV; return; } if (query_current_values_with_pending_wait(init_on_cpu->data)) { init_on_cpu->rc = -ENODEV; return; } |
e1f0b8e9b cpufreq: Remove s... |
1034 |
fidvid_msr_init(); |
1ff6e97f1 [CPUFREQ] cpumask... |
1035 1036 1037 |
init_on_cpu->rc = 0; } |
e54173b4e cpufreq: powernow... |
1038 1039 1040 1041 1042 1043 1044 |
#define MISSING_PSS_MSG \ FW_BUG "No compatible ACPI _PSS objects found. " \ FW_BUG "First, make sure Cool'N'Quiet is enabled in the BIOS. " \ FW_BUG "If that doesn't help, try upgrading your BIOS. " |
56835e6cc cpufreq / powerno... |
1045 |
|
1da177e4c Linux-2.6.12-rc2 |
1046 |
/* per CPU init entry point to the driver */ |
2760984f6 cpufreq: delete _... |
1047 |
static int powernowk8_cpu_init(struct cpufreq_policy *pol) |
1da177e4c Linux-2.6.12-rc2 |
1048 1049 |
{ struct powernow_k8_data *data; |
1ff6e97f1 [CPUFREQ] cpumask... |
1050 |
struct init_on_cpu init_on_cpu; |
c3274763b cpufreq: powernow... |
1051 |
int rc, cpu; |
1da177e4c Linux-2.6.12-rc2 |
1052 |
|
1ff6e97f1 [CPUFREQ] cpumask... |
1053 1054 |
smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1); if (rc) |
1da177e4c Linux-2.6.12-rc2 |
1055 |
return -ENODEV; |
d5b73cd87 cpufreq: Use size... |
1056 |
data = kzalloc(sizeof(*data), GFP_KERNEL); |
7f3a1d66d cpufreq: powernow... |
1057 |
if (!data) |
1da177e4c Linux-2.6.12-rc2 |
1058 |
return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
1059 1060 |
data->cpu = pol->cpu; |
a0abd520f cpumask: fix powe... |
1061 |
if (powernow_k8_cpu_init_acpi(data)) { |
1da177e4c Linux-2.6.12-rc2 |
1062 |
/* |
0d2eb44f6 x86: Fix common m... |
1063 |
* Use the PSB BIOS structure. This is only available on |
1da177e4c Linux-2.6.12-rc2 |
1064 1065 |
* an UP version, and is deprecated by AMD. */ |
9ed059e15 [CPUFREQ] Fix pow... |
1066 |
if (num_online_cpus() != 1) { |
e54173b4e cpufreq: powernow... |
1067 |
pr_err_once(MISSING_PSS_MSG); |
0cb8bc256 [CPUFREQ] powerno... |
1068 |
goto err_out; |
1da177e4c Linux-2.6.12-rc2 |
1069 1070 |
} if (pol->cpu != 0) { |
e54173b4e cpufreq: powernow... |
1071 1072 |
pr_err(FW_BUG "No ACPI _PSS objects for CPU other than CPU0. Complain to your BIOS vendor. "); |
0cb8bc256 [CPUFREQ] powerno... |
1073 |
goto err_out; |
1da177e4c Linux-2.6.12-rc2 |
1074 1075 |
} rc = find_psb_table(data); |
0cb8bc256 [CPUFREQ] powerno... |
1076 1077 |
if (rc) goto err_out; |
732553e56 [CPUFREQ] powerno... |
1078 1079 1080 1081 1082 1083 1084 |
/* 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 Linux-2.6.12-rc2 |
1085 1086 |
/* only run on specific CPU from here on */ |
1ff6e97f1 [CPUFREQ] cpumask... |
1087 1088 1089 1090 1091 1092 |
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 Linux-2.6.12-rc2 |
1093 |
|
38c52e634 powernow-k8: Repl... |
1094 |
cpumask_copy(pol->cpus, topology_core_cpumask(pol->cpu)); |
835481d9b cpumask: convert ... |
1095 |
data->available_cores = pol->cpus; |
e2376d1fa cpufreq: powernow... |
1096 |
pol->freq_table = data->powernow_table; |
1da177e4c Linux-2.6.12-rc2 |
1097 |
|
e1f0b8e9b cpufreq: Remove s... |
1098 1099 |
pr_debug("cpu_init done, current fid 0x%x, vid 0x%x ", |
e54173b4e cpufreq: powernow... |
1100 |
data->currfid, data->currvid); |
1da177e4c Linux-2.6.12-rc2 |
1101 |
|
c3274763b cpufreq: powernow... |
1102 1103 1104 |
/* Point all the CPUs in this policy to the same data */ for_each_cpu(cpu, pol->cpus) per_cpu(powernow_data, cpu) = data; |
1da177e4c Linux-2.6.12-rc2 |
1105 1106 |
return 0; |
1ff6e97f1 [CPUFREQ] cpumask... |
1107 |
err_out_exit_acpi: |
1da177e4c Linux-2.6.12-rc2 |
1108 |
powernow_k8_cpu_exit_acpi(data); |
0cb8bc256 [CPUFREQ] powerno... |
1109 |
err_out: |
1da177e4c Linux-2.6.12-rc2 |
1110 1111 1112 |
kfree(data); return -ENODEV; } |
c0e61cb15 cpufreq: remove u... |
1113 |
static int powernowk8_cpu_exit(struct cpufreq_policy *pol) |
1da177e4c Linux-2.6.12-rc2 |
1114 |
{ |
2c6b8c030 x86: change NR_CP... |
1115 |
struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); |
c3274763b cpufreq: powernow... |
1116 |
int cpu; |
1da177e4c Linux-2.6.12-rc2 |
1117 1118 1119 1120 1121 |
if (!data) return -EINVAL; powernow_k8_cpu_exit_acpi(data); |
1da177e4c Linux-2.6.12-rc2 |
1122 1123 |
kfree(data->powernow_table); kfree(data); |
c3274763b cpufreq: powernow... |
1124 1125 |
for_each_cpu(cpu, pol->cpus) per_cpu(powernow_data, cpu) = NULL; |
1da177e4c Linux-2.6.12-rc2 |
1126 1127 1128 |
return 0; } |
1ff6e97f1 [CPUFREQ] cpumask... |
1129 1130 1131 |
static void query_values_on_cpu(void *_err) { int *err = _err; |
0a3aee0da x86: Use this_cpu... |
1132 |
struct powernow_k8_data *data = __this_cpu_read(powernow_data); |
1ff6e97f1 [CPUFREQ] cpumask... |
1133 1134 1135 |
*err = query_current_values_with_pending_wait(data); } |
0e64a0c98 [CPUFREQ] checkpa... |
1136 |
static unsigned int powernowk8_get(unsigned int cpu) |
1da177e4c Linux-2.6.12-rc2 |
1137 |
{ |
e15bc4559 [CPUFREQ] powerno... |
1138 |
struct powernow_k8_data *data = per_cpu(powernow_data, cpu); |
1da177e4c Linux-2.6.12-rc2 |
1139 |
unsigned int khz = 0; |
1ff6e97f1 [CPUFREQ] cpumask... |
1140 |
int err; |
eef5167e5 [CPUFREQ] hotplug... |
1141 1142 |
if (!data) |
557a701c1 [CPUFREQ] Fix use... |
1143 |
return 0; |
eef5167e5 [CPUFREQ] hotplug... |
1144 |
|
1ff6e97f1 [CPUFREQ] cpumask... |
1145 1146 |
smp_call_function_single(cpu, query_values_on_cpu, &err, true); if (err) |
1da177e4c Linux-2.6.12-rc2 |
1147 |
goto out; |
e1f0b8e9b cpufreq: Remove s... |
1148 |
khz = find_khz_freq_from_fid(data->currfid); |
58389a86d [CPUFREQ] fix cpu... |
1149 |
|
1da177e4c Linux-2.6.12-rc2 |
1150 |
|
b9111b7b7 [CPUFREQ] Remove ... |
1151 |
out: |
1da177e4c Linux-2.6.12-rc2 |
1152 1153 |
return khz; } |
221dee285 Revert "[CPUFREQ]... |
1154 |
static struct cpufreq_driver cpufreq_amd64_driver = { |
7dbf694db cpufreq: distingu... |
1155 |
.flags = CPUFREQ_ASYNC_NOTIFICATION, |
d63bd27fe cpufreq: powernow... |
1156 |
.verify = cpufreq_generic_frequency_table_verify, |
9c0ebcf78 cpufreq: Implemen... |
1157 |
.target_index = powernowk8_target, |
e2f74f355 [ACPI/CPUFREQ] In... |
1158 1159 |
.bios_limit = acpi_processor_get_bios_limit, .init = powernowk8_cpu_init, |
ce2650d40 cpufreq: remove u... |
1160 |
.exit = powernowk8_cpu_exit, |
e2f74f355 [ACPI/CPUFREQ] In... |
1161 1162 |
.get = powernowk8_get, .name = "powernow-k8", |
d63bd27fe cpufreq: powernow... |
1163 |
.attr = cpufreq_generic_attr, |
1da177e4c Linux-2.6.12-rc2 |
1164 |
}; |
4827ea6ec powernow-k8: Clea... |
1165 1166 |
static void __request_acpi_cpufreq(void) { |
063246641 format-security: ... |
1167 1168 |
const char drv[] = "acpi-cpufreq"; const char *cur_drv; |
4827ea6ec powernow-k8: Clea... |
1169 1170 1171 1172 1173 1174 |
cur_drv = cpufreq_get_current_driver(); if (!cur_drv) goto request; if (strncmp(cur_drv, drv, min_t(size_t, strlen(cur_drv), strlen(drv)))) |
e54173b4e cpufreq: powernow... |
1175 1176 |
pr_warn("WTF driver: %s ", cur_drv); |
4827ea6ec powernow-k8: Clea... |
1177 1178 1179 1180 |
return; request: |
e54173b4e cpufreq: powernow... |
1181 1182 |
pr_warn("This CPU is not supported anymore, using acpi-cpufreq instead. "); |
4827ea6ec powernow-k8: Clea... |
1183 1184 |
request_module(drv); } |
1da177e4c Linux-2.6.12-rc2 |
1185 |
/* driver entry point for init */ |
2760984f6 cpufreq: delete _... |
1186 |
static int powernowk8_init(void) |
1da177e4c Linux-2.6.12-rc2 |
1187 |
{ |
e1f0b8e9b cpufreq: Remove s... |
1188 |
unsigned int i, supported_cpus = 0; |
c0939e46a powernow-k8: Clea... |
1189 |
int ret; |
1da177e4c Linux-2.6.12-rc2 |
1190 |
|
108ec36b6 drivers/cpufreq: ... |
1191 |
if (boot_cpu_has(X86_FEATURE_HW_PSTATE)) { |
4827ea6ec powernow-k8: Clea... |
1192 |
__request_acpi_cpufreq(); |
fa8031aef cpufreq: Add supp... |
1193 |
return -ENODEV; |
e1f0b8e9b cpufreq: Remove s... |
1194 |
} |
fa8031aef cpufreq: Add supp... |
1195 |
|
fa8031aef cpufreq: Add supp... |
1196 1197 |
if (!x86_match_cpu(powernow_k8_ids)) return -ENODEV; |
c0939e46a powernow-k8: Clea... |
1198 |
get_online_cpus(); |
a72011567 [PATCH] more-for_... |
1199 |
for_each_online_cpu(i) { |
c0939e46a powernow-k8: Clea... |
1200 1201 |
smp_call_function_single(i, check_supported_cpu, &ret, 1); if (!ret) |
1da177e4c Linux-2.6.12-rc2 |
1202 1203 |
supported_cpus++; } |
c0939e46a powernow-k8: Clea... |
1204 1205 |
if (supported_cpus != num_online_cpus()) { put_online_cpus(); |
73860c6b2 powernow-k8: Add ... |
1206 |
return -ENODEV; |
c0939e46a powernow-k8: Clea... |
1207 1208 |
} put_online_cpus(); |
73860c6b2 powernow-k8: Add ... |
1209 |
|
c0939e46a powernow-k8: Clea... |
1210 1211 1212 |
ret = cpufreq_register_driver(&cpufreq_amd64_driver); if (ret) return ret; |
73860c6b2 powernow-k8: Add ... |
1213 |
|
e54173b4e cpufreq: powernow... |
1214 1215 |
pr_info("Found %d %s (%d cpu cores) (" VERSION ") ", |
c0939e46a powernow-k8: Clea... |
1216 |
num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus); |
73860c6b2 powernow-k8: Add ... |
1217 |
|
c0939e46a powernow-k8: Clea... |
1218 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
1219 1220 1221 1222 1223 |
} /* driver entry point for term */ static void __exit powernowk8_exit(void) { |
2d06d8c49 [CPUFREQ] use dyn... |
1224 1225 |
pr_debug("exit "); |
1da177e4c Linux-2.6.12-rc2 |
1226 1227 1228 |
cpufreq_unregister_driver(&cpufreq_amd64_driver); } |
e54173b4e cpufreq: powernow... |
1229 1230 |
MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com>"); MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@amd.com>"); |
1da177e4c Linux-2.6.12-rc2 |
1231 1232 1233 1234 1235 |
MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver."); MODULE_LICENSE("GPL"); late_initcall(powernowk8_init); module_exit(powernowk8_exit); |