This source file includes following definitions.
- k7_powernow_setperf
- k7pnow_decode_pst
- k7pnow_states
- k7pnow_acpi_states
- k7pnow_acpi_pss_changed
- k7pnow_acpi_init
- k7_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
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/malloc.h>
35 #include <sys/sysctl.h>
36
37 #include <machine/cpu.h>
38 #include <machine/cpufunc.h>
39 #include <machine/bus.h>
40
41 #include <dev/isa/isareg.h>
42 #include <i386/isa/isa_machdep.h>
43
44 #include "acpicpu.h"
45
46 #if NACPICPU > 0
47 #include <dev/acpi/acpidev.h>
48 #include <dev/acpi/acpivar.h>
49 #endif
50
51 #define BIOS_START 0xe0000
52 #define BIOS_LEN 0x20000
53 #define BIOS_STEP 16
54
55
56
57
58 #define MSR_AMDK7_FIDVID_CTL 0xc0010041
59 #define MSR_AMDK7_FIDVID_STATUS 0xc0010042
60 #define AMD_PN_FID_VID 0x06
61 #define AMD_ERRATA_A0_CPUSIG 0x660
62
63 #define PN7_FLAG_ERRATA_A0 0x01
64 #define PN7_FLAG_DESKTOP_VRM 0x02
65
66
67 #define PN7_PSB_VERSION 0x12
68 #define PN7_CTR_FID(x) ((x) & 0x1f)
69 #define PN7_CTR_VID(x) (((x) & 0x1f) << 8)
70 #define PN7_CTR_FIDC 0x00010000
71 #define PN7_CTR_VIDC 0x00020000
72 #define PN7_CTR_FIDCHRATIO 0x00100000
73 #define PN7_CTR_SGTC(x) (((uint64_t)(x) & 0x000fffff) << 32)
74
75 #define PN7_STA_CFID(x) ((x) & 0x1f)
76 #define PN7_STA_SFID(x) (((x) >> 8) & 0x1f)
77 #define PN7_STA_MFID(x) (((x) >> 16) & 0x1f)
78 #define PN7_STA_CVID(x) (((x) >> 32) & 0x1f)
79 #define PN7_STA_SVID(x) (((x) >> 40) & 0x1f)
80 #define PN7_STA_MVID(x) (((x) >> 48) & 0x1f)
81
82
83
84
85 #define PN7_ACPI_CTRL_TO_FID(x) ((x) & 0x1f)
86 #define PN7_ACPI_CTRL_TO_VID(x) (((x) >> 5) & 0x1f)
87 #define PN7_ACPI_CTRL_TO_SGTC(x) (((x) >> 10) & 0xffff)
88
89 #define WRITE_FIDVID(fid, vid, ctrl) \
90 wrmsr(MSR_AMDK7_FIDVID_CTL, \
91 (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
92
93
94
95
96
97 static int k7pnow_fid_to_mult[32] = {
98 110, 115, 120, 125, 50, 55, 60, 65,
99 70, 75, 80, 85, 90, 95, 100, 105,
100 30, 190, 40, 200, 130, 135, 140, 210,
101 150, 225, 160, 165, 170, 180, -1, -1
102 };
103
104 #define POWERNOW_MAX_STATES 16
105
106 struct k7pnow_state {
107 int freq;
108 int fid;
109 int vid;
110 };
111
112 struct k7pnow_cpu_state {
113 unsigned int fsb;
114 unsigned int sgtc;
115 struct k7pnow_state state_table[POWERNOW_MAX_STATES];
116 unsigned int n_states;
117 int flags;
118 };
119
120 struct psb_s {
121 char signature[10];
122 uint8_t version;
123 uint8_t flags;
124 uint16_t ttime;
125 uint8_t reserved;
126 uint8_t n_pst;
127 };
128
129 struct pst_s {
130 uint32_t signature;
131 uint8_t fsb;
132 uint8_t fid;
133 uint8_t vid;
134 uint8_t n_states;
135 };
136
137 struct k7pnow_cpu_state *k7pnow_current_state;
138 extern int setperf_prio;
139
140 int k7pnow_decode_pst(struct k7pnow_cpu_state *, uint8_t *, int);
141 int k7pnow_states(struct k7pnow_cpu_state *, uint32_t, unsigned int,
142 unsigned int);
143
144 #if NACPICPU > 0
145 int k7pnow_acpi_init(struct k7pnow_cpu_state * cstate, uint64_t status);
146 int k7pnow_acpi_states(struct k7pnow_cpu_state * cstate,
147 struct acpicpu_pss *pss, int nstates, uint64_t status);
148 void k7pnow_acpi_pss_changed(struct acpicpu_pss *pss, int npss);
149 #endif
150
151 void
152 k7_powernow_setperf(int level)
153 {
154 unsigned int i;
155 int cvid, cfid, vid = 0, fid = 0;
156 uint64_t status, ctl;
157 struct k7pnow_cpu_state * cstate;
158
159 cstate = k7pnow_current_state;
160
161 i = ((level * cstate->n_states) + 1) / 101;
162 if (i >= cstate->n_states)
163 i = cstate->n_states - 1;
164 fid = cstate->state_table[i].fid;
165 vid = cstate->state_table[i].vid;
166
167 if (fid == 0 || vid == 0)
168 return;
169
170 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
171 cfid = PN7_STA_CFID(status);
172 cvid = PN7_STA_CVID(status);
173
174
175
176
177 if (fid == cfid && vid == cvid)
178 return;
179
180 ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO;
181
182 ctl |= PN7_CTR_FID(fid);
183 ctl |= PN7_CTR_VID(vid);
184 ctl |= PN7_CTR_SGTC(cstate->sgtc);
185
186 if (cstate->flags & PN7_FLAG_ERRATA_A0)
187 disable_intr();
188
189 if (k7pnow_fid_to_mult[fid] < k7pnow_fid_to_mult[cfid]) {
190 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
191 if (vid != cvid)
192 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
193 } else {
194 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
195 if (fid != cfid)
196 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
197 }
198
199 if (cstate->flags & PN7_FLAG_ERRATA_A0)
200 enable_intr();
201
202 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
203 cfid = PN7_STA_CFID(status);
204 cvid = PN7_STA_CVID(status);
205 if (cfid == fid || cvid == vid)
206 cpuspeed = cstate->state_table[i].freq;
207 }
208
209
210
211
212
213 int
214 k7pnow_decode_pst(struct k7pnow_cpu_state * cstate, uint8_t *p, int npst)
215 {
216 int i, j, n;
217 struct k7pnow_state state;
218
219 for (n = 0, i = 0; i < npst; ++i) {
220 state.fid = *p++;
221 state.vid = *p++;
222 state.freq = k7pnow_fid_to_mult[state.fid]/10 * cstate->fsb;
223 if ((cstate->flags & PN7_FLAG_ERRATA_A0) &&
224 (k7pnow_fid_to_mult[state.fid] % 10) == 5)
225 continue;
226
227 j = n;
228 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
229 memcpy(&cstate->state_table[j],
230 &cstate->state_table[j - 1],
231 sizeof(struct k7pnow_state));
232 --j;
233 }
234 memcpy(&cstate->state_table[j], &state,
235 sizeof(struct k7pnow_state));
236 ++n;
237 }
238
239
240
241
242 cstate->n_states = n;
243 return 1;
244 }
245
246 int
247 k7pnow_states(struct k7pnow_cpu_state *cstate, uint32_t cpusig,
248 unsigned int fid, unsigned int vid)
249 {
250 int maxpst;
251 struct psb_s *psb;
252 struct pst_s *pst;
253 uint8_t *p;
254
255
256
257
258
259 for (p = (u_int8_t *)ISA_HOLE_VADDR(BIOS_START);
260 p < (u_int8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); p+=
261 BIOS_STEP) {
262 if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
263 psb = (struct psb_s *)p;
264 if (psb->version != PN7_PSB_VERSION)
265 return 0;
266
267 cstate->sgtc = psb->ttime * cstate->fsb;
268 if (cstate->sgtc < 100 * cstate->fsb)
269 cstate->sgtc = 100 * cstate->fsb;
270 if (psb->flags & 1)
271 cstate->flags |= PN7_FLAG_DESKTOP_VRM;
272 p += sizeof(struct psb_s);
273
274 for (maxpst = 0; maxpst < psb->n_pst; maxpst++) {
275 pst = (struct pst_s*) p;
276
277 if (cpusig == pst->signature && fid == pst->fid
278 && vid == pst->vid) {
279
280 if (abs(cstate->fsb - pst->fsb) > 5)
281 continue;
282 cstate->n_states = pst->n_states;
283 return (k7pnow_decode_pst(cstate,
284 p + sizeof(struct pst_s),
285 cstate->n_states));
286 }
287 p += sizeof(struct pst_s) +
288 (2 * pst->n_states);
289 }
290 }
291 }
292
293 return 0;
294 }
295
296 #if NACPICPU > 0
297
298 int
299 k7pnow_acpi_states(struct k7pnow_cpu_state * cstate, struct acpicpu_pss *pss,
300 int nstates, uint64_t status)
301 {
302 struct k7pnow_state state;
303 int j, k, n;
304 uint32_t ctrl;
305
306 k = -1;
307 for (n = 0; n < cstate->n_states; n++) {
308 if (status == pss[n].pss_status)
309 k = n;
310 ctrl = pss[n].pss_ctrl;
311 state.fid = PN7_ACPI_CTRL_TO_FID(ctrl);
312 state.vid = PN7_ACPI_CTRL_TO_VID(ctrl);
313
314 state.freq = pss[n].pss_core_freq;
315 j = n;
316 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
317 memcpy(&cstate->state_table[j],
318 &cstate->state_table[j - 1],
319 sizeof(struct k7pnow_state));
320 --j;
321 }
322 memcpy(&cstate->state_table[j], &state,
323 sizeof(struct k7pnow_state));
324 }
325 return k;
326 }
327
328 void
329 k7pnow_acpi_pss_changed(struct acpicpu_pss *pss, int npss)
330 {
331 int curs;
332 struct k7pnow_cpu_state *cstate;
333 uint32_t ctrl;
334 uint64_t status;
335
336 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
337 cstate = k7pnow_current_state;
338
339 curs = k7pnow_acpi_states(cstate, pss, npss, status);
340 ctrl = pss[curs].pss_ctrl;
341 cstate->sgtc = PN7_ACPI_CTRL_TO_SGTC(ctrl);
342 cstate->n_states = npss;
343 }
344
345 int
346 k7pnow_acpi_init(struct k7pnow_cpu_state *cstate, uint64_t status)
347 {
348 int curs;
349 uint32_t ctrl;
350 struct acpicpu_pss *pss;
351 int mfid;
352
353 cstate->n_states = acpicpu_fetch_pss(&pss);
354 if (cstate->n_states == 0)
355 return 0;
356
357
358
359
360
361
362 mfid = PN7_STA_MFID(status);
363 if (mfid != cstate->state_table[cstate->n_states - 1].fid) {
364 return 0;
365 }
366 curs = k7pnow_acpi_states(cstate, pss, cstate->n_states, status);
367
368 acpicpu_set_notify(k7pnow_acpi_pss_changed);
369 ctrl = pss[curs].pss_ctrl;
370 cstate->sgtc = PN7_ACPI_CTRL_TO_SGTC(ctrl);
371
372 return 1;
373 }
374
375 #endif
376
377 void
378 k7_powernow_init(void)
379 {
380 u_int regs[4];
381 uint64_t status;
382 u_int maxfid, startvid, currentfid;
383 struct k7pnow_cpu_state *cstate;
384 struct k7pnow_state *state;
385 struct cpu_info *ci;
386 char *techname = NULL;
387 int i;
388
389 if (setperf_prio > 1)
390 return;
391
392 ci = curcpu();
393
394 cpuid(0x80000000, regs);
395 if (regs[0] < 0x80000007)
396 return;
397
398 cpuid(0x80000007, regs);
399 if (!(regs[3] & AMD_PN_FID_VID))
400 return;
401
402
403 cpuid(0x80000001, regs);
404
405 cstate = malloc(sizeof(struct k7pnow_cpu_state), M_DEVBUF, M_NOWAIT);
406 if (!cstate)
407 return;
408
409 cstate->flags = cstate->n_states = 0;
410 if (ci->ci_signature == AMD_ERRATA_A0_CPUSIG)
411 cstate->flags |= PN7_FLAG_ERRATA_A0;
412
413 status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
414 maxfid = PN7_STA_MFID(status);
415 startvid = PN7_STA_SVID(status);
416 currentfid = PN7_STA_CFID(status);
417
418 cstate->fsb = cpuspeed / (k7pnow_fid_to_mult[currentfid]/10);
419
420 #if NACPICPU > 0
421
422 if (!k7pnow_acpi_init(cstate, status))
423 #endif
424 {
425
426 if (!k7pnow_states(cstate, ci->ci_signature, maxfid, startvid))
427 k7pnow_states(cstate, regs[0], maxfid, startvid);
428 }
429
430 if (cstate->n_states) {
431 if (cstate->flags & PN7_FLAG_DESKTOP_VRM)
432 techname = "Cool'n'Quiet K7";
433 else
434 techname = "PowerNow! K7";
435 printf("%s: %s %d MHz: speeds:",
436 ci->ci_dev.dv_xname, techname, cpuspeed);
437 for (i = cstate->n_states; i > 0; i--) {
438 state = &cstate->state_table[i-1];
439 printf(" %d", state->freq);
440 }
441 printf(" MHz\n");
442
443 k7pnow_current_state = cstate;
444 cpu_setperf = k7_powernow_setperf;
445 setperf_prio = 1;
446 return;
447 }
448 free(cstate, M_DEVBUF);
449 }