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> 235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/msr.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/processor.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/cpufeature.h> 28fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen#include <asm/cpu_device_id.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PFX "speedstep-centrino: " 31dec102aa9ac112d66133314815d20233c96ad749Viresh Kumar#define MAINTAINER "linux-pm@vger.kernel.org" 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 338b9c6671f8dbedbd071a9a6c787d4086a8990db4Gary Hade#define INTEL_MSR_RANGE (0xffff) 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct cpu_id 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 x86; /* CPU family */ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 x86_model; /* model */ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 x86_mask; /* stepping */ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum { 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CPU_BANIAS, 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CPU_DOTHAN_A1, 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CPU_DOTHAN_A2, 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CPU_DOTHAN_B0, 478282864a96ef0a7b88ee9e4b357e08504131394dDave Jones CPU_MP4HT_D0, 488282864a96ef0a7b88ee9e4b357e08504131394dDave Jones CPU_MP4HT_E0, 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct cpu_id cpu_ids[] = { 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [CPU_BANIAS] = { 6, 9, 5 }, 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [CPU_DOTHAN_A1] = { 6, 13, 1 }, 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [CPU_DOTHAN_A2] = { 6, 13, 2 }, 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [CPU_DOTHAN_B0] = { 6, 13, 6 }, 568282864a96ef0a7b88ee9e4b357e08504131394dDave Jones [CPU_MP4HT_D0] = {15, 3, 4 }, 578282864a96ef0a7b88ee9e4b357e08504131394dDave Jones [CPU_MP4HT_E0] = {15, 4, 1 }, 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5938e548ee1a79c8da7b3d9e26f2adce9b61413f84Tobias Klauser#define N_IDS ARRAY_SIZE(cpu_ids) 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct cpu_model 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct cpu_id *cpu_id; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *model_name; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned max_freq; /* max clock in kHz */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 69c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travisstatic int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, 70c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis const struct cpu_id *x); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Operating points for current CPU */ 73c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travisstatic DEFINE_PER_CPU(struct cpu_model *, centrino_model); 74c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travisstatic DEFINE_PER_CPU(const struct cpu_id *, centrino_cpu); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_driver centrino_driver; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Computes the correct form for IA32_PERF_CTL MSR for a particular 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frequency/voltage operating point; frequency in MHz, volts in mV. 825070158804b5339c71809f5e673cea1cfacd804dViresh Kumar This is stored as "driver_data" in the structure. */ 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OP(mhz, mv) \ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { \ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .frequency = (mhz) * 1000, \ 865070158804b5339c71809f5e673cea1cfacd804dViresh Kumar .driver_data = (((mhz)/100) << 8) | ((mv - 700) / 16) \ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These voltage tables were derived from the Intel Pentium M 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * datasheet, document 25261202.pdf, Table 5. I have verified they 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * M. 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ultra Low Voltage Intel Pentium M processor 900MHz (Banias) */ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_900[] = 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(600, 844), 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(800, 988), 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(900, 1004), 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1000[] = 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(600, 844), 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(800, 972), 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(900, 988), 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1004), 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Low Voltage Intel Pentium M processor 1.10GHz (Banias) */ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1100[] = 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1020), 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 900, 1100), 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1164), 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1100, 1180), 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Low Voltage Intel Pentium M processor 1.20GHz (Banias) */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1200[] = 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1004), 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 900, 1020), 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1100), 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1100, 1164), 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1180), 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Intel Pentium M processor 1.30GHz (Banias) */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1300[] = 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1260), 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1292), 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1356), 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1300, 1388), 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Intel Pentium M processor 1.40GHz (Banias) */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1400[] = 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1180), 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1308), 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1436), 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1400, 1484), 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Intel Pentium M processor 1.50GHz (Banias) */ 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1500[] = 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1116), 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1228), 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1356), 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1400, 1452), 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1500, 1484), 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Intel Pentium M processor 1.60GHz (Banias) */ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1600[] = 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1036), 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1164), 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1276), 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1400, 1420), 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1600, 1484), 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Intel Pentium M processor 1.70GHz (Banias) */ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table banias_1700[] = 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 600, 956), 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP( 800, 1004), 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1000, 1116), 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1200, 1228), 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1400, 1308), 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OP(1700, 1484), 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { .frequency = CPUFREQ_TABLE_END } 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef OP 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _BANIAS(cpuid, max, name) \ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ .cpu_id = cpuid, \ 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .model_name = "Intel(R) Pentium(R) M processor " name "MHz", \ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .max_freq = (max)*1000, \ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .op_points = banias_##max, \ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BANIAS(max) _BANIAS(&cpu_ids[CPU_BANIAS], max, #max) 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CPU models, their operating frequency range, and freq/voltage 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds operating points */ 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpu_model models[] = 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _BANIAS(&cpu_ids[CPU_BANIAS], 900, " 900"), 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1000), 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1100), 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1200), 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1300), 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1400), 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1500), 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1600), 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BANIAS(1700), 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NULL model_name is a wildcard */ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL }, 2248282864a96ef0a7b88ee9e4b357e08504131394dDave Jones { &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL }, 2258282864a96ef0a7b88ee9e4b357e08504131394dDave Jones { &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL }, 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { NULL, } 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef _BANIAS 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef BANIAS 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int centrino_cpu_init_table(struct cpufreq_policy *policy) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23492cb7612aee39642d109b8d935ad265e602c0563Mike Travis struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cpu_model *model; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(model = models; model->cpu_id != NULL; model++) 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (centrino_verify_cpu_id(cpu, model->cpu_id) && 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (model->model_name == NULL || 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcmp(cpu->x86_model_id, model->model_name) == 0)) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (model->cpu_id == NULL) { 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No match at all */ 2452d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("no support for CPU model \"%s\": " 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "send /proc/cpuinfo to " MAINTAINER "\n", 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu->x86_model_id); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (model->op_points == NULL) { 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Matched a non-match */ 2532d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("no table support for CPU model \"%s\"\n", 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu->x86_model_id); 2552d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("try using the acpi-cpufreq driver\n"); 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 259c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, policy->cpu) = model; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2612d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("found \"%s\": max frequency: %dkHz\n", 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds model->model_name, model->max_freq); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 268c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travisstatic inline int centrino_cpu_init_table(struct cpufreq_policy *policy) 269c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis{ 270c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis return -ENODEV; 271c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis} 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 274c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travisstatic int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, 275c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis const struct cpu_id *x) 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((c->x86 == x->x86) && 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (c->x86_model == x->x86_model) && 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (c->x86_mask == x->x86_mask)) 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* To be called only after centrino_model is initialized */ 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe) 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Extract clock in kHz from PERF_CTL value 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for centrino, as some DSDTs are buggy. 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ideally, this can be done using the acpi_data structure. 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 294c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if ((per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_BANIAS]) || 295c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis (per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_DOTHAN_A1]) || 296c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis (per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_DOTHAN_B0])) { 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msr = (msr >> 8) & 0xff; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return msr * 100000; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if ((!per_cpu(centrino_model, cpu)) || 302c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis (!per_cpu(centrino_model, cpu)->op_points)) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msr &= 0xffff; 306c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis for (i = 0; 307c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, cpu)->op_points[i].frequency 308c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis != CPUFREQ_TABLE_END; 309c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis i++) { 3105070158804b5339c71809f5e673cea1cfacd804dViresh Kumar if (msr == per_cpu(centrino_model, cpu)->op_points[i].driver_data) 311c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis return per_cpu(centrino_model, cpu)-> 312c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis op_points[i].frequency; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (failsafe) 315c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis return per_cpu(centrino_model, cpu)->op_points[i-1].frequency; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return the current CPU frequency in kHz */ 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int get_cur_freq(unsigned int cpu) 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned l, h; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned clock_freq; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 326e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell rdmsr_on_cpu(cpu, MSR_IA32_PERF_STATUS, &l, &h); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clock_freq = extract_clock(l, cpu, 0); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(clock_freq == 0)) { 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On some CPUs, we can see transient MSR values (which are 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not present in _PSS), while CPU is doing some automatic 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * P-state transition (like TM2). Get the last freq set 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in PERF_CTL. 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 336e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell rdmsr_on_cpu(cpu, MSR_IA32_PERF_CTL, &l, &h); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clock_freq = extract_clock(l, cpu, 1); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return clock_freq; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int centrino_cpu_init(struct cpufreq_policy *policy) 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 34592cb7612aee39642d109b8d935ad265e602c0563Mike Travis struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned l, h; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Only Intel makes Enhanced Speedstep-capable CPUs */ 350c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if (cpu->x86_vendor != X86_VENDOR_INTEL || 351c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis !cpu_has(cpu, X86_FEATURE_EST)) 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3548ad5496d2359a19127ad9f2eda69485025c9917fDave Jones if (cpu_has(cpu, X86_FEATURE_CONSTANT_TSC)) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds centrino_driver.flags |= CPUFREQ_CONST_LOOPS; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35768485695e5a84399da7b48b208ac42623fe22963Adrian Bunk if (policy->cpu != 0) 35868485695e5a84399da7b48b208ac42623fe22963Adrian Bunk return -ENODEV; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36068485695e5a84399da7b48b208ac42623fe22963Adrian Bunk for (i = 0; i < N_IDS; i++) 36168485695e5a84399da7b48b208ac42623fe22963Adrian Bunk if (centrino_verify_cpu_id(cpu, &cpu_ids[i])) 36268485695e5a84399da7b48b208ac42623fe22963Adrian Bunk break; 363f914be79ab2144efe291d9fc383661e0e23dca44Venkatesh Pallipadi 36468485695e5a84399da7b48b208ac42623fe22963Adrian Bunk if (i != N_IDS) 365c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_cpu, policy->cpu) = &cpu_ids[i]; 366f914be79ab2144efe291d9fc383661e0e23dca44Venkatesh Pallipadi 367c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if (!per_cpu(centrino_cpu, policy->cpu)) { 3682d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("found unsupported CPU with " 36968485695e5a84399da7b48b208ac42623fe22963Adrian Bunk "Enhanced SpeedStep: send /proc/cpuinfo to " 37068485695e5a84399da7b48b208ac42623fe22963Adrian Bunk MAINTAINER "\n"); 37168485695e5a84399da7b48b208ac42623fe22963Adrian Bunk return -ENODEV; 37268485695e5a84399da7b48b208ac42623fe22963Adrian Bunk } 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3747b6f38f09ebb4b88e8ed7740bcbcc08a8882bbb7Evgeny Kapaev if (centrino_cpu_init_table(policy)) 37568485695e5a84399da7b48b208ac42623fe22963Adrian Bunk return -ENODEV; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check to see if Enhanced SpeedStep is enabled, and try to 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable it if not. */ 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rdmsr(MSR_IA32_MISC_ENABLE, l, h); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381ecab22aa6dc9d42ca52de2cad0854b4c6bd85ac9Vegard Nossum if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { 382ecab22aa6dc9d42ca52de2cad0854b4c6bd85ac9Vegard Nossum l |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP; 3832d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("trying to enable Enhanced SpeedStep (%x)\n", l); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wrmsr(MSR_IA32_MISC_ENABLE, l, h); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check to see if it stuck */ 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rdmsr(MSR_IA32_MISC_ENABLE, l, h); 388ecab22aa6dc9d42ca52de2cad0854b4c6bd85ac9Vegard Nossum if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { 389c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis printk(KERN_INFO PFX 390c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis "couldn't enable Enhanced SpeedStep\n"); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 395c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis policy->cpuinfo.transition_latency = 10000; 396c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis /* 10uS transition latency */ 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3985f3a2d39bb9dd4372c52fb2568c4520bcc91c8c4Viresh Kumar return cpufreq_table_validate_and_show(policy, 399c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, policy->cpu)->op_points); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int centrino_cpu_exit(struct cpufreq_policy *policy) 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cpu = policy->cpu; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 406c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if (!per_cpu(centrino_model, cpu)) 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 409c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis per_cpu(centrino_model, cpu) = NULL; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * centrino_setpolicy - set a new CPUFreq policy 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @policy: new policy 4179c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar * @index: index of target frequency 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sets a new CPUFreq policy. 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4219c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumarstatic int centrino_target(struct cpufreq_policy *policy, unsigned int index) 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 423c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; 424c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi int retval = 0; 425d4019f0a92ab802f385cc9c8ad3ab7b5449712cbViresh Kumar unsigned int j, first_cpu; 4269c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar struct cpufreq_frequency_table *op_points; 427e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell cpumask_var_t covered_cpus; 428eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis 429e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell if (unlikely(!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))) 4305cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell return -ENOMEM; 431eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis 432c4762aba0b1f72659aae9ce37b772ca8bd8f06f4Mike Travis if (unlikely(per_cpu(centrino_model, cpu) == NULL)) { 433eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis retval = -ENODEV; 434eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis goto out; 435eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis } 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 437c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi first_cpu = 1; 4389c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar op_points = &per_cpu(centrino_model, cpu)->op_points[index]; 439835481d9bcd65720b473db6b38746a74a3964218Rusty Russell for_each_cpu(j, policy->cpus) { 440e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell int good_cpu; 4419963d1aad40946b1b6d34f9bee8d8a1b9032ae22Rusty Russell 442c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi /* 443c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * Support for SMP systems. 444c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * Make sure we are running on CPU that wants to change freq 445c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi */ 446c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 447e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell good_cpu = cpumask_any_and(policy->cpus, 448e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell cpu_online_mask); 449c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi else 450e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell good_cpu = j; 451c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi 452e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell if (good_cpu >= nr_cpu_ids) { 4532d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("couldn't limit to CPUs in this domain\n"); 454c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi retval = -EAGAIN; 455c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (first_cpu) { 456c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi /* We haven't started the transition yet. */ 457e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell goto out; 458c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 459c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi break; 460c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4629c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar msr = op_points->driver_data; 463c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi 464c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (first_cpu) { 465e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h); 466c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (msr == (oldmsr & 0xffff)) { 4672d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("no change needed - msr was and needs " 468c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi "to be %x\n", oldmsr); 469c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi retval = 0; 470e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell goto out; 471c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 472c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi 473c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi first_cpu = 0; 474c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi /* all but 16 LSB are reserved, treat them with care */ 475c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi oldmsr &= ~0xffff; 476c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi msr &= 0xffff; 477c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi oldmsr |= msr; 478c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 480e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell wrmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, oldmsr, h); 481e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 482c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi break; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 484e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell cpumask_set_cpu(j, covered_cpus); 485c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 487c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi if (unlikely(retval)) { 488c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi /* 489c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * We have failed halfway through the frequency change. 490c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * We have sent callbacks to policy->cpus and 491c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * MSRs have already been written on coverd_cpus. 492c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi * Best effort undo.. 493c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi */ 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 495e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell for_each_cpu(j, covered_cpus) 496e3f996c26ff6c4c084aaaa64dce6e54d31f517beRusty Russell wrmsr_on_cpu(j, MSR_IA32_PERF_CTL, oldmsr, h); 497c52851b60cc0aaaf974ff0e49989fb698220447dVenkatesh Pallipadi } 498eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis retval = 0; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 500eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travisout: 5015cb0535f1713b51610f2881b17d0fe3656114364Rusty Russell free_cpumask_var(covered_cpus); 502eb53fac5cafc4b2f8443ff064938b4494a28c54eMike Travis return retval; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_driver centrino_driver = { 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "centrino", /* should be speedstep-centrino, 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds but there's a 16 char limit */ 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .init = centrino_cpu_init, 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .exit = centrino_cpu_exit, 5103be1394a6873496c36d99899fb6ba76ff03a2e96Viresh Kumar .verify = cpufreq_generic_frequency_table_verify, 5119c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar .target_index = centrino_target, 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get = get_cur_freq, 5133be1394a6873496c36d99899fb6ba76ff03a2e96Viresh Kumar .attr = cpufreq_generic_attr, 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 516fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen/* 517fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen * This doesn't replace the detailed checks above because 518fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen * the generic CPU IDs don't have a way to match for steppings 519fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen * or ASCII model IDs. 520fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen */ 521fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleenstatic const struct x86_cpu_id centrino_ids[] = { 522fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen { X86_VENDOR_INTEL, 6, 9, X86_FEATURE_EST }, 523fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen { X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST }, 524fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen { X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST }, 525fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen { X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST }, 526fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen { X86_VENDOR_INTEL, 15, 3, X86_FEATURE_EST }, 527fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen { X86_VENDOR_INTEL, 15, 4, X86_FEATURE_EST }, 528fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen {} 529fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen}; 530fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen#if 0 531fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen/* Autoload or not? Do not for now. */ 532fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi KleenMODULE_DEVICE_TABLE(x86cpu, centrino_ids); 533fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen#endif 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initializes the Enhanced SpeedStep support. Returns -ENODEV on 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unsupported devices, -ENOENT if there's no voltage table for this 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * particular CPU model, -EINVAL on problems during initiatization, 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and zero on success. 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is quite picky. Not only does the CPU have to advertise the 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "est" flag in the cpuid capability flags, we look for a specific 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CPU model and stepping, and we need to have the exact model name in 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * our voltage tables. That is, be paranoid about not releasing 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * someone's valuable magic smoke. 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init centrino_init(void) 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 551fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen if (!x86_match_cpu(centrino_ids)) 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cpufreq_register_driver(¢rino_driver); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit centrino_exit(void) 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpufreq_unregister_driver(¢rino_driver); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>"); 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors."); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL"); 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslate_initcall(centrino_init); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(centrino_exit); 567