11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * AMD K7 Powernow driver. 3f4432c5caec5fa95ea7eefd00f8e6cee17e2e023Dave Jones * (C) 2003 Dave Jones on behalf of SuSE Labs. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) 2003-2004 Dave Jones <davej@redhat.com> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Licensed under the terms of the GNU GPL License version 2. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based upon datasheets & sample CPUs kindly provided by AMD. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones * Errata 5: 10b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones * CPU may fail to execute a FID/VID change in presence of interrupt. 11b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones * - We cli/sti on stepping A0 CPUs around the FID/VID transition. 12b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones * Errata 15: 13b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones * CPU with half frequency multipliers may hang upon wakeup from disconnect. 14b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones * - We disable half multipliers if ACPI is used on A0 stepping CPUs. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cpufreq.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dmi.h> 25b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones#include <linux/timex.h> 26b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones#include <linux/io.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones#include <asm/timer.h> /* Needed for recalibrate_cpu_khz() */ 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/msr.h> 30fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen#include <asm/cpu_device_id.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86_POWERNOW_K7_ACPI 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/acpi.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/processor.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "powernow-k7.h" 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PFX "powernow: " 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct psb_s { 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 signature[10]; 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 tableversion; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 flags; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 settlingtime; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 reserved1; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 numpst; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pst_s { 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 cpuid; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fsbspeed; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 maxfid; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 startvid; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 numpstates; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86_POWERNOW_K7_ACPI 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunion powernow_acpi_control_t { 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct { 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long fid:5, 63b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones vid:5, 64b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones sgtc:20, 65b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones res1:2; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } bits; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* divide by 1000 to get VCore voltage in V. */ 72bd5ab26a7d0cc834d846fe5dd7291f0aed3be72bDave Jonesstatic const int mobile_vid_table[32] = { 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1075, 1050, 1025, 1000, 975, 950, 925, 0, 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* divide by 10 to get FID. */ 80bd5ab26a7d0cc834d846fe5dd7291f0aed3be72bDave Jonesstatic const int fid_codes[32] = { 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 110, 115, 120, 125, 50, 55, 60, 65, 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70, 75, 80, 85, 90, 95, 100, 105, 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30, 190, 40, 200, 130, 135, 140, 210, 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 150, 225, 160, 165, 170, 180, -1, -1, 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This parameter is used in order to force ACPI instead of legacy method for 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configuration purpose. 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acpi_force; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cpufreq_frequency_table *powernow_table; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int can_scale_bus; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int can_scale_vid; 97fff78ad5cee1d6f695103ec590cbd2a9f3c39e8cDave Jonesstatic unsigned int minimum_speed = -1; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int maximum_speed; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int number_scales; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int fsb; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int latency; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char have_a0; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_fsb(unsigned int fsbspeed) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int delta; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int f = fsb / 1000; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed; 110b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones return delta < 5; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 113fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleenstatic const struct x86_cpu_id powernow_k7_cpuids[] = { 11430bcfff9bd41db5edab6420d0ae2e435609eb083Ben Hutchings { X86_VENDOR_AMD, 6, }, 115fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen {} 116fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen}; 117fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi KleenMODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids); 118fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_powernow(void) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12192cb7612aee39642d109b8d935ad265e602c0563Mike Travis struct cpuinfo_x86 *c = &cpu_data(0); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int maxei, eax, ebx, ecx, edx; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 124fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen if (!x86_match_cpu(powernow_k7_cpuids)) 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get maximum capabilities */ 128b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones maxei = cpuid_eax(0x80000000); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (maxei < 0x80000007) { /* Any powernow info ? */ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE 131b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX "No powernow capabilities detected\n"); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((c->x86_model == 6) && (c->x86_mask == 0)) { 137b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX "K7 660[A0] core detected, " 138b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "enabling errata workarounds\n"); 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds have_a0 = 1; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpuid(0x80000007, &eax, &ebx, &ecx, &edx); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check we can actually do something before we say anything.*/ 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(edx & (1 << 1 | 1 << 2))) 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 148b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX "PowerNOW! Technology present. Can scale: "); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (edx & 1 << 1) { 151b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk("frequency"); 152b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones can_scale_bus = 1; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((edx & (1 << 1 | 1 << 2)) == 0x6) 156b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(" and "); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (edx & 1 << 2) { 159b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk("voltage"); 160b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones can_scale_vid = 1; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 163b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(".\n"); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 167d38e73e8dad454a5916f446b0d3523c1161ae95aDave Jones#ifdef CONFIG_X86_POWERNOW_K7_ACPI 168b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jonesstatic void invalidate_entry(unsigned int entry) 169b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones{ 170b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID; 171b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones} 172d38e73e8dad454a5916f446b0d3523c1161ae95aDave Jones#endif 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 174b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jonesstatic int get_ranges(unsigned char *pst) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int j; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int speed; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fid, vid; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 180d5b73cd870e2b049ef566aec2791dbf5fd26a7ecViresh Kumar powernow_table = kzalloc((sizeof(*powernow_table) * 181b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones (number_scales + 1)), GFP_KERNEL); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!powernow_table) 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 185b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones for (j = 0 ; j < number_scales; j++) { 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fid = *pst++; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10; 1895070158804b5339c71809f5e673cea1cfacd804dViresh Kumar powernow_table[j].driver_data = fid; /* lower 8 bits */ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds speed = powernow_table[j].frequency; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 193b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones if ((fid_codes[fid] % 10) == 5) { 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86_POWERNOW_K7_ACPI 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (have_a0 == 1) 196b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones invalidate_entry(j); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (speed < minimum_speed) 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds minimum_speed = speed; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (speed > maximum_speed) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maximum_speed = speed; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vid = *pst++; 2065070158804b5339c71809f5e673cea1cfacd804dViresh Kumar powernow_table[j].driver_data |= (vid << 8); /* upper 8 bits */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2082d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) " 20932ee8c3e470d86588b51dc42ed01e85c5fa0f180Dave Jones "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, 21032ee8c3e470d86588b51dc42ed01e85c5fa0f180Dave Jones fid_codes[fid] % 10, speed/1000, vid, 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mobile_vid_table[vid]/1000, 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mobile_vid_table[vid]%1000); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds powernow_table[number_scales].frequency = CPUFREQ_TABLE_END; 2155070158804b5339c71809f5e673cea1cfacd804dViresh Kumar powernow_table[number_scales].driver_data = 0; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void change_FID(int fid) 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union msr_fidvidctl fidvidctl; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 225b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fidvidctl.bits.FID != fid) { 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fidvidctl.bits.SGTC = latency; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fidvidctl.bits.FID = fid; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fidvidctl.bits.VIDC = 0; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fidvidctl.bits.FIDC = 1; 231b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void change_VID(int vid) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union msr_fidvidctl fidvidctl; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 240b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fidvidctl.bits.VID != vid) { 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fidvidctl.bits.SGTC = latency; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fidvidctl.bits.VID = vid; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fidvidctl.bits.FIDC = 0; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fidvidctl.bits.VIDC = 1; 246b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2519c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumarstatic int powernow_target(struct cpufreq_policy *policy, unsigned int index) 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fid, vid; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cpufreq_freqs freqs; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union msr_fidvidstatus fidvidstatus; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cfid; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* fid are the lower 8 bits of the index we stored into 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the cpufreq frequency table in powernow_decode_bios, 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vid are the upper 8 bits. 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2635070158804b5339c71809f5e673cea1cfacd804dViresh Kumar fid = powernow_table[index].driver_data & 0xFF; 2645070158804b5339c71809f5e673cea1cfacd804dViresh Kumar vid = (powernow_table[index].driver_data & 0xFF00) >> 8; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 266b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfid = fidvidstatus.bits.CFID; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds freqs.old = fsb * fid_codes[cfid] / 10; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds freqs.new = powernow_table[index].frequency; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now do the magic poking into the MSRs. */ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (have_a0 == 1) /* A0 errata 5 */ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_disable(); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (freqs.old > freqs.new) { 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Going down, so change FID first */ 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds change_FID(fid); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds change_VID(vid); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Going up, so change VID first */ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds change_VID(vid); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds change_FID(fid); 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (have_a0 == 1) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_enable(); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2919c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar return 0; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86_POWERNOW_K7_ACPI 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_processor_performance *acpi_processor_perf; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int powernow_acpi_init(void) 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union powernow_acpi_control_t pc; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_processor_perf != NULL && powernow_table != NULL) { 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EINVAL; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err0; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 310d5b73cd870e2b049ef566aec2791dbf5fd26a7ecViresh Kumar acpi_processor_perf = kzalloc(sizeof(*acpi_processor_perf), GFP_KERNEL); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!acpi_processor_perf) { 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENOMEM; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err0; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 316eaa958402ea40851097d051f52ba1bb7a885efe9Yinghai Lu if (!zalloc_cpumask_var(&acpi_processor_perf->shared_cpu_map, 3172fdf66b491ac706657946442789ec644cc317e1aRusty Russell GFP_KERNEL)) { 3182fdf66b491ac706657946442789ec644cc317e1aRusty Russell retval = -ENOMEM; 3192fdf66b491ac706657946442789ec644cc317e1aRusty Russell goto err05; 3202fdf66b491ac706657946442789ec644cc317e1aRusty Russell } 3212fdf66b491ac706657946442789ec644cc317e1aRusty Russell 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_processor_register_performance(acpi_processor_perf, 0)) { 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EIO; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err1; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 327b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones if (acpi_processor_perf->control_register.space_id != 328b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones ACPI_ADR_SPACE_FIXED_HARDWARE) { 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err2; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 333b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones if (acpi_processor_perf->status_register.space_id != 334b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones ACPI_ADR_SPACE_FIXED_HARDWARE) { 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err2; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds number_scales = acpi_processor_perf->state_count; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (number_scales < 2) { 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err2; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 346d5b73cd870e2b049ef566aec2791dbf5fd26a7ecViresh Kumar powernow_table = kzalloc((sizeof(*powernow_table) * 347b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones (number_scales + 1)), GFP_KERNEL); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!powernow_table) { 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENOMEM; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err2; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc.val = (unsigned long) acpi_processor_perf->states[0].control; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < number_scales; i++) { 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fid, vid; 356dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake struct acpi_processor_px *state = 357dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake &acpi_processor_perf->states[i]; 358dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake unsigned int speed, speed_mhz; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 360dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake pc.val = (unsigned long) state->control; 3612d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n", 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i, 363dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake (u32) state->core_frequency, 364dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake (u32) state->power, 365dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake (u32) state->transition_latency, 366dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake (u32) state->control, 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc.bits.sgtc); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vid = pc.bits.vid; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fid = pc.bits.fid; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds powernow_table[i].frequency = fsb * fid_codes[fid] / 10; 3735070158804b5339c71809f5e673cea1cfacd804dViresh Kumar powernow_table[i].driver_data = fid; /* lower 8 bits */ 3745070158804b5339c71809f5e673cea1cfacd804dViresh Kumar powernow_table[i].driver_data |= (vid << 8); /* upper 8 bits */ 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds speed = powernow_table[i].frequency; 377dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake speed_mhz = speed / 1000; 378dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake 379dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake /* processor_perflib will multiply the MHz value by 1000 to 380dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake * get a KHz value (e.g. 1266000). However, powernow-k7 works 381dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake * with true KHz values (e.g. 1266768). To ensure that all 382dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake * powernow frequencies are available, we must ensure that 383dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake * ACPI doesn't restrict them, so we round up the MHz value 384dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake * to ensure that perflib's computed KHz value is greater than 385dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake * or equal to powernow's KHz value. 386dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake */ 387dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake if (speed % 1000 > 0) 388dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake speed_mhz++; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 390b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones if ((fid_codes[fid] % 10) == 5) { 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (have_a0 == 1) 392b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones invalidate_entry(i); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3952d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) " 39632ee8c3e470d86588b51dc42ed01e85c5fa0f180Dave Jones "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, 397dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake fid_codes[fid] % 10, speed_mhz, vid, 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mobile_vid_table[vid]/1000, 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mobile_vid_table[vid]%1000); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake if (state->core_frequency != speed_mhz) { 402dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake state->core_frequency = speed_mhz; 4032d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug(" Corrected ACPI frequency to %d\n", 404dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake speed_mhz); 405dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake } 406dc2585eb478cfeb45b3d6e235ac7b5918fb859f7Daniel Drake 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (latency < pc.bits.sgtc) 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds latency = pc.bits.sgtc; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (speed < minimum_speed) 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds minimum_speed = speed; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (speed > maximum_speed) 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maximum_speed = speed; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds powernow_table[i].frequency = CPUFREQ_TABLE_END; 4175070158804b5339c71809f5e673cea1cfacd804dViresh Kumar powernow_table[i].driver_data = 0; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* notify BIOS that we exist */ 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_processor_notify_smm(THIS_MODULE); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr2: 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_processor_unregister_performance(acpi_processor_perf, 0); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr1: 4272fdf66b491ac706657946442789ec644cc317e1aRusty Russell free_cpumask_var(acpi_processor_perf->shared_cpu_map); 4282fdf66b491ac706657946442789ec644cc317e1aRusty Russellerr05: 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(acpi_processor_perf); 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr0: 431b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_WARNING PFX "ACPI perflib can not be used on " 432b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "this platform\n"); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_processor_perf = NULL; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int powernow_acpi_init(void) 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO PFX "no support for ACPI processor found." 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " Please recompile your kernel with ACPI processor\n"); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 445b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jonesstatic void print_pst_entry(struct pst_s *pst, unsigned int j) 446b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones{ 4472d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("PST:%d (@%p)\n", j, pst); 4482d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n", 449b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid); 450b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones} 451b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones 452b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jonesstatic int powernow_decode_bios(int maxfid, int startvid) 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct psb_s *psb; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pst_s *pst; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i, j; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *p; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int etuple; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ret; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds etuple = cpuid_eax(0x80000001); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 463b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones for (i = 0xC0000; i < 0xffff0 ; i += 16) { 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = phys_to_virt(i); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 467b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones if (memcmp(p, "AMDK7PNOW!", 10) == 0) { 4682d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("Found PSB header at %p\n", p); 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psb = (struct psb_s *) p; 4702d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("Table version: 0x%x\n", psb->tableversion); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (psb->tableversion != 0x12) { 472b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX "Sorry, only v1.2 tables" 473b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones " supported right now\n"); 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4772d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("Flags: 0x%x\n", psb->flags); 478b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones if ((psb->flags & 1) == 0) 4792d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("Mobile voltage regulator\n"); 480b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones else 4812d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("Desktop voltage regulator\n"); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds latency = psb->settlingtime; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (latency < 100) { 485b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX "BIOS set settling time " 486b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "to %d microseconds. " 487b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "Should be at least 100. " 488b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "Correcting.\n", latency); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds latency = 100; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4912d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("Settling Time: %d microseconds.\n", 492b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones psb->settlingtime); 4932d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("Has %d PST tables. (Only dumping ones " 494b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "relevant to this CPU).\n", 495b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones psb->numpst); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 497d5b73cd870e2b049ef566aec2791dbf5fd26a7ecViresh Kumar p += sizeof(*psb); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pst = (struct pst_s *) p; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones for (j = 0; j < psb->numpst; j++) { 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pst = (struct pst_s *) p; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds number_scales = pst->numpstates; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 505b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones if ((etuple == pst->cpuid) && 506b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones check_fsb(pst->fsbspeed) && 507b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones (maxfid == pst->maxfid) && 508b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones (startvid == pst->startvid)) { 509b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones print_pst_entry(pst, j); 510d5b73cd870e2b049ef566aec2791dbf5fd26a7ecViresh Kumar p = (char *)pst + sizeof(*pst); 511b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones ret = get_ranges(p); 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5148cbe0169053ffa185ad349088eb0901946c14a09Dave Jones unsigned int k; 515d5b73cd870e2b049ef566aec2791dbf5fd26a7ecViresh Kumar p = (char *)pst + sizeof(*pst); 516b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones for (k = 0; k < number_scales; k++) 517b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones p += 2; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 520b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX "No PST tables match this cpuid " 521b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "(0x%x)\n", etuple); 522b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX "This is indicative of a broken " 523b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "BIOS.\n"); 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p++; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We use the fact that the bus frequency is somehow 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a multiple of 100000/3 khz, then we compute sgtc according 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to this multiple. 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * That way, we match more how AMD thinks all of that work. 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We will then get the same kind of behaviour already tested under 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the "well-known" other OS. 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5422760984f6578d5a462155bb4727766d0c8b68387Paul Gortmakerstatic int fixup_sgtc(void) 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int sgtc; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int m; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m = fsb / 3333; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((m % 10) >= 5) 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m += 5; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m /= 10; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgtc = 100 * m * latency; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgtc = sgtc / 3; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sgtc > 0xfffff) { 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgtc = 0xfffff; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sgtc; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int powernow_get(unsigned int cpu) 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union msr_fidvidstatus fidvidstatus; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cfid; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cpu) 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 569b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfid = fidvidstatus.bits.CFID; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 572b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones return fsb * fid_codes[cfid] / 10; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5762760984f6578d5a462155bb4727766d0c8b68387Paul Gortmakerstatic int acer_cpufreq_pst(const struct dmi_system_id *d) 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 578b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_WARNING PFX 579b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "%s laptop with broken PST tables in BIOS detected.\n", 580b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones d->ident); 581b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_WARNING PFX 582b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "You need to downgrade to 3A21 (09/09/2002), or try a newer " 583b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "BIOS than 3A71 (01/20/2003)\n"); 584b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_WARNING PFX 585b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "cpufreq scaling has been disabled as a result of this.\n"); 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Some Athlon laptops have really fucked PST tables. 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A BIOS update is all that can save them. 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Mention this, and disable cpufreq. 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5942760984f6578d5a462155bb4727766d0c8b68387Paul Gortmakerstatic struct dmi_system_id powernow_dmi_table[] = { 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .callback = acer_cpufreq_pst, 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ident = "Acer Aspire", 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .matches = { 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"), 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMI_MATCH(DMI_BIOS_VERSION, "3A71"), 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6062760984f6578d5a462155bb4727766d0c8b68387Paul Gortmakerstatic int powernow_cpu_init(struct cpufreq_policy *policy) 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union msr_fidvidstatus fidvidstatus; 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (policy->cpu != 0) 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 614b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 616436fe7b8b4a5016ef1fcb32bff77bde84003e15dDave Jones recalibrate_cpu_khz(); 61791350ed49bf3613e243c2e216228cd4ae8f32516Dave Jones 61891350ed49bf3613e243c2e216228cd4ae8f32516Dave Jones fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsb) { 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING PFX "can not determine bus frequency\n"); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6232d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski pr_debug("FSB: %3dMHz\n", fsb/1000); 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dmi_check_system(powernow_dmi_table) || acpi_force) { 626b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX "PSB/PST known to be broken. " 627b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "Trying ACPI instead\n"); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = powernow_acpi_init(); 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 630b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones result = powernow_decode_bios(fidvidstatus.bits.MFID, 631b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones fidvidstatus.bits.SVID); 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 633b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX "Trying ACPI perflib\n"); 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maximum_speed = 0; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds minimum_speed = -1; 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds latency = 0; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = powernow_acpi_init(); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 639b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX 640b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones "ACPI and legacy methods failed\n"); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* SGTC use the bus clock as timer */ 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds latency = fixup_sgtc(); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO PFX "SGTC: %d\n", latency); 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 652b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones printk(KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n", 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds minimum_speed/1000, maximum_speed/1000); 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 655b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones policy->cpuinfo.transition_latency = 656b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones cpufreq_scale(2000000UL, fsb, latency); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 658b147405aa8e568750bfa99501c7fa831edef47c9Viresh Kumar return cpufreq_table_validate_and_show(policy, powernow_table); 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jonesstatic int powernow_cpu_exit(struct cpufreq_policy *policy) 662b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones{ 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86_POWERNOW_K7_ACPI 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_processor_perf) { 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acpi_processor_unregister_performance(acpi_processor_perf, 0); 6662fdf66b491ac706657946442789ec644cc317e1aRusty Russell free_cpumask_var(acpi_processor_perf->shared_cpu_map); 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(acpi_processor_perf); 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6714ae6673e029d609da7ef4311440d6de501d6967aJesper Juhl kfree(powernow_table); 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 675221dee285ee38099b82437531bcae9fa9cb64cc4Linus Torvaldsstatic struct cpufreq_driver powernow_driver = { 676d63bd27fe953daa402a108e141c36dcc59c6931cViresh Kumar .verify = cpufreq_generic_frequency_table_verify, 6779c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar .target_index = powernow_target, 678e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger .get = powernow_get, 679e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger#ifdef CONFIG_X86_POWERNOW_K7_ACPI 680e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger .bios_limit = acpi_processor_get_bios_limit, 681e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger#endif 682e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger .init = powernow_cpu_init, 683e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger .exit = powernow_cpu_exit, 684e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger .name = "powernow-k7", 685d63bd27fe953daa402a108e141c36dcc59c6931cViresh Kumar .attr = cpufreq_generic_attr, 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 688b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jonesstatic int __init powernow_init(void) 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 690b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jones if (check_powernow() == 0) 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cpufreq_register_driver(&powernow_driver); 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 696b9e7638a301b1245d4675087a05fa90fb4fa1845Dave Jonesstatic void __exit powernow_exit(void) 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpufreq_unregister_driver(&powernow_driver); 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(acpi_force, int, 0444); 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(acpi_force, "Force ACPI to be used."); 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 704b9e7638a301b1245d4675087a05fa90fb4fa1845Dave JonesMODULE_AUTHOR("Dave Jones <davej@redhat.com>"); 705b9e7638a301b1245d4675087a05fa90fb4fa1845Dave JonesMODULE_DESCRIPTION("Powernow driver for AMD K7 processors."); 706b9e7638a301b1245d4675087a05fa90fb4fa1845Dave JonesMODULE_LICENSE("GPL"); 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslate_initcall(powernow_init); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(powernow_exit); 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711