Most recent kernel where this bug did not occur: Distribution: Fedora core 6 Hardware Environment: Laptop Prestigio Nobile 157 #cat /proc/cpuinfo [olda@Prestigio ~]$ cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 13 model name : Intel(R) Pentium(R) M processor 1.70GHz stepping : 6 cpu MHz : 600.000 cache size : 2048 KB fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 2 wp : yes flags : fpu vme de pse tsc msr mce cx8 sep mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss tm pbe est tm2 bogomips : 1197.27 [olda@Prestigio ~]$ cpuid CPU: vendor_id = "GenuineIntel" version information (1/eax): processor type = primary processor (0) family = Intel Pentium Pro/II/III/Celeron, AMD Athlon/Duron, Cyrix M2, VIA C3 (6) model = 0xd (13) stepping id = 0x6 (6) extended family = 0x0 (0) extended model = 0x0 (0) (simple synth) = Intel Pentium M (Dothan B1) / Celeron M (Dothan B1), 90nm miscellaneous (1/ebx): process local APIC physical ID = 0x0 (0) cpu count = 0x0 (0) CLFLUSH line size = 0x8 (8) brand index = 0x16 (22) brand id = 0x16 (22): Intel Pentium M, .13um feature information (1/edx): x87 FPU on chip = true virtual-8086 mode enhancement = true debugging extensions = true page size extensions = true time stamp counter = true RDMSR and WRMSR support = true physical address extensions = false machine check exception = true CMPXCHG8B inst. = true APIC on chip = false SYSENTER and SYSEXIT = true memory type range registers = true PTE global bit = true machine check architecture = true conditional move/compare instruction = true page attribute table = true page size extension = false processor serial number = false CLFLUSH instruction = true debug store = true thermal monitor and clock ctrl = true MMX Technology = true FXSAVE/FXRSTOR = true SSE extensions = true SSE2 extensions = true self snoop = true hyper-threading / multi-core supported = false therm. monitor = true IA64 = false pending break event = true feature information (1/ecx): PNI/SSE3: Prescott New Instructions = false MONITOR/MWAIT = false CPL-qualified debug store = false VMX: virtual machine extensions = false Enhanced Intel SpeedStep Technology = true thermal monitor 2 = true context ID: adaptive or shared L1 data = false cmpxchg16b available = false xTPR disable = false cache and TLB information (2): 0xb0: instruction TLB: 4K, 4-way, 128 entries 0xb3: data TLB: 4K, 4-way, 128 entries 0x02: instruction TLB: 4M pages, 4-way, 2 entries 0xf0: 64 byte prefetching 0x7d: L2 cache: 2M, 8-way, sectored, 64 byte lines 0x30: L1 cache: 32K, 8-way, 64 byte lines 0x04: data TLB: 4M pages, 4-way, 8 entries 0x2c: L1 data cache: 32K, 8-way, 64 byte lines extended feature flags (0x80000001/edx): SYSCALL and SYSRET instructions = false execution disable = false 64-bit extensions technology available = false Intel feature flags (0x80000001/ecx): LAHF/SAHF supported in 64-bit mode = false brand = " Intel(R) Pentium(R) M processor 1.70GHz" (multi-processing synth): none (synth) = Intel Pentium M (Dothan B1), 90nm Software Environment: standard kernel without any proprietary modules Problem Description: CPU frequency scaling (cpufreq) does not work if I use vanilla kernel or kernel from distribution. I had this problem for quiet a long time. Once I found a file from Jeremy Fitzhardinge which solved the problem. There are defined exact processor types and one of them is mine. That file only defines cpufreq_frequency_table based on the document http://www.intel.com/design/mobile/datashts/302189.htm /* Intel Pentium M processor 735 / 1.70GHz (Dothan) */ static struct cpufreq_frequency_table dothan_1700[] = { OP( 600, 988, 988, 988, 988), OP( 800, 1052, 1052, 1052, 1052), OP(1000, 1116, 1116, 1116, 1100), OP(1200, 1180, 1180, 1164, 1148), OP(1400, 1244, 1244, 1228, 1212), OP(1700, 1340, 1324, 1308, 1276), { .frequency = CPUFREQ_TABLE_END } }; With this speedstep-centrino.c everything works great without any problem. So I have to compile kernel every time I upgrade distro or want a new functionality from kernel. I will include the source of sppedstep-centrino.c, kernel compiles and works just fine if I replace original speedstep-centrino.c with the file I use. /* * cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium * M (part of the Centrino chipset). * * Despite the "SpeedStep" in the name, this is almost entirely unlike * traditional SpeedStep. * * Modelled on speedstep.c * * Copyright (C) 2003 Jeremy Fitzhardinge <jeremy@goop.org> * * WARNING WARNING WARNING * * This driver manipulates the PERF_CTL MSR, which is only somewhat * documented. While it seems to work on my laptop, it has not been * tested anywhere else, and it may not work for you, do strange * things or simply crash. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/cpufreq.h> #include <linux/config.h> #include <linux/delay.h> #include <linux/compiler.h> #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI #include <linux/acpi.h> #include <acpi/processor.h> #endif #include <asm/msr.h> #include <asm/processor.h> #include <asm/cpufeature.h> #include "speedstep-est-common.h" #define PFX "speedstep-centrino: " #define MAINTAINER "Jeremy Fitzhardinge <jeremy@goop.org>" #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg) struct cpu_id { __u8 x86; /* CPU family */ __u8 x86_model; /* model */ __u8 x86_mask; /* stepping */ }; enum { CPU_BANIAS, CPU_DOTHAN_A1, CPU_DOTHAN_A2, CPU_DOTHAN_B0, }; static const struct cpu_id cpu_ids[] = { [CPU_BANIAS] = { 6, 9, 5 }, [CPU_DOTHAN_A1] = { 6, 13, 1 }, [CPU_DOTHAN_A2] = { 6, 13, 2 }, [CPU_DOTHAN_B0] = { 6, 13, 6 }, }; #define N_IDS (sizeof(cpu_ids)/sizeof(cpu_ids[0])) struct cpu_model { const struct cpu_id *cpu_id; const char *model_name; unsigned max_freq; /* max clock in kHz */ struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */ }; static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x); /* Operating points for current CPU */ static struct cpu_model *centrino_model[NR_CPUS]; static const struct cpu_id *centrino_cpu[NR_CPUS]; static struct cpufreq_driver centrino_driver; #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE /* Computes the correct form for IA32_PERF_CTL MSR for a particular frequency/voltage operating point; frequency in MHz, volts in mV. This is stored as "index" in the structure. */ #define OP(mhz, mv) \ { \ .frequency = (mhz) * 1000, \ .index = (((mhz)/100) << 8) | ((mv - 700) / 16) \ } /* * These voltage tables were derived from the Intel Pentium M * datasheet, document 25261202.pdf, Table 5. I have verified they * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium * M. */ /* Ultra Low Voltage Intel Pentium M processor 900MHz (Banias) */ static struct cpufreq_frequency_table banias_900[] = { OP(600, 844), OP(800, 988), OP(900, 1004), { .frequency = CPUFREQ_TABLE_END } }; /* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */ static struct cpufreq_frequency_table banias_1000[] = { OP(600, 844), OP(800, 972), OP(900, 988), OP(1000, 1004), { .frequency = CPUFREQ_TABLE_END } }; /* Low Voltage Intel Pentium M processor 1.10GHz (Banias) */ static struct cpufreq_frequency_table banias_1100[] = { OP( 600, 956), OP( 800, 1020), OP( 900, 1100), OP(1000, 1164), OP(1100, 1180), { .frequency = CPUFREQ_TABLE_END } }; /* Low Voltage Intel Pentium M processor 1.20GHz (Banias) */ static struct cpufreq_frequency_table banias_1200[] = { OP( 600, 956), OP( 800, 1004), OP( 900, 1020), OP(1000, 1100), OP(1100, 1164), OP(1200, 1180), { .frequency = CPUFREQ_TABLE_END } }; /* Intel Pentium M processor 1.30GHz (Banias) */ static struct cpufreq_frequency_table banias_1300[] = { OP( 600, 956), OP( 800, 1260), OP(1000, 1292), OP(1200, 1356), OP(1300, 1388), { .frequency = CPUFREQ_TABLE_END } }; /* Intel Pentium M processor 1.40GHz (Banias) */ static struct cpufreq_frequency_table banias_1400[] = { OP( 600, 956), OP( 800, 1180), OP(1000, 1308), OP(1200, 1436), OP(1400, 1484), { .frequency = CPUFREQ_TABLE_END } }; /* Intel Pentium M processor 1.50GHz (Banias) */ static struct cpufreq_frequency_table banias_1500[] = { OP( 600, 956), OP( 800, 1116), OP(1000, 1228), OP(1200, 1356), OP(1400, 1452), OP(1500, 1484), { .frequency = CPUFREQ_TABLE_END } }; /* Intel Pentium M processor 1.60GHz (Banias) */ static struct cpufreq_frequency_table banias_1600[] = { OP( 600, 956), OP( 800, 1036), OP(1000, 1164), OP(1200, 1276), OP(1400, 1420), OP(1600, 1484), { .frequency = CPUFREQ_TABLE_END } }; /* Intel Pentium M processor 1.70GHz (Banias) */ static struct cpufreq_frequency_table banias_1700[] = { OP( 600, 956), OP( 800, 1004), OP(1000, 1116), OP(1200, 1228), OP(1400, 1308), OP(1700, 1484), { .frequency = CPUFREQ_TABLE_END } }; #undef OP /* Dothan processor datasheet 30218903.pdf defines 4 voltages for each frequency (VID#A through VID#D) - this macro allows us to define all of these but we only use the VID#C voltages at compile time - this may need some work if we want to select the voltage profile at runtime. */ #define OP(mhz, mva, mvb, mvc, mvd) \ { \ .frequency = (mhz) * 1000, \ .index = (((mhz)/100) << 8) | ((mvc - 700) / 16) \ } /* Intel Pentium M processor 715 / 1.50GHz (Dothan) */ static struct cpufreq_frequency_table dothan_1500[] = { OP( 600, 988, 988, 988, 988), OP( 800, 1068, 1068, 1068, 1052), OP(1000, 1148, 1148, 1132, 1116), OP(1200, 1228, 1212, 1212, 1180), OP(1500, 1340, 1324, 1308, 1276), { .frequency = CPUFREQ_TABLE_END } }; /* Intel Pentium M processor 725 / 1.60GHz (Dothan) */ static struct cpufreq_frequency_table dothan_1600[] = { OP( 600, 988, 988, 988, 988), OP( 800, 1068, 1068, 1052, 1052), OP(1000, 1132, 1132, 1116, 1116), OP(1200, 1212, 1196, 1180, 1164), OP(1400, 1276, 1260, 1244, 1228), OP(1600, 1340, 1324, 1308, 1276), { .frequency = CPUFREQ_TABLE_END } }; /* Intel Pentium M processor 735 / 1.70GHz (Dothan) */ static struct cpufreq_frequency_table dothan_1700[] = { OP( 600, 988, 988, 988, 988), OP( 800, 1052, 1052, 1052, 1052), OP(1000, 1116, 1116, 1116, 1100), OP(1200, 1180, 1180, 1164, 1148), OP(1400, 1244, 1244, 1228, 1212), OP(1700, 1340, 1324, 1308, 1276), { .frequency = CPUFREQ_TABLE_END } }; /* Intel Pentium M processor 745 / 1.80GHz (Dothan) */ static struct cpufreq_frequency_table dothan_1800[] = { OP( 600, 988, 988, 988, 988), OP( 800, 1052, 1052, 1052, 1036), OP(1000, 1116, 1100, 1100, 1084), OP(1200, 1164, 1164, 1148, 1132), OP(1400, 1228, 1212, 1212, 1180), OP(1600, 1292, 1276, 1260, 1228), OP(1800, 1340, 1324, 1308, 1276), { .frequency = CPUFREQ_TABLE_END } }; /* Intel Pentium M processor 755 / 2.00GHz (Dothan) */ static struct cpufreq_frequency_table dothan_2000[] = { OP( 600, 988, 988, 988, 988), OP( 800, 1052, 1036, 1036, 1036), OP(1000, 1100, 1084, 1084, 1084), OP(1200, 1148, 1132, 1132, 1116), OP(1400, 1196, 1180, 1180, 1164), OP(1600, 1244, 1228, 1228, 1196), OP(1800, 1292, 1276, 1276, 1244), OP(2000, 1340, 1324, 1308, 1276), { .frequency = CPUFREQ_TABLE_END } }; #undef OP #define _BANIAS(cpuid, max, name) \ { .cpu_id = cpuid, \ .model_name = "Intel(R) Pentium(R) M processor " name "MHz", \ .max_freq = (max)*1000, \ .op_points = banias_##max, \ } #define BANIAS(max) _BANIAS(&cpu_ids[CPU_BANIAS], max, #max) #define DOTHAN(cpuid, max, name) \ { .cpu_id = cpuid, \ .model_name = "Intel(R) Pentium(R) M processor " name "GHz", \ .max_freq = (max)*1000, \ .op_points = dothan_##max, \ } /* CPU models, their operating frequency range, and freq/voltage operating points */ static struct cpu_model models[] = { _BANIAS(&cpu_ids[CPU_BANIAS], 900, " 900"), BANIAS(1000), BANIAS(1100), BANIAS(1200), BANIAS(1300), BANIAS(1400), BANIAS(1500), BANIAS(1600), BANIAS(1700), DOTHAN(&cpu_ids[CPU_DOTHAN_B0], 1500, "1.50"), DOTHAN(&cpu_ids[CPU_DOTHAN_B0], 1600, "1.60"), DOTHAN(&cpu_ids[CPU_DOTHAN_B0], 1700, "1.70"), DOTHAN(&cpu_ids[CPU_DOTHAN_B0], 1800, "1.80"), DOTHAN(&cpu_ids[CPU_DOTHAN_B0], 2000, "2.00"), /* NULL model_name is a wildcard */ { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL }, { NULL, } }; #undef _BANIAS #undef BANIAS #undef DOTHAN static int centrino_cpu_init_table(struct cpufreq_policy *policy) { struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu]; struct cpu_model *model; for(model = models; model->cpu_id != NULL; model++) if (centrino_verify_cpu_id(cpu, model->cpu_id) && (model->model_name == NULL || strcmp(cpu->x86_model_id, model->model_name) == 0)) break; if (model->cpu_id == NULL) { /* No match at all */ dprintk(KERN_INFO PFX "no support for CPU model \"%s\": " "send /proc/cpuinfo to " MAINTAINER "\n", cpu->x86_model_id); return -ENOENT; } if (model->op_points == NULL) { /* Matched a non-match */ dprintk(KERN_INFO PFX "no table support for CPU model \"%s\": \n", cpu->x86_model_id); #ifndef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI dprintk(KERN_INFO PFX "try compiling with CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI enabled\n"); #endif return -ENOENT; } centrino_model[policy->cpu] = model; dprintk("found \"%s\": max frequency: %dkHz\n", model->model_name, model->max_freq); return 0; } #else static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) { return -ENODEV; } #endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */ static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x) { if ((c->x86 == x->x86) && (c->x86_model == x->x86_model) && (c->x86_mask == x->x86_mask)) return 1; return 0; } /* To be called only after centrino_model is initialized */ static unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe) { int i; /* * Extract clock in kHz from PERF_CTL value * for centrino, as some DSDTs are buggy. * Ideally, this can be done using the acpi_data structure. */ if ((centrino_cpu[cpu] == &cpu_ids[CPU_BANIAS]) || (centrino_cpu[cpu] == &cpu_ids[CPU_DOTHAN_A1]) || (centrino_cpu[cpu] == &cpu_ids[CPU_DOTHAN_B0])) { msr = (msr >> 8) & 0xff; return msr * 100000; } if ((!centrino_model[cpu]) || (!centrino_model[cpu]->op_points)) return 0; msr &= 0xffff; for (i=0;centrino_model[cpu]->op_points[i].frequency != CPUFREQ_TABLE_END; i++) { if (msr == centrino_model[cpu]->op_points[i].index) return centrino_model[cpu]->op_points[i].frequency; } if (failsafe) return centrino_model[cpu]->op_points[i-1].frequency; else return 0; } /* Return the current CPU frequency in kHz */ static unsigned int get_cur_freq(unsigned int cpu) { unsigned l, h; unsigned clock_freq; cpumask_t saved_mask; saved_mask = current->cpus_allowed; set_cpus_allowed(current, cpumask_of_cpu(cpu)); if (smp_processor_id() != cpu) return 0; rdmsr(MSR_IA32_PERF_STATUS, l, h); clock_freq = extract_clock(l, cpu, 0); if (unlikely(clock_freq == 0)) { /* * On some CPUs, we can see transient MSR values (which are * not present in _PSS), while CPU is doing some automatic * P-state transition (like TM2). Get the last freq set * in PERF_CTL. */ rdmsr(MSR_IA32_PERF_CTL, l, h); clock_freq = extract_clock(l, cpu, 1); } set_cpus_allowed(current, saved_mask); return clock_freq; } #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI static struct acpi_processor_performance p; /* * centrino_cpu_init_acpi - register with ACPI P-States library * * Register with the ACPI P-States library (part of drivers/acpi/processor.c) * in order to determine correct frequency and voltage pairings by reading * the _PSS of the ACPI DSDT or SSDT tables. */ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { union acpi_object arg0 = {ACPI_TYPE_BUFFER}; u32 arg0_buf[3]; struct acpi_object_list arg_list = {1, &arg0}; unsigned long cur_freq; int result = 0, i; unsigned int cpu = policy->cpu; /* _PDC settings */ arg0.buffer.length = 12; arg0.buffer.pointer = (u8 *) arg0_buf; arg0_buf[0] = ACPI_PDC_REVISION_ID; arg0_buf[1] = 1; arg0_buf[2] = ACPI_PDC_EST_CAPABILITY_SMP_MSR; // | ACPI_PDC_EST_CAPABILITY_MSR; p.pdc = &arg_list; /* register with ACPI core */ if (acpi_processor_register_performance(&p, cpu)) { dprintk(KERN_INFO PFX "obtaining ACPI data failed\n"); return -EIO; } /* verify the acpi_data */ if (p.state_count <= 1) { dprintk("No P-States\n"); result = -ENODEV; goto err_unreg; } if ((p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) || (p.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { dprintk("Invalid control/status registers (%x - %x)\n", p.control_register.space_id, p.status_register.space_id); result = -EIO; goto err_unreg; } for (i=0; i<p.state_count; i++) { if (p.states[i].control != p.states[i].status) { dprintk("Different control (%x) and status values (%x)\n", p.states[i].control, p.states[i].status); result = -EINVAL; goto err_unreg; } if (!p.states[i].core_frequency) { dprintk("Zero core frequency for state %u\n", i); result = -EINVAL; goto err_unreg; } if (p.states[i].core_frequency > p.states[0].core_frequency) { dprintk("P%u has larger frequency (%u) than P0 (%u), skipping\n", i, p.states[i].core_frequency, p.states[0].core_frequency); p.states[i].core_frequency = 0; continue; } } centrino_model[cpu] = kmalloc(sizeof(struct cpu_model), GFP_KERNEL); if (!centrino_model[cpu]) { result = -ENOMEM; goto err_unreg; } memset(centrino_model[cpu], 0, sizeof(struct cpu_model)); centrino_model[cpu]->model_name=NULL; centrino_model[cpu]->max_freq = p.states[0].core_frequency * 1000; centrino_model[cpu]->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) * (p.state_count + 1), GFP_KERNEL); if (!centrino_model[cpu]->op_points) { result = -ENOMEM; goto err_kfree; } for (i=0; i<p.state_count; i++) { centrino_model[cpu]->op_points[i].index = p.states[i].control; centrino_model[cpu]->op_points[i].frequency = p.states[i].core_frequency * 1000; dprintk("adding state %i with frequency %u and control value %04x\n", i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index); } centrino_model[cpu]->op_points[p.state_count].frequency = CPUFREQ_TABLE_END; cur_freq = get_cur_freq(cpu); for (i=0; i<p.state_count; i++) { if (!p.states[i].core_frequency) { dprintk("skipping state %u\n", i); centrino_model[cpu]->op_points[i].frequency = CPUFREQ_ENTRY_INVALID; continue; } if (extract_clock(centrino_model[cpu]->op_points[i].index, cpu, 0) != (centrino_model[cpu]->op_points[i].frequency)) { dprintk("Invalid encoded frequency (%u vs. %u)\n", extract_clock(centrino_model[cpu]->op_points[i].index, cpu, 0), centrino_model[cpu]->op_points[i].frequency); result = -EINVAL; goto err_kfree_all; } if (cur_freq == centrino_model[cpu]->op_points[i].frequency) p.state = i; } /* notify BIOS that we exist */ acpi_processor_notify_smm(THIS_MODULE); return 0; err_kfree_all: kfree(centrino_model[cpu]->op_points); err_kfree: kfree(centrino_model[cpu]); err_unreg: acpi_processor_unregister_performance(&p, cpu); dprintk(KERN_INFO PFX "invalid ACPI data\n"); return (result); } #else static inline int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { return -ENODEV; } #endif static int centrino_cpu_init(struct cpufreq_policy *policy) { struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu]; unsigned freq; unsigned l, h; int ret; int i; /* Only Intel makes Enhanced Speedstep-capable CPUs */ if (cpu->x86_vendor != X86_VENDOR_INTEL || !cpu_has(cpu, X86_FEATURE_EST)) return -ENODEV; for (i = 0; i < N_IDS; i++) if (centrino_verify_cpu_id(cpu, &cpu_ids[i])) break; if (i != N_IDS) centrino_cpu[policy->cpu] = &cpu_ids[i]; if (is_const_loops_cpu(policy->cpu)) { centrino_driver.flags |= CPUFREQ_CONST_LOOPS; } if (centrino_cpu_init_acpi(policy)) { if (policy->cpu != 0) return -ENODEV; if (!centrino_cpu[policy->cpu]) { dprintk(KERN_INFO PFX "found unsupported CPU with " "Enhanced SpeedStep: send /proc/cpuinfo to " MAINTAINER "\n"); return -ENODEV; } if (centrino_cpu_init_table(policy)) { return -ENODEV; } } /* Check to see if Enhanced SpeedStep is enabled, and try to enable it if not. */ rdmsr(MSR_IA32_MISC_ENABLE, l, h); if (!(l & (1<<16))) { l |= (1<<16); dprintk("trying to enable Enhanced SpeedStep (%x)\n", l); wrmsr(MSR_IA32_MISC_ENABLE, l, h); /* check to see if it stuck */ rdmsr(MSR_IA32_MISC_ENABLE, l, h); if (!(l & (1<<16))) { printk(KERN_INFO PFX "couldn't enable Enhanced SpeedStep\n"); return -ENODEV; } } freq = get_cur_freq(policy->cpu); policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */ policy->cur = freq; dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur); ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model[policy->cpu]->op_points); if (ret) return (ret); cpufreq_frequency_table_get_attr(centrino_model[policy->cpu]->op_points, policy->cpu); return 0; } static int centrino_cpu_exit(struct cpufreq_policy *policy) { unsigned int cpu = policy->cpu; if (!centrino_model[cpu]) return -ENODEV; cpufreq_frequency_table_put_attr(cpu); #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI if (!centrino_model[cpu]->model_name) { dprintk("unregistering and freeing ACPI data\n"); acpi_processor_unregister_performance(&p, cpu); kfree(centrino_model[cpu]->op_points); kfree(centrino_model[cpu]); } #endif centrino_model[cpu] = NULL; return 0; } /** * centrino_verify - verifies a new CPUFreq policy * @policy: new policy * * Limit must be within this model's frequency range at least one * border included. */ static int centrino_verify (struct cpufreq_policy *policy) { return cpufreq_frequency_table_verify(policy, centrino_model[policy->cpu]->op_points); } /** * centrino_setpolicy - set a new CPUFreq policy * @policy: new policy * @target_freq: the target frequency * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) * * Sets a new CPUFreq policy. */ static int centrino_target (struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { unsigned int newstate = 0; unsigned int msr, oldmsr, h, cpu = policy->cpu; struct cpufreq_freqs freqs; cpumask_t saved_mask; int retval; if (centrino_model[cpu] == NULL) return -ENODEV; /* * Support for SMP systems. * Make sure we are running on the CPU that wants to change frequency */ saved_mask = current->cpus_allowed; set_cpus_allowed(current, policy->cpus); if (!cpu_isset(smp_processor_id(), policy->cpus)) { dprintk("couldn't limit to CPUs in this domain\n"); return(-EAGAIN); } if (cpufreq_frequency_table_target(policy, centrino_model[cpu]->op_points, target_freq, relation, &newstate)) { retval = -EINVAL; goto migrate_end; } msr = centrino_model[cpu]->op_points[newstate].index; rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); if (msr == (oldmsr & 0xffff)) { retval = 0; dprintk("no change needed - msr was and needs to be %x\n", oldmsr); goto migrate_end; } freqs.cpu = cpu; freqs.old = extract_clock(oldmsr, cpu, 0); freqs.new = extract_clock(msr, cpu, 0); dprintk("target=%dkHz old=%d new=%d msr=%04x\n", target_freq, freqs.old, freqs.new, msr); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); /* all but 16 LSB are "reserved", so treat them with care */ oldmsr &= ~0xffff; msr &= 0xffff; oldmsr |= msr; wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); retval = 0; migrate_end: set_cpus_allowed(current, saved_mask); return (retval); } static struct freq_attr* centrino_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, NULL, }; static struct cpufreq_driver centrino_driver = { .name = "centrino", /* should be speedstep-centrino, but there's a 16 char limit */ .init = centrino_cpu_init, .exit = centrino_cpu_exit, .verify = centrino_verify, .target = centrino_target, .get = get_cur_freq, .attr = centrino_attr, .owner = THIS_MODULE, }; /** * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver * * Initializes the Enhanced SpeedStep support. Returns -ENODEV on * unsupported devices, -ENOENT if there's no voltage table for this * particular CPU model, -EINVAL on problems during initiatization, * and zero on success. * * This is quite picky. Not only does the CPU have to advertise the * "est" flag in the cpuid capability flags, we look for a specific * CPU model and stepping, and we need to have the exact model name in * our voltage tables. That is, be paranoid about not releasing * someone's valuable magic smoke. */ static int __init centrino_init(void) { struct cpuinfo_x86 *cpu = cpu_data; if (!cpu_has(cpu, X86_FEATURE_EST)) return -ENODEV; return cpufreq_register_driver(¢rino_driver); } static void __exit centrino_exit(void) { cpufreq_unregister_driver(¢rino_driver); } MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>"); MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors."); MODULE_LICENSE ("GPL"); late_initcall(centrino_init); module_exit(centrino_exit); Steps to reproduce: Everytime with standard kernel and my notebook. Maybe this can be a notebook related problem, but I think it should be solvable and adjust the speedstep-centrino.c I have found many discussions over internet forums and I think this could help many people.
Jeremy, could you please take a look, see if we can get a patch out of this?
Hello again, I think it could be ACPI related problem. Maybe some types of BIOS does not provide that frequency tables in a correct way. I heard some people resolved this problem by upgrading BIOS. Maybe we could chceck if we obtained correct values and if not, we could try values coded in the speedstep-centrino.c, which are based on the Intel datasheets. Olda
Yes. Please check whether there are any BIOS updates (and also any special options inside you BIOS to enable this feature). And try having both acpi-cpufreq and speedstep-centrino driver (preferably with latest base kernel). Sometimes BIOS exports information in such a way that acpi-cpufreq driver can be enabled on Centrino platforms. Thanks, Venki
bugme-daemon@bugzilla.kernel.org wrote: > Jeremy, could you please take a look, see if we can get a patch out of this? > As others said, this is something that should be fixable by getting info from ACPI rather than patching the driver. J
Any updates on this problem? Does the CPU frequency still need to be hardcoded? Adding ACPI contacts.
Hello, latest beta version of bios for my notebook resolved this issue, but I heard that not all manufacturers provide bios updates for older models and the problem still exists. If the bios is unable to pass correct values to kernel the only way is to use the patched speedstep-centrino.c with hard-coded values. That is a bad situation for the owners of the older notebooks where this problem exists. I wonder how FreeBSD does this, because when I tried my notebook with old BIOS with FreeBSD 7.0 Current it worked fine, maybe they are not relying on ACPI. If we rely only on ACPI and BIOS we have a problem as we are not able to push all vendors to release correct BIOS update:-( But the situeation improved at least for me... I am the lucky one. Best regards, Olda
Then I guess we can ask Intel developers if it is possible to have "generic" table that fits one and for all and not necessarily does scaling optimal way but at least gives reasonable set of values. Any recommendations? Thanks.
speedstep-centrino module don't work to me too! Can someone provide a cpufreq_frequency_table to my Pentium M 750 (1.86Ghz)? Datasheet available in: <http://download.intel.com/design/mobile/datashts/30526202.pdf> Best regards, Renato
Subject: Re: CPU frequency scaling(cpufreq) does not work. speedstep-centrino.c problem bugme-daemon@bugzilla.kernel.org wrote: > Can someone provide a cpufreq_frequency_table to my Pentium M 750 (1.86Ghz)? > Datasheet available in: > <http://download.intel.com/design/mobile/datashts/30526202.pdf> > The trouble with newer Pentium M's (Dothan) is that they have 4 voltage grades (similar to different speed grades), and you need 4 tables to match. The tricky part is that it doesn't appear to be possible to tell what voltage grade your chip is without digging the table out of ACPI anyway. J
Hi Len, can you help us? Our problem is that speedstep-centrino don't work with some Pentium M models, as all models available in this documents below: <http://download.intel.com/design/mobile/datashts/30526202.pdf> <http://download.intel.com/design/mobile/datashts/30218908.pdf> To this models is necessary use acpi_cpufreq, installing powersaved and configure parameter CPUFREQD_MODULE="acpi_cpufreq" (/etc/powersave/cpufreq) Currently, my .config in 2.6.21.1 is to my machine with Pentium M 750 Model (1.86Ghz) is: # CPUFreq processor drivers # CONFIG_X86_ACPI_CPUFREQ=m # CONFIG_X86_POWERNOW_K6 is not set # CONFIG_X86_POWERNOW_K7 is not set # CONFIG_X86_POWERNOW_K8 is not set # CONFIG_X86_GX_SUSPMOD is not set CONFIG_X86_SPEEDSTEP_CENTRINO=y CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y CONFIG_X86_SPEEDSTEP_ICH=m # CONFIG_X86_SPEEDSTEP_SMI is not set # CONFIG_X86_P4_CLOCKMOD is not set # CONFIG_X86_CPUFREQ_NFORCE2 is not set # CONFIG_X86_LONGRUN is not set # CONFIG_X86_LONGHAUL is not set # CONFIG_X86_E_POWERSAVER is not set # # shared options # # CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set CONFIG_X86_SPEEDSTEP_LIB=m CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK=y Best regards, Renato
acpi-cpufreq works on the system at hand, and so I advocate that this sighting be closed as WILL_NOT_FIX. Nobody is maintaining speedstep-centrino, and I do not advocate that it be enhanced.
I have laptop (MAxdata 8100X) with dothan 1.6GHz and no luck - both speedstep-centrino and acpi-cpufreq (kernel 2.6.22 from gutsy). So there are STILL some old laptops with are in need for hardcoded freq tables (everyting was working on old ubuntu kernels with were pathed this way). Please don't ignore old machines...
I asked davej about this and he said: The only safe way to use scaling on 'dothan' cores is with ACPI. We just have no way to tell which of the four sets of voltages is in use. People keep proposing patches to hardcode a set of tables for them which "works for them", but could do *anything* on someone elses system. Even if we added it as a CONFIG option, I'm worried that people will turn it on not understanding the consequences and either plague us with crappy bug reports of flaky kernels (or worse). (And you guarantee some distros will turn it on to "make hardware 'just work'") All-round crappy situation really, we're between a rock and a hard place, and ACPI is the best hope we've got.
*** Bug 7607 has been marked as a duplicate of this bug. ***
Oldrich and other reporters, were you able to use acpi_cpufreq? Has the problem been resolved for you? Thanks.
This work fine to me: grep -i acpi ../linux-2.6.23.16/.config # Power management options (ACPI, APM) CONFIG_ACPI=y CONFIG_ACPI_SLEEP=y CONFIG_ACPI_PROCFS=y CONFIG_ACPI_PROC_EVENT=y CONFIG_ACPI_AC=m CONFIG_ACPI_BATTERY=m CONFIG_ACPI_BUTTON=m CONFIG_ACPI_VIDEO=m CONFIG_ACPI_FAN=m CONFIG_ACPI_DOCK=m CONFIG_ACPI_BAY=m CONFIG_ACPI_PROCESSOR=m CONFIG_ACPI_HOTPLUG_CPU=y CONFIG_ACPI_THERMAL=m # CONFIG_ACPI_ASUS is not set CONFIG_ACPI_TOSHIBA=m CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_DEBUG is not set CONFIG_ACPI_EC=y CONFIG_ACPI_POWER=y CONFIG_ACPI_SYSTEM=y CONFIG_ACPI_CONTAINER=m CONFIG_ACPI_SBS=m CONFIG_X86_ACPI_CPUFREQ=m # CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set CONFIG_PNPACPI=y CONFIG_THINKPAD_ACPI=m # CONFIG_THINKPAD_ACPI_DEBUG is not set CONFIG_THINKPAD_ACPI_BAY=y CONFIG_BLK_DEV_IDEACPI=y CONFIG_ATA_ACPI=y Regards, Renato S. Yamane
Hello, since i have upgraded my notebook with a latest beta of available bios, everything started to work. From then, also acpi_cpufreq works. I think we would need info from someone whos bios still does not handle the CPU correctly. I am sorry, I can not post more relevant results. Thanks a lot, Oldrich Plchot
Can't we close this bug then, if upgrading the BIOS fixes this issue?
I don't have any problem with Kernel available in Debian Lenny or other release >=2.6.23.16 # hwinfo --bios 01: None 00.0: 10105 BIOS [Created at bios.174] Unique ID: rdCR.lZF+r4EgHp4 Hardware Class: bios BIOS Keyboard LED Status: Scroll Lock: off Num Lock: off Caps Lock: off Base Memory: 639 kB PnP BIOS: SST2400 BIOS: extended read supported BIOS32 Service Directory Entry: 0xea7c0 SMBIOS Version: 2.3 BIOS Info: #0 Vendor: "TOSHIBA" Version: "Version 2.00" Date: "02/07/2006" Start Address: 0xeb000 ROM Size: 512 kB Features: 0x02b3000000007f1a9f90 ISA supported PCI supported PCMCIA supported PnP supported APM supported BIOS flashable BIOS shadowing allowed CD boot supported BIOS ROM socketed EDD spec supported 1.2MB NEC 9800 Japanese Floppy supported 720kB Floppy supported 2.88MB Floppy supported Print Screen supported 8042 Keyboard Services supported Serial Services supported Printer Services supported CGA/Mono Video supported ACPI supported USB Legacy supported LS-120 boot supported ATAPI ZIP boot supported Smart Battery supported F12 Network boot supported In my case, this bug can be closed. Best regards, Renato S. Yamane