1/* 2 * Pentium 4/Xeon CPU on demand clock modulation/speed scaling 3 * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de> 4 * (C) 2002 Zwane Mwaikambo <zwane@commfireservices.com> 5 * (C) 2002 Arjan van de Ven <arjanv@redhat.com> 6 * (C) 2002 Tora T. Engstad 7 * All Rights Reserved 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 12 * 2 of the License, or (at your option) any later version. 13 * 14 * The author(s) of this software shall not be held liable for damages 15 * of any nature resulting due to the use of this software. This 16 * software is provided AS-IS with no warranties. 17 * 18 * Date Errata Description 19 * 20020525 N44, O17 12.5% or 25% DC causes lockup 20 * 21 */ 22 23#include <linux/kernel.h> 24#include <linux/module.h> 25#include <linux/init.h> 26#include <linux/smp.h> 27#include <linux/cpufreq.h> 28#include <linux/slab.h> 29#include <linux/cpumask.h> 30 31#include <asm/processor.h> 32#include <asm/msr.h> 33#include <asm/timex.h> 34 35#include "speedstep-lib.h" 36 37#define PFX "p4-clockmod: " 38#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "p4-clockmod", msg) 39 40/* 41 * Duty Cycle (3bits), note DC_DISABLE is not specified in 42 * intel docs i just use it to mean disable 43 */ 44enum { 45 DC_RESV, DC_DFLT, DC_25PT, DC_38PT, DC_50PT, 46 DC_64PT, DC_75PT, DC_88PT, DC_DISABLE 47}; 48 49#define DC_ENTRIES 8 50 51 52static int has_N44_O17_errata[NR_CPUS]; 53static unsigned int stock_freq; 54static struct cpufreq_driver p4clockmod_driver; 55static unsigned int cpufreq_p4_get(unsigned int cpu); 56 57static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) 58{ 59 u32 l, h; 60 61 if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV)) 62 return -EINVAL; 63 64 rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); 65 66 if (l & 0x01) 67 dprintk("CPU#%d currently thermal throttled\n", cpu); 68 69 if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT)) 70 newstate = DC_38PT; 71 72 rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); 73 if (newstate == DC_DISABLE) { 74 dprintk("CPU#%d disabling modulation\n", cpu); 75 wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); 76 } else { 77 dprintk("CPU#%d setting duty cycle to %d%%\n", 78 cpu, ((125 * newstate) / 10)); 79 /* bits 63 - 5 : reserved 80 * bit 4 : enable/disable 81 * bits 3-1 : duty cycle 82 * bit 0 : reserved 83 */ 84 l = (l & ~14); 85 l = l | (1<<4) | ((newstate & 0x7)<<1); 86 wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l, h); 87 } 88 89 return 0; 90} 91 92 93static struct cpufreq_frequency_table p4clockmod_table[] = { 94 {DC_RESV, CPUFREQ_ENTRY_INVALID}, 95 {DC_DFLT, 0}, 96 {DC_25PT, 0}, 97 {DC_38PT, 0}, 98 {DC_50PT, 0}, 99 {DC_64PT, 0}, 100 {DC_75PT, 0}, 101 {DC_88PT, 0}, 102 {DC_DISABLE, 0}, 103 {DC_RESV, CPUFREQ_TABLE_END}, 104}; 105 106 107static int cpufreq_p4_target(struct cpufreq_policy *policy, 108 unsigned int target_freq, 109 unsigned int relation) 110{ 111 unsigned int newstate = DC_RESV; 112 struct cpufreq_freqs freqs; 113 int i; 114 115 if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate)) 116 return -EINVAL; 117 118 freqs.old = cpufreq_p4_get(policy->cpu); 119 freqs.new = stock_freq * p4clockmod_table[newstate].index / 8; 120 121 if (freqs.new == freqs.old) 122 return 0; 123 124 /* notifiers */ 125 for_each_cpu_mask(i, policy->cpus) { 126 freqs.cpu = i; 127 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 128 } 129 130 /* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software 131 * Developer's Manual, Volume 3 132 */ 133 for_each_cpu_mask(i, policy->cpus) 134 cpufreq_p4_setdc(i, p4clockmod_table[newstate].index); 135 136 /* notifiers */ 137 for_each_cpu_mask(i, policy->cpus) { 138 freqs.cpu = i; 139 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 140 } 141 142 return 0; 143} 144 145 146static int cpufreq_p4_verify(struct cpufreq_policy *policy) 147{ 148 return cpufreq_frequency_table_verify(policy, &p4clockmod_table[0]); 149} 150 151 152static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) 153{ 154 if (c->x86 == 0x06) { 155 if (cpu_has(c, X86_FEATURE_EST)) 156 printk(KERN_WARNING PFX "Warning: EST-capable CPU detected. " 157 "The acpi-cpufreq module offers voltage scaling" 158 " in addition of frequency scaling. You should use " 159 "that instead of p4-clockmod, if possible.\n"); 160 switch (c->x86_model) { 161 case 0x0E: /* Core */ 162 case 0x0F: /* Core Duo */ 163 p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; 164 return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PCORE); 165 case 0x0D: /* Pentium M (Dothan) */ 166 p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; 167 /* fall through */ 168 case 0x09: /* Pentium M (Banias) */ 169 return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); 170 } 171 } 172 173 if (c->x86 != 0xF) { 174 printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <cpufreq@lists.linux.org.uk>\n"); 175 return 0; 176 } 177 178 /* on P-4s, the TSC runs with constant frequency independent whether 179 * throttling is active or not. */ 180 p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; 181 182 if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) { 183 printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. " 184 "The speedstep-ich or acpi cpufreq modules offer " 185 "voltage scaling in addition of frequency scaling. " 186 "You should use either one instead of p4-clockmod, " 187 "if possible.\n"); 188 return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4M); 189 } 190 191 return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4D); 192} 193 194 195 196static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) 197{ 198 struct cpuinfo_x86 *c = &cpu_data[policy->cpu]; 199 int cpuid = 0; 200 unsigned int i; 201 202#ifdef CONFIG_SMP 203 policy->cpus = cpu_sibling_map[policy->cpu]; 204#endif 205 206 cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask; 207 switch (cpuid) { 208 case 0x0f07: 209 case 0x0f0a: 210 case 0x0f11: 211 case 0x0f12: 212 has_N44_O17_errata[policy->cpu] = 1; 213 dprintk("has errata -- disabling low frequencies\n"); 214 } 215 216 /* get max frequency */ 217 stock_freq = cpufreq_p4_get_frequency(c); 218 if (!stock_freq) 219 return -EINVAL; 220 221 /* table init */ 222 for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) { 223 if ((i<2) && (has_N44_O17_errata[policy->cpu])) 224 p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID; 225 else 226 p4clockmod_table[i].frequency = (stock_freq * i)/8; 227 } 228 cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu); 229 230 /* cpuinfo and default policy values */ 231 policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 232 policy->cpuinfo.transition_latency = 1000000; /* assumed */ 233 policy->cur = stock_freq; 234 235 return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]); 236} 237 238 239static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy) 240{ 241 cpufreq_frequency_table_put_attr(policy->cpu); 242 return 0; 243} 244 245static unsigned int cpufreq_p4_get(unsigned int cpu) 246{ 247 u32 l, h; 248 249 rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); 250 251 if (l & 0x10) { 252 l = l >> 1; 253 l &= 0x7; 254 } else 255 l = DC_DISABLE; 256 257 if (l != DC_DISABLE) 258 return (stock_freq * l / 8); 259 260 return stock_freq; 261} 262 263static struct freq_attr* p4clockmod_attr[] = { 264 &cpufreq_freq_attr_scaling_available_freqs, 265 NULL, 266}; 267 268static struct cpufreq_driver p4clockmod_driver = { 269 .verify = cpufreq_p4_verify, 270 .target = cpufreq_p4_target, 271 .init = cpufreq_p4_cpu_init, 272 .exit = cpufreq_p4_cpu_exit, 273 .get = cpufreq_p4_get, 274 .name = "p4-clockmod", 275 .owner = THIS_MODULE, 276 .attr = p4clockmod_attr, 277}; 278 279 280static int __init cpufreq_p4_init(void) 281{ 282 struct cpuinfo_x86 *c = cpu_data; 283 int ret; 284 285 /* 286 * THERM_CONTROL is architectural for IA32 now, so 287 * we can rely on the capability checks 288 */ 289 if (c->x86_vendor != X86_VENDOR_INTEL) 290 return -ENODEV; 291 292 if (!test_bit(X86_FEATURE_ACPI, c->x86_capability) || 293 !test_bit(X86_FEATURE_ACC, c->x86_capability)) 294 return -ENODEV; 295 296 ret = cpufreq_register_driver(&p4clockmod_driver); 297 if (!ret) 298 printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock Modulation available\n"); 299 300 return (ret); 301} 302 303 304static void __exit cpufreq_p4_exit(void) 305{ 306 cpufreq_unregister_driver(&p4clockmod_driver); 307} 308 309 310MODULE_AUTHOR ("Zwane Mwaikambo <zwane@commfireservices.com>"); 311MODULE_DESCRIPTION ("cpufreq driver for Pentium(TM) 4/Xeon(TM)"); 312MODULE_LICENSE ("GPL"); 313 314late_initcall(cpufreq_p4_init); 315module_exit(cpufreq_p4_exit); 316