📄 speedstep.c
字号:
{ 66, 0x0 }, { 100, 0x2 }, { 133, 0x1 }, { 0, 0xff} }; u32 msr_lo, msr_tmp; int i = 0, j = 0; struct cpuinfo_x86 *c = cpu_data; /* read MSR 0x2a - we only need the low 32 bits */ rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); dprintk(KERN_DEBUG "cpufreq: P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); msr_tmp = msr_lo; /* decode the FSB */ msr_tmp &= 0x00c0000; msr_tmp >>= 18; while (msr_tmp != msr_decode_fsb[i].bitmap) { if (msr_decode_fsb[i].bitmap == 0xff) return -EINVAL; i++; } /* decode the multiplier */ if ((c->x86_model == 0x08) && (c->x86_mask == 0x01)) /* different on early Coppermine PIII */ msr_lo &= 0x03c00000; else msr_lo &= 0x0bc00000; msr_lo >>= 22; while (msr_lo != msr_decode_mult[j].bitmap) { if (msr_decode_mult[j].bitmap == 0xff) return -EINVAL; j++; } return (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100);}/** * pentium4_get_frequency - get the core frequency for P4-Ms * * Should return the core frequency (in kHz) for P4-Ms. */static unsigned int pentium4_get_frequency(void){ u32 msr_lo, msr_hi; rdmsr(0x2c, msr_lo, msr_hi); dprintk(KERN_DEBUG "cpufreq: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi); /* First 12 bits seem to change a lot (0x511, 0x410 and 0x30f seen * yet). Next 12 bits always seem to be 0x300. If this is not true * on this CPU, complain. Last 8 bits are frequency (in 100MHz). */ if (msr_hi || ((msr_lo & 0x00FFF000) != 0x300000)) { printk(KERN_DEBUG "cpufreq: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi); printk(KERN_INFO "cpufreq: problem in initialization. Please contact Dominik Brodowski\n"); printk(KERN_INFO "cpufreq: <linux@brodo.de> and attach this dmesg. Thanks in advance\n"); return 0; } msr_lo >>= 24; return (msr_lo * 100000);}/** * speedstep_detect_processor - detect Intel SpeedStep-capable processors. * * Returns the SPEEDSTEP_PROCESSOR_-number for the detected processor, * or zero on failure. */static unsigned int speedstep_detect_processor (void){ struct cpuinfo_x86 *c = cpu_data; u32 ebx; if ((c->x86_vendor != X86_VENDOR_INTEL) || ((c->x86 != 6) && (c->x86 != 0xF))) return 0; if (c->x86 == 0xF) { /* Intel Pentium 4 Mobile P4-M */ if (c->x86_model != 2) return 0; if ((c->x86_mask != 4) && (c->x86_mask != 7)) return 0; ebx = cpuid_ebx(0x00000001); ebx &= 0x000000FF; if ((ebx != 0x0e) && (ebx != 0x0f)) return 0; return SPEEDSTEP_PROCESSOR_P4M; } switch (c->x86_model) { case 0x0B: /* Intel PIII [Tualatin] */ /* cpuid_ebx(1) is 0x04 for desktop PIII, 0x06 for mobile PIII-M */ ebx = cpuid_ebx(0x00000001); ebx &= 0x000000FF; if (ebx != 0x06) return 0; /* So far all PIII-M processors support SpeedStep. See * Intel's 24540633.pdf of August 2002 */ return SPEEDSTEP_PROCESSOR_PIII_T; case 0x08: /* Intel PIII [Coppermine] */ { u32 msr_lo, msr_hi; /* all mobile PIII Coppermines have FSB 100 MHz * ==> sort out a few desktop PIIIs. */ rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_EBL_Cr_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi); msr_lo &= 0x00c0000; if (msr_lo != 0x0080000) return 0; if (speedstep_coppermine) return SPEEDSTEP_PROCESSOR_PIII_C; printk(KERN_INFO "cpufreq: in case this is a SpeedStep-capable Intel Pentium III Coppermine\n"); printk(KERN_INFO "cpufreq: processor, please pass the boot option or module parameter\n"); printk(KERN_INFO "cpufreq: `speedstep_coppermine=1` to the kernel. Thanks!\n"); return 0; } default: return 0; }}/********************************************************************* * HIGH LEVEL FUNCTIONS * *********************************************************************//** * speedstep_detect_speeds - detects low and high CPU frequencies. * * Detects the low and high CPU frequencies in kHz. Returns 0 on * success or -EINVAL / -EIO on problems. */static int speedstep_detect_speeds (void){ unsigned long flags; unsigned int state; int i, result; /* Disable irqs for entire detection process */ local_irq_save(flags); for (i=0; i<2; i++) { /* read the current state */ result = speedstep_get_state(&state); if (result) return result; /* save the correct value, and switch to other */ if (state == SPEEDSTEP_LOW) { switch (speedstep_processor) { case SPEEDSTEP_PROCESSOR_PIII_C: case SPEEDSTEP_PROCESSOR_PIII_T: speedstep_low_freq = pentium3_get_frequency(); break; case SPEEDSTEP_PROCESSOR_P4M: speedstep_low_freq = pentium4_get_frequency(); } speedstep_set_state(SPEEDSTEP_HIGH, 0); } else { switch (speedstep_processor) { case SPEEDSTEP_PROCESSOR_PIII_C: case SPEEDSTEP_PROCESSOR_PIII_T: speedstep_high_freq = pentium3_get_frequency(); break; case SPEEDSTEP_PROCESSOR_P4M: speedstep_high_freq = pentium4_get_frequency(); } speedstep_set_state(SPEEDSTEP_LOW, 0); } } local_irq_restore(flags); if (!speedstep_low_freq || !speedstep_high_freq || (speedstep_low_freq == speedstep_high_freq)) return -EIO; return 0;}/** * speedstep_setpolicy - set a new CPUFreq policy * @policy: new policy * * Sets a new CPUFreq policy. */static int speedstep_setpolicy (struct cpufreq_policy *policy){ unsigned int newstate = 0; if (cpufreq_frequency_table_setpolicy(policy, &speedstep_freqs[0], &newstate)) return -EINVAL; speedstep_set_state(newstate, 1); return 0;}/** * speedstep_verify - verifies a new CPUFreq policy * @freq: new policy * * Limit must be within speedstep_low_freq and speedstep_high_freq, with * at least one border included. */static int speedstep_verify (struct cpufreq_policy *policy){ return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);}#ifndef MODULE/** * speedstep_setup speedstep command line parameter parsing * * speedstep command line parameter. Use: * speedstep_coppermine=1 * if the CPU in your notebook is a SpeedStep-capable Intel * Pentium III Coppermine. These processors cannot be detected * automatically, as Intel continues to consider the detection * alogrithm as proprietary material. */static int __init speedstep_setup(char *str){ speedstep_coppermine = simple_strtoul(str, &str, 0); return 1;}__setup("speedstep_coppermine=", speedstep_setup);#endif/** * speedstep_init - initializes the SpeedStep CPUFreq driver * * Initializes the SpeedStep support. Returns -ENODEV on unsupported * devices, -EINVAL on problems during initiatization, and zero on * success. */static int __init speedstep_init(void){ int result; unsigned int speed; struct cpufreq_driver *driver; /* detect chipset */ speedstep_chipset = speedstep_detect_chipset(); /* detect chipset */ if (speedstep_chipset) speedstep_processor = speedstep_detect_processor(); if ((!speedstep_chipset) || (!speedstep_processor)) { printk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) for this %s not (yet) available.\n", speedstep_chipset ? "processor" : "chipset"); return -ENODEV; } dprintk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) support $Revision: 1.64 $\n"); dprintk(KERN_DEBUG "cpufreq: chipset 0x%x - processor 0x%x\n", speedstep_chipset, speedstep_processor); /* activate speedstep support */ result = speedstep_activate(); if (result) return result; /* detect low and high frequency */ result = speedstep_detect_speeds(); if (result) return result; /* get current speed setting */ result = speedstep_get_state(&speed); if (result) return result; speed = (speed == SPEEDSTEP_LOW) ? speedstep_low_freq : speedstep_high_freq; dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", (speed == speedstep_low_freq) ? "low" : "high", (speed / 1000)); /* initialization of main "cpufreq" code*/ driver = kmalloc(sizeof(struct cpufreq_driver) + NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); if (!driver) return -ENOMEM; driver->policy = (struct cpufreq_policy *) (driver + 1); driver->policy[0].cpu = 0; result = cpufreq_frequency_table_cpuinfo(&driver->policy[0], &speedstep_freqs[0]); if (result) { kfree(driver); return result; }#ifdef CONFIG_CPU_FREQ_24_API driver->cpu_cur_freq[0] = speed;#endif driver->verify = &speedstep_verify; driver->setpolicy = &speedstep_setpolicy; driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL; driver->policy[0].policy = (speed == speedstep_low_freq) ? CPUFREQ_POLICY_POWERSAVE : CPUFREQ_POLICY_PERFORMANCE; speedstep_driver = driver; result = cpufreq_register(driver); if (result) { speedstep_driver = NULL; kfree(driver); } return result;}/** * speedstep_exit - unregisters SpeedStep support * * Unregisters SpeedStep support. */static void __exit speedstep_exit(void){ if (speedstep_driver) { cpufreq_unregister(); kfree(speedstep_driver); }}MODULE_AUTHOR ("Dave Jones <davej@suse.de>, Dominik Brodowski <linux@brodo.de>");MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors.");MODULE_LICENSE ("GPL");module_init(speedstep_init);module_exit(speedstep_exit);MODULE_PARM (speedstep_coppermine, "i");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -