This source file includes following definitions.
- k8pnow_read_pending_wait
- k8_powernow_setperf
- k8pnow_decode_pst
- k8pnow_states
- k8pnow_acpi_states
- k8pnow_acpi_pss_changed
- k8pnow_acpi_init
- k8_powernow_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/sysctl.h>
35
36 #include <dev/isa/isareg.h>
37 #include <i386/isa/isa_machdep.h>
38
39 #include <machine/cpu.h>
40 #include <machine/cpufunc.h>
41 #include <machine/bus.h>
42
43 #include "acpicpu.h"
44
45 #if NACPICPU > 0
46 #include <dev/acpi/acpidev.h>
47 #include <dev/acpi/acpivar.h>
48 #endif
49
50 #define BIOS_START 0xe0000
51 #define BIOS_LEN 0x20000
52 #define BIOS_STEP 16
53
54
55
56
57 #define MSR_AMDK7_FIDVID_CTL 0xc0010041
58 #define MSR_AMDK7_FIDVID_STATUS 0xc0010042
59 #define AMD_PN_FID_VID 0x06
60
61
62
63 #define PN8_CTR_FID(x) ((x) & 0x3f)
64 #define PN8_CTR_VID(x) (((x) & 0x1f) << 8)
65 #define PN8_CTR_PENDING(x) (((x) & 1) << 32)
66
67 #define PN8_STA_CFID(x) ((x) & 0x3f)
68 #define PN8_STA_SFID(x) (((x) >> 8) & 0x3f)
69 #define PN8_STA_MFID(x) (((x) >> 16) & 0x3f)
70 #define PN8_STA_PENDING(x) (((x) >> 31) & 0x01)
71 #define PN8_STA_CVID(x) (((x) >> 32) & 0x1f)
72 #define PN8_STA_SVID(x) (((x) >> 40) & 0x1f)
73 #define PN8_STA_MVID(x) (((x) >> 48) & 0x1f)
74
75
76 #define PN8_PSB_VERSION 0x14
77 #define PN8_PSB_TO_RVO(x) ((x) & 0x03)
78 #define PN8_PSB_TO_IRT(x) (((x) >> 2) & 0x03)
79 #define PN8_PSB_TO_MVS(x) (((x) >> 4) & 0x03)
80 #define PN8_PSB_TO_BATT(x) (((x) >> 6) & 0x03)
81
82
83 #define PN8_ACPI_CTRL_TO_FID(x) ((x) & 0x3f)
84 #define PN8_ACPI_CTRL_TO_VID(x) (((x) >> 6) & 0x1f)
85 #define PN8_ACPI_CTRL_TO_VST(x) (((x) >> 11) & 0x1f)
86 #define PN8_ACPI_CTRL_TO_MVS(x) (((x) >> 18) & 0x03)
87 #define PN8_ACPI_CTRL_TO_PLL(x) (((x) >> 20) & 0x7f)
88 #define PN8_ACPI_CTRL_TO_RVO(x) (((x) >> 28) & 0x03)
89 #define PN8_ACPI_CTRL_TO_IRT(x) (((x) >> 30) & 0x03)
90
91 #define PN8_PLL_LOCK(x) ((x) * 1000/5)
92 #define WRITE_FIDVID(fid, vid, ctrl) \
93 wrmsr(MSR_AMDK7_FIDVID_CTL, \
94 (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
95
96 #define COUNT_OFF_IRT(irt) DELAY(10 * (1 << (irt)))
97 #define COUNT_OFF_VST(vst) DELAY(20 * (vst))
98
99 #define FID_TO_VCO_FID(fid) \
100 (((fid) < 8) ? (8 + ((fid) << 1)) : (fid))
101
102 #define POWERNOW_MAX_STATES 16
103
104 struct k8pnow_state {
105 int freq;
106 uint8_t fid;
107 uint8_t vid;
108 };
109
110 struct k8pnow_cpu_state {
111 struct k8pnow_state state_table[POWERNOW_MAX_STATES];
112 unsigned int n_states;
113 unsigned int sgtc;
114 unsigned int vst;
115 unsigned int mvs;
116 unsigned int pll;
117 unsigned int rvo;
118 unsigned int irt;
119 int low;
120 };
121
122 struct psb_s {
123 char signature[10];
124 uint8_t version;
125 uint8_t flags;
126 uint16_t ttime;
127 uint8_t reserved;
128 uint8_t n_pst;
129 };
130
131 struct pst_s {
132 uint32_t cpuid;
133 uint8_t pll;
134 uint8_t fid;
135 uint8_t vid;
136 uint8_t n_states;
137 };
138
139 struct k8pnow_cpu_state *k8pnow_current_state = NULL;
140 extern int setperf_prio;
141
142 int k8pnow_read_pending_wait(uint64_t *);
143 int k8pnow_decode_pst(struct k8pnow_cpu_state *, uint8_t *);
144 int k8pnow_states(struct k8pnow_cpu_state *, uint32_t, unsigned int,
145 unsigned int);
146
147 #if NACPICPU > 0
148 int k8pnow_acpi_init(struct k8pnow_cpu_state *, uint64_t);
149 void k8pnow_acpi_pss_changed(struct acpicpu_pss *, int);
150 int k8pnow_acpi_states(struct k8pnow_cpu_state *, struct acpicpu_pss *, int,
151 uint64_t);
152 #endif
153
154 int
155 k8pnow_read_pending_wait(uint64_t *status)
156 {
157 unsigned int i = 100000;
158
159 while (i--) {
160 *status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
161 if (!PN8_STA_PENDING(*status))
162 return 0;
163
164 }
165 printf("k8pnow_read_pending_wait: change pending stuck.\n");
166 return 1;
167 }
168
169 void
170 k8_powernow_setperf(int level)
171 {
172 unsigned int i;
173 uint64_t status;
174 int cfid, cvid, fid = 0, vid = 0, rvo;
175 u_int val;
176 struct k8pnow_cpu_state *cstate;
177
178
179
180
181
182 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
183 if (PN8_STA_PENDING(status))
184 return;
185 cfid = PN8_STA_CFID(status);
186 cvid = PN8_STA_CVID(status);
187
188 cstate = k8pnow_current_state;
189
190 i = ((level * cstate->n_states) + 1) / 101;
191 if (i >= cstate->n_states)
192 i = cstate->n_states - 1;
193 fid = cstate->state_table[i].fid;
194 vid = cstate->state_table[i].vid;
195
196 if (fid == cfid && vid == cvid)
197 return;
198
199
200
201
202
203 while (cvid > vid) {
204 val = cvid - (1 << cstate->mvs);
205 WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL);
206 if (k8pnow_read_pending_wait(&status))
207 return;
208 cvid = PN8_STA_CVID(status);
209 COUNT_OFF_VST(cstate->vst);
210 }
211
212
213 for (rvo = cstate->rvo; rvo > 0 && cvid > 0; --rvo) {
214
215
216
217 WRITE_FIDVID(cfid, cvid - 1, 1ULL);
218 if (k8pnow_read_pending_wait(&status))
219 return;
220 cvid = PN8_STA_CVID(status);
221 COUNT_OFF_VST(cstate->vst);
222 }
223
224
225 if (cfid != fid) {
226 u_int vco_fid, vco_cfid;
227
228 vco_fid = FID_TO_VCO_FID(fid);
229 vco_cfid = FID_TO_VCO_FID(cfid);
230
231 while (abs(vco_fid - vco_cfid) > 2) {
232 if (fid > cfid) {
233 if (cfid > 6)
234 val = cfid + 2;
235 else
236 val = FID_TO_VCO_FID(cfid) + 2;
237 } else
238 val = cfid - 2;
239 WRITE_FIDVID(val, cvid, (uint64_t)
240 PN8_PLL_LOCK(cstate->pll));
241
242 if (k8pnow_read_pending_wait(&status))
243 return;
244 cfid = PN8_STA_CFID(status);
245 COUNT_OFF_IRT(cstate->irt);
246
247 vco_cfid = FID_TO_VCO_FID(cfid);
248 }
249
250 WRITE_FIDVID(fid, cvid, (uint64_t) PN8_PLL_LOCK(cstate->pll));
251 if (k8pnow_read_pending_wait(&status))
252 return;
253 cfid = PN8_STA_CFID(status);
254 COUNT_OFF_IRT(cstate->irt);
255 }
256
257
258 if (cvid != vid) {
259 WRITE_FIDVID(cfid, vid, 1ULL);
260 if (k8pnow_read_pending_wait(&status))
261 return;
262 cvid = PN8_STA_CVID(status);
263 COUNT_OFF_VST(cstate->vst);
264 }
265
266 if (cfid == fid || cvid == vid)
267 cpuspeed = cstate->state_table[i].freq;
268 }
269
270
271
272
273
274 int
275 k8pnow_decode_pst(struct k8pnow_cpu_state *cstate, uint8_t *p)
276 {
277 int i, j, n;
278 struct k8pnow_state state;
279
280 for (n = 0, i = 0; i < cstate->n_states; i++) {
281 state.fid = *p++;
282 state.vid = *p++;
283
284
285
286
287
288 state.freq = 800 + state.fid * 100;
289 j = n;
290 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
291 memcpy(&cstate->state_table[j],
292 &cstate->state_table[j - 1],
293 sizeof(struct k8pnow_state));
294 --j;
295 }
296 memcpy(&cstate->state_table[j], &state,
297 sizeof(struct k8pnow_state));
298 n++;
299 }
300 return 1;
301 }
302
303 int
304 k8pnow_states(struct k8pnow_cpu_state *cstate, uint32_t cpusig,
305 unsigned int fid, unsigned int vid)
306 {
307 struct psb_s *psb;
308 struct pst_s *pst;
309 uint8_t *p;
310 int i;
311
312 for (p = (u_int8_t *)ISA_HOLE_VADDR(BIOS_START);
313 p < (u_int8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); p +=
314 BIOS_STEP) {
315 if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
316 psb = (struct psb_s *)p;
317 if (psb->version != PN8_PSB_VERSION)
318 return 0;
319
320 cstate->vst = psb->ttime;
321 cstate->rvo = PN8_PSB_TO_RVO(psb->reserved);
322 cstate->irt = PN8_PSB_TO_IRT(psb->reserved);
323 cstate->mvs = PN8_PSB_TO_MVS(psb->reserved);
324 cstate->low = PN8_PSB_TO_BATT(psb->reserved);
325 p+= sizeof(struct psb_s);
326
327 for (i = 0; i < psb->n_pst; ++i) {
328 pst = (struct pst_s *) p;
329
330 cstate->pll = pst->pll;
331 cstate->n_states = pst->n_states;
332 if (cpusig == pst->cpuid &&
333 pst->fid == fid && pst->vid == vid) {
334 return (k8pnow_decode_pst(cstate,
335 p+= sizeof (struct pst_s)));
336 }
337 p += sizeof(struct pst_s) + 2
338 * cstate->n_states;
339 }
340 }
341 }
342
343 return 0;
344
345 }
346
347 #if NACPICPU > 0
348
349 int
350 k8pnow_acpi_states(struct k8pnow_cpu_state * cstate, struct acpicpu_pss * pss,
351 int nstates, uint64_t status)
352 {
353 struct k8pnow_state state;
354 int j, k, n;
355 uint32_t ctrl;
356
357 k = -1;
358
359 for (n = 0; n < cstate->n_states; n++) {
360 if (status == pss[n].pss_status)
361 k = n;
362 ctrl = pss[n].pss_ctrl;
363 state.fid = PN8_ACPI_CTRL_TO_FID(ctrl);
364 state.vid = PN8_ACPI_CTRL_TO_VID(ctrl);
365
366 state.freq = pss[n].pss_core_freq;
367 j = n;
368 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
369 memcpy(&cstate->state_table[j],
370 &cstate->state_table[j - 1],
371 sizeof(struct k8pnow_state));
372 --j;
373 }
374 memcpy(&cstate->state_table[j], &state,
375 sizeof(struct k8pnow_state));
376 }
377
378 return k;
379 }
380
381 void
382 k8pnow_acpi_pss_changed(struct acpicpu_pss * pss, int npss)
383 {
384 int curs;
385 struct k8pnow_cpu_state * cstate;
386 uint32_t ctrl;
387 uint64_t status;
388
389 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
390 cstate = k8pnow_current_state;
391
392 curs = k8pnow_acpi_states(cstate, pss, npss, status);
393 ctrl = pss[curs].pss_ctrl;
394 cstate->vst = PN8_ACPI_CTRL_TO_VST(ctrl);
395 cstate->mvs = PN8_ACPI_CTRL_TO_MVS(ctrl);
396 cstate->pll = PN8_ACPI_CTRL_TO_PLL(ctrl);
397 cstate->irt = PN8_ACPI_CTRL_TO_IRT(ctrl);
398 cstate->low = 0;
399 cstate->n_states = npss;
400 }
401
402 int
403 k8pnow_acpi_init(struct k8pnow_cpu_state * cstate, uint64_t status)
404 {
405 int curs;
406 uint32_t ctrl;
407 struct acpicpu_pss *pss;
408
409 cstate->n_states = acpicpu_fetch_pss(&pss);
410 if (cstate->n_states == 0)
411 return 0;
412 acpicpu_set_notify(k8pnow_acpi_pss_changed);
413
414 curs = k8pnow_acpi_states(cstate, pss, cstate->n_states, status);
415 ctrl = pss[curs].pss_ctrl;
416
417 cstate->vst = PN8_ACPI_CTRL_TO_VST(ctrl);
418 cstate->mvs = PN8_ACPI_CTRL_TO_MVS(ctrl);
419 cstate->pll = PN8_ACPI_CTRL_TO_PLL(ctrl);
420 cstate->irt = PN8_ACPI_CTRL_TO_IRT(ctrl);
421 cstate->low = 0;
422
423 return 1;
424 }
425
426 #endif
427
428 void
429 k8_powernow_init(void)
430 {
431 uint64_t status;
432 u_int maxfid, maxvid, i;
433 struct k8pnow_cpu_state *cstate;
434 struct k8pnow_state *state;
435 struct cpu_info * ci;
436 char * techname = NULL;
437 u_int32_t regs[4];
438
439 ci = curcpu();
440
441 if (setperf_prio > 1)
442 return;
443
444 if (k8pnow_current_state)
445 return;
446
447 cpuid(0x80000000, regs);
448 if (regs[0] < 0x80000007)
449 return;
450
451 cpuid(0x80000007, regs);
452 if (!(regs[3] & AMD_PN_FID_VID))
453 return;
454
455
456 cpuid(0x80000001, regs);
457
458 cstate = malloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF, M_NOWAIT);
459 if (!cstate)
460 return;
461
462 cstate->n_states = 0;
463 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
464 maxfid = PN8_STA_MFID(status);
465 maxvid = PN8_STA_MVID(status);
466
467
468
469
470
471
472 if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
473 techname = "PowerNow! K8";
474 else
475 techname = "Cool'n'Quiet K8";
476
477 #if NACPICPU > 0
478
479 if (!k8pnow_acpi_init(cstate, status))
480 #endif
481 {
482 if (!k8pnow_states(cstate, ci->ci_signature, maxfid, maxvid))
483 k8pnow_states(cstate, regs[0], maxfid, maxvid);
484 }
485 if (cstate->n_states) {
486 printf("%s: %s %d MHz: speeds:",
487 ci->ci_dev.dv_xname, techname, cpuspeed);
488 for (i = cstate->n_states; i > 0; i--) {
489 state = &cstate->state_table[i-1];
490 printf(" %d", state->freq);
491 }
492 printf(" MHz\n");
493 k8pnow_current_state = cstate;
494 cpu_setperf = k8_powernow_setperf;
495 setperf_prio = 1;
496 return;
497 }
498 free(cstate, M_DEVBUF);
499 }