GIT 474a14df3fce60bebde64d25c6adbdab7d30594a git+ssh://master.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq.git commit Author: Dave Jones Date: Wed Nov 8 19:22:45 2006 -0500 Revert "[CPUFREQ] speedstep-centrino should ignore upper performance control bits" This reverts commit d7a1944e8da5e91859b98259189aaaa4d8b7fa07. commit 6fdc2d07501f1fff1637f3c8efdc860e7fd28eb0 Author: Alexey Dobriyan Date: Thu Nov 9 01:04:35 2006 +0300 [CPUFREQ] gx-suspmod: fix "&& 0xff" typo Signed-off-by: Alexey Dobriyan Signed-off-by: Dave Jones commit caede347c3578b9dca49f53eab781fcaaacd3234 Author: akpm@osdl.org Date: Wed Nov 8 01:09:25 2006 -0800 [CPUFREQ] Fix build failure on x86-64 arch/x86_64/kernel/cpufreq/../../../i386/kernel/cpu/cpufreq/speedstep-lib.c:131: error: 'MSR_FSB_FREQ' undeclared (first use in this function) Signed-off-by: Andrew Morton Signed-off-by: Dave Jones commit d7a1944e8da5e91859b98259189aaaa4d8b7fa07 Author: Gary Hade Date: Mon Nov 6 15:39:23 2006 -0800 [CPUFREQ] speedstep-centrino should ignore upper performance control bits On some systems such as the IBM x3650 there are bits set in the upper half of the control values provided by the _PSS object. These bits are only relevant for cpufreq drivers that use IO ports which are not currently supported by the speedstep-centrino driver. The current MSR oriented code assumes that upper bits are not set and thus fails to work correctly when they are. e.g. the control and status value equality check fails even though the ACPI spec allows the inequality. Signed-off-by: Gary Hade Signed-off-by: Dave Jones commit 4e74663c5d7eefc1f953b9b0bdacab09917b4eac Author: Dominik Brodowski Date: Tue Oct 31 12:44:08 2006 -0500 [CPUFREQ] p4-clockmod: add more CPUs Several more Intel CPUs are now capable using the p4-clockmod cpufreq driver. As it is of limited use most of the time, print a big bold warning if a better cpufreq driver might be available. Signed-off-by: Dominik Brodowski Signed-off-by: Dave Jones commit e08f5f5bb5dfaaa28d69ffe37eb774533297657f Author: Gautham R Shenoy Date: Thu Oct 26 16:20:58 2006 +0530 [CPUFREQ] Fix coding style issues in cpufreq. Clean up cpufreq subsystem to fix coding style issues and to improve the readability. Signed-off-by: Gautham R Shenoy Signed-off-by: Dave Jones commit 95625b8f19e1e030c7fe3c010407d90fa248c68f Author: Dave Jones Date: Sat Oct 21 01:37:39 2006 -0400 [CPUFREQ] ifdef more unused on !SMP code. acpi-cpufreq needs the same patch as the previous speedstep-centrino change. Additionally, the centrino driver can have its ifdef moved out a little further to eliminate some more code/variables. Signed-off-by: Dave Jones commit fe0f96020d5158b6579548666c842706ce3af371 Author: Andrew Morton Date: Fri Oct 20 14:31:01 2006 -0700 [CPUFREQ] speedstep-centrino: remove dead code arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c:396: warning: 'sw_any_bug_dmi_table' defined but not used Signed-off-by: Andrew Morton Signed-off-by: Dave Jones commit 914f7c31b0bea0ccf3bf474d0b99d803f7985097 Author: Jeff Garzik Date: Fri Oct 20 14:31:00 2006 -0700 [CPUFREQ] handle sysfs errors Signed-off-by: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Dave Jones commit 95dd722700dc9bbb000d51cab07dde48720e9178 Author: Dave Jones Date: Wed Oct 18 00:41:48 2006 -0400 [CPUFREQ] acpi-cpufreq: Fix up some CodingStyle nits leftover from the lindenting. Signed-off-by: Dave Jones commit 0a1230acb549593949397d331f1ecf07889dde20 Author: Dave Jones Date: Wed Oct 18 00:15:49 2006 -0400 [CPUFREQ] Remove duplicate include from acpi-cpufreq Signed-off-by: Dave Jones commit 8c6193684928407ea097f370778e3df7e971d957 Author: Hiroshi Miura Date: Wed Oct 18 12:59:33 2006 +0900 [CPUFREQ] Fix speedstep-smi CPU detection to not run on Pentium 4. If someone inserts speedstep-smi on a mobile P4, it prevents other cpufreq modules from loading until it is unloaded. Signed-off-by: Hiroshi Miura Signed-off-by: Dave Jones commit 3e74341c7b356ce142ace4e9b5ff08448c9f320e Author: Amol Lad Date: Tue Oct 17 10:02:55 2006 +0530 [CPUFREQ] sc520_freq.c: ioremap balanced with iounmap ioremap must be balanced by an iounmap and failing to do so can result in a memory leak. Tested (compilation only): - using allmodconfig - making sure the files are compiling without any warning/error due to new changes Signed-off-by: Amol Lad Signed-off-by: Dave Jones commit dfde5d62ed9b28b0bda676c16e8cb635df244ef2 Author: Venkatesh Pallipadi Date: Tue Oct 3 12:38:45 2006 -0700 [CPUFREQ][8/8] acpi-cpufreq: Add support for freq feedback from hardware Enable ondemand governor and acpi-cpufreq to use IA32_APERF and IA32_MPERF MSR to get active frequency feedback for the last sampling interval. This will make ondemand take right frequency decisions when hardware coordination of frequency is going on. Without APERF/MPERF, ondemand can take wrong decision at times due to underlying hardware coordination or TM2. Example: * CPU 0 and CPU 1 are hardware cooridnated. * CPU 1 running at highest frequency. * CPU 0 was running at highest freq. Now ondemand reduces it to some intermediate frequency based on utilization. * Due to underlying hardware coordination with other CPU 1, CPU 0 continues to run at highest frequency (as long as other CPU is at highest). * When ondemand samples CPU 0 again next time, without actual frequency feedback from APERF/MPERF, it will think that previous frequency change was successful and can go to wrong target frequency. This is because it thinks that utilization it has got this sampling interval is when running at intermediate frequency, rather than actual highest frequency. More information about IA32_APERF IA32_MPERF MSR: Refer to IA-32 IntelĀ® Architecture Software Developer's Manual at http://developer.intel.com Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones commit a6f6e6e6ab464c9d1dff66570b78be2f66d8ba3d Author: Venkatesh Pallipadi Date: Tue Oct 3 12:37:42 2006 -0700 [CPUFREQ][7/8] acpi-cpufreq: Fix get of current frequency breakage Recent speedstep-centrino unification onto acpi-cpufreq patchset broke cpuinfo_cur_freq interface in /sys/../cpuinfo/, when MSR was used for transitions. Attached patch fixes that breakage. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones commit 7650b281b091f39f5e97f13b45ab3813b1526b65 Author: Venkatesh Pallipadi Date: Tue Oct 3 12:36:30 2006 -0700 [CPUFREQ][6/8] acpi-cpufreq: Eliminate get of current freq on notification Only change the frequency if the state previously set is different from what we are trying to set. We don't really have to get the current frequency at this point. Signed-off-by: Denis Sadykov Signed-off-by: Venkatesh Pallipadi Signed-off-by: Alexey Starikovskiy Signed-off-by: Dave Jones commit 64be7eedb2fd0d41614739b265b22708aa81734c Author: Venkatesh Pallipadi Date: Tue Oct 3 12:35:23 2006 -0700 [CPUFREQ][5/8] acpi-cpufreq: lindent acpi-cpufreq.c Lindent acpi-cpufreq. Additional changes replacing "return (..)" by "return ..". No functionality changes in this patch. Signed-off-by: Denis Sadykov Signed-off-by: Venkatesh Pallipadi Signed-off-by: Alexey Starikovskiy Signed-off-by: Dave Jones commit 83d0515bbb10c7a3e52eee697d1032e447291eda Author: Venkatesh Pallipadi Date: Tue Oct 3 12:34:28 2006 -0700 [CPUFREQ][4/8] acpi-cpufreq: Mark speedstep-centrino ACPI as deprecated Mark ACPI hooks in speedstep-centrino as deprecated. Change the order in which speedstep-centrino and acpi-cpufreq (when both are in kernel) will be added. First driver to be tried is now acpi-cpufreq, followed by speedstep-centrino. Add a note in feature-removal-schedule to mark this deprecation. Signed-off-by: Denis Sadykov Signed-off-by: Venkatesh Pallipadi Signed-off-by: Alexey Starikovskiy Signed-off-by: Dave Jones commit dde9f7ba60adac0cade262ab9b17654e93c626e2 Author: Venkatesh Pallipadi Date: Tue Oct 3 12:33:14 2006 -0700 [CPUFREQ][3/8] acpi-cpufreq: Pull in MSR based transition support Add in the support for Intel Enhanced Speedstep - MSR based transitions. With this change, the ACPI based support in speedstep-centrino can be deprecated and duplicate code in that driver can be marked for removal. Much easier to maintain and support this way. This also reduces the user misconfigurations and questions on which driver is to be used under which CPUs to support Enhanced Speedstep. Signed-off-by: Denis Sadykov Signed-off-by: Venkatesh Pallipadi Signed-off-by: Alexey Starikovskiy Signed-off-by: Dave Jones commit fe27cb358835cfa525b5831ec8ddb9b9bfda3c73 Author: Venkatesh Pallipadi Date: Tue Oct 3 12:29:15 2006 -0700 [CPUFREQ][2/8] acpi: reorganize code to make MSR support addition easier Some clean up and redsign of the driver. Mainly making it easier to add support for multiple sub-mechanisms of changing frequency. Currently this driver supports only ACPI SYSTEM_IO address space. With the changes below it is easier to add support for other address spaces like Intel Enhanced Speedstep which uses MSR (ACPI FIXED_FEATURE_HARDWARE) to do the transitions. Signed-off-by: Denis Sadykov Signed-off-by: Venkatesh Pallipadi Signed-off-by: Alexey Starikovskiy Signed-off-by: Dave Jones commit 519ce3ec76bf5c068e575800a9977659f7cccec4 Author: Venkatesh Pallipadi Date: Tue Oct 3 12:27:10 2006 -0700 [CPUFREQ][1/8] acpi-cpufreq: software coordination and handle all CPUs in the group This patchset has refresh/rebase of a bunch of patches/bugfixes related to acpi-cpufreq that were sent earlier on this list. patch 1/8 Patch that fixes a bug in swcoordination code in acpi-cpufreq patch 2/8 through patch 7/8 Grand unification of ACPI based speedstep-centrino and acpi-cpufreq drivers. ACPI allows P-state transitions in multiple ways. Like using IO ports or using processor native method (MSR). Without this patch, IO port based P-state transitions are handled in acpi-cpufreq driver and MSR based transitions on Intel CPUs are handled in speedstep-centrino driver. Even though most of the code in these two drivers should be similar, except for final changing/checking of frequency (one driver does it using IO port and other does it through MSR), we have duplicated code in these two drivers. There are also issues around BIOSes supporting both MSR and IO port and which driver should be loaded first in standard installations. The patchset combines functionality of these two driver into acpi-cpufreq driver. ACPI based functionality in speedstep-centrino is marked deprecated and will be removed in future. speedstep-centrino will continue to work on systems that depend on older non-ACPI table based P-state chanes. * 2/8 - Patch that reorganizes the code in acpi-cpufreq, cleaning it up a little and making it easier to add MSR support later. * 3/8 - Pull in the MSR based transition support into acpi-cpufreq. * 4/8 - Mark speedstep-centrino deprecated. Change the order in Makefile to load acpi-cpufreq first and speedstep-centrino later, in cases where both are configured in. * 5/8 - lindent acpi-cpufreq.c * 6/8 - Minor change to eliminate the check of current frequency on notifications. We can use last set frequency instead. * 7/8 - Make cpufreq->get of acpi_cpufreq work correctly again. There will be a patch in future that removes ACPI based support in speedstep-centrino in coming months. patch 8/8 Add support for IA32_APERF and IA32_MPERF MSR and get the actual frequency from these MSRs and use it to determine the next frequency target in ondemand governor This patch: There is a bug in software coordination patch in acpi-cpufreq, due to which frequency will only be set on first CPU of any coordinated group. Bug identified by Denis, was not recognised earlier as there are no platforms yet that use software coordination with acpi-cpufreq driver. Signed-off-by: Denis Sadykov Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones commit eff0df65da81c75084d936e86854a3418347c27f Author: Dominik Brodowski Date: Mon Oct 2 19:26:47 2006 -0400 [CPUFREQ] Documentation fix Fix reference to where the code actually is. Noted by Hero Wanders. Signed-off-by: Dominik Brodowski Signed-off-by: Dave Jones Documentation/cpu-freq/core.txt | 2 Documentation/feature-removal-schedule.txt | 22 + arch/i386/kernel/cpu/cpufreq/Kconfig | 6 arch/i386/kernel/cpu/cpufreq/Makefile | 2 arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 813 +++++++++++++-------- arch/i386/kernel/cpu/cpufreq/gx-suspmod.c | 2 arch/i386/kernel/cpu/cpufreq/p4-clockmod.c | 38 - arch/i386/kernel/cpu/cpufreq/sc520_freq.c | 7 arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | 7 arch/i386/kernel/cpu/cpufreq/speedstep-lib.c | 35 + arch/i386/kernel/cpu/cpufreq/speedstep-lib.h | 1 arch/i386/kernel/cpu/cpufreq/speedstep-smi.c | 3 arch/x86_64/kernel/cpufreq/Kconfig | 6 arch/x86_64/kernel/cpufreq/Makefile | 2 drivers/cpufreq/cpufreq.c | 159 +++- drivers/cpufreq/cpufreq_conservative.c | 33 + drivers/cpufreq/cpufreq_ondemand.c | 33 + drivers/cpufreq/cpufreq_performance.c | 9 drivers/cpufreq/cpufreq_powersave.c | 9 drivers/cpufreq/cpufreq_stats.c | 11 drivers/cpufreq/cpufreq_userspace.c | 11 drivers/cpufreq/freq_table.c | 28 - include/asm-i386/msr.h | 5 include/asm-x86_64/msr.h | 3 include/linux/cpufreq.h | 3 25 files changed, 827 insertions(+), 423 deletions(-) diff --git a/Documentation/cpu-freq/core.txt b/Documentation/cpu-freq/core.txt index 29b3f9f..ce0666e 100644 --- a/Documentation/cpu-freq/core.txt +++ b/Documentation/cpu-freq/core.txt @@ -24,7 +24,7 @@ Contents: 1. General Information ======================= -The CPUFreq core code is located in linux/kernel/cpufreq.c. This +The CPUFreq core code is located in drivers/cpufreq/cpufreq.c. This cpufreq code offers a standardized interface for the CPUFreq architecture drivers (those pieces of code that do actual frequency transitions), as well as to "notifiers". These are device diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 46f2a55..3aa012c 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -270,3 +270,25 @@ Why: The new layer 3 independant connect Who: Patrick McHardy --------------------------- + +What: ACPI hooks (X86_SPEEDSTEP_CENTRINO_ACPI) in speedstep-centrino driver +When: December 2006 +Why: Speedstep-centrino driver with ACPI hooks and acpi-cpufreq driver are + functionally very much similar. They talk to ACPI in same way. Only + difference between them is the way they do frequency transitions. + One uses MSRs and the other one uses IO ports. Functionaliy of + speedstep_centrino with ACPI hooks is now merged into acpi-cpufreq. + That means one common driver will support all Intel Enhanced Speedstep + capable CPUs. That means less confusion over name of + speedstep-centrino driver (with that driver supposed to be used on + non-centrino platforms). That means less duplication of code and + less maintenance effort and no possibility of these two drivers + going out of sync. + Current users of speedstep_centrino with ACPI hooks are requested to + switch over to acpi-cpufreq driver. speedstep-centrino will continue + to work using older non-ACPI static table based scheme even after this + date. + +Who: Venkatesh Pallipadi + +--------------------------- diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig index ccc1edf..5299c5b 100644 --- a/arch/i386/kernel/cpu/cpufreq/Kconfig +++ b/arch/i386/kernel/cpu/cpufreq/Kconfig @@ -17,6 +17,7 @@ config X86_ACPI_CPUFREQ help This driver adds a CPUFreq driver which utilizes the ACPI Processor Performance States. + This driver also supports Intel Enhanced Speedstep. For details, take a look at . @@ -121,11 +122,14 @@ config X86_SPEEDSTEP_CENTRINO If in doubt, say N. config X86_SPEEDSTEP_CENTRINO_ACPI - bool "Use ACPI tables to decode valid frequency/voltage pairs" + bool "Use ACPI tables to decode valid frequency/voltage (deprecated)" depends on X86_SPEEDSTEP_CENTRINO && ACPI_PROCESSOR depends on !(X86_SPEEDSTEP_CENTRINO = y && ACPI_PROCESSOR = m) default y help + This is deprecated and this functionality is now merged into + acpi_cpufreq (X86_ACPI_CPUFREQ). Use that driver instead of + speedstep_centrino. Use primarily the information provided in the BIOS ACPI tables to determine valid CPU frequency and voltage pairings. It is required for the driver to work on non-Banias CPUs. diff --git a/arch/i386/kernel/cpu/cpufreq/Makefile b/arch/i386/kernel/cpu/cpufreq/Makefile index 2e894f1..8de3abe 100644 --- a/arch/i386/kernel/cpu/cpufreq/Makefile +++ b/arch/i386/kernel/cpu/cpufreq/Makefile @@ -7,9 +7,9 @@ obj-$(CONFIG_SC520_CPUFREQ) += sc520_fr obj-$(CONFIG_X86_LONGRUN) += longrun.o obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o -obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o +obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 57c880b..60d20cf 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -1,9 +1,10 @@ /* - * acpi-cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.3 $) + * acpi-cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.4 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh * Copyright (C) 2002 - 2004 Dominik Brodowski + * Copyright (C) 2006 Denis Sadykov * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -27,202 +28,387 @@ #include #include #include +#include +#include #include -#include -#include #include -#include /* current */ #include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include + #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg) MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); MODULE_DESCRIPTION("ACPI Processor P-States Driver"); MODULE_LICENSE("GPL"); +enum { + UNDEFINED_CAPABLE = 0, + SYSTEM_INTEL_MSR_CAPABLE, + SYSTEM_IO_CAPABLE, +}; + +#define INTEL_MSR_RANGE (0xffff) +#define CPUID_6_ECX_APERFMPERF_CAPABILITY (0x1) -struct cpufreq_acpi_io { - struct acpi_processor_performance *acpi_data; - struct cpufreq_frequency_table *freq_table; - unsigned int resume; +struct acpi_cpufreq_data { + struct acpi_processor_performance *acpi_data; + struct cpufreq_frequency_table *freq_table; + unsigned int max_freq; + unsigned int resume; + unsigned int cpu_feature; }; -static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; -static struct acpi_processor_performance *acpi_perf_data[NR_CPUS]; +static struct acpi_cpufreq_data *drv_data[NR_CPUS]; +static struct acpi_processor_performance *acpi_perf_data[NR_CPUS]; static struct cpufreq_driver acpi_cpufreq_driver; static unsigned int acpi_pstate_strict; -static int -acpi_processor_write_port( - u16 port, - u8 bit_width, - u32 value) +static int check_est_cpu(unsigned int cpuid) +{ + struct cpuinfo_x86 *cpu = &cpu_data[cpuid]; + + if (cpu->x86_vendor != X86_VENDOR_INTEL || + !cpu_has(cpu, X86_FEATURE_EST)) + return 0; + + return 1; +} + +static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) +{ + struct acpi_processor_performance *perf; + int i; + + perf = data->acpi_data; + + for (i=0; istate_count; i++) { + if (value == perf->states[i].status) + return data->freq_table[i].frequency; + } + return 0; +} + +static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) { - if (bit_width <= 8) { + int i; + struct acpi_processor_performance *perf; + + msr &= INTEL_MSR_RANGE; + perf = data->acpi_data; + + for (i=0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { + if (msr == perf->states[data->freq_table[i].index].status) + return data->freq_table[i].frequency; + } + return data->freq_table[0].frequency; +} + +static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data) +{ + switch (data->cpu_feature) { + case SYSTEM_INTEL_MSR_CAPABLE: + return extract_msr(val, data); + case SYSTEM_IO_CAPABLE: + return extract_io(val, data); + default: + return 0; + } +} + +static void wrport(u16 port, u8 bit_width, u32 value) +{ + if (bit_width <= 8) outb(value, port); - } else if (bit_width <= 16) { + else if (bit_width <= 16) outw(value, port); - } else if (bit_width <= 32) { + else if (bit_width <= 32) outl(value, port); - } else { - return -ENODEV; - } - return 0; } -static int -acpi_processor_read_port( - u16 port, - u8 bit_width, - u32 *ret) +static void rdport(u16 port, u8 bit_width, u32 * ret) { *ret = 0; - if (bit_width <= 8) { + if (bit_width <= 8) *ret = inb(port); - } else if (bit_width <= 16) { + else if (bit_width <= 16) *ret = inw(port); - } else if (bit_width <= 32) { + else if (bit_width <= 32) *ret = inl(port); - } else { - return -ENODEV; +} + +struct msr_addr { + u32 reg; +}; + +struct io_addr { + u16 port; + u8 bit_width; +}; + +typedef union { + struct msr_addr msr; + struct io_addr io; +} drv_addr_union; + +struct drv_cmd { + unsigned int type; + cpumask_t mask; + drv_addr_union addr; + u32 val; +}; + +static void do_drv_read(struct drv_cmd *cmd) +{ + u32 h; + + switch (cmd->type) { + case SYSTEM_INTEL_MSR_CAPABLE: + rdmsr(cmd->addr.msr.reg, cmd->val, h); + break; + case SYSTEM_IO_CAPABLE: + rdport(cmd->addr.io.port, cmd->addr.io.bit_width, &cmd->val); + break; + default: + break; } - return 0; } -static int -acpi_processor_set_performance ( - struct cpufreq_acpi_io *data, - unsigned int cpu, - int state) +static void do_drv_write(struct drv_cmd *cmd) { - u16 port = 0; - u8 bit_width = 0; - int i = 0; - int ret = 0; - u32 value = 0; - int retval; - struct acpi_processor_performance *perf; - - dprintk("acpi_processor_set_performance\n"); - - retval = 0; - perf = data->acpi_data; - if (state == perf->state) { - if (unlikely(data->resume)) { - dprintk("Called after resume, resetting to P%d\n", state); - data->resume = 0; - } else { - dprintk("Already at target state (P%d)\n", state); - return (retval); - } + u32 h = 0; + + switch (cmd->type) { + case SYSTEM_INTEL_MSR_CAPABLE: + wrmsr(cmd->addr.msr.reg, cmd->val, h); + break; + case SYSTEM_IO_CAPABLE: + wrport(cmd->addr.io.port, cmd->addr.io.bit_width, cmd->val); + break; + default: + break; } +} - dprintk("Transitioning from P%d to P%d\n", perf->state, state); +static void drv_read(struct drv_cmd *cmd) +{ + cpumask_t saved_mask = current->cpus_allowed; + cmd->val = 0; - /* - * First we write the target state's 'control' value to the - * control_register. - */ + set_cpus_allowed(current, cmd->mask); + do_drv_read(cmd); + set_cpus_allowed(current, saved_mask); +} + +static void drv_write(struct drv_cmd *cmd) +{ + cpumask_t saved_mask = current->cpus_allowed; + unsigned int i; + + for_each_cpu_mask(i, cmd->mask) { + set_cpus_allowed(current, cpumask_of_cpu(i)); + do_drv_write(cmd); + } + + set_cpus_allowed(current, saved_mask); + return; +} + +static u32 get_cur_val(cpumask_t mask) +{ + struct acpi_processor_performance *perf; + struct drv_cmd cmd; + + if (unlikely(cpus_empty(mask))) + return 0; + + switch (drv_data[first_cpu(mask)]->cpu_feature) { + case SYSTEM_INTEL_MSR_CAPABLE: + cmd.type = SYSTEM_INTEL_MSR_CAPABLE; + cmd.addr.msr.reg = MSR_IA32_PERF_STATUS; + break; + case SYSTEM_IO_CAPABLE: + cmd.type = SYSTEM_IO_CAPABLE; + perf = drv_data[first_cpu(mask)]->acpi_data; + cmd.addr.io.port = perf->control_register.address; + cmd.addr.io.bit_width = perf->control_register.bit_width; + break; + default: + return 0; + } + + cmd.mask = mask; - port = perf->control_register.address; - bit_width = perf->control_register.bit_width; - value = (u32) perf->states[state].control; + drv_read(&cmd); - dprintk("Writing 0x%08x to port 0x%04x\n", value, port); + dprintk("get_cur_val = %u\n", cmd.val); - ret = acpi_processor_write_port(port, bit_width, value); - if (ret) { - dprintk("Invalid port width 0x%04x\n", bit_width); - return (ret); + return cmd.val; +} + +/* + * Return the measured active (C0) frequency on this CPU since last call + * to this function. + * Input: cpu number + * Return: Average CPU frequency in terms of max frequency (zero on error) + * + * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance + * over a period of time, while CPU is in C0 state. + * IA32_MPERF counts at the rate of max advertised frequency + * IA32_APERF counts at the rate of actual CPU frequency + * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and + * no meaning should be associated with absolute values of these MSRs. + */ +static unsigned int get_measured_perf(unsigned int cpu) +{ + union { + struct { + u32 lo; + u32 hi; + } split; + u64 whole; + } aperf_cur, mperf_cur; + + cpumask_t saved_mask; + unsigned int perf_percent; + unsigned int retval; + + saved_mask = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + if (get_cpu() != cpu) { + /* We were not able to run on requested processor */ + put_cpu(); + return 0; } + rdmsr(MSR_IA32_APERF, aperf_cur.split.lo, aperf_cur.split.hi); + rdmsr(MSR_IA32_MPERF, mperf_cur.split.lo, mperf_cur.split.hi); + + wrmsr(MSR_IA32_APERF, 0,0); + wrmsr(MSR_IA32_MPERF, 0,0); + +#ifdef __i386__ /* - * Assume the write went through when acpi_pstate_strict is not used. - * As read status_register is an expensive operation and there - * are no specific error cases where an IO port write will fail. + * We dont want to do 64 bit divide with 32 bit kernel + * Get an approximate value. Return failure in case we cannot get + * an approximate value. */ - if (acpi_pstate_strict) { - /* Then we read the 'status_register' and compare the value - * with the target state's 'status' to make sure the - * transition was successful. - * Note that we'll poll for up to 1ms (100 cycles of 10us) - * before giving up. - */ - - port = perf->status_register.address; - bit_width = perf->status_register.bit_width; - - dprintk("Looking for 0x%08x from port 0x%04x\n", - (u32) perf->states[state].status, port); - - for (i = 0; i < 100; i++) { - ret = acpi_processor_read_port(port, bit_width, &value); - if (ret) { - dprintk("Invalid port width 0x%04x\n", bit_width); - return (ret); - } - if (value == (u32) perf->states[state].status) - break; - udelay(10); - } - } else { - value = (u32) perf->states[state].status; + if (unlikely(aperf_cur.split.hi || mperf_cur.split.hi)) { + int shift_count; + u32 h; + + h = max_t(u32, aperf_cur.split.hi, mperf_cur.split.hi); + shift_count = fls(h); + + aperf_cur.whole >>= shift_count; + mperf_cur.whole >>= shift_count; + } + + if (((unsigned long)(-1) / 100) < aperf_cur.split.lo) { + int shift_count = 7; + aperf_cur.split.lo >>= shift_count; + mperf_cur.split.lo >>= shift_count; + } + + if (aperf_cur.split.lo && mperf_cur.split.lo) + perf_percent = (aperf_cur.split.lo * 100) / mperf_cur.split.lo; + else + perf_percent = 0; + +#else + if (unlikely(((unsigned long)(-1) / 100) < aperf_cur.whole)) { + int shift_count = 7; + aperf_cur.whole >>= shift_count; + mperf_cur.whole >>= shift_count; } - if (unlikely(value != (u32) perf->states[state].status)) { - printk(KERN_WARNING "acpi-cpufreq: Transition failed\n"); - retval = -ENODEV; - return (retval); + if (aperf_cur.whole && mperf_cur.whole) + perf_percent = (aperf_cur.whole * 100) / mperf_cur.whole; + else + perf_percent = 0; + +#endif + + retval = drv_data[cpu]->max_freq * perf_percent / 100; + + put_cpu(); + set_cpus_allowed(current, saved_mask); + + dprintk("cpu %d: performance percent %d\n", cpu, perf_percent); + return retval; +} + +static unsigned int get_cur_freq_on_cpu(unsigned int cpu) +{ + struct acpi_cpufreq_data *data = drv_data[cpu]; + unsigned int freq; + + dprintk("get_cur_freq_on_cpu (%d)\n", cpu); + + if (unlikely(data == NULL || + data->acpi_data == NULL || data->freq_table == NULL)) { + return 0; } - dprintk("Transition successful after %d microseconds\n", i * 10); + freq = extract_freq(get_cur_val(cpumask_of_cpu(cpu)), data); + dprintk("cur freq = %u\n", freq); - perf->state = state; - return (retval); + return freq; } +static unsigned int check_freqs(cpumask_t mask, unsigned int freq, + struct acpi_cpufreq_data *data) +{ + unsigned int cur_freq; + unsigned int i; + + for (i=0; i<100; i++) { + cur_freq = extract_freq(get_cur_val(mask), data); + if (cur_freq == freq) + return 1; + udelay(10); + } + return 0; +} -static int -acpi_cpufreq_target ( - struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int acpi_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) { - struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; + struct acpi_cpufreq_data *data = drv_data[policy->cpu]; struct acpi_processor_performance *perf; struct cpufreq_freqs freqs; cpumask_t online_policy_cpus; - cpumask_t saved_mask; - cpumask_t set_mask; - cpumask_t covered_cpus; - unsigned int cur_state = 0; + struct drv_cmd cmd; + unsigned int msr; unsigned int next_state = 0; - unsigned int result = 0; - unsigned int j; - unsigned int tmp; + unsigned int next_perf_state = 0; + unsigned int i; + int result = 0; - dprintk("acpi_cpufreq_setpolicy\n"); + dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); - result = cpufreq_frequency_table_target(policy, - data->freq_table, - target_freq, - relation, - &next_state); - if (unlikely(result)) - return (result); + if (unlikely(data == NULL || + data->acpi_data == NULL || data->freq_table == NULL)) { + return -ENODEV; + } perf = data->acpi_data; - cur_state = perf->state; - freqs.old = data->freq_table[cur_state].frequency; - freqs.new = data->freq_table[next_state].frequency; + result = cpufreq_frequency_table_target(policy, + data->freq_table, + target_freq, + relation, &next_state); + if (unlikely(result)) + return -ENODEV; #ifdef CONFIG_HOTPLUG_CPU /* cpufreq holds the hotplug lock, so we are safe from here on */ @@ -231,106 +417,84 @@ #else online_policy_cpus = policy->cpus; #endif - for_each_cpu_mask(j, online_policy_cpus) { - freqs.cpu = j; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + next_perf_state = data->freq_table[next_state].index; + if (perf->state == next_perf_state) { + if (unlikely(data->resume)) { + dprintk("Called after resume, resetting to P%d\n", + next_perf_state); + data->resume = 0; + } else { + dprintk("Already at target state (P%d)\n", + next_perf_state); + return 0; + } } - /* - * We need to call driver->target() on all or any CPU in - * policy->cpus, depending on policy->shared_type. - */ - saved_mask = current->cpus_allowed; - cpus_clear(covered_cpus); - for_each_cpu_mask(j, online_policy_cpus) { - /* - * Support for SMP systems. - * Make sure we are running on CPU that wants to change freq - */ - cpus_clear(set_mask); - if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) - cpus_or(set_mask, set_mask, online_policy_cpus); - else - cpu_set(j, set_mask); - - set_cpus_allowed(current, set_mask); - if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) { - dprintk("couldn't limit to CPUs in this domain\n"); - result = -EAGAIN; - break; - } + switch (data->cpu_feature) { + case SYSTEM_INTEL_MSR_CAPABLE: + cmd.type = SYSTEM_INTEL_MSR_CAPABLE; + cmd.addr.msr.reg = MSR_IA32_PERF_CTL; + msr = + (u32) perf->states[next_perf_state]. + control & INTEL_MSR_RANGE; + cmd.val = (cmd.val & ~INTEL_MSR_RANGE) | msr; + break; + case SYSTEM_IO_CAPABLE: + cmd.type = SYSTEM_IO_CAPABLE; + cmd.addr.io.port = perf->control_register.address; + cmd.addr.io.bit_width = perf->control_register.bit_width; + cmd.val = (u32) perf->states[next_perf_state].control; + break; + default: + return -ENODEV; + } - result = acpi_processor_set_performance (data, j, next_state); - if (result) { - result = -EAGAIN; - break; - } + cpus_clear(cmd.mask); - if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) - break; - - cpu_set(j, covered_cpus); - } + if (policy->shared_type != CPUFREQ_SHARED_TYPE_ANY) + cmd.mask = online_policy_cpus; + else + cpu_set(policy->cpu, cmd.mask); - for_each_cpu_mask(j, online_policy_cpus) { - freqs.cpu = j; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + freqs.old = data->freq_table[perf->state].frequency; + freqs.new = data->freq_table[next_perf_state].frequency; + for_each_cpu_mask(i, cmd.mask) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); } - if (unlikely(result)) { - /* - * We have failed halfway through the frequency change. - * We have sent callbacks to online_policy_cpus and - * acpi_processor_set_performance() has been called on - * coverd_cpus. Best effort undo.. - */ - - if (!cpus_empty(covered_cpus)) { - for_each_cpu_mask(j, covered_cpus) { - policy->cpu = j; - acpi_processor_set_performance (data, - j, - cur_state); - } - } + drv_write(&cmd); - tmp = freqs.new; - freqs.new = freqs.old; - freqs.old = tmp; - for_each_cpu_mask(j, online_policy_cpus) { - freqs.cpu = j; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + if (acpi_pstate_strict) { + if (!check_freqs(cmd.mask, freqs.new, data)) { + dprintk("acpi_cpufreq_target failed (%d)\n", + policy->cpu); + return -EAGAIN; } } - set_cpus_allowed(current, saved_mask); - return (result); -} + for_each_cpu_mask(i, cmd.mask) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + perf->state = next_perf_state; + return result; +} -static int -acpi_cpufreq_verify ( - struct cpufreq_policy *policy) +static int acpi_cpufreq_verify(struct cpufreq_policy *policy) { - unsigned int result = 0; - struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; + struct acpi_cpufreq_data *data = drv_data[policy->cpu]; dprintk("acpi_cpufreq_verify\n"); - result = cpufreq_frequency_table_verify(policy, - data->freq_table); - - return (result); + return cpufreq_frequency_table_verify(policy, data->freq_table); } - static unsigned long -acpi_cpufreq_guess_freq ( - struct cpufreq_acpi_io *data, - unsigned int cpu) +acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu) { - struct acpi_processor_performance *perf = data->acpi_data; + struct acpi_processor_performance *perf = data->acpi_data; if (cpu_khz) { /* search the closest match to cpu_khz */ @@ -338,16 +502,16 @@ acpi_cpufreq_guess_freq ( unsigned long freq; unsigned long freqn = perf->states[0].core_frequency * 1000; - for (i = 0; i < (perf->state_count - 1); i++) { + for (i=0; i<(perf->state_count-1); i++) { freq = freqn; freqn = perf->states[i+1].core_frequency * 1000; if ((2 * cpu_khz) > (freqn + freq)) { perf->state = i; - return (freq); + return freq; } } - perf->state = perf->state_count - 1; - return (freqn); + perf->state = perf->state_count-1; + return freqn; } else { /* assume CPU is at P0... */ perf->state = 0; @@ -355,7 +519,6 @@ acpi_cpufreq_guess_freq ( } } - /* * acpi_cpufreq_early_init - initialize ACPI P-States library * @@ -364,30 +527,34 @@ acpi_cpufreq_guess_freq ( * do _PDC and _PSD and find out the processor dependency for the * actual init that will happen later... */ -static int acpi_cpufreq_early_init_acpi(void) +static int acpi_cpufreq_early_init(void) { - struct acpi_processor_performance *data; - unsigned int i, j; + struct acpi_processor_performance *data; + cpumask_t covered; + unsigned int i, j; dprintk("acpi_cpufreq_early_init\n"); for_each_possible_cpu(i) { - data = kzalloc(sizeof(struct acpi_processor_performance), - GFP_KERNEL); + data = kzalloc(sizeof(struct acpi_processor_performance), + GFP_KERNEL); if (!data) { - for_each_possible_cpu(j) { + for_each_cpu_mask(j, covered) { kfree(acpi_perf_data[j]); acpi_perf_data[j] = NULL; } - return (-ENOMEM); + return -ENOMEM; } acpi_perf_data[i] = data; + cpu_set(i, covered); } /* Do initialization in ACPI core */ - return acpi_processor_preregister_performance(acpi_perf_data); + acpi_processor_preregister_performance(acpi_perf_data); + return 0; } +#ifdef CONFIG_SMP /* * Some BIOSes do SW_ANY coordination internally, either set it up in hw * or do it in BIOS firmware and won't inform about it to OS. If not @@ -414,39 +581,42 @@ static struct dmi_system_id sw_any_bug_d }, { } }; +#endif -static int -acpi_cpufreq_cpu_init ( - struct cpufreq_policy *policy) +static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) { - unsigned int i; - unsigned int cpu = policy->cpu; - struct cpufreq_acpi_io *data; - unsigned int result = 0; + unsigned int i; + unsigned int valid_states = 0; + unsigned int cpu = policy->cpu; + struct acpi_cpufreq_data *data; + unsigned int result = 0; struct cpuinfo_x86 *c = &cpu_data[policy->cpu]; - struct acpi_processor_performance *perf; + struct acpi_processor_performance *perf; dprintk("acpi_cpufreq_cpu_init\n"); if (!acpi_perf_data[cpu]) - return (-ENODEV); + return -ENODEV; - data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); + data = kzalloc(sizeof(struct acpi_cpufreq_data), GFP_KERNEL); if (!data) - return (-ENOMEM); + return -ENOMEM; data->acpi_data = acpi_perf_data[cpu]; - acpi_io_data[cpu] = data; + drv_data[cpu] = data; - result = acpi_processor_register_performance(data->acpi_data, cpu); + if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) + acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; + result = acpi_processor_register_performance(data->acpi_data, cpu); if (result) goto err_free; perf = data->acpi_data; policy->shared_type = perf->shared_type; + /* - * Will let policy->cpus know about dependency only when software + * Will let policy->cpus know about dependency only when software * coordination is required. */ if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL || @@ -462,10 +632,6 @@ #ifdef CONFIG_SMP } #endif - if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) { - acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; - } - /* capability check */ if (perf->state_count <= 1) { dprintk("No P-States\n"); @@ -473,17 +639,33 @@ #endif goto err_unreg; } - if ((perf->control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) || - (perf->status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { - dprintk("Unsupported address space [%d, %d]\n", - (u32) (perf->control_register.space_id), - (u32) (perf->status_register.space_id)); + if (perf->control_register.space_id != perf->status_register.space_id) { + result = -ENODEV; + goto err_unreg; + } + + switch (perf->control_register.space_id) { + case ACPI_ADR_SPACE_SYSTEM_IO: + dprintk("SYSTEM IO addr space\n"); + data->cpu_feature = SYSTEM_IO_CAPABLE; + break; + case ACPI_ADR_SPACE_FIXED_HARDWARE: + dprintk("HARDWARE addr space\n"); + if (!check_est_cpu(cpu)) { + result = -ENODEV; + goto err_unreg; + } + data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE; + break; + default: + dprintk("Unknown addr space %d\n", + (u32) (perf->control_register.space_id)); result = -ENODEV; goto err_unreg; } - /* alloc freq_table */ - data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (perf->state_count + 1), GFP_KERNEL); + data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * + (perf->state_count+1), GFP_KERNEL); if (!data->freq_table) { result = -ENOMEM; goto err_unreg; @@ -492,129 +674,140 @@ #endif /* detect transition latency */ policy->cpuinfo.transition_latency = 0; for (i=0; istate_count; i++) { - if ((perf->states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency) - policy->cpuinfo.transition_latency = perf->states[i].transition_latency * 1000; + if ((perf->states[i].transition_latency * 1000) > + policy->cpuinfo.transition_latency) + policy->cpuinfo.transition_latency = + perf->states[i].transition_latency * 1000; } policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - /* The current speed is unknown and not detectable by ACPI... */ - policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); - + data->max_freq = perf->states[0].core_frequency * 1000; /* table init */ - for (i=0; i<=perf->state_count; i++) - { - data->freq_table[i].index = i; - if (istate_count) - data->freq_table[i].frequency = perf->states[i].core_frequency * 1000; - else - data->freq_table[i].frequency = CPUFREQ_TABLE_END; + for (i=0; istate_count; i++) { + if (i>0 && perf->states[i].core_frequency == + perf->states[i-1].core_frequency) + continue; + + data->freq_table[valid_states].index = i; + data->freq_table[valid_states].frequency = + perf->states[i].core_frequency * 1000; + valid_states++; } + data->freq_table[perf->state_count].frequency = CPUFREQ_TABLE_END; result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); - if (result) { + if (result) goto err_freqfree; + + switch (data->cpu_feature) { + case ACPI_ADR_SPACE_SYSTEM_IO: + /* Current speed is unknown and not detectable by IO port */ + policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); + break; + case ACPI_ADR_SPACE_FIXED_HARDWARE: + acpi_cpufreq_driver.get = get_cur_freq_on_cpu; + get_cur_freq_on_cpu(cpu); + break; + default: + break; } /* notify BIOS that we exist */ acpi_processor_notify_smm(THIS_MODULE); - printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management activated.\n", - cpu); + /* Check for APERF/MPERF support in hardware */ + if (c->x86_vendor == X86_VENDOR_INTEL && c->cpuid_level >= 6) { + unsigned int ecx; + ecx = cpuid_ecx(6); + if (ecx & CPUID_6_ECX_APERFMPERF_CAPABILITY) + acpi_cpufreq_driver.getavg = get_measured_perf; + } + + dprintk("CPU%u - ACPI performance management activated.\n", cpu); for (i = 0; i < perf->state_count; i++) dprintk(" %cP%d: %d MHz, %d mW, %d uS\n", - (i == perf->state?'*':' '), i, + (i == perf->state ? '*' : ' '), i, (u32) perf->states[i].core_frequency, (u32) perf->states[i].power, (u32) perf->states[i].transition_latency); cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); - + /* * the first call to ->target() should result in us actually * writing something to the appropriate registers. */ data->resume = 1; - - return (result); - err_freqfree: + return result; + +err_freqfree: kfree(data->freq_table); - err_unreg: +err_unreg: acpi_processor_unregister_performance(perf, cpu); - err_free: +err_free: kfree(data); - acpi_io_data[cpu] = NULL; + drv_data[cpu] = NULL; - return (result); + return result; } - -static int -acpi_cpufreq_cpu_exit ( - struct cpufreq_policy *policy) +static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) { - struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; - + struct acpi_cpufreq_data *data = drv_data[policy->cpu]; dprintk("acpi_cpufreq_cpu_exit\n"); if (data) { cpufreq_frequency_table_put_attr(policy->cpu); - acpi_io_data[policy->cpu] = NULL; - acpi_processor_unregister_performance(data->acpi_data, policy->cpu); + drv_data[policy->cpu] = NULL; + acpi_processor_unregister_performance(data->acpi_data, + policy->cpu); kfree(data); } - return (0); + return 0; } -static int -acpi_cpufreq_resume ( - struct cpufreq_policy *policy) +static int acpi_cpufreq_resume(struct cpufreq_policy *policy) { - struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; - + struct acpi_cpufreq_data *data = drv_data[policy->cpu]; dprintk("acpi_cpufreq_resume\n"); data->resume = 1; - return (0); + return 0; } - -static struct freq_attr* acpi_cpufreq_attr[] = { +static struct freq_attr *acpi_cpufreq_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, NULL, }; static struct cpufreq_driver acpi_cpufreq_driver = { - .verify = acpi_cpufreq_verify, - .target = acpi_cpufreq_target, - .init = acpi_cpufreq_cpu_init, - .exit = acpi_cpufreq_cpu_exit, - .resume = acpi_cpufreq_resume, - .name = "acpi-cpufreq", - .owner = THIS_MODULE, - .attr = acpi_cpufreq_attr, + .verify = acpi_cpufreq_verify, + .target = acpi_cpufreq_target, + .init = acpi_cpufreq_cpu_init, + .exit = acpi_cpufreq_cpu_exit, + .resume = acpi_cpufreq_resume, + .name = "acpi-cpufreq", + .owner = THIS_MODULE, + .attr = acpi_cpufreq_attr, }; - -static int __init -acpi_cpufreq_init (void) +static int __init acpi_cpufreq_init(void) { dprintk("acpi_cpufreq_init\n"); - acpi_cpufreq_early_init_acpi(); + acpi_cpufreq_early_init(); return cpufreq_register_driver(&acpi_cpufreq_driver); } - -static void __exit -acpi_cpufreq_exit (void) +static void __exit acpi_cpufreq_exit(void) { - unsigned int i; + unsigned int i; dprintk("acpi_cpufreq_exit\n"); cpufreq_unregister_driver(&acpi_cpufreq_driver); @@ -627,7 +820,9 @@ acpi_cpufreq_exit (void) } module_param(acpi_pstate_strict, uint, 0644); -MODULE_PARM_DESC(acpi_pstate_strict, "value 0 or non-zero. non-zero -> strict ACPI checks are performed during frequency changes."); +MODULE_PARM_DESC(acpi_pstate_strict, + "value 0 or non-zero. non-zero -> strict ACPI checks are " + "performed during frequency changes."); late_initcall(acpi_cpufreq_init); module_exit(acpi_cpufreq_exit); diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c index 92afa3b..0b9cc8a 100644 --- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c +++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c @@ -473,7 +473,7 @@ static int __init cpufreq_gx_init(void) pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration)); pci_read_config_byte(params->cs55x0, PCI_MODOFF, &(params->off_duration)); pci_read_config_dword(params->cs55x0, PCI_CLASS_REVISION, &class_rev); - params->pci_rev = class_rev && 0xff; + params->pci_rev = class_rev & 0xff; if ((ret = cpufreq_register_driver(&gx_suspmod_driver))) { kfree(params); diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index 304d2ea..bec5017 100644 --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -163,29 +163,27 @@ static int cpufreq_p4_verify(struct cpuf static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) { - if ((c->x86 == 0x06) && (c->x86_model == 0x09)) { - /* Pentium M (Banias) */ - printk(KERN_WARNING PFX "Warning: Pentium M detected. " - "The speedstep_centrino module offers voltage scaling" - " in addition of frequency scaling. You should use " - "that instead of p4-clockmod, if possible.\n"); - return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); - } - - if ((c->x86 == 0x06) && (c->x86_model == 0x0D)) { - /* Pentium M (Dothan) */ - printk(KERN_WARNING PFX "Warning: Pentium M detected. " - "The speedstep_centrino module offers voltage scaling" - " in addition of frequency scaling. You should use " - "that instead of p4-clockmod, if possible.\n"); - /* on P-4s, the TSC runs with constant frequency independent whether - * throttling is active or not. */ - p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; - return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); + if (c->x86 == 0x06) { + if (cpu_has(c, X86_FEATURE_EST)) + printk(KERN_WARNING PFX "Warning: EST-capable CPU detected. " + "The acpi-cpufreq module offers voltage scaling" + " in addition of frequency scaling. You should use " + "that instead of p4-clockmod, if possible.\n"); + switch (c->x86_model) { + case 0x0E: /* Core */ + case 0x0F: /* Core Duo */ + p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PCORE); + case 0x0D: /* Pentium M (Dothan) */ + p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + /* fall through */ + case 0x09: /* Pentium M (Banias) */ + return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); + } } if (c->x86 != 0xF) { - printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to \n"); + printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to \n"); return 0; } diff --git a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c index ef457d5..b8fb4b5 100644 --- a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c +++ b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c @@ -153,6 +153,7 @@ static struct cpufreq_driver sc520_freq_ static int __init sc520_freq_init(void) { struct cpuinfo_x86 *c = cpu_data; + int err; /* Test if we have the right hardware */ if(c->x86_vendor != X86_VENDOR_AMD || @@ -166,7 +167,11 @@ static int __init sc520_freq_init(void) return -ENOMEM; } - return cpufreq_register_driver(&sc520_freq_driver); + err = cpufreq_register_driver(&sc520_freq_driver); + if (err) + iounmap(cpuctl); + + return err; } diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index e8993ba..d2d9caf 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -379,6 +379,7 @@ static int centrino_cpu_early_init_acpi( } +#ifdef CONFIG_SMP /* * Some BIOSes do SW_ANY coordination internally, either set it up in hw * or do it in BIOS firmware and won't inform about it to OS. If not @@ -392,7 +393,6 @@ static int sw_any_bug_found(struct dmi_s return 0; } - static struct dmi_system_id sw_any_bug_dmi_table[] = { { .callback = sw_any_bug_found, @@ -405,7 +405,7 @@ static struct dmi_system_id sw_any_bug_d }, { } }; - +#endif /* * centrino_cpu_init_acpi - register with ACPI P-States library @@ -531,6 +531,9 @@ #endif /* notify BIOS that we exist */ acpi_processor_notify_smm(THIS_MODULE); + printk("speedstep-centrino with X86_SPEEDSTEP_CENTRINO_ACPI" + "config is deprecated.\n " + "Use X86_ACPI_CPUFREQ (acpi-cpufreq instead.\n" ); return 0; diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c index 4f46cac..a709f6d 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c @@ -123,6 +123,37 @@ static unsigned int pentiumM_get_frequen return (msr_tmp * 100 * 1000); } +#ifdef CONFIG_X86_32 +static unsigned int pentium_core_get_frequency(void) +{ + u32 fsb = 0; + u32 msr_lo, msr_tmp; + + rdmsr(MSR_FSB_FREQ, msr_lo, msr_tmp); + /* see table B-2 of 24547212.pdf */ + switch (msr_lo & 0x07) { + case 5: + fsb = 400; + break; + case 1: + fsb = 533; + break; + case 3: + fsb = 667; + break; + default: + printk(KERN_ERR "PCORE - MSR_FSB_FREQ undefined value"); + } + + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); + dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); + + msr_tmp = (msr_lo >> 22) & 0x1f; + dprintk("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * fsb * 1000)); + + return (msr_tmp * fsb * 1000); +} +#endif static unsigned int pentium4_get_frequency(void) { @@ -174,6 +205,10 @@ static unsigned int pentium4_get_frequen unsigned int speedstep_get_processor_frequency(unsigned int processor) { switch (processor) { +#ifdef CONFIG_X86_32 + case SPEEDSTEP_PROCESSOR_PCORE: + return pentium_core_get_frequency(); +#endif case SPEEDSTEP_PROCESSOR_PM: return pentiumM_get_frequency(); case SPEEDSTEP_PROCESSOR_P4D: diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h index b735429..b11bcc6 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.h @@ -22,6 +22,7 @@ #define SPEEDSTEP_PROCESSOR_P4M 0x0000 * the speedstep_get_processor_frequency() call. */ #define SPEEDSTEP_PROCESSOR_PM 0xFFFFFF03 /* Pentium M */ #define SPEEDSTEP_PROCESSOR_P4D 0xFFFFFF04 /* desktop P4 */ +#define SPEEDSTEP_PROCESSOR_PCORE 0xFFFFFF05 /* Core */ /* speedstep states -- only two of them */ diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c index c28333d..ff0d898 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c @@ -360,9 +360,6 @@ static int __init speedstep_init(void) case SPEEDSTEP_PROCESSOR_PIII_C: case SPEEDSTEP_PROCESSOR_PIII_C_EARLY: break; - case SPEEDSTEP_PROCESSOR_P4M: - printk(KERN_INFO "speedstep-smi: you're trying to use this cpufreq driver on a Pentium 4-based CPU. Most likely it will not work.\n"); - break; default: speedstep_processor = 0; } diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig index 81f1562..3abcfa3 100644 --- a/arch/x86_64/kernel/cpufreq/Kconfig +++ b/arch/x86_64/kernel/cpufreq/Kconfig @@ -27,10 +27,13 @@ config X86_POWERNOW_K8_ACPI default y config X86_SPEEDSTEP_CENTRINO - tristate "Intel Enhanced SpeedStep" + tristate "Intel Enhanced SpeedStep (deprecated)" select CPU_FREQ_TABLE depends on ACPI_PROCESSOR help + This is deprecated and this functionality is now merged into + acpi_cpufreq (X86_ACPI_CPUFREQ). Use that driver instead of + speedstep_centrino. This adds the CPUFreq driver for Enhanced SpeedStep enabled mobile CPUs. This means Intel Pentium M (Centrino) CPUs or 64bit enabled Intel Xeons. @@ -50,6 +53,7 @@ config X86_ACPI_CPUFREQ help This driver adds a CPUFreq driver which utilizes the ACPI Processor Performance States. + This driver also supports Intel Enhanced Speedstep. For details, take a look at . diff --git a/arch/x86_64/kernel/cpufreq/Makefile b/arch/x86_64/kernel/cpufreq/Makefile index d8b5938..753ce1d 100644 --- a/arch/x86_64/kernel/cpufreq/Makefile +++ b/arch/x86_64/kernel/cpufreq/Makefile @@ -5,8 +5,8 @@ # SRCDIR := ../../../i386/kernel/cpu/cpufreq obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o -obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o +obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 47ab42d..d907807 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -29,7 +29,8 @@ #include #include #include -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "cpufreq-core", msg) +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \ + "cpufreq-core", msg) /** * The "cpufreq driver" - the arch- or hardware-dependent low @@ -41,8 +42,14 @@ static struct cpufreq_policy *cpufreq_cp static DEFINE_SPINLOCK(cpufreq_driver_lock); /* internal prototypes */ +<<<<<<< HEAD/drivers/cpufreq/cpufreq.c static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); static void handle_update(struct work_struct *work); +======= +static int __cpufreq_governor(struct cpufreq_policy *policy, + unsigned int event); +static void handle_update(void *data); +>>>>>>> /drivers/cpufreq/cpufreq.c /** * Two notifier lists: the "policy" list is involved in the @@ -151,7 +158,8 @@ static void cpufreq_debug_disable_rateli spin_unlock_irqrestore(&disable_ratelimit_lock, flags); } -void cpufreq_debug_printk(unsigned int type, const char *prefix, const char *fmt, ...) +void cpufreq_debug_printk(unsigned int type, const char *prefix, + const char *fmt, ...) { char s[256]; va_list args; @@ -161,7 +169,8 @@ void cpufreq_debug_printk(unsigned int t WARN_ON(!prefix); if (type & debug) { spin_lock_irqsave(&disable_ratelimit_lock, flags); - if (!disable_ratelimit && debug_ratelimit && !printk_ratelimit()) { + if (!disable_ratelimit && debug_ratelimit + && !printk_ratelimit()) { spin_unlock_irqrestore(&disable_ratelimit_lock, flags); return; } @@ -182,10 +191,12 @@ EXPORT_SYMBOL(cpufreq_debug_printk); module_param(debug, uint, 0644); -MODULE_PARM_DESC(debug, "CPUfreq debugging: add 1 to debug core, 2 to debug drivers, and 4 to debug governors."); +MODULE_PARM_DESC(debug, "CPUfreq debugging: add 1 to debug core," + " 2 to debug drivers, and 4 to debug governors."); module_param(debug_ratelimit, uint, 0644); -MODULE_PARM_DESC(debug_ratelimit, "CPUfreq debugging: set to 0 to disable ratelimiting."); +MODULE_PARM_DESC(debug_ratelimit, "CPUfreq debugging:" + " set to 0 to disable ratelimiting."); #else /* !CONFIG_CPU_FREQ_DEBUG */ @@ -219,17 +230,23 @@ static void adjust_jiffies(unsigned long if (!l_p_j_ref_freq) { l_p_j_ref = loops_per_jiffy; l_p_j_ref_freq = ci->old; - dprintk("saving %lu as reference value for loops_per_jiffy; freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq); + dprintk("saving %lu as reference value for loops_per_jiffy;" + "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq); } if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { - loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); - dprintk("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new); + loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, + ci->new); + dprintk("scaling loops_per_jiffy to %lu" + "for frequency %u kHz\n", loops_per_jiffy, ci->new); } } #else -static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; } +static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) +{ + return; +} #endif @@ -316,7 +333,8 @@ static int cpufreq_parse_governor (char if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { *policy = CPUFREQ_POLICY_PERFORMANCE; err = 0; - } else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) { + } else if (!strnicmp(str_governor, "powersave", + CPUFREQ_NAME_LEN)) { *policy = CPUFREQ_POLICY_POWERSAVE; err = 0; } @@ -328,7 +346,8 @@ static int cpufreq_parse_governor (char t = __find_governor(str_governor); if (t == NULL) { - char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", str_governor); + char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", + str_governor); if (name) { int ret; @@ -361,7 +380,8 @@ extern struct sysdev_class cpu_sysdev_cl /** - * cpufreq_per_cpu_attr_read() / show_##file_name() - print out cpufreq information + * cpufreq_per_cpu_attr_read() / show_##file_name() - + * print out cpufreq information * * Write out information from cpufreq_driver->policy[cpu]; object must be * "unsigned int". @@ -380,7 +400,8 @@ show_one(scaling_min_freq, min); show_one(scaling_max_freq, max); show_one(scaling_cur_freq, cur); -static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_policy *policy); +static int __cpufreq_set_policy(struct cpufreq_policy *data, + struct cpufreq_policy *policy); /** * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access @@ -416,7 +437,8 @@ store_one(scaling_max_freq,max); /** * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware */ -static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, char *buf) +static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, + char *buf) { unsigned int cur_freq = cpufreq_get(policy->cpu); if (!cur_freq) @@ -428,7 +450,8 @@ static ssize_t show_cpuinfo_cur_freq (st /** * show_scaling_governor - show the current policy for the specified CPU */ -static ssize_t show_scaling_governor (struct cpufreq_policy * policy, char *buf) +static ssize_t show_scaling_governor (struct cpufreq_policy * policy, + char *buf) { if(policy->policy == CPUFREQ_POLICY_POWERSAVE) return sprintf(buf, "powersave\n"); @@ -458,7 +481,8 @@ static ssize_t store_scaling_governor (s if (ret != 1) return -EINVAL; - if (cpufreq_parse_governor(str_governor, &new_policy.policy, &new_policy.governor)) + if (cpufreq_parse_governor(str_governor, &new_policy.policy, + &new_policy.governor)) return -EINVAL; lock_cpu_hotplug(); @@ -474,7 +498,10 @@ static ssize_t store_scaling_governor (s unlock_cpu_hotplug(); - return ret ? ret : count; + if (ret) + return ret; + else + return count; } /** @@ -488,7 +515,7 @@ static ssize_t show_scaling_driver (stru /** * show_scaling_available_governors - show the available CPUfreq governors */ -static ssize_t show_scaling_available_governors (struct cpufreq_policy * policy, +static ssize_t show_scaling_available_governors (struct cpufreq_policy *policy, char *buf) { ssize_t i = 0; @@ -574,7 +601,11 @@ static ssize_t show(struct kobject * kob policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; - ret = fattr->show ? fattr->show(policy,buf) : -EIO; + if (fattr->show) + ret = fattr->show(policy, buf); + else + ret = -EIO; + cpufreq_cpu_put(policy); return ret; } @@ -588,7 +619,11 @@ static ssize_t store(struct kobject * ko policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; - ret = fattr->store ? fattr->store(policy,buf,count) : -EIO; + if (fattr->store) + ret = fattr->store(policy, buf, count); + else + ret = -EIO; + cpufreq_cpu_put(policy); return ret; } @@ -913,7 +948,8 @@ static void handle_update(struct work_st * We adjust to current frequency first, and need to clean up later. So either call * to cpufreq_update_policy() or schedule handle_update()). */ -static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigned int new_freq) +static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, + unsigned int new_freq) { struct cpufreq_freqs freqs; @@ -938,16 +974,16 @@ static void cpufreq_out_of_sync(unsigned unsigned int cpufreq_quick_get(unsigned int cpu) { struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); - unsigned int ret = 0; + unsigned int ret_freq = 0; if (policy) { mutex_lock(&policy->lock); - ret = policy->cur; + ret_freq = policy->cur; mutex_unlock(&policy->lock); cpufreq_cpu_put(policy); } - return (ret); + return (ret_freq); } EXPORT_SYMBOL(cpufreq_quick_get); @@ -961,7 +997,7 @@ EXPORT_SYMBOL(cpufreq_quick_get); unsigned int cpufreq_get(unsigned int cpu) { struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); - unsigned int ret = 0; + unsigned int ret_freq = 0; if (!policy) return 0; @@ -971,12 +1007,14 @@ unsigned int cpufreq_get(unsigned int cp mutex_lock(&policy->lock); - ret = cpufreq_driver->get(cpu); + ret_freq = cpufreq_driver->get(cpu); - if (ret && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { - /* verify no discrepancy between actual and saved value exists */ - if (unlikely(ret != policy->cur)) { - cpufreq_out_of_sync(cpu, policy->cur, ret); + if (ret_freq && policy->cur && + !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { + /* verify no discrepancy between actual and + saved value exists */ + if (unlikely(ret_freq != policy->cur)) { + cpufreq_out_of_sync(cpu, policy->cur, ret_freq); schedule_work(&policy->update); } } @@ -986,7 +1024,7 @@ unsigned int cpufreq_get(unsigned int cp out: cpufreq_cpu_put(policy); - return (ret); + return (ret_freq); } EXPORT_SYMBOL(cpufreq_get); @@ -998,7 +1036,7 @@ EXPORT_SYMBOL(cpufreq_get); static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) { int cpu = sysdev->id; - unsigned int ret = 0; + int ret = 0; unsigned int cur_freq = 0; struct cpufreq_policy *cpu_policy; @@ -1080,7 +1118,7 @@ out: static int cpufreq_resume(struct sys_device * sysdev) { int cpu = sysdev->id; - unsigned int ret = 0; + int ret = 0; struct cpufreq_policy *cpu_policy; dprintk("resuming cpu %u\n", cpu); @@ -1276,22 +1314,45 @@ int cpufreq_driver_target(struct cpufreq } EXPORT_SYMBOL_GPL(cpufreq_driver_target); +int cpufreq_driver_getavg(struct cpufreq_policy *policy) +{ + int ret = 0; + + policy = cpufreq_cpu_get(policy->cpu); + if (!policy) + return -EINVAL; + + mutex_lock(&policy->lock); + + if (cpu_online(policy->cpu) && cpufreq_driver->getavg) + ret = cpufreq_driver->getavg(policy->cpu); + + mutex_unlock(&policy->lock); + + cpufreq_cpu_put(policy); + return ret; +} +EXPORT_SYMBOL_GPL(cpufreq_driver_getavg); + /* * Locking: Must be called with the lock_cpu_hotplug() lock held * when "event" is CPUFREQ_GOV_LIMITS */ -static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) +static int __cpufreq_governor(struct cpufreq_policy *policy, + unsigned int event) { int ret; if (!try_module_get(policy->governor->owner)) return -EINVAL; - dprintk("__cpufreq_governor for CPU %u, event %u\n", policy->cpu, event); + dprintk("__cpufreq_governor for CPU %u, event %u\n", + policy->cpu, event); ret = policy->governor->governor(policy, event); - /* we keep one module reference alive for each CPU governed by this CPU */ + /* we keep one module reference alive for + each CPU governed by this CPU */ if ((event != CPUFREQ_GOV_START) || ret) module_put(policy->governor->owner); if ((event == CPUFREQ_GOV_STOP) && !ret) @@ -1367,9 +1428,12 @@ EXPORT_SYMBOL(cpufreq_get_policy); /* + * data : current policy. + * policy : policy to be set. * Locking: Must be called with the lock_cpu_hotplug() lock held */ -static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_policy *policy) +static int __cpufreq_set_policy(struct cpufreq_policy *data, + struct cpufreq_policy *policy) { int ret = 0; @@ -1377,7 +1441,8 @@ static int __cpufreq_set_policy(struct c dprintk("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, policy->min, policy->max); - memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo)); + memcpy(&policy->cpuinfo, &data->cpuinfo, + sizeof(struct cpufreq_cpuinfo)); if (policy->min > data->min && policy->min > policy->max) { ret = -EINVAL; @@ -1410,7 +1475,8 @@ static int __cpufreq_set_policy(struct c data->min = policy->min; data->max = policy->max; - dprintk("new min and max freqs are %u - %u kHz\n", data->min, data->max); + dprintk("new min and max freqs are %u - %u kHz\n", + data->min, data->max); if (cpufreq_driver->setpolicy) { data->policy = policy->policy; @@ -1431,10 +1497,12 @@ static int __cpufreq_set_policy(struct c data->governor = policy->governor; if (__cpufreq_governor(data, CPUFREQ_GOV_START)) { /* new governor failed, so re-start old one */ - dprintk("starting governor %s failed\n", data->governor->name); + dprintk("starting governor %s failed\n", + data->governor->name); if (old_gov) { data->governor = old_gov; - __cpufreq_governor(data, CPUFREQ_GOV_START); + __cpufreq_governor(data, + CPUFREQ_GOV_START); } ret = -EINVAL; goto error_out; @@ -1524,7 +1592,8 @@ int cpufreq_update_policy(unsigned int c data->cur = policy.cur; } else { if (data->cur != policy.cur) - cpufreq_out_of_sync(cpu, data->cur, policy.cur); + cpufreq_out_of_sync(cpu, data->cur, + policy.cur); } } @@ -1626,8 +1695,10 @@ int cpufreq_register_driver(struct cpufr /* if all ->init() calls failed, unregister */ if (ret) { - dprintk("no CPU initialized for driver %s\n", driver_data->name); - sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); + dprintk("no CPU initialized for driver %s\n", + driver_data->name); + sysdev_driver_unregister(&cpu_sysdev_class, + &cpufreq_sysdev_driver); spin_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_driver = NULL; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 5ef5ede..eef0270 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -44,15 +44,17 @@ #define DEF_FREQUENCY_DOWN_THRESHOLD (2 * latency of the processor. The governor will work on any processor with * transition latency <= 10mS, using appropriate sampling * rate. - * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) - * this governor will not work. + * For CPUs with transition latency > 10mS (mostly drivers + * with CPUFREQ_ETERNAL), this governor will not work. * All times here are in uS. */ static unsigned int def_sampling_rate; #define MIN_SAMPLING_RATE_RATIO (2) /* for correct statistics, we need at least 10 ticks between each measure */ -#define MIN_STAT_SAMPLING_RATE (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) -#define MIN_SAMPLING_RATE (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) +#define MIN_STAT_SAMPLING_RATE \ + (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) +#define MIN_SAMPLING_RATE \ + (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) #define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define DEF_SAMPLING_DOWN_FACTOR (1) @@ -103,11 +105,16 @@ static struct dbs_tuners dbs_tuners_ins static inline unsigned int get_cpu_idle_time(unsigned int cpu) { - return kstat_cpu(cpu).cpustat.idle + + unsigned int add_nice = 0, ret; + + if (dbs_tuners_ins.ignore_nice) + add_nice = kstat_cpu(cpu).cpustat.nice; + + ret = kstat_cpu(cpu).cpustat.idle + kstat_cpu(cpu).cpustat.iowait + - ( dbs_tuners_ins.ignore_nice ? - kstat_cpu(cpu).cpustat.nice : - 0); + add_nice; + + return ret; } /************************** sysfs interface ************************/ @@ -452,6 +459,7 @@ static int cpufreq_governor_dbs(struct c unsigned int cpu = policy->cpu; struct cpu_dbs_info_s *this_dbs_info; unsigned int j; + int rc; this_dbs_info = &per_cpu(cpu_dbs_info, cpu); @@ -468,6 +476,13 @@ static int cpufreq_governor_dbs(struct c break; mutex_lock(&dbs_mutex); + + rc = sysfs_create_group(&policy->kobj, &dbs_attr_group); + if (rc) { + mutex_unlock(&dbs_mutex); + return rc; + } + for_each_cpu_mask(j, policy->cpus) { struct cpu_dbs_info_s *j_dbs_info; j_dbs_info = &per_cpu(cpu_dbs_info, j); @@ -480,7 +495,7 @@ static int cpufreq_governor_dbs(struct c this_dbs_info->enable = 1; this_dbs_info->down_skip = 0; this_dbs_info->requested_freq = policy->cur; - sysfs_create_group(&policy->kobj, &dbs_attr_group); + dbs_enable++; /* * Start the timerschedule work, when this governor diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index e1cc511..f697449 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -41,8 +41,10 @@ #define MAX_FREQUENCY_UP_THRESHOLD (100 static unsigned int def_sampling_rate; #define MIN_SAMPLING_RATE_RATIO (2) /* for correct statistics, we need at least 10 ticks between each measure */ -#define MIN_STAT_SAMPLING_RATE (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) -#define MIN_SAMPLING_RATE (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) +#define MIN_STAT_SAMPLING_RATE \ + (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) +#define MIN_SAMPLING_RATE \ + (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) #define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define TRANSITION_LATENCY_LIMIT (10 * 1000) @@ -206,7 +208,8 @@ static ssize_t store_sampling_rate(struc ret = sscanf(buf, "%u", &input); mutex_lock(&dbs_mutex); - if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) { + if (ret != 1 || input > MAX_SAMPLING_RATE + || input < MIN_SAMPLING_RATE) { mutex_unlock(&dbs_mutex); return -EINVAL; } @@ -397,8 +400,15 @@ static void dbs_check_cpu(struct cpu_dbs * policy. To be safe, we focus 10 points under the threshold. */ if (load < (dbs_tuners_ins.up_threshold - 10)) { - unsigned int freq_next = (policy->cur * load) / + unsigned int freq_next, freq_cur; + + freq_cur = cpufreq_driver_getavg(policy); + if (!freq_cur) + freq_cur = policy->cur; + + freq_next = (freq_cur * load) / (dbs_tuners_ins.up_threshold - 10); + if (!dbs_tuners_ins.powersave_bias) { __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); @@ -472,6 +482,7 @@ static int cpufreq_governor_dbs(struct c unsigned int cpu = policy->cpu; struct cpu_dbs_info_s *this_dbs_info; unsigned int j; + int rc; this_dbs_info = &per_cpu(cpu_dbs_info, cpu); @@ -494,12 +505,23 @@ static int cpufreq_governor_dbs(struct c if (dbs_enable == 1) { kondemand_wq = create_workqueue("kondemand"); if (!kondemand_wq) { - printk(KERN_ERR "Creation of kondemand failed\n"); + printk(KERN_ERR + "Creation of kondemand failed\n"); dbs_enable--; mutex_unlock(&dbs_mutex); return -ENOSPC; } } + + rc = sysfs_create_group(&policy->kobj, &dbs_attr_group); + if (rc) { + if (dbs_enable == 1) + destroy_workqueue(kondemand_wq); + dbs_enable--; + mutex_unlock(&dbs_mutex); + return rc; + } + for_each_cpu_mask(j, policy->cpus) { struct cpu_dbs_info_s *j_dbs_info; j_dbs_info = &per_cpu(cpu_dbs_info, j); @@ -509,7 +531,6 @@ static int cpufreq_governor_dbs(struct c j_dbs_info->prev_cpu_wall = get_jiffies_64(); } this_dbs_info->enable = 1; - sysfs_create_group(&policy->kobj, &dbs_attr_group); /* * Start the timerschedule work, when this governor * is used for first time diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c index de91e33..e8e1451 100644 --- a/drivers/cpufreq/cpufreq_performance.c +++ b/drivers/cpufreq/cpufreq_performance.c @@ -15,7 +15,8 @@ #include #include #include -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "performance", msg) +#define dprintk(msg...) \ + cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "performance", msg) static int cpufreq_governor_performance(struct cpufreq_policy *policy, @@ -24,8 +25,10 @@ static int cpufreq_governor_performance( switch (event) { case CPUFREQ_GOV_START: case CPUFREQ_GOV_LIMITS: - dprintk("setting to %u kHz because of event %u\n", policy->max, event); - __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); + dprintk("setting to %u kHz because of event %u\n", + policy->max, event); + __cpufreq_driver_target(policy, policy->max, + CPUFREQ_RELATION_H); break; default: break; diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index 0a25960..13fe06b 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -15,7 +15,8 @@ #include #include #include -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "powersave", msg) +#define dprintk(msg...) \ + cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "powersave", msg) static int cpufreq_governor_powersave(struct cpufreq_policy *policy, unsigned int event) @@ -23,8 +24,10 @@ static int cpufreq_governor_powersave(st switch (event) { case CPUFREQ_GOV_START: case CPUFREQ_GOV_LIMITS: - dprintk("setting to %u kHz because of event %u\n", policy->min, event); - __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); + dprintk("setting to %u kHz because of event %u\n", + policy->min, event); + __cpufreq_driver_target(policy, policy->min, + CPUFREQ_RELATION_L); break; default: break; diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index c2ecc59..6742b1a 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -351,8 +351,8 @@ __init cpufreq_stats_init(void) register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE, - (void *)(long)cpu); + cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, + CPU_ONLINE, (void *)(long)cpu); } return 0; } @@ -368,14 +368,15 @@ __exit cpufreq_stats_exit(void) unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); lock_cpu_hotplug(); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD, - (void *)(long)cpu); + cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, + CPU_DEAD, (void *)(long)cpu); } unlock_cpu_hotplug(); } MODULE_AUTHOR ("Zou Nan hai "); -MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats through sysfs filesystem"); +MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats" + "through sysfs filesystem"); MODULE_LICENSE ("GPL"); module_init(cpufreq_stats_init); diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index a06c204..2a4eb0b 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -131,19 +131,26 @@ static int cpufreq_governor_userspace(st unsigned int event) { unsigned int cpu = policy->cpu; + int rc = 0; + switch (event) { case CPUFREQ_GOV_START: if (!cpu_online(cpu)) return -EINVAL; BUG_ON(!policy->cur); mutex_lock(&userspace_mutex); + rc = sysfs_create_file (&policy->kobj, + &freq_attr_scaling_setspeed.attr); + if (rc) + goto start_out; + cpu_is_managed[cpu] = 1; cpu_min_freq[cpu] = policy->min; cpu_max_freq[cpu] = policy->max; cpu_cur_freq[cpu] = policy->cur; cpu_set_freq[cpu] = policy->cur; - sysfs_create_file (&policy->kobj, &freq_attr_scaling_setspeed.attr); dprintk("managing cpu %u started (%u - %u kHz, currently %u kHz)\n", cpu, cpu_min_freq[cpu], cpu_max_freq[cpu], cpu_cur_freq[cpu]); +start_out: mutex_unlock(&userspace_mutex); break; case CPUFREQ_GOV_STOP: @@ -180,7 +187,7 @@ static int cpufreq_governor_userspace(st mutex_unlock(&userspace_mutex); break; } - return 0; + return rc; } diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 551f4cc..e749092 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -9,7 +9,8 @@ #include #include #include -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg) +#define dprintk(msg...) \ + cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg) /********************************************************************* * FREQUENCY TABLE HELPERS * @@ -29,7 +30,8 @@ int cpufreq_frequency_table_cpuinfo(stru continue; } - dprintk("table entry %u: %u kHz, %u index\n", i, freq, table[i].index); + dprintk("table entry %u: %u kHz, %u index\n", + i, freq, table[i].index); if (freq < min_freq) min_freq = freq; if (freq > max_freq) @@ -54,13 +56,14 @@ int cpufreq_frequency_table_verify(struc unsigned int i; unsigned int count = 0; - dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu); + dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n", + policy->min, policy->max, policy->cpu); if (!cpu_online(policy->cpu)) return -EINVAL; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { unsigned int freq = table[i].frequency; @@ -75,10 +78,11 @@ int cpufreq_frequency_table_verify(struc if (!count) policy->max = next_larger; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); - dprintk("verification lead to (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu); + dprintk("verification lead to (%u - %u kHz) for cpu %u\n", + policy->min, policy->max, policy->cpu); return 0; } @@ -101,7 +105,8 @@ int cpufreq_frequency_table_target(struc }; unsigned int i; - dprintk("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu); + dprintk("request for target %u kHz (relation: %u) for cpu %u\n", + target_freq, relation, policy->cpu); switch (relation) { case CPUFREQ_RELATION_H: @@ -192,7 +197,10 @@ static ssize_t show_available_freqs (str } struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { - .attr = { .name = "scaling_available_frequencies", .mode = 0444, .owner=THIS_MODULE }, + .attr = { .name = "scaling_available_frequencies", + .mode = 0444, + .owner=THIS_MODULE + }, .show = show_available_freqs, }; EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h index 5679d49..609a389 100644 --- a/include/asm-i386/msr.h +++ b/include/asm-i386/msr.h @@ -100,6 +100,8 @@ #define MSR_IA32_UCODE_REV 0x8b #define MSR_P6_PERFCTR0 0xc1 #define MSR_P6_PERFCTR1 0xc2 +#define MSR_FSB_FREQ 0xcd + #define MSR_IA32_BBL_CR_CTL 0x119 @@ -130,6 +132,9 @@ #define MSR_P6_EVNTSEL1 0x187 #define MSR_IA32_PERF_STATUS 0x198 #define MSR_IA32_PERF_CTL 0x199 +#define MSR_IA32_MPERF 0xE7 +#define MSR_IA32_APERF 0xE8 + #define MSR_IA32_THERM_CONTROL 0x19a #define MSR_IA32_THERM_INTERRUPT 0x19b #define MSR_IA32_THERM_STATUS 0x19c diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h index 952783d..3d1d048 100644 --- a/include/asm-x86_64/msr.h +++ b/include/asm-x86_64/msr.h @@ -311,6 +311,9 @@ #define MSR_P6_EVNTSEL1 0x187 #define MSR_IA32_PERF_STATUS 0x198 #define MSR_IA32_PERF_CTL 0x199 +#define MSR_IA32_MPERF 0xE7 +#define MSR_IA32_APERF 0xE8 + #define MSR_IA32_THERM_CONTROL 0x19a #define MSR_IA32_THERM_INTERRUPT 0x19b #define MSR_IA32_THERM_STATUS 0x19c diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 4ea39fe..7f008f6 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -172,6 +172,8 @@ extern int __cpufreq_driver_target(struc unsigned int relation); +extern int cpufreq_driver_getavg(struct cpufreq_policy *policy); + int cpufreq_register_governor(struct cpufreq_governor *governor); void cpufreq_unregister_governor(struct cpufreq_governor *governor); @@ -204,6 +206,7 @@ struct cpufreq_driver { unsigned int (*get) (unsigned int cpu); /* optional */ + unsigned int (*getavg) (unsigned int cpu); int (*exit) (struct cpufreq_policy *policy); int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg); int (*resume) (struct cpufreq_policy *policy);