speedstep-centrino.c revision 5cb0535f1713b51610f2881b17d0fe3656114364
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * M (part of the Centrino chipset). 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5491b07c98f2ac75f1a4370af76ae2403a4c579f5Jeremy Fitzhardinge * Since the original Pentium M, most new Intel CPUs support Enhanced 6491b07c98f2ac75f1a4370af76ae2403a4c579f5Jeremy Fitzhardinge * SpeedStep. 7491b07c98f2ac75f1a4370af76ae2403a4c579f5Jeremy Fitzhardinge * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Despite the "SpeedStep" in the name, this is almost entirely unlike 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * traditional SpeedStep. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modelled on speedstep.c 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 Jeremy Fitzhardinge <jeremy@goop.org> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cpufreq.h> 204e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/sched.h> /* current */ 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/compiler.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/msr.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/processor.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/cpufeature.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PFX "speedstep-centrino: " 298d5922572038bae9f7b16fcb974eee806727b44cNémeth Márton#define MAINTAINER "cpufreq@vger.kernel.org" 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis#define dprintk(msg...) \ 32c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg) 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 348b9c6671f8dbedbd071a9a6c787d4086a8990db4Gary Hade#define INTEL_MSR_RANGE (0xffff) 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct cpu_id 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 x86; /* CPU family */ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 x86_model; /* model */ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 x86_mask; /* stepping */ 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum { 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CPU_BANIAS, 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CPU_DOTHAN_A1, 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CPU_DOTHAN_A2, 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CPU_DOTHAN_B0, 488282864a96ef0a7b88ee9e4b357e08504131394dDave Jones CPU_MP4HT_D0, 498282864a96ef0a7b88ee9e4b357e08504131394dDave Jones CPU_MP4HT_E0, 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct cpu_id cpu_ids[] = { 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [CPU_BANIAS] = { 6, 9, 5 }, 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [CPU_DOTHAN_A1] = { 6, 13, 1 }, 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [CPU_DOTHAN_A2] = { 6, 13, 2 }, 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [CPU_DOTHAN_B0] = { 6, 13, 6 }, 578282864a96ef0a7b88ee9e4b357e08504131394dDave Jones [CPU_MP4HT_D0] = {15, 3, 4 }, 588282864a96ef0a7b88ee9e4b357e08504131394dDave Jones [CPU_MP4HT_E0] = {15, 4, 1 }, 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6038e548ee1a79c8da7b3d9e26f2adce9b61413f84Tobias Klauser#define N_IDS ARRAY_SIZE(cpu_ids) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct cpu_model 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct cpu_id *cpu_id; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *model_name; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned max_freq; /* max clock in kHz */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 70c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travisstatic int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, 71c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis const struct cpu_id *x); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Operating points for current CPU */ 74c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travisstatic DEFINE_PER_CPU(struct cpu_model *, centrino_model); 75c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travisstatic DEFINE_PER_CPU(const struct cpu_id *, centrino_cpu); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_driver centrino_driver; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Computes the correct form for IA32_PERF_CTL MSR for a particular 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frequency/voltage operating point; frequency in MHz, volts in mV. 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This is stored as "index" in the structure. */ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP(mhz, mv) \ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { \ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .frequency = (mhz) * 1000, \ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .index = (((mhz)/100) << 8) | ((mv - 700) / 16) \ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These voltage tables were derived from the Intel Pentium M 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * datasheet, document 25261202.pdf, Table 5. I have verified they 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * M. 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ultra Low Voltage Intel Pentium M processor 900MHz (Banias) */ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_900[] = 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(600, 844), 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(800, 988), 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(900, 1004), 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */ 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1000[] = 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(600, 844), 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(800, 972), 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(900, 988), 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1004), 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Low Voltage Intel Pentium M processor 1.10GHz (Banias) */ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1100[] = 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1020), 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 900, 1100), 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1164), 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1100, 1180), 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Low Voltage Intel Pentium M processor 1.20GHz (Banias) */ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1200[] = 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1004), 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 900, 1020), 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1100), 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1100, 1164), 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1180), 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Intel Pentium M processor 1.30GHz (Banias) */ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1300[] = 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1260), 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1292), 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1356), 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1300, 1388), 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Intel Pentium M processor 1.40GHz (Banias) */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1400[] = 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1180), 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1308), 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1436), 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1400, 1484), 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Intel Pentium M processor 1.50GHz (Banias) */ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1500[] = 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1116), 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1228), 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1356), 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1400, 1452), 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1500, 1484), 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Intel Pentium M processor 1.60GHz (Banias) */ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1600[] = 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1036), 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1164), 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1276), 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1400, 1420), 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1600, 1484), 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Intel Pentium M processor 1.70GHz (Banias) */ 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1700[] = 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1004), 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1116), 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1228), 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1400, 1308), 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1700, 1484), 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef OP 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _BANIAS(cpuid, max, name) \ 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ .cpu_id = cpuid, \ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .model_name = "Intel(R) Pentium(R) M processor " name "MHz", \ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .max_freq = (max)*1000, \ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .op_points = banias_##max, \ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BANIAS(max) _BANIAS(&cpu_ids[CPU_BANIAS], max, #max) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CPU models, their operating frequency range, and freq/voltage 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds operating points */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpu_model models[] = 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _BANIAS(&cpu_ids[CPU_BANIAS], 900, " 900"), 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1000), 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1100), 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1200), 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1300), 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1400), 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1500), 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1600), 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1700), 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NULL model_name is a wildcard */ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL }, 2258282864a96ef0a7b88ee9e4b357e08504131394dDave Jones { &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL }, 2268282864a96ef0a7b88ee9e4b357e08504131394dDave Jones { &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL }, 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { NULL, } 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef _BANIAS 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef BANIAS 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int centrino_cpu_init_table(struct cpufreq_policy *policy) 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23592cb7612aee39642d109b8d935ad265e602c0563Mike Travis struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cpu_model *model; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(model = models; model->cpu_id != NULL; model++) 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (centrino_verify_cpu_id(cpu, model->cpu_id) && 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (model->model_name == NULL || 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcmp(cpu->x86_model_id, model->model_name) == 0)) 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (model->cpu_id == NULL) { 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No match at all */ 2468c362a5d62c98ee117b229c3555f402e72f5c21eJan Beulich dprintk("no support for CPU model \"%s\": " 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "send /proc/cpuinfo to " MAINTAINER "\n", 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu->x86_model_id); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (model->op_points == NULL) { 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Matched a non-match */ 2548c362a5d62c98ee117b229c3555f402e72f5c21eJan Beulich dprintk("no table support for CPU model \"%s\"\n", 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu->x86_model_id); 25668485695e5a84399da7b48b208ac42623fe22963Adrian Bunk dprintk("try using the acpi-cpufreq driver\n"); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 260c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, policy->cpu) = model; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("found \"%s\": max frequency: %dkHz\n", 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds model->model_name, model->max_freq); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 269c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travisstatic inline int centrino_cpu_init_table(struct cpufreq_policy *policy) 270c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis{ 271c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis return -ENODEV; 272c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis} 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 275c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travisstatic int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, 276c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis const struct cpu_id *x) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((c->x86 == x->x86) && 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (c->x86_model == x->x86_model) && 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (c->x86_mask == x->x86_mask)) 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* To be called only after centrino_model is initialized */ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe) 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Extract clock in kHz from PERF_CTL value 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for centrino, as some DSDTs are buggy. 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ideally, this can be done using the acpi_data structure. 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 295c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if ((per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_BANIAS]) || 296c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis (per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_DOTHAN_A1]) || 297c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis (per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_DOTHAN_B0])) { 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msr = (msr >> 8) & 0xff; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return msr * 100000; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 302c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if ((!per_cpu(centrino_model, cpu)) || 303c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis (!per_cpu(centrino_model, cpu)->op_points)) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msr &= 0xffff; 307c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis for (i = 0; 308c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, cpu)->op_points[i].frequency 309c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis != CPUFREQ_TABLE_END; 310c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis i++) { 311c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if (msr == per_cpu(centrino_model, cpu)->op_points[i].index) 312c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis return per_cpu(centrino_model, cpu)-> 313c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis op_points[i].frequency; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (failsafe) 316c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis return per_cpu(centrino_model, cpu)->op_points[i-1].frequency; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return the current CPU frequency in kHz */ 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int get_cur_freq(unsigned int cpu) 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned l, h; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned clock_freq; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpumask_t saved_mask; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds saved_mask = current->cpus_allowed; 3290bc3cc03fa6e1c20aecb5a33356bcaae410640b9Mike Travis set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (smp_processor_id() != cpu) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rdmsr(MSR_IA32_PERF_STATUS, l, h); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clock_freq = extract_clock(l, cpu, 0); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(clock_freq == 0)) { 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On some CPUs, we can see transient MSR values (which are 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not present in _PSS), while CPU is doing some automatic 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * P-state transition (like TM2). Get the last freq set 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in PERF_CTL. 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rdmsr(MSR_IA32_PERF_CTL, l, h); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clock_freq = extract_clock(l, cpu, 1); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 347fc0e474840d1fd96f28fbd76d4f36b80e7ad1cc3Mike Travis set_cpus_allowed_ptr(current, &saved_mask); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return clock_freq; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int centrino_cpu_init(struct cpufreq_policy *policy) 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 35492cb7612aee39642d109b8d935ad265e602c0563Mike Travis struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned freq; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned l, h; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Only Intel makes Enhanced Speedstep-capable CPUs */ 361c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if (cpu->x86_vendor != X86_VENDOR_INTEL || 362c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis !cpu_has(cpu, X86_FEATURE_EST)) 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3658ad5496d2359a19127ad9f2eda69485025c9917fDave Jones if (cpu_has(cpu, X86_FEATURE_CONSTANT_TSC)) 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds centrino_driver.flags |= CPUFREQ_CONST_LOOPS; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36868485695e5a84399da7b48b208ac42623fe22963Adrian Bunk if (policy->cpu != 0) 36968485695e5a84399da7b48b208ac42623fe22963Adrian Bunk return -ENODEV; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37168485695e5a84399da7b48b208ac42623fe22963Adrian Bunk for (i = 0; i < N_IDS; i++) 37268485695e5a84399da7b48b208ac42623fe22963Adrian Bunk if (centrino_verify_cpu_id(cpu, &cpu_ids[i])) 37368485695e5a84399da7b48b208ac42623fe22963Adrian Bunk break; 374f914be79ab2144efe291d9fc383661e0e23dca44Venkatesh Pallipadi 37568485695e5a84399da7b48b208ac42623fe22963Adrian Bunk if (i != N_IDS) 376c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_cpu, policy->cpu) = &cpu_ids[i]; 377f914be79ab2144efe291d9fc383661e0e23dca44Venkatesh Pallipadi 378c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if (!per_cpu(centrino_cpu, policy->cpu)) { 37968485695e5a84399da7b48b208ac42623fe22963Adrian Bunk dprintk("found unsupported CPU with " 38068485695e5a84399da7b48b208ac42623fe22963Adrian Bunk "Enhanced SpeedStep: send /proc/cpuinfo to " 38168485695e5a84399da7b48b208ac42623fe22963Adrian Bunk MAINTAINER "\n"); 38268485695e5a84399da7b48b208ac42623fe22963Adrian Bunk return -ENODEV; 38368485695e5a84399da7b48b208ac42623fe22963Adrian Bunk } 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38568485695e5a84399da7b48b208ac42623fe22963Adrian Bunk if (centrino_cpu_init_table(policy)) { 38668485695e5a84399da7b48b208ac42623fe22963Adrian Bunk return -ENODEV; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check to see if Enhanced SpeedStep is enabled, and try to 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable it if not. */ 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rdmsr(MSR_IA32_MISC_ENABLE, l, h); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(l & (1<<16))) { 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds l |= (1<<16); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("trying to enable Enhanced SpeedStep (%x)\n", l); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wrmsr(MSR_IA32_MISC_ENABLE, l, h); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check to see if it stuck */ 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rdmsr(MSR_IA32_MISC_ENABLE, l, h); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(l & (1<<16))) { 401c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis printk(KERN_INFO PFX 402c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis "couldn't enable Enhanced SpeedStep\n"); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds freq = get_cur_freq(policy->cpu); 408c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis policy->cpuinfo.transition_latency = 10000; 409c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis /* 10uS transition latency */ 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds policy->cur = freq; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 414c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis ret = cpufreq_frequency_table_cpuinfo(policy, 415c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, policy->cpu)->op_points); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (ret); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 419c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis cpufreq_frequency_table_get_attr( 420c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, policy->cpu)->op_points, policy->cpu); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int centrino_cpu_exit(struct cpufreq_policy *policy) 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cpu = policy->cpu; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 429c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if (!per_cpu(centrino_model, cpu)) 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpufreq_frequency_table_put_attr(cpu); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 434c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, cpu) = NULL; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * centrino_verify - verifies a new CPUFreq policy 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @policy: new policy 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Limit must be within this model's frequency range at least one 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * border included. 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int centrino_verify (struct cpufreq_policy *policy) 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 448c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis return cpufreq_frequency_table_verify(policy, 449c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, policy->cpu)->op_points); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * centrino_setpolicy - set a new CPUFreq policy 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @policy: new policy 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @target_freq: the target frequency 456c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis * @relation: how that frequency relates to achieved frequency 457c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sets a new CPUFreq policy. 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int centrino_target (struct cpufreq_policy *policy, 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int target_freq, 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int relation) 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int newstate = 0; 466c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cpufreq_freqs freqs; 468c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi int retval = 0; 469c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi unsigned int j, k, first_cpu, tmp; 4705cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell cpumask_var_t saved_mask, covered_cpus; 471eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis 4725cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell if (unlikely(!alloc_cpumask_var(&saved_mask, GFP_KERNEL))) 473eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis return -ENOMEM; 4745cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell if (unlikely(!alloc_cpumask_var(&covered_cpus, GFP_KERNEL))) { 4755cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell free_cpumask_var(saved_mask); 4765cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell return -ENOMEM; 4775cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell } 4785cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell cpumask_copy(saved_mask, ¤t->cpus_allowed); 479eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis 480c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if (unlikely(per_cpu(centrino_model, cpu) == NULL)) { 481eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis retval = -ENODEV; 482eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis goto out; 483eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis } 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 485c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (unlikely(cpufreq_frequency_table_target(policy, 486c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, cpu)->op_points, 487c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi target_freq, 488c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi relation, 489c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi &newstate))) { 490eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis retval = -EINVAL; 491eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis goto out; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 494c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi first_cpu = 1; 4959963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell for_each_cpu_mask_nr(j, policy->cpus) { 4969963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell const cpumask_t *mask; 4979963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell 4989963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell /* cpufreq holds the hotplug lock, so we are safe here */ 4999963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell if (!cpu_online(j)) 5009963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell continue; 5019963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell 502c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi /* 503c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * Support for SMP systems. 504c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * Make sure we are running on CPU that wants to change freq 505c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi */ 506c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 5079963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell mask = &policy->cpus; 508c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi else 5099963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell mask = &cpumask_of_cpu(j); 510c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi 5119963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell set_cpus_allowed_ptr(current, mask); 512e8e49190f64896afe79f7136a67c2bdefbd3e322Dave Jones preempt_disable(); 5139963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell if (unlikely(!cpu_isset(smp_processor_id(), *mask))) { 514c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi dprintk("couldn't limit to CPUs in this domain\n"); 515c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi retval = -EAGAIN; 516c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (first_cpu) { 517c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi /* We haven't started the transition yet. */ 518c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi goto migrate_end; 519c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 520e8e49190f64896afe79f7136a67c2bdefbd3e322Dave Jones preempt_enable(); 521c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi break; 522c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 524c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis msr = per_cpu(centrino_model, cpu)->op_points[newstate].index; 525c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi 526c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (first_cpu) { 527c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); 528c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (msr == (oldmsr & 0xffff)) { 529c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi dprintk("no change needed - msr was and needs " 530c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi "to be %x\n", oldmsr); 531c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi retval = 0; 532c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi goto migrate_end; 533c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 534c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi 535c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi freqs.old = extract_clock(oldmsr, cpu, 0); 536c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi freqs.new = extract_clock(msr, cpu, 0); 537c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi 538c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi dprintk("target=%dkHz old=%d new=%d msr=%04x\n", 539c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi target_freq, freqs.old, freqs.new, msr); 540c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi 5419963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell for_each_cpu_mask_nr(k, policy->cpus) { 5429963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell if (!cpu_online(k)) 5439963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell continue; 544c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi freqs.cpu = k; 545c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi cpufreq_notify_transition(&freqs, 546c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi CPUFREQ_PRECHANGE); 547c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 548c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi 549c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi first_cpu = 0; 550c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi /* all but 16 LSB are reserved, treat them with care */ 551c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi oldmsr &= ~0xffff; 552c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi msr &= 0xffff; 553c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi oldmsr |= msr; 554c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 556c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); 557e8e49190f64896afe79f7136a67c2bdefbd3e322Dave Jones if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { 558e8e49190f64896afe79f7136a67c2bdefbd3e322Dave Jones preempt_enable(); 559c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi break; 560e8e49190f64896afe79f7136a67c2bdefbd3e322Dave Jones } 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 562eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis cpu_set(j, *covered_cpus); 563e8e49190f64896afe79f7136a67c2bdefbd3e322Dave Jones preempt_enable(); 564c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5669963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell for_each_cpu_mask_nr(k, policy->cpus) { 5679963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell if (!cpu_online(k)) 5689963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell continue; 569c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi freqs.cpu = k; 570c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 571c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 573c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (unlikely(retval)) { 574c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi /* 575c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * We have failed halfway through the frequency change. 576c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * We have sent callbacks to policy->cpus and 577c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * MSRs have already been written on coverd_cpus. 578c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * Best effort undo.. 579c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi */ 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5819963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell for_each_cpu_mask_nr(j, *covered_cpus) { 5829963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell set_cpus_allowed_ptr(current, &cpumask_of_cpu(j)); 5839963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); 5849963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell } 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 586c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi tmp = freqs.new; 587c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi freqs.new = freqs.old; 588c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi freqs.old = tmp; 5899963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell for_each_cpu_mask_nr(j, policy->cpus) { 5909963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell if (!cpu_online(j)) 5919963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell continue; 592c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 593c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 594c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 595c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 596eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis set_cpus_allowed_ptr(current, saved_mask); 597eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis retval = 0; 598eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis goto out; 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmigrate_end: 601e8e49190f64896afe79f7136a67c2bdefbd3e322Dave Jones preempt_enable(); 602eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis set_cpus_allowed_ptr(current, saved_mask); 603eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travisout: 6045cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell free_cpumask_var(saved_mask); 6055cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell free_cpumask_var(covered_cpus); 606eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis return retval; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct freq_attr* centrino_attr[] = { 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &cpufreq_freq_attr_scaling_available_freqs, 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NULL, 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_driver centrino_driver = { 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "centrino", /* should be speedstep-centrino, 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds but there's a 16 char limit */ 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .init = centrino_cpu_init, 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .exit = centrino_cpu_exit, 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .verify = centrino_verify, 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .target = centrino_target, 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get = get_cur_freq, 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .attr = centrino_attr, 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initializes the Enhanced SpeedStep support. Returns -ENODEV on 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unsupported devices, -ENOENT if there's no voltage table for this 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * particular CPU model, -EINVAL on problems during initiatization, 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and zero on success. 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is quite picky. Not only does the CPU have to advertise the 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "est" flag in the cpuid capability flags, we look for a specific 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CPU model and stepping, and we need to have the exact model name in 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * our voltage tables. That is, be paranoid about not releasing 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * someone's valuable magic smoke. 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init centrino_init(void) 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 64392cb7612aee39642d109b8d935ad265e602c0563Mike Travis struct cpuinfo_x86 *cpu = &cpu_data(0); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cpu_has(cpu, X86_FEATURE_EST)) 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cpufreq_register_driver(¢rino_driver); 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit centrino_exit(void) 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpufreq_unregister_driver(¢rino_driver); 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>"); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors."); 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL"); 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslate_initcall(centrino_init); 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(centrino_exit); 662