1 /* $NetBSD: powernow.c,v 1.12 2021/10/07 12:52:27 msaitoh Exp $ */ 2 /* $OpenBSD: powernow-k8.c,v 1.8 2006/06/16 05:58:50 gwk Exp $ */ 3 4 /*- 5 * Copyright (c) 2004, 2006, 2008 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Juan Romero Pardines and Martin Vegiard. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 2004-2005 Bruno Ducrot 35 * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda (at) spa.is.uec.ac.jp> 36 * Copyright (c) 2004 Martin Vegiard 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 */ 58 59 #include <sys/cdefs.h> 60 __KERNEL_RCSID(0, "$NetBSD: powernow.c,v 1.12 2021/10/07 12:52:27 msaitoh Exp $"); 61 62 #include <sys/param.h> 63 #include <sys/device.h> 64 #include <sys/kmem.h> 65 #include <sys/module.h> 66 #include <sys/sysctl.h> 67 #include <sys/xcall.h> 68 69 #include <dev/isa/isareg.h> 70 71 #include <x86/cpuvar.h> 72 #include <x86/cputypes.h> 73 #include <x86/cpu_msr.h> 74 #include <x86/isa_machdep.h> 75 #include <x86/powernow.h> 76 #include <x86/specialreg.h> 77 78 #ifdef __i386__ 79 /* 80 * Divide each value by 10 to get the processor multiplier. 81 * Taken from powernow-k7.c/Linux by Dave Jones. 82 */ 83 static int powernow_k7_fidtomult[32] = { 84 110, 115, 120, 125, 50, 55, 60, 65, 85 70, 75, 80, 85, 90, 95, 100, 105, 86 30, 190, 40, 200, 130, 135, 140, 210, 87 150, 225, 160, 165, 170, 180, -1, -1 88 }; 89 90 /* 91 * The following CPUs do not have same CPUID signature 92 * in the PST tables, but they have correct FID/VID values. 93 */ 94 static struct powernow_k7_quirk { 95 uint32_t rcpusig; /* Correct cpu signature */ 96 uint32_t pcpusig; /* PST cpu signature */ 97 } powernow_k7_quirk[] = { 98 { 0x680, 0x780 }, /* Reported by Olaf 'Rhialto' Seibert */ 99 { 0x6a0, 0x781 }, /* Reported by Eric Schnoebelen */ 100 { 0x6a0, 0x7a0 }, /* Reported by Nino Dehne */ 101 { 0, 0 } 102 }; 103 104 #endif /* __i386__ */ 105 106 struct powernow_softc { 107 device_t sc_dev; 108 struct cpu_info *sc_ci; 109 struct sysctllog *sc_log; 110 struct powernow_cpu_state *sc_state; 111 const char *sc_tech; 112 char *sc_freqs; 113 size_t sc_freqs_len; 114 unsigned int sc_freqs_cur; 115 int sc_node_target; 116 int sc_node_current; 117 int sc_flags; 118 }; 119 120 static int powernow_match(device_t, cfdata_t, void *); 121 static void powernow_attach(device_t, device_t, void *); 122 static int powernow_detach(device_t, int); 123 static int powernow_sysctl(device_t); 124 static int powernow_sysctl_helper(SYSCTLFN_PROTO); 125 126 #ifdef __i386__ 127 static int powernow_k7_init(device_t); 128 static int powernow_k7_states(device_t, unsigned int, unsigned int); 129 static int powernow_k7_setperf(device_t, unsigned int); 130 static bool powernow_k7_check(uint32_t, uint32_t); 131 static int powernow_k7_decode_pst(struct powernow_softc *, uint8_t *,int); 132 #endif 133 134 static int powernow_k8_init(device_t); 135 static int powernow_k8_states(device_t, unsigned int, unsigned int); 136 static int powernow_k8_setperf(device_t, unsigned int); 137 static uint64_t powernow_k8_fidvid(u_int fid, uint64_t vid, uint64_t ctrl); 138 static int powernow_k8_decode_pst(struct powernow_cpu_state *, uint8_t *); 139 140 CFATTACH_DECL_NEW(powernow, sizeof(struct powernow_softc), 141 powernow_match, powernow_attach, powernow_detach, NULL); 142 143 static int 144 powernow_match(device_t parent, cfdata_t cf, void *aux) 145 { 146 struct cpufeature_attach_args *cfaa = aux; 147 struct cpu_info *ci = cfaa->ci; 148 uint32_t family, regs[4]; 149 150 if (strcmp(cfaa->name, "frequency") != 0) 151 return 0; 152 153 if (cpu_vendor != CPUVENDOR_AMD) 154 return 0; 155 156 family = CPUID_TO_BASEFAMILY(ci->ci_signature); 157 158 if (family != 0x06 && family != 0x0f) 159 return 0; 160 else { 161 x86_cpuid(0x80000000, regs); 162 163 if (regs[0] < 0x80000007) 164 return 0; 165 166 x86_cpuid(0x80000007, regs); 167 168 if ((regs[3] & AMD_PN_FID_VID) == AMD_PN_FID_VID) 169 return 5; 170 } 171 172 return 0; 173 } 174 175 static void 176 powernow_attach(device_t parent, device_t self, void *aux) 177 { 178 struct powernow_softc *sc = device_private(self); 179 struct cpufeature_attach_args *cfaa = aux; 180 struct cpu_info *ci = cfaa->ci; 181 uint32_t family; 182 int rv; 183 184 sc->sc_ci = ci; 185 sc->sc_dev = self; 186 187 sc->sc_flags = 0; 188 sc->sc_log = NULL; 189 sc->sc_tech = NULL; 190 sc->sc_state = NULL; 191 sc->sc_freqs = NULL; 192 193 family = CPUID_TO_BASEFAMILY(ci->ci_signature); 194 195 switch (family) { 196 197 #ifdef __i386__ 198 case 0x06: 199 rv = powernow_k7_init(self); 200 break; 201 #endif 202 case 0x0f: 203 rv = powernow_k8_init(self); 204 break; 205 206 default: 207 rv = ENODEV; 208 } 209 210 if (rv != 0) { 211 aprint_normal(": failed to initialize (err %d)\n", rv); 212 return; 213 } 214 215 rv = powernow_sysctl(self); 216 217 if (rv != 0) { 218 aprint_normal(": failed to initialize sysctl (err %d)\n", rv); 219 return; 220 } 221 222 KASSERT(sc->sc_tech != NULL); 223 224 aprint_naive("\n"); 225 aprint_normal(": AMD %s\n", sc->sc_tech); 226 227 (void)pmf_device_register(self, NULL, NULL); 228 } 229 230 static int 231 powernow_detach(device_t self, int flags) 232 { 233 struct powernow_softc *sc = device_private(self); 234 235 if (sc->sc_log != NULL) 236 sysctl_teardown(&sc->sc_log); 237 238 if (sc->sc_state != NULL) 239 kmem_free(sc->sc_state, sizeof(*sc->sc_state)); 240 241 if (sc->sc_freqs != NULL) 242 kmem_free(sc->sc_freqs, sc->sc_freqs_len); 243 244 pmf_device_deregister(self); 245 246 return 0; 247 } 248 249 static int 250 powernow_sysctl(device_t self) 251 { 252 const struct sysctlnode *freqnode, *node, *cpunode; 253 struct powernow_softc *sc = device_private(self); 254 int rv; 255 256 /* 257 * Setup the sysctl sub-tree machdep.powernow. 258 */ 259 rv = sysctl_createv(&sc->sc_log, 0, NULL, &node, 260 CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL, 261 NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL); 262 263 if (rv != 0) 264 goto fail; 265 266 rv = sysctl_createv(&sc->sc_log, 0, &node, &cpunode, 267 0, CTLTYPE_NODE, "cpu", NULL, 268 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 269 270 if (rv != 0) 271 goto fail; 272 273 rv = sysctl_createv(&sc->sc_log, 0, &cpunode, &freqnode, 274 0, CTLTYPE_NODE, "frequency", NULL, 275 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 276 277 if (rv != 0) 278 goto fail; 279 280 rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node, 281 CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL, 282 powernow_sysctl_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); 283 284 if (rv != 0) 285 goto fail; 286 287 sc->sc_node_target = node->sysctl_num; 288 289 rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node, 290 0, CTLTYPE_INT, "current", NULL, 291 powernow_sysctl_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL); 292 293 if (rv != 0) 294 goto fail; 295 296 sc->sc_node_current = node->sysctl_num; 297 298 rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node, 299 0, CTLTYPE_STRING, "available", NULL, 300 NULL, 0, sc->sc_freqs, sc->sc_freqs_len, CTL_CREATE, CTL_EOL); 301 302 if (rv != 0) 303 goto fail; 304 305 return 0; 306 307 fail: 308 sysctl_teardown(&sc->sc_log); 309 sc->sc_log = NULL; 310 311 return rv; 312 } 313 314 static int 315 powernow_sysctl_helper(SYSCTLFN_ARGS) 316 { 317 struct powernow_softc *sc; 318 struct sysctlnode node; 319 int fq, oldfq, error; 320 uint32_t family; 321 int rv; 322 323 fq = oldfq = 0; 324 325 node = *rnode; 326 sc = node.sysctl_data; 327 328 if (sc->sc_state == NULL) 329 return EOPNOTSUPP; 330 331 node.sysctl_data = &fq; 332 333 if (rnode->sysctl_num == sc->sc_node_target) 334 fq = oldfq = sc->sc_freqs_cur; 335 else if (rnode->sysctl_num == sc->sc_node_current) 336 fq = sc->sc_freqs_cur; 337 else 338 return EOPNOTSUPP; 339 340 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 341 342 if (error || newp == NULL) 343 return error; 344 345 family = CPUID_TO_BASEFAMILY(sc->sc_ci->ci_signature); 346 347 if (rnode->sysctl_num == sc->sc_node_target && fq != oldfq) { 348 349 switch (family) { 350 351 #ifdef __i386__ 352 case 0x06: 353 rv = powernow_k7_setperf(sc->sc_dev, fq); 354 break; 355 #endif 356 case 0x0f: 357 rv = powernow_k8_setperf(sc->sc_dev, fq); 358 break; 359 360 default: 361 return ENODEV; 362 } 363 364 if (rv != 0) 365 return EINVAL; 366 367 sc->sc_freqs_cur = fq; 368 } 369 370 return 0; 371 } 372 373 #ifdef __i386__ 374 375 static int 376 powernow_k7_init(device_t self) 377 { 378 struct powernow_softc *sc = device_private(self); 379 uint32_t currentfid, maxfid, mhz, startvid; 380 uint64_t status; 381 int i, rv; 382 char tmp[6]; 383 384 sc->sc_state = kmem_alloc(sizeof(*sc->sc_state), KM_SLEEP); 385 386 if (sc->sc_ci->ci_signature == AMD_ERRATA_A0_CPUSIG) 387 sc->sc_flags |= PN7_FLAG_ERRATA_A0; 388 389 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 390 maxfid = PN7_STA_MFID(status); 391 startvid = PN7_STA_SVID(status); 392 currentfid = PN7_STA_CFID(status); 393 394 mhz = sc->sc_ci->ci_data.cpu_cc_freq / 1000000; 395 sc->sc_state->fsb = mhz / (powernow_k7_fidtomult[currentfid] / 10); 396 397 if (powernow_k7_states(self, maxfid, startvid) == 0) { 398 rv = ENXIO; 399 goto fail; 400 } 401 402 if (sc->sc_state->n_states == 0) { 403 rv = ENODEV; 404 goto fail; 405 } 406 407 sc->sc_freqs_len = sc->sc_state->n_states * (sizeof("9999 ") - 1) + 1; 408 sc->sc_freqs = kmem_zalloc(sc->sc_freqs_len, KM_SLEEP); 409 410 for (i = 0; i < sc->sc_state->n_states; i++) { 411 412 /* Skip duplicated matches. */ 413 if (i > 0 && (sc->sc_state->state_table[i].freq == 414 sc->sc_state->state_table[i - 1].freq)) 415 continue; 416 417 DPRINTF(("%s: cstate->state_table.freq=%d\n", 418 __func__, sc->sc_state->state_table[i].freq)); 419 DPRINTF(("%s: fid=%d vid=%d\n", __func__, 420 sc->sc_state->state_table[i].fid, 421 sc->sc_state->state_table[i].vid)); 422 423 snprintf(tmp, sizeof(tmp), "%d%s", 424 sc->sc_state->state_table[i].freq, 425 i < sc->sc_state->n_states - 1 ? " " : ""); 426 427 DPRINTF(("%s: tmp=%s\n", __func__, tmp)); 428 429 (void)strlcat(sc->sc_freqs, tmp, sc->sc_freqs_len); 430 } 431 432 sc->sc_tech = ((sc->sc_flags & PN7_FLAG_DESKTOP_VRM) != 0) ? 433 "Cool`n'Quiet K7" : "Powernow! K7"; 434 435 return 0; 436 437 fail: 438 kmem_free(sc->sc_state, sizeof(*sc->sc_state)); 439 sc->sc_state = NULL; 440 441 return rv; 442 } 443 444 static int 445 powernow_k7_states(device_t self, unsigned int fid, unsigned int vid) 446 { 447 struct powernow_softc *sc = device_private(self); 448 struct powernow_cpu_state *cstate; 449 struct powernow_psb_s *psb; 450 struct powernow_pst_s *pst; 451 uint32_t cpusig, maxpst; 452 bool cpusig_ok; 453 uint8_t *p; 454 455 cstate = sc->sc_state; 456 cpusig = sc->sc_ci->ci_signature; 457 458 /* 459 * Look in the 0xe0000 - 0x100000 physical address 460 * range for the pst tables; 16 byte blocks 461 */ 462 for (p = (uint8_t *)ISA_HOLE_VADDR(BIOS_START); 463 p < (uint8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); 464 p+= BIOS_STEP) { 465 466 if (memcmp(p, "AMDK7PNOW!", 10) == 0) { 467 468 psb = (struct powernow_psb_s *)p; 469 470 if (psb->version != PN7_PSB_VERSION) 471 return 0; 472 473 cstate->sgtc = psb->ttime * cstate->fsb; 474 475 if (cstate->sgtc < 100 * cstate->fsb) 476 cstate->sgtc = 100 * cstate->fsb; 477 478 if (psb->flags & 1) 479 sc->sc_flags |= PN7_FLAG_DESKTOP_VRM; 480 481 p += sizeof(struct powernow_psb_s); 482 483 for (maxpst = 0; maxpst < psb->n_pst; maxpst++) { 484 pst = (struct powernow_pst_s*) p; 485 486 /* 487 * Some models do not have same CPUID 488 * signature in the PST table. Accept to 489 * report frequencies via a quirk table 490 * and fid/vid match. 491 */ 492 DPRINTF(("%s: cpusig=0x%x pst->sig:0x%x\n", 493 __func__, cpusig, pst->signature)); 494 495 cpusig_ok = powernow_k7_check(cpusig, 496 pst->signature); 497 498 if ((cpusig_ok != false && 499 (fid == pst->fid && vid == pst->vid))) { 500 DPRINTF(("%s: pst->signature ok\n", 501 __func__)); 502 if (abs(cstate->fsb - pst->pll) > 5) 503 continue; 504 cstate->n_states = pst->n_states; 505 return (powernow_k7_decode_pst(sc, 506 p + sizeof(struct powernow_pst_s), 507 cstate->n_states)); 508 509 } 510 511 p += sizeof(struct powernow_pst_s) + 512 (2 * pst->n_states); 513 } 514 } 515 } 516 517 return 0; 518 } 519 520 static int 521 powernow_k7_setperf(device_t self, unsigned int freq) 522 { 523 struct powernow_softc *sc = device_private(self); 524 int cvid, cfid, vid = 0, fid = 0; 525 uint64_t status, ctl; 526 unsigned int i; 527 528 DPRINTF(("%s: cstate->n_states=%d\n", 529 __func__, sc->sc_state->n_states)); 530 531 for (i = 0; i < sc->sc_state->n_states; i++) { 532 533 if (sc->sc_state->state_table[i].freq >= freq) { 534 DPRINTF(("%s: freq=%d\n", __func__, freq)); 535 fid = sc->sc_state->state_table[i].fid; 536 vid = sc->sc_state->state_table[i].vid; 537 DPRINTF(("%s: fid=%d vid=%d\n", __func__, fid, vid)); 538 break; 539 } 540 } 541 542 if (fid == 0 || vid == 0) 543 return 0; 544 545 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 546 cfid = PN7_STA_CFID(status); 547 cvid = PN7_STA_CVID(status); 548 549 /* 550 * We're already at the requested level. 551 */ 552 if (fid == cfid && vid == cvid) 553 return 0; 554 555 ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO; 556 557 ctl |= PN7_CTR_FID(fid); 558 ctl |= PN7_CTR_VID(vid); 559 ctl |= PN7_CTR_SGTC(sc->sc_state->sgtc); 560 561 if ((sc->sc_flags & PN7_FLAG_ERRATA_A0) != 0) 562 x86_disable_intr(); 563 564 if (powernow_k7_fidtomult[fid] < powernow_k7_fidtomult[cfid]) { 565 566 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC); 567 568 if (vid != cvid) 569 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC); 570 571 } else { 572 573 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC); 574 575 if (fid != cfid) 576 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC); 577 } 578 579 if ((sc->sc_flags & PN7_FLAG_ERRATA_A0) != 0) 580 x86_enable_intr(); 581 582 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 583 584 cfid = PN7_STA_CFID(status); 585 cvid = PN7_STA_CVID(status); 586 587 if (cfid == fid || cvid == vid) 588 freq = sc->sc_state->state_table[i].freq; 589 590 return 0; 591 } 592 593 static bool 594 powernow_k7_check(uint32_t real_cpusig, uint32_t pst_cpusig) 595 { 596 int j; 597 598 if (real_cpusig == pst_cpusig) 599 return true; 600 601 for (j = 0; powernow_k7_quirk[j].rcpusig != 0; j++) { 602 603 if ((real_cpusig == powernow_k7_quirk[j].rcpusig) && 604 (pst_cpusig == powernow_k7_quirk[j].pcpusig)) 605 return true; 606 } 607 608 return false; 609 } 610 611 static int 612 powernow_k7_decode_pst(struct powernow_softc *sc, uint8_t *p, int npst) 613 { 614 struct powernow_cpu_state *cstate = sc->sc_state; 615 struct powernow_state state; 616 int i, j, n; 617 618 for (n = 0, i = 0; i < npst; ++i) { 619 620 state.fid = *p++; 621 state.vid = *p++; 622 state.freq = powernow_k7_fidtomult[state.fid]/10 * cstate->fsb; 623 624 if ((sc->sc_flags & PN7_FLAG_ERRATA_A0) != 0 && 625 (powernow_k7_fidtomult[state.fid] % 10) == 5) 626 continue; 627 628 j = n; 629 630 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) { 631 632 (void)memcpy(&cstate->state_table[j], 633 &cstate->state_table[j - 1], 634 sizeof(struct powernow_state)); 635 636 --j; 637 } 638 639 (void)memcpy(&cstate->state_table[j], &state, 640 sizeof(struct powernow_state)); 641 642 ++n; 643 } 644 645 /* 646 * Fix powernow_max_states, if errata_a0 gave 647 * us less states than expected. 648 */ 649 cstate->n_states = n; 650 651 return 1; 652 } 653 654 #endif /* __i386__ */ 655 656 static int 657 powernow_k8_init(device_t self) 658 { 659 struct powernow_softc *sc = device_private(self); 660 uint32_t i, maxfid, maxvid; 661 uint64_t status; 662 int rv; 663 char tmp[6]; 664 665 sc->sc_state = kmem_alloc(sizeof(*sc->sc_state), KM_SLEEP); 666 667 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 668 maxfid = PN8_STA_MFID(status); 669 maxvid = PN8_STA_MVID(status); 670 671 if (powernow_k8_states(self, maxfid, maxvid) == 0) { 672 rv = ENXIO; 673 goto fail; 674 } 675 676 if (sc->sc_state->n_states == 0) { 677 rv = ENODEV; 678 goto fail; 679 } 680 681 sc->sc_freqs_len = sc->sc_state->n_states * (sizeof("9999 ") - 1) + 1; 682 sc->sc_freqs = kmem_zalloc(sc->sc_freqs_len, KM_SLEEP); 683 684 for (i = 0; i < sc->sc_state->n_states; i++) { 685 686 DPRINTF(("%s: cstate->state_table.freq=%d\n", 687 __func__, sc->sc_state->state_table[i].freq)); 688 689 DPRINTF(("%s: fid=%d vid=%d\n", __func__, 690 sc->sc_state->state_table[i].fid, 691 sc->sc_state->state_table[i].vid)); 692 693 snprintf(tmp, sizeof(tmp), "%d%s", 694 sc->sc_state->state_table[i].freq, 695 i < sc->sc_state->n_states - 1 ? " " : ""); 696 697 DPRINTF(("%s: tmp=%s\n", __func__, tmp)); 698 699 (void)strlcat(sc->sc_freqs, tmp, sc->sc_freqs_len); 700 } 701 702 /* 703 * If start FID is different to max FID, then it is a mobile 704 * processor. If not, it is a low powered desktop processor. 705 */ 706 sc->sc_tech = (PN8_STA_SFID(status) != PN8_STA_MFID(status)) ? 707 "PowerNow!" : "Cool`n'Quiet"; 708 709 return 0; 710 711 fail: 712 kmem_free(sc->sc_state, sizeof(*sc->sc_state)); 713 sc->sc_state = NULL; 714 715 return rv; 716 } 717 718 static int 719 powernow_k8_states(device_t self, unsigned int fid, unsigned int vid) 720 { 721 struct powernow_softc *sc = device_private(self); 722 struct powernow_cpu_state *cstate; 723 struct powernow_psb_s *psb; 724 struct powernow_pst_s *pst; 725 uint32_t cpusig; 726 uint8_t *p; 727 int i; 728 729 cstate = sc->sc_state; 730 cpusig = sc->sc_ci->ci_signature; 731 732 DPRINTF(("%s: before the for loop\n", __func__)); 733 734 for (p = (uint8_t *)ISA_HOLE_VADDR(BIOS_START); 735 p < (uint8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); p += 16) { 736 737 if (memcmp(p, "AMDK7PNOW!", 10) != 0) 738 continue; 739 740 DPRINTF(("%s: inside the for loop\n", __func__)); 741 742 psb = (struct powernow_psb_s *)p; 743 744 if (psb->version != 0x14) { 745 DPRINTF(("%s: psb->version != 0x14\n", __func__)); 746 return 0; 747 } 748 749 cstate->vst = psb->ttime; 750 cstate->rvo = PN8_PSB_TO_RVO(psb->reserved); 751 cstate->irt = PN8_PSB_TO_IRT(psb->reserved); 752 cstate->mvs = PN8_PSB_TO_MVS(psb->reserved); 753 cstate->low = PN8_PSB_TO_BATT(psb->reserved); 754 755 p += sizeof(struct powernow_psb_s); 756 757 for (i = 0; i < psb->n_pst; ++i) { 758 759 pst = (struct powernow_pst_s *)p; 760 761 cstate->pll = pst->pll; 762 cstate->n_states = pst->n_states; 763 764 if (cpusig == pst->signature && 765 pst->fid == fid && pst->vid == vid) { 766 767 DPRINTF(("%s: cpusig = sig\n", __func__)); 768 769 return (powernow_k8_decode_pst(cstate, 770 p+= sizeof(struct powernow_pst_s))); 771 } 772 773 p += sizeof(struct powernow_pst_s) + 774 2 * cstate->n_states; 775 } 776 } 777 778 DPRINTF(("%s: returns 0!\n", __func__)); 779 780 return 0; 781 } 782 783 static int 784 powernow_k8_setperf(device_t self, unsigned int freq) 785 { 786 struct powernow_softc *sc = device_private(self); 787 int cfid, cvid, fid = 0, vid = 0; 788 uint64_t status; 789 unsigned int i; 790 uint32_t val; 791 int rvo; 792 793 /* 794 * We dont do a "pending wait" here, given 795 * that we need to ensure that the change 796 * pending bit is not stuck. 797 */ 798 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 799 800 if (PN8_STA_PENDING(status)) 801 return 1; 802 803 cfid = PN8_STA_CFID(status); 804 cvid = PN8_STA_CVID(status); 805 806 DPRINTF(("%s: sc->sc_state->n_states=%d\n", 807 __func__, sc->sc_state->n_states)); 808 809 for (i = 0; i < sc->sc_state->n_states; i++) { 810 811 if (sc->sc_state->state_table[i].freq >= freq) { 812 DPRINTF(("%s: freq=%d\n", __func__, freq)); 813 fid = sc->sc_state->state_table[i].fid; 814 vid = sc->sc_state->state_table[i].vid; 815 DPRINTF(("%s: fid=%d vid=%d\n", __func__, fid, vid)); 816 break; 817 } 818 819 } 820 821 if (fid == cfid && vid == cvid) 822 return 0; 823 824 /* 825 * Phase 1: raise the core voltage to the 826 * requested VID if frequency is going up. 827 */ 828 while (cvid > vid) { 829 val = cvid - (1 << sc->sc_state->mvs); 830 status = powernow_k8_fidvid(cfid, (val > 0) ? val : 0, 1ULL); 831 cvid = PN8_STA_CVID(status); 832 COUNT_OFF_VST(sc->sc_state->vst); 833 } 834 835 /* 836 * Then raise to voltage + RVO (if required). 837 */ 838 for (rvo = sc->sc_state->rvo; rvo > 0 && cvid > 0; --rvo) { 839 /* 840 * XXX: It is not clear from the specification if we have 841 * to do that in 0.25 step or in MVS. Therefore do it 842 * as it is done under Linux. 843 */ 844 status = powernow_k8_fidvid(cfid, cvid - 1, 1ULL); 845 cvid = PN8_STA_CVID(status); 846 COUNT_OFF_VST(sc->sc_state->vst); 847 } 848 849 /* 850 * Phase 2: change to requested core frequency. 851 */ 852 if (cfid != fid) { 853 uint32_t vco_fid, vco_cfid; 854 855 vco_fid = FID_TO_VCO_FID(fid); 856 vco_cfid = FID_TO_VCO_FID(cfid); 857 858 while (abs(vco_fid - vco_cfid) > 2) { 859 860 if (fid > cfid) { 861 if (cfid > 6) 862 val = cfid + 2; 863 else 864 val = FID_TO_VCO_FID(cfid) + 2; 865 } else 866 val = cfid - 2; 867 868 status = powernow_k8_fidvid(val, cvid, 869 (uint64_t)sc->sc_state->pll * 1000 / 5); 870 871 cfid = PN8_STA_CFID(status); 872 COUNT_OFF_IRT(sc->sc_state->irt); 873 vco_cfid = FID_TO_VCO_FID(cfid); 874 } 875 876 877 status = powernow_k8_fidvid(fid, cvid, 878 (uint64_t)sc->sc_state->pll * 1000 / 5); 879 880 cfid = PN8_STA_CFID(status); 881 COUNT_OFF_IRT(sc->sc_state->irt); 882 } 883 884 /* 885 * Phase 3: change to requested voltage. 886 */ 887 if (cvid != vid) { 888 status = powernow_k8_fidvid(cfid, vid, 1ULL); 889 cvid = PN8_STA_CVID(status); 890 COUNT_OFF_VST(sc->sc_state->vst); 891 } 892 893 #if 0 894 if (cfid == fid || cvid == vid) 895 freq = sc->sc_state->state_table[i].freq; 896 #endif 897 898 return 0; 899 } 900 901 static uint64_t 902 powernow_k8_fidvid(u_int fid, uint64_t vid, uint64_t ctrl) 903 { 904 struct msr_rw_info msr; 905 uint64_t status, xc; 906 907 msr.msr_read = false; 908 msr.msr_value = (ctrl << 32) | (1ULL << 16) | (vid << 8) | fid; 909 msr.msr_type = MSR_AMDK7_FIDVID_CTL; 910 911 xc = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL); 912 xc_wait(xc); 913 914 do { 915 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 916 917 } while (PN8_STA_PENDING(status)); 918 919 return status; 920 } 921 922 /* 923 * Given a set of pair of FID/VID, and a number of performance 924 * states, compute a state table via an insertion sort. 925 */ 926 static int 927 powernow_k8_decode_pst(struct powernow_cpu_state *cstate, uint8_t *p) 928 { 929 struct powernow_state state; 930 int i, j, n; 931 932 for (n = 0, i = 0; i < cstate->n_states; i++) { 933 934 state.fid = *p++; 935 state.vid = *p++; 936 937 /* 938 * The minimum supported frequency per the data sheet is 939 * 800 MHz. The maximum supported frequency is 5000 MHz. 940 */ 941 state.freq = 800 + state.fid * 100; 942 j = n; 943 944 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) { 945 946 (void)memcpy(&cstate->state_table[j], 947 &cstate->state_table[j - 1], 948 sizeof(struct powernow_state)); 949 950 --j; 951 } 952 953 (void)memcpy(&cstate->state_table[j], &state, 954 sizeof(struct powernow_state)); 955 956 n++; 957 } 958 959 return 1; 960 } 961 962 MODULE(MODULE_CLASS_DRIVER, powernow, NULL); 963 964 #ifdef _MODULE 965 #include "ioconf.c" 966 #endif 967 968 static int 969 powernow_modcmd(modcmd_t cmd, void *aux) 970 { 971 int error = 0; 972 973 switch (cmd) { 974 case MODULE_CMD_INIT: 975 #ifdef _MODULE 976 error = config_init_component(cfdriver_ioconf_powernow, 977 cfattach_ioconf_powernow, cfdata_ioconf_powernow); 978 #endif 979 return error; 980 case MODULE_CMD_FINI: 981 #ifdef _MODULE 982 error = config_fini_component(cfdriver_ioconf_powernow, 983 cfattach_ioconf_powernow, cfdata_ioconf_powernow); 984 #endif 985 return error; 986 default: 987 return ENOTTY; 988 } 989 } 990