|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/drv/dev/cpufreq/est.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.1 /* $OpenBSD: est.c,v 1.11 2005/03/07 06:59:14 mbalmer Exp $ */ 2 /* 3 * Copyright (c) 2003 Michael Eriksson. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 /* 29 * This is a driver for Intel's Enhanced SpeedStep, as implemented in 30 * Pentium M processors. 31 * 32 * Reference documentation: 33 * 34 * - IA-32 Intel Architecture Software Developer's Manual, Volume 3: 35 * System Programming Guide. 36 * Section 13.14, Enhanced Intel SpeedStep technology. 37 * Table B-2, MSRs in Pentium M Processors. 38 * http://www.intel.com/design/pentium4/manuals/245472.htm 39 * 40 * - Intel Pentium M Processor Datasheet. 41 * Table 5, Voltage and Current Specifications. 42 * http://www.intel.com/design/mobile/datashts/252612.htm 43 * 44 * - Intel Pentium M Processor on 90 nm Process with 2-MB L2 Cache Datasheet 45 * Table 3-4, Voltage and Current Specifications. 46 * http://www.intel.com/design/mobile/datashts/302189.htm 47 * 48 * - Linux cpufreq patches, speedstep-centrino.c. 49 * Encoding of MSR_PERF_CTL and MSR_PERF_STATUS. 50 * http://www.codemonkey.org.uk/projects/cpufreq/cpufreq-2.4.22-pre6-1.gz 51 */ 52 53 /* 54 * est.c - Intel enhanced speedstep driver from OpenBSD. 55 */ 56 57 #include <driver.h> 58 #include <cpufreq.h> 59 #include <cpufunc.h> 60 #include <sys/ioctl.h> 61 62 /* #define DEBUG_EST 1 */ 63 64 #ifdef DEBUG_EST 65 #define DPRINTF(a) printf a 66 #else 67 #define DPRINTF(a) 68 #endif 69 70 /* Status/control registers (from the IA-32 System Programming Guide). */ 71 #define MSR_PERF_STATUS 0x198 72 #define MSR_PERF_CTL 0x199 73 74 /* Register and bit for enabling SpeedStep. */ 75 #define MSR_MISC_ENABLE 0x1a0 76 #define MSR_SS_ENABLE (1<<16) 77 78 static int est_probe(struct driver *); 79 static int est_init(struct driver *); 80 static int est_setperf(int); 81 static int est_getperf(void); 82 static void est_getinfo(struct cpufreqinfo *); 83 static int est_identify(char *); 84 85 static struct cpufreq_ops est_ops = { 86 /* setperf */ est_setperf, 87 /* getpref */ est_getperf, 88 /* getinfo */ est_getinfo, 89 }; 90 91 struct driver est_driver = { 92 /* name */ "est", 93 /* devops */ NULL, 94 /* flags */ 0, 95 /* flags */ 0, 96 /* probe */ est_probe, 97 /* init */ est_init, 98 /* shutdown */ NULL, 99 }; 100 101 /* 102 * Frequency tables 103 */ 104 struct fq_info { 105 int mhz; 106 int mv; 107 }; 108 109 /* Ultra Low Voltage Intel Pentium M processor 900 MHz */ 110 static const struct fq_info pentium_m_900[] = { 111 { 900, 1004 }, 112 { 800, 988 }, 113 { 600, 844 }, 114 }; 115 116 /* Ultra Low Voltage Intel Pentium M processor 1.00 GHz */ 117 static const struct fq_info pentium_m_1000[] = { 118 { 1000, 1004 }, 119 { 900, 988 }, 120 { 800, 972 }, 121 { 600, 844 }, 122 }; 123 124 /* Low Voltage Intel Pentium M processor 1.10 GHz */ 125 static const struct fq_info pentium_m_1100[] = { 126 { 1100, 1180 }, 127 { 1000, 1164 }, 128 { 900, 1100 }, 129 { 800, 1020 }, 130 { 600, 956 }, 131 }; 132 133 /* Low Voltage Intel Pentium M processor 1.20 GHz */ 134 static const struct fq_info pentium_m_1200[] = { 135 { 1200, 1180 }, 136 { 1100, 1164 }, 137 { 1000, 1100 }, 138 { 900, 1020 }, 139 { 800, 1004 }, 140 { 600, 956 }, 141 }; 142 143 /* Intel Pentium M processor 1.30 GHz */ 144 static const struct fq_info pentium_m_1300[] = { 145 { 1300, 1388 }, 146 { 1200, 1356 }, 147 { 1000, 1292 }, 148 { 800, 1260 }, 149 { 600, 956 }, 150 }; 151 152 /* Intel Pentium M processor 1.40 GHz */ 153 static const struct fq_info pentium_m_1400[] = { 154 { 1400, 1484 }, 155 { 1200, 1436 }, 156 { 1000, 1308 }, 157 { 800, 1180 }, 158 { 600, 956 } 159 }; 160 161 /* Intel Pentium M processor 1.50 GHz */ 162 static const struct fq_info pentium_m_1500[] = { 163 { 1500, 1484 }, 164 { 1400, 1452 }, 165 { 1200, 1356 }, 166 { 1000, 1228 }, 167 { 800, 1116 }, 168 { 600, 956 } 169 }; 170 171 /* Intel Pentium M processor 1.60 GHz */ 172 static const struct fq_info pentium_m_1600[] = { 173 { 1600, 1484 }, 174 { 1400, 1420 }, 175 { 1200, 1276 }, 176 { 1000, 1164 }, 177 { 800, 1036 }, 178 { 600, 956 } 179 }; 180 181 /* Intel Pentium M processor 1.70 GHz */ 182 static const struct fq_info pentium_m_1700[] = { 183 { 1700, 1484 }, 184 { 1400, 1308 }, 185 { 1200, 1228 }, 186 { 1000, 1116 }, 187 { 800, 1004 }, 188 { 600, 956 } 189 }; 190 191 192 /* Intel Pentium M processor 723 1.0 GHz */ 193 static const struct fq_info pentium_m_n723[] = { 194 { 1000, 940 }, 195 { 900, 908 }, 196 { 800, 876 }, 197 { 600, 812 } 198 }; 199 200 /* Intel Pentium M processor 733 1.1 GHz */ 201 static const struct fq_info pentium_m_n733[] = { 202 { 1100, 940 }, 203 { 1000, 924 }, 204 { 900, 892 }, 205 { 800, 876 }, 206 { 600, 812 } 207 }; 208 209 /* Intel Pentium M processor 753 1.2 GHz */ 210 static const struct fq_info pentium_m_n753[] = { 211 { 1200, 940 }, 212 { 1100, 924 }, 213 { 1000, 908 }, 214 { 900, 876 }, 215 { 800, 860 }, 216 { 600, 812 } 217 }; 218 219 /* Intel Pentium M processor 738 1.4 GHz */ 220 static const struct fq_info pentium_m_n738[] = { 221 { 1400, 1116 }, 222 { 1300, 1116 }, 223 { 1200, 1100 }, 224 { 1100, 1068 }, 225 { 1000, 1052 }, 226 { 900, 1036 }, 227 { 800, 1020 }, 228 { 600, 988 } 229 }; 230 231 #if 0 232 /* Intel Pentium M processor 758 1.5 GHz */ 233 static const struct fq_info pentium_m_n758[] = { 234 { 1500, 1116 }, 235 { 1400, 1116 }, 236 { 1300, 1100 }, 237 { 1200, 1084 }, 238 { 1100, 1068 }, 239 { 1000, 1052 }, 240 { 900, 1036 }, 241 { 800, 1020 }, 242 { 600, 988 } 243 }; 244 #endif 245 246 /* Intel Pentium M processor 715 1.5 GHz */ 247 static const struct fq_info pentium_m_n715[] = { 248 { 1500, 1340 }, 249 { 1200, 1228 }, 250 { 1000, 1148 }, 251 { 800, 1068 }, 252 { 600, 988 } 253 }; 254 255 /* Intel Pentium M processor 725 1.6 GHz */ 256 static const struct fq_info pentium_m_n725[] = { 257 { 1600, 1340 }, 258 { 1400, 1276 }, 259 { 1200, 1212 }, 260 { 1000, 1132 }, 261 { 800, 1068 }, 262 { 600, 988 } 263 }; 264 265 /* Intel Pentium M processor 735 1.7 GHz */ 266 static const struct fq_info pentium_m_n735[] = { 267 { 1700, 1340 }, 268 { 1400, 1244 }, 269 { 1200, 1180 }, 270 { 1000, 1116 }, 271 { 800, 1052 }, 272 { 600, 988 } 273 }; 274 275 /* Intel Pentium M processor 745 1.8 GHz */ 276 static const struct fq_info pentium_m_n745[] = { 277 { 1800, 1340 }, 278 { 1600, 1292 }, 279 { 1400, 1228 }, 280 { 1200, 1164 }, 281 { 1000, 1116 }, 282 { 800, 1052 }, 283 { 600, 988 } 284 }; 285 286 /* Intel Pentium M processor 755 2.0 GHz */ 287 static const struct fq_info pentium_m_n755[] = { 288 { 2000, 1340 }, 289 { 1800, 1292 }, 290 { 1600, 1244 }, 291 { 1400, 1196 }, 292 { 1200, 1148 }, 293 { 1000, 1100 }, 294 { 800, 1052 }, 295 { 600, 988 } 296 }; 297 298 /* Intel Pentium M processor 765 2.1 GHz */ 299 static const struct fq_info pentium_m_n765[] = { 300 { 2100, 1340 }, 301 { 1800, 1276 }, 302 { 1600, 1228 }, 303 { 1400, 1180 }, 304 { 1200, 1132 }, 305 { 1000, 1084 }, 306 { 800, 1036 }, 307 { 600, 988 } 308 }; 309 310 struct fqlist { 311 const char *brand_tag; 312 const struct fq_info *table; 313 int n; 314 }; 315 316 static const struct fqlist pentium_m[] = { 317 #define ENTRY(s, v) { s, v, (int)(sizeof(v) / sizeof((v)[0])) } 318 ENTRY(" 900", pentium_m_900), 319 ENTRY("1000", pentium_m_1000), 320 ENTRY("1100", pentium_m_1100), 321 ENTRY("1200", pentium_m_1200), 322 ENTRY("1300", pentium_m_1300), 323 ENTRY("1400", pentium_m_1400), 324 ENTRY("1500", pentium_m_1500), 325 ENTRY("1600", pentium_m_1600), 326 ENTRY("1700", pentium_m_1700), 327 #undef ENTRY 328 }; 329 330 static const struct fqlist pentium_m_dothan[] = { 331 #define ENTRY(s, v) { s, v, (int)(sizeof(v) / sizeof((v)[0])) } 332 ENTRY("1.00", pentium_m_n723), 333 ENTRY("1.10", pentium_m_n733), 334 ENTRY("1.20", pentium_m_n753), 335 ENTRY("1.40", pentium_m_n738), 336 #if 0 337 ENTRY("1.50", pentium_m_n758), 338 #endif 339 ENTRY("1.50", pentium_m_n715), 340 ENTRY("1.60", pentium_m_n725), 341 ENTRY("1.70", pentium_m_n735), 342 ENTRY("1.80", pentium_m_n745), 343 ENTRY("2.00", pentium_m_n755), 344 ENTRY("2.10", pentium_m_n765), 345 #undef ENTRY 346 }; 347 348 struct est_cpu { 349 const char *brand_prefix; 350 const char *brand_suffix; 351 const struct fqlist *list; 352 int n; 353 }; 354 355 static const struct est_cpu est_cpus[] = { 356 { 357 "Intel(R) Pentium(R) M processor ", "MHz", 358 pentium_m, 359 (int)(sizeof(pentium_m) / sizeof(pentium_m[0])) 360 }, 361 { 362 "Intel(R) Pentium(R) M processor ", "GHz", 363 pentium_m_dothan, 364 (int)(sizeof(pentium_m_dothan) / sizeof(pentium_m_dothan[0])) 365 }, 366 }; 367 368 #define NESTCPUS (int)(sizeof(est_cpus) / sizeof(est_cpus[0])) 369 370 371 #define MSRVALUE(mhz, mv) ((((mhz) / 100) << 8) | (((mv) - 700) / 16)) 372 #define MSR2MHZ(msr) (int)((((u_int) (msr) >> 8) & 0xff) * 100) 373 #define MSR2MV(msr) (((int) (msr) & 0xff) * 16 + 700) 374 375 static const struct fqlist *est_fqlist; 376 377 static int maxfreq; /* max speed in Mhz */ 378 static int maxvolts; /* max voltage in mV */ 379 static int curfreq; /* current speed in Mhz */ 380 static int curvolts; /* current voltage in mV */ 381 #ifdef CONFIG_DVS_EMULATION 382 static int bochs; /* true if bochs is active */ 383 #endif 384 385 /* 386 * Set CPU performance 387 * 388 * @level: percent of cpu speed 389 */ 390 static int 391 est_setperf(int level) 392 { 393 int i; 394 int fq, max_mhz; 395 u_int msr_lo, msr_hi; 396 397 max_mhz = est_fqlist->table[0].mhz; 398 fq = max_mhz * level / 100; 399 400 for (i = est_fqlist->n - 1; i > 0; i--) 401 if (est_fqlist->table[i].mhz >= fq) 402 break; 403 404 if (est_fqlist->table[i].mhz == curfreq) 405 return 0; 406 407 curfreq = est_fqlist->table[i].mhz; 408 curvolts = est_fqlist->table[i].mv; 409 #ifdef DEBUG_EST 410 DPRINTF(("setperf: %dMHz %dmV\n", curfreq, curvolts)); 411 #endif 412 #ifdef CONFIG_DVS_EMULATION 413 if (bochs) 414 return 0; 415 #endif 416 rdmsr(MSR_PERF_CTL, &msr_lo, &msr_hi); 417 msr_lo = (msr_lo & ~0xffff) | 418 MSRVALUE(est_fqlist->table[i].mhz, est_fqlist->table[i].mv); 419 wrmsr(MSR_PERF_CTL, msr_lo, msr_hi); 420 return 0; 421 } 422 423 /* 424 * Get CPU performance 425 */ 426 static int 427 est_getperf(void) 428 { 429 int max_mhz; 430 int level; 431 432 max_mhz = est_fqlist->table[0].mhz; 433 ASSERT(max_mhz); 434 level = curfreq * 100 / max_mhz; 435 return level; 436 } 437 438 static void 439 est_getinfo(struct cpufreqinfo *info) 440 { 441 442 info->maxfreq = maxfreq; 443 info->maxvolts = maxvolts; 444 info->freq = curfreq; 445 info->volts = curvolts; 446 } 447 448 static int 449 est_identify(char *brand_str) 450 { 451 int i, j, mhz, mv; 452 size_t len; 453 const struct est_cpu *cpu; 454 u_int msr_lo, msr_hi; 455 char *tag; 456 const struct fqlist *fql; 457 458 DPRINTF(("CPU brand: %s\n", brand_str)); 459 460 #ifdef CONFIG_DVS_EMULATION 461 if (bochs) { 462 msr_lo = 0x1031; 463 cpu = &est_cpus[0]; 464 est_fqlist = &cpu->list[7]; 465 } else 466 rdmsr(MSR_PERF_STATUS, &msr_lo, &msr_hi); 467 #else 468 rdmsr(MSR_PERF_STATUS, &msr_lo, &msr_hi); 469 #endif 470 mhz = MSR2MHZ(msr_lo); 471 mv = MSR2MV(msr_lo); 472 473 #ifdef CONFIG_DVS_EMULATION 474 if (!bochs) { 475 #endif 476 /* 477 * Look for a CPU matching brand_str. 478 */ 479 for (i = 0; est_fqlist == NULL && i < NESTCPUS; i++) { 480 cpu = &est_cpus[i]; 481 len = strnlen(cpu->brand_prefix, 48); 482 if (strncmp(cpu->brand_prefix, brand_str, len) != 0) 483 continue; 484 tag = brand_str + len; 485 for (j = 0; j < cpu->n; j++) { 486 fql = &cpu->list[j]; 487 len = strnlen(fql->brand_tag, 48); 488 if (!strncmp(fql->brand_tag, tag, len) && 489 !strncmp(cpu->brand_suffix, tag + len, 48)) { 490 est_fqlist = fql; 491 break; 492 } 493 } 494 } 495 if (est_fqlist == NULL) { 496 DPRINTF(("Unknown EST cpu, no changes possible\n")); 497 return ENXIO; 498 } 499 500 /* 501 * Check that the current operating point is in our list. 502 */ 503 for (i = est_fqlist->n - 1; i >= 0; i--) 504 if (est_fqlist->table[i].mhz == mhz) 505 break; 506 if (i < 0) { 507 DPRINTF((" (not in table)\n")); 508 return ENXIO; 509 } 510 #ifdef CONFIG_DVS_EMULATION 511 } 512 #endif 513 /* 514 * Store current state 515 */ 516 maxfreq = est_fqlist->table[0].mhz; 517 maxvolts = est_fqlist->table[0].mv; 518 curfreq = mhz; 519 curvolts = mv; 520 return 0; 521 } 522 523 static int 524 est_probe(struct driver *self) 525 { 526 u_int regs[4]; 527 char brand_str[49]; 528 char *p, *q; 529 u_int cpu_id; 530 531 #ifdef CONFIG_DVS_EMULATION 532 bochs = 0; 533 if (bus_read_8(0xe9) == 0xe9) { 534 /* 535 * Detect Bochs. Fake the cpuid value. 536 */ 537 bochs = 1; 538 cpu_id = 0x6d6; 539 strlcpy(brand_str, 540 "Intel(R) Pentium(R) M processor 1600MHz", 541 sizeof(brand_str)); 542 DPRINTF(("CPU ID: %08x\n", cpu_id)); 543 return est_identify(brand_str); 544 } 545 #endif 546 /* 547 * Check enhanced speed step capability 548 */ 549 cpuid(1, regs); 550 cpu_id = regs[0]; 551 DPRINTF(("CPU ID: %08x\n", cpu_id)); 552 if ((regs[2] & 0x80) == 0) { 553 DPRINTF(("cpu: clock control not supported\n")); 554 return ENXIO; 555 } 556 557 /* 558 * Get CPU brand string 559 */ 560 cpuid(0x80000002, regs); 561 memcpy(brand_str, regs, sizeof(regs)); 562 cpuid(0x80000003, regs); 563 memcpy(brand_str + 16, regs, sizeof(regs)); 564 cpuid(0x80000004, regs); 565 memcpy(brand_str + 32, regs, sizeof(regs)); 566 567 /* Store string with lef-align */ 568 p = q = brand_str; 569 while (*p == ' ') 570 p++; 571 while (*p) 572 *q++ = *p++; 573 *q = '\0'; 574 575 return est_identify(brand_str); 576 } 577 578 static int 579 est_init(struct driver *self) 580 { 581 #ifdef DEBUG 582 int i; 583 #endif 584 585 cpufreq_attach(&est_ops); 586 587 #ifdef DEBUG 588 printf("Enhanced SpeedStep %d MHz (%d mV)\n", curfreq, curvolts); 589 printf("Speeds: "); 590 for (i = 0; i < est_fqlist->n; i++) 591 printf("%d%s", est_fqlist->table[i].mhz, 592 i < est_fqlist->n - 1 ? ", " : " MHz\n"); 593 #endif 594 return 0; 595 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |