📄 speedstep-centrino.c
字号:
/* * cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium * M (part of the Centrino chipset). * * Since the original Pentium M, most new Intel CPUs support Enhanced * SpeedStep. * * 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> */#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/cpufreq.h>#include <linux/sched.h> /* current */#include <linux/delay.h>#include <linux/compiler.h>#include <asm/msr.h>#include <asm/processor.h>#include <asm/cpufeature.h>#define PFX "speedstep-centrino: "#define MAINTAINER "cpufreq@lists.linux.org.uk"#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg)#define INTEL_MSR_RANGE (0xffff)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, CPU_MP4HT_D0, CPU_MP4HT_E0,};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 }, [CPU_MP4HT_D0] = {15, 3, 4 }, [CPU_MP4HT_E0] = {15, 4, 1 },};#define N_IDS ARRAY_SIZE(cpu_ids)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#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)/* 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), /* 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 }, { &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL }, { &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL }, { NULL, }};#undef _BANIAS#undef BANIASstatic 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("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("no table support for CPU model \"%s\"\n", cpu->x86_model_id); dprintk("try using the acpi-cpufreq driver\n"); return -ENOENT; } centrino_model[policy->cpu] = model; dprintk("found \"%s\": max frequency: %dkHz\n", model->model_name, model->max_freq); return 0;}#elsestatic 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -