Commit ba420e28 authored by Dave Jones's avatar Dave Jones

Merge delerium.kernelslacker.org:/mnt/data/src/bk/bk-linus

into delerium.kernelslacker.org:/mnt/data/src/bk/cpufreq
parents 812ab7f3 c24a8e84
...@@ -35,10 +35,10 @@ Mailing List ...@@ -35,10 +35,10 @@ Mailing List
------------ ------------
There is a CPU frequency changing CVS commit and general list where There is a CPU frequency changing CVS commit and general list where
you can report bugs, problems or submit patches. To post a message, you can report bugs, problems or submit patches. To post a message,
send an email to cpufreq@www.linux.org.uk, to subscribe go to send an email to cpufreq@lists.linux.org.uk, to subscribe go to
http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the http://lists.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the
mailing list are available to subscribers at mailing list are available to subscribers at
http://www.linux.org.uk/mailman/private/cpufreq/. http://lists.linux.org.uk/mailman/private/cpufreq/.
Links Links
...@@ -50,7 +50,7 @@ how to access the CVS repository: ...@@ -50,7 +50,7 @@ how to access the CVS repository:
* http://cvs.arm.linux.org.uk/ * http://cvs.arm.linux.org.uk/
the CPUFreq Mailing list: the CPUFreq Mailing list:
* http://www.linux.org.uk/mailman/listinfo/cpufreq * http://lists.linux.org.uk/mailman/listinfo/cpufreq
Clock and voltage scaling for the SA-1100: Clock and voltage scaling for the SA-1100:
* http://www.lart.tudelft.nl/projects/scaling * http://www.lart.tudelft.nl/projects/scaling
...@@ -575,7 +575,7 @@ S: Maintained ...@@ -575,7 +575,7 @@ S: Maintained
CPU FREQUENCY DRIVERS CPU FREQUENCY DRIVERS
P: Dave Jones P: Dave Jones
M: davej@codemonkey.org.uk M: davej@codemonkey.org.uk
L: cpufreq@www.linux.org.uk L: cpufreq@lists.linux.org.uk
W: http://www.codemonkey.org.uk/projects/cpufreq/ W: http://www.codemonkey.org.uk/projects/cpufreq/
S: Maintained S: Maintained
......
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <acpi/processor.h> #include <acpi/processor.h>
#include "speedstep-est-common.h"
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
...@@ -48,10 +50,12 @@ MODULE_LICENSE("GPL"); ...@@ -48,10 +50,12 @@ MODULE_LICENSE("GPL");
struct cpufreq_acpi_io { struct cpufreq_acpi_io {
struct acpi_processor_performance acpi_data; struct acpi_processor_performance acpi_data;
struct cpufreq_frequency_table *freq_table; struct cpufreq_frequency_table *freq_table;
unsigned int resume;
}; };
static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS];
static struct cpufreq_driver acpi_cpufreq_driver;
static int static int
acpi_processor_write_port( acpi_processor_write_port(
...@@ -119,9 +123,14 @@ acpi_processor_set_performance ( ...@@ -119,9 +123,14 @@ acpi_processor_set_performance (
} }
if (state == data->acpi_data.state) { if (state == data->acpi_data.state) {
dprintk("Already at target state (P%d)\n", state); if (unlikely(data->resume)) {
retval = 0; dprintk("Called after resume, resetting to P%d\n", state);
goto migrate_end; data->resume = 0;
} else {
dprintk("Already at target state (P%d)\n", state);
retval = 0;
goto migrate_end;
}
} }
dprintk("Transitioning from P%d to P%d\n", dprintk("Transitioning from P%d to P%d\n",
...@@ -368,6 +377,10 @@ acpi_cpufreq_cpu_init ( ...@@ -368,6 +377,10 @@ acpi_cpufreq_cpu_init (
if (result) if (result)
goto err_free; goto err_free;
if (is_const_loops_cpu(cpu)) {
acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
}
/* capability check */ /* capability check */
if (data->acpi_data.state_count <= 1) { if (data->acpi_data.state_count <= 1) {
dprintk("No P-States\n"); dprintk("No P-States\n");
...@@ -462,6 +475,20 @@ acpi_cpufreq_cpu_exit ( ...@@ -462,6 +475,20 @@ acpi_cpufreq_cpu_exit (
return (0); return (0);
} }
static int
acpi_cpufreq_resume (
struct cpufreq_policy *policy)
{
struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
dprintk("acpi_cpufreq_resume\n");
data->resume = 1;
return (0);
}
static struct freq_attr* acpi_cpufreq_attr[] = { static struct freq_attr* acpi_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
...@@ -473,6 +500,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = { ...@@ -473,6 +500,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.target = acpi_cpufreq_target, .target = acpi_cpufreq_target,
.init = acpi_cpufreq_cpu_init, .init = acpi_cpufreq_cpu_init,
.exit = acpi_cpufreq_cpu_exit, .exit = acpi_cpufreq_cpu_exit,
.resume = acpi_cpufreq_resume,
.name = "acpi-cpufreq", .name = "acpi-cpufreq",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.attr = acpi_cpufreq_attr, .attr = acpi_cpufreq_attr,
......
...@@ -55,16 +55,7 @@ MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)"); ...@@ -55,16 +55,7 @@ MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
MODULE_PARM_DESC(min_fsb, MODULE_PARM_DESC(min_fsb,
"Minimum FSB to use, if not defined: current FSB - 50"); "Minimum FSB to use, if not defined: current FSB - 50");
/* DEBUG #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-nforce2", msg)
* Define it if you want verbose debug output, e.g. for bug reporting
*/
//#define NFORCE2_DEBUG
#ifdef NFORCE2_DEBUG
#define dprintk(msg...) printk(msg)
#else
#define dprintk(msg...) do { } while(0)
#endif
/* /*
* nforce2_calc_fsb - calculate FSB * nforce2_calc_fsb - calculate FSB
......
...@@ -209,7 +209,7 @@ static unsigned int gx_get_cpuspeed(unsigned int cpu) ...@@ -209,7 +209,7 @@ static unsigned int gx_get_cpuspeed(unsigned int cpu)
if ((gx_params->pci_suscfg & SUSMOD) == 0) if ((gx_params->pci_suscfg & SUSMOD) == 0)
return stock_freq; return stock_freq;
return (stock_freq * gx_params->on_duration) return (stock_freq * gx_params->off_duration)
/ (gx_params->on_duration + gx_params->off_duration); / (gx_params->on_duration + gx_params->off_duration);
} }
......
...@@ -171,7 +171,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) ...@@ -171,7 +171,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
} }
if ((c->x86 == 0x06) && (c->x86_model == 0x13)) { if ((c->x86 == 0x06) && (c->x86_model == 0x0D)) {
/* Pentium M (Dothan) */ /* Pentium M (Dothan) */
printk(KERN_WARNING PFX "Warning: Pentium M detected. " printk(KERN_WARNING PFX "Warning: Pentium M detected. "
"The speedstep_centrino module offers voltage scaling" "The speedstep_centrino module offers voltage scaling"
......
...@@ -635,6 +635,17 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) ...@@ -635,6 +635,17 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
static int powernow_cpu_exit (struct cpufreq_policy *policy) { static int powernow_cpu_exit (struct cpufreq_policy *policy) {
cpufreq_frequency_table_put_attr(policy->cpu); cpufreq_frequency_table_put_attr(policy->cpu);
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
if (acpi_processor_perf) {
acpi_processor_unregister_performance(acpi_processor_perf, 0);
kfree(acpi_processor_perf);
}
#endif
if (powernow_table)
kfree(powernow_table);
return 0; return 0;
} }
...@@ -664,15 +675,7 @@ static int __init powernow_init (void) ...@@ -664,15 +675,7 @@ static int __init powernow_init (void)
static void __exit powernow_exit (void) static void __exit powernow_exit (void)
{ {
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
if (acpi_processor_perf) {
acpi_processor_unregister_performance(acpi_processor_perf, 0);
kfree(acpi_processor_perf);
}
#endif
cpufreq_unregister_driver(&powernow_driver); cpufreq_unregister_driver(&powernow_driver);
if (powernow_table)
kfree(powernow_table);
} }
module_param(acpi_force, int, 0444); module_param(acpi_force, int, 0444);
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
* Processor information obtained from Chapter 9 (Power and Thermal Management) * Processor information obtained from Chapter 9 (Power and Thermal Management)
* of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD * of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
* Opteron Processors" available for download from www.amd.com * Opteron Processors" available for download from www.amd.com
*
* Tables for specific CPUs can be infrerred from
* http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -65,7 +68,12 @@ static u32 find_millivolts_from_vid(struct powernow_k8_data *data, u32 vid) ...@@ -65,7 +68,12 @@ static u32 find_millivolts_from_vid(struct powernow_k8_data *data, u32 vid)
return 1550-vid*25; return 1550-vid*25;
} }
/* Return the vco fid for an input fid */ /* Return the vco fid for an input fid
*
* Each "low" fid has corresponding "high" fid, and you can get to "low" fids
* only from corresponding high fids. This returns "high" fid corresponding to
* "low" one.
*/
static u32 convert_fid_to_vco_fid(u32 fid) static u32 convert_fid_to_vco_fid(u32 fid)
{ {
if (fid < HI_FID_TABLE_BOTTOM) { if (fid < HI_FID_TABLE_BOTTOM) {
...@@ -278,7 +286,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid ...@@ -278,7 +286,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
return 1; return 1;
} }
while (rvosteps > 0) { while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) {
if (data->currvid == 0) { if (data->currvid == 0) {
rvosteps = 0; rvosteps = 0;
} else { } else {
...@@ -307,10 +315,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid ...@@ -307,10 +315,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
/* Phase 2 - core frequency transition */ /* Phase 2 - core frequency transition */
static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
{ {
u32 vcoreqfid; u32 vcoreqfid, vcocurrfid, vcofiddiff, savevid = data->currvid;
u32 vcocurrfid;
u32 vcofiddiff;
u32 savevid = data->currvid;
if ((reqfid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) { if ((reqfid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) {
printk(KERN_ERR PFX "ph2: illegal lo-lo transition 0x%x 0x%x\n", printk(KERN_ERR PFX "ph2: illegal lo-lo transition 0x%x 0x%x\n",
...@@ -498,7 +503,7 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 ...@@ -498,7 +503,7 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8
|| (pst[j].fid & 1) || (pst[j].fid & 1)
|| (j && (pst[j].fid < HI_FID_TABLE_BOTTOM))) { || (j && (pst[j].fid < HI_FID_TABLE_BOTTOM))) {
/* Only first fid is allowed to be in "low" range */ /* Only first fid is allowed to be in "low" range */
printk(KERN_ERR PFX "fid %d invalid : 0x%x\n", j, pst[j].fid); printk(KERN_ERR PFX "two low fids - %d : 0x%x\n", j, pst[j].fid);
return -EINVAL; return -EINVAL;
} }
if (pst[j].fid < lastfid) if (pst[j].fid < lastfid)
...@@ -618,7 +623,7 @@ static int find_psb_table(struct powernow_k8_data *data) ...@@ -618,7 +623,7 @@ static int find_psb_table(struct powernow_k8_data *data)
return -ENODEV; return -ENODEV;
} }
data->vstable = psb->voltagestabilizationtime; data->vstable = psb->vstable;
dprintk("voltage stabilization time: %d(*20us)\n", data->vstable); dprintk("voltage stabilization time: %d(*20us)\n", data->vstable);
dprintk("flags2: 0x%x\n", psb->flags2); dprintk("flags2: 0x%x\n", psb->flags2);
...@@ -632,8 +637,8 @@ static int find_psb_table(struct powernow_k8_data *data) ...@@ -632,8 +637,8 @@ static int find_psb_table(struct powernow_k8_data *data)
dprintk("isochronous relief time: %d\n", data->irt); dprintk("isochronous relief time: %d\n", data->irt);
dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs); dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs);
dprintk("numpst: 0x%x\n", psb->numpst); dprintk("numpst: 0x%x\n", psb->num_tables);
cpst = psb->numpst; cpst = psb->num_tables;
if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0) ){ if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0) ){
thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) { if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) {
...@@ -651,7 +656,7 @@ static int find_psb_table(struct powernow_k8_data *data) ...@@ -651,7 +656,7 @@ static int find_psb_table(struct powernow_k8_data *data)
dprintk("maxvid: 0x%x\n", psb->maxvid); dprintk("maxvid: 0x%x\n", psb->maxvid);
maxvid = psb->maxvid; maxvid = psb->maxvid;
data->numps = psb->numpstates; data->numps = psb->numps;
dprintk("numpstates: 0x%x\n", data->numps); dprintk("numpstates: 0x%x\n", data->numps);
return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid); return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid);
} }
...@@ -1010,6 +1015,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1010,6 +1015,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol)
/* min/max the cpu is capable of */ /* min/max the cpu is capable of */
if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) { if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) {
printk(KERN_ERR PFX "invalid powernow_table\n"); printk(KERN_ERR PFX "invalid powernow_table\n");
powernow_k8_cpu_exit_acpi(data);
kfree(data->powernow_table); kfree(data->powernow_table);
kfree(data); kfree(data);
return -EINVAL; return -EINVAL;
...@@ -1027,6 +1033,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1027,6 +1033,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol)
err_out: err_out:
set_cpus_allowed(current, oldmask); set_cpus_allowed(current, oldmask);
schedule(); schedule();
powernow_k8_cpu_exit_acpi(data);
kfree(data); kfree(data);
return -ENODEV; return -ENODEV;
......
...@@ -21,8 +21,7 @@ struct powernow_k8_data { ...@@ -21,8 +21,7 @@ struct powernow_k8_data {
u32 plllock; /* pll lock time, units 1 us */ u32 plllock; /* pll lock time, units 1 us */
/* keep track of the current fid / vid */ /* keep track of the current fid / vid */
u32 currvid; u32 currvid, currfid;
u32 currfid;
/* the powernow_table includes all frequency and vid/fid pairings: /* the powernow_table includes all frequency and vid/fid pairings:
* fid are the lower 8 bits of the index, vid are the upper 8 bits. * fid are the lower 8 bits of the index, vid are the upper 8 bits.
...@@ -152,14 +151,14 @@ struct psb_s { ...@@ -152,14 +151,14 @@ struct psb_s {
u8 signature[10]; u8 signature[10];
u8 tableversion; u8 tableversion;
u8 flags1; u8 flags1;
u16 voltagestabilizationtime; u16 vstable;
u8 flags2; u8 flags2;
u8 numpst; u8 num_tables;
u32 cpuid; u32 cpuid;
u8 plllocktime; u8 plllocktime;
u8 maxfid; u8 maxfid;
u8 maxvid; u8 maxvid;
u8 numpstates; u8 numps;
}; };
/* Pairs of fid/vid values are appended to the version 1.4 PSB table. */ /* Pairs of fid/vid values are appended to the version 1.4 PSB table. */
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/delay.h>
#include <linux/compiler.h>
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
#include <linux/acpi.h> #include <linux/acpi.h>
...@@ -32,6 +34,8 @@ ...@@ -32,6 +34,8 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include "speedstep-est-common.h"
#define PFX "speedstep-centrino: " #define PFX "speedstep-centrino: "
#define MAINTAINER "Jeremy Fitzhardinge <jeremy@goop.org>" #define MAINTAINER "Jeremy Fitzhardinge <jeremy@goop.org>"
...@@ -71,8 +75,10 @@ struct cpu_model ...@@ -71,8 +75,10 @@ struct cpu_model
static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x); static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x);
/* Operating points for current CPU */ /* Operating points for current CPU */
static struct cpu_model *centrino_model; static struct cpu_model *centrino_model[NR_CPUS];
static const struct cpu_id *centrino_cpu; static const struct cpu_id *centrino_cpu[NR_CPUS];
static struct cpufreq_driver centrino_driver;
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE
...@@ -239,7 +245,7 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) ...@@ -239,7 +245,7 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
if (model->cpu_id == NULL) { if (model->cpu_id == NULL) {
/* No match at all */ /* No match at all */
printk(KERN_INFO PFX "no support for CPU model \"%s\": " dprintk(KERN_INFO PFX "no support for CPU model \"%s\": "
"send /proc/cpuinfo to " MAINTAINER "\n", "send /proc/cpuinfo to " MAINTAINER "\n",
cpu->x86_model_id); cpu->x86_model_id);
return -ENOENT; return -ENOENT;
...@@ -247,15 +253,15 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) ...@@ -247,15 +253,15 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
if (model->op_points == NULL) { if (model->op_points == NULL) {
/* Matched a non-match */ /* Matched a non-match */
printk(KERN_INFO PFX "no table support for CPU model \"%s\": \n", dprintk(KERN_INFO PFX "no table support for CPU model \"%s\": \n",
cpu->x86_model_id); cpu->x86_model_id);
#ifndef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI #ifndef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
printk(KERN_INFO PFX "try compiling with CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI enabled\n"); dprintk(KERN_INFO PFX "try compiling with CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI enabled\n");
#endif #endif
return -ENOENT; return -ENOENT;
} }
centrino_model = model; centrino_model[policy->cpu] = model;
dprintk("found \"%s\": max frequency: %dkHz\n", dprintk("found \"%s\": max frequency: %dkHz\n",
model->model_name, model->max_freq); model->model_name, model->max_freq);
...@@ -277,7 +283,7 @@ static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_ ...@@ -277,7 +283,7 @@ static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_
} }
/* To be called only after centrino_model is initialized */ /* To be called only after centrino_model is initialized */
static unsigned extract_clock(unsigned msr) static unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe)
{ {
int i; int i;
...@@ -286,28 +292,32 @@ static unsigned extract_clock(unsigned msr) ...@@ -286,28 +292,32 @@ static unsigned extract_clock(unsigned msr)
* for centrino, as some DSDTs are buggy. * for centrino, as some DSDTs are buggy.
* Ideally, this can be done using the acpi_data structure. * Ideally, this can be done using the acpi_data structure.
*/ */
if ((centrino_cpu == &cpu_ids[CPU_BANIAS]) || if ((centrino_cpu[cpu] == &cpu_ids[CPU_BANIAS]) ||
(centrino_cpu == &cpu_ids[CPU_DOTHAN_A1]) || (centrino_cpu[cpu] == &cpu_ids[CPU_DOTHAN_A1]) ||
(centrino_cpu == &cpu_ids[CPU_DOTHAN_B0])) { (centrino_cpu[cpu] == &cpu_ids[CPU_DOTHAN_B0])) {
msr = (msr >> 8) & 0xff; msr = (msr >> 8) & 0xff;
return msr * 100000; return msr * 100000;
} }
if ((!centrino_model) || (!centrino_model->op_points)) if ((!centrino_model[cpu]) || (!centrino_model[cpu]->op_points))
return 0; return 0;
msr &= 0xffff; msr &= 0xffff;
for (i=0;centrino_model->op_points[i].frequency != CPUFREQ_TABLE_END; i++) { for (i=0;centrino_model[cpu]->op_points[i].frequency != CPUFREQ_TABLE_END; i++) {
if (msr == centrino_model->op_points[i].index) if (msr == centrino_model[cpu]->op_points[i].index)
return centrino_model->op_points[i].frequency; return centrino_model[cpu]->op_points[i].frequency;
} }
return 0; if (failsafe)
return centrino_model[cpu]->op_points[i-1].frequency;
else
return 0;
} }
/* Return the current CPU frequency in kHz */ /* Return the current CPU frequency in kHz */
static unsigned int get_cur_freq(unsigned int cpu) static unsigned int get_cur_freq(unsigned int cpu)
{ {
unsigned l, h; unsigned l, h;
unsigned clock_freq;
cpumask_t saved_mask; cpumask_t saved_mask;
saved_mask = current->cpus_allowed; saved_mask = current->cpus_allowed;
...@@ -316,8 +326,21 @@ static unsigned int get_cur_freq(unsigned int cpu) ...@@ -316,8 +326,21 @@ static unsigned int get_cur_freq(unsigned int cpu)
return 0; return 0;
rdmsr(MSR_IA32_PERF_STATUS, l, h); rdmsr(MSR_IA32_PERF_STATUS, l, h);
clock_freq = extract_clock(l, cpu, 0);
if (unlikely(clock_freq == 0)) {
/*
* On some CPUs, we can see transient MSR values (which are
* not present in _PSS), while CPU is doing some automatic
* P-state transition (like TM2). Get the last freq set
* in PERF_CTL.
*/
rdmsr(MSR_IA32_PERF_CTL, l, h);
clock_freq = extract_clock(l, cpu, 1);
}
set_cpus_allowed(current, saved_mask); set_cpus_allowed(current, saved_mask);
return extract_clock(l); return clock_freq;
} }
...@@ -339,6 +362,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) ...@@ -339,6 +362,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
struct acpi_object_list arg_list = {1, &arg0}; struct acpi_object_list arg_list = {1, &arg0};
unsigned long cur_freq; unsigned long cur_freq;
int result = 0, i; int result = 0, i;
unsigned int cpu = policy->cpu;
/* _PDC settings */ /* _PDC settings */
arg0.buffer.length = 12; arg0.buffer.length = 12;
...@@ -350,8 +374,8 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) ...@@ -350,8 +374,8 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
p.pdc = &arg_list; p.pdc = &arg_list;
/* register with ACPI core */ /* register with ACPI core */
if (acpi_processor_register_performance(&p, policy->cpu)) { if (acpi_processor_register_performance(&p, cpu)) {
printk(KERN_INFO PFX "obtaining ACPI data failed\n"); dprintk(KERN_INFO PFX "obtaining ACPI data failed\n");
return -EIO; return -EIO;
} }
...@@ -392,49 +416,49 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) ...@@ -392,49 +416,49 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
} }
} }
centrino_model = kmalloc(sizeof(struct cpu_model), GFP_KERNEL); centrino_model[cpu] = kmalloc(sizeof(struct cpu_model), GFP_KERNEL);
if (!centrino_model) { if (!centrino_model[cpu]) {
result = -ENOMEM; result = -ENOMEM;
goto err_unreg; goto err_unreg;
} }
memset(centrino_model, 0, sizeof(struct cpu_model)); memset(centrino_model[cpu], 0, sizeof(struct cpu_model));
centrino_model->model_name=NULL; centrino_model[cpu]->model_name=NULL;
centrino_model->max_freq = p.states[0].core_frequency * 1000; centrino_model[cpu]->max_freq = p.states[0].core_frequency * 1000;
centrino_model->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) * centrino_model[cpu]->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) *
(p.state_count + 1), GFP_KERNEL); (p.state_count + 1), GFP_KERNEL);
if (!centrino_model->op_points) { if (!centrino_model[cpu]->op_points) {
result = -ENOMEM; result = -ENOMEM;
goto err_kfree; goto err_kfree;
} }
for (i=0; i<p.state_count; i++) { for (i=0; i<p.state_count; i++) {
centrino_model->op_points[i].index = p.states[i].control; centrino_model[cpu]->op_points[i].index = p.states[i].control;
centrino_model->op_points[i].frequency = p.states[i].core_frequency * 1000; centrino_model[cpu]->op_points[i].frequency = p.states[i].core_frequency * 1000;
dprintk("adding state %i with frequency %u and control value %04x\n", dprintk("adding state %i with frequency %u and control value %04x\n",
i, centrino_model->op_points[i].frequency, centrino_model->op_points[i].index); i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index);
} }
centrino_model->op_points[p.state_count].frequency = CPUFREQ_TABLE_END; centrino_model[cpu]->op_points[p.state_count].frequency = CPUFREQ_TABLE_END;
cur_freq = get_cur_freq(policy->cpu); cur_freq = get_cur_freq(cpu);
for (i=0; i<p.state_count; i++) { for (i=0; i<p.state_count; i++) {
if (!p.states[i].core_frequency) { if (!p.states[i].core_frequency) {
dprintk("skipping state %u\n", i); dprintk("skipping state %u\n", i);
centrino_model->op_points[i].frequency = CPUFREQ_ENTRY_INVALID; centrino_model[cpu]->op_points[i].frequency = CPUFREQ_ENTRY_INVALID;
continue; continue;
} }
if (extract_clock(centrino_model->op_points[i].index) != if (extract_clock(centrino_model[cpu]->op_points[i].index, cpu, 0) !=
(centrino_model->op_points[i].frequency)) { (centrino_model[cpu]->op_points[i].frequency)) {
dprintk("Invalid encoded frequency (%u vs. %u)\n", dprintk("Invalid encoded frequency (%u vs. %u)\n",
extract_clock(centrino_model->op_points[i].index), extract_clock(centrino_model[cpu]->op_points[i].index, cpu, 0),
centrino_model->op_points[i].frequency); centrino_model[cpu]->op_points[i].frequency);
result = -EINVAL; result = -EINVAL;
goto err_kfree_all; goto err_kfree_all;
} }
if (cur_freq == centrino_model->op_points[i].frequency) if (cur_freq == centrino_model[cpu]->op_points[i].frequency)
p.state = i; p.state = i;
} }
...@@ -444,12 +468,12 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) ...@@ -444,12 +468,12 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
return 0; return 0;
err_kfree_all: err_kfree_all:
kfree(centrino_model->op_points); kfree(centrino_model[cpu]->op_points);
err_kfree: err_kfree:
kfree(centrino_model); kfree(centrino_model[cpu]);
err_unreg: err_unreg:
acpi_processor_unregister_performance(&p, policy->cpu); acpi_processor_unregister_performance(&p, cpu);
printk(KERN_INFO PFX "invalid ACPI data\n"); dprintk(KERN_INFO PFX "invalid ACPI data\n");
return (result); return (result);
} }
#else #else
...@@ -473,14 +497,18 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) ...@@ -473,14 +497,18 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
break; break;
if (i != N_IDS) if (i != N_IDS)
centrino_cpu = &cpu_ids[i]; centrino_cpu[policy->cpu] = &cpu_ids[i];
if (is_const_loops_cpu(policy->cpu)) {
centrino_driver.flags |= CPUFREQ_CONST_LOOPS;
}
if (centrino_cpu_init_acpi(policy)) { if (centrino_cpu_init_acpi(policy)) {
if (policy->cpu != 0) if (policy->cpu != 0)
return -ENODEV; return -ENODEV;
if (!centrino_cpu) { if (!centrino_cpu[policy->cpu]) {
printk(KERN_INFO PFX "found unsupported CPU with " dprintk(KERN_INFO PFX "found unsupported CPU with "
"Enhanced SpeedStep: send /proc/cpuinfo to " "Enhanced SpeedStep: send /proc/cpuinfo to "
MAINTAINER "\n"); MAINTAINER "\n");
return -ENODEV; return -ENODEV;
...@@ -516,32 +544,34 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) ...@@ -516,32 +544,34 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur); dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur);
ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points); ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model[policy->cpu]->op_points);
if (ret) if (ret)
return (ret); return (ret);
cpufreq_frequency_table_get_attr(centrino_model->op_points, policy->cpu); cpufreq_frequency_table_get_attr(centrino_model[policy->cpu]->op_points, policy->cpu);
return 0; return 0;
} }
static int centrino_cpu_exit(struct cpufreq_policy *policy) static int centrino_cpu_exit(struct cpufreq_policy *policy)
{ {
if (!centrino_model) unsigned int cpu = policy->cpu;
if (!centrino_model[cpu])
return -ENODEV; return -ENODEV;
cpufreq_frequency_table_put_attr(policy->cpu); cpufreq_frequency_table_put_attr(cpu);
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
if (!centrino_model->model_name) { if (!centrino_model[cpu]->model_name) {
dprintk("unregistering and freeing ACPI data\n"); dprintk("unregistering and freeing ACPI data\n");
acpi_processor_unregister_performance(&p, policy->cpu); acpi_processor_unregister_performance(&p, cpu);
kfree(centrino_model->op_points); kfree(centrino_model[cpu]->op_points);
kfree(centrino_model); kfree(centrino_model[cpu]);
} }
#endif #endif
centrino_model = NULL; centrino_model[cpu] = NULL;
return 0; return 0;
} }
...@@ -555,7 +585,7 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy) ...@@ -555,7 +585,7 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
*/ */
static int centrino_verify (struct cpufreq_policy *policy) static int centrino_verify (struct cpufreq_policy *policy)
{ {
return cpufreq_frequency_table_verify(policy, centrino_model->op_points); return cpufreq_frequency_table_verify(policy, centrino_model[policy->cpu]->op_points);
} }
/** /**
...@@ -571,12 +601,12 @@ static int centrino_target (struct cpufreq_policy *policy, ...@@ -571,12 +601,12 @@ static int centrino_target (struct cpufreq_policy *policy,
unsigned int relation) unsigned int relation)
{ {
unsigned int newstate = 0; unsigned int newstate = 0;
unsigned int msr, oldmsr, h; unsigned int msr, oldmsr, h, cpu = policy->cpu;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
cpumask_t saved_mask; cpumask_t saved_mask;
int retval; int retval;
if (centrino_model == NULL) if (centrino_model[cpu] == NULL)
return -ENODEV; return -ENODEV;
/* /*
...@@ -585,18 +615,18 @@ static int centrino_target (struct cpufreq_policy *policy, ...@@ -585,18 +615,18 @@ static int centrino_target (struct cpufreq_policy *policy,
*/ */
saved_mask = current->cpus_allowed; saved_mask = current->cpus_allowed;
set_cpus_allowed(current, policy->cpus); set_cpus_allowed(current, policy->cpus);
if (smp_processor_id() != policy->cpu) { if (!cpu_isset(smp_processor_id(), policy->cpus)) {
dprintk("couldn't limit to CPUs in this domain\n"); dprintk("couldn't limit to CPUs in this domain\n");
return(-EAGAIN); return(-EAGAIN);
} }
if (cpufreq_frequency_table_target(policy, centrino_model->op_points, target_freq, if (cpufreq_frequency_table_target(policy, centrino_model[cpu]->op_points, target_freq,
relation, &newstate)) { relation, &newstate)) {
retval = -EINVAL; retval = -EINVAL;
goto migrate_end; goto migrate_end;
} }
msr = centrino_model->op_points[newstate].index; msr = centrino_model[cpu]->op_points[newstate].index;
rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
if (msr == (oldmsr & 0xffff)) { if (msr == (oldmsr & 0xffff)) {
...@@ -605,9 +635,9 @@ static int centrino_target (struct cpufreq_policy *policy, ...@@ -605,9 +635,9 @@ static int centrino_target (struct cpufreq_policy *policy,
goto migrate_end; goto migrate_end;
} }
freqs.cpu = policy->cpu; freqs.cpu = cpu;
freqs.old = extract_clock(oldmsr); freqs.old = extract_clock(oldmsr, cpu, 0);
freqs.new = extract_clock(msr); freqs.new = extract_clock(msr, cpu, 0);
dprintk("target=%dkHz old=%d new=%d msr=%04x\n", dprintk("target=%dkHz old=%d new=%d msr=%04x\n",
target_freq, freqs.old, freqs.new, msr); target_freq, freqs.old, freqs.new, msr);
......
/*
* Routines common for drivers handling Enhanced Speedstep Technology
* Copyright (C) 2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
*
* Licensed under the terms of the GNU GPL License version 2 -- see
* COPYING for details.
*/
static inline int is_const_loops_cpu(unsigned int cpu)
{
struct cpuinfo_x86 *c = cpu_data + cpu;
if (c->x86_vendor != X86_VENDOR_INTEL || !cpu_has(c, X86_FEATURE_EST))
return 0;
/*
* on P-4s, the TSC runs with constant frequency independent of cpu freq
* when we use EST
*/
if (c->x86 == 0xf)
return 1;
return 0;
}
...@@ -27,17 +27,21 @@ config CPU_FREQ_DEBUG ...@@ -27,17 +27,21 @@ config CPU_FREQ_DEBUG
2 to activate CPUfreq drivers debugging, and 2 to activate CPUfreq drivers debugging, and
4 to activate CPUfreq governor debugging 4 to activate CPUfreq governor debugging
config CPU_FREQ_PROC_INTF config CPU_FREQ_STAT
tristate "/proc/cpufreq interface (deprecated)" tristate "CPU frequency translation statistics"
depends on CPU_FREQ && PROC_FS depends on CPU_FREQ && CPU_FREQ_TABLE
help default y
This enables the /proc/cpufreq interface for controlling help
CPUFreq. Please note that it is recommended to use the sysfs This driver exports CPU frequency statistics information through sysfs
interface instead (which is built automatically). file system
For details, take a look at <file:Documentation/cpu-freq/>. config CPU_FREQ_STAT_DETAILS
bool "CPU frequency translation statistics details"
If in doubt, say N. depends on CPU_FREQ && CPU_FREQ_STAT
default n
help
This will show detail CPU frequency translation table in sysfs file
system
choice choice
prompt "Default CPUFreq governor" prompt "Default CPUFreq governor"
...@@ -98,21 +102,6 @@ config CPU_FREQ_GOV_USERSPACE ...@@ -98,21 +102,6 @@ config CPU_FREQ_GOV_USERSPACE
If in doubt, say Y. If in doubt, say Y.
config CPU_FREQ_24_API
bool "/proc/sys/cpu/ interface (2.4. / OLD)"
depends on CPU_FREQ_GOV_USERSPACE
depends on SYSCTL
help
This enables the /proc/sys/cpu/ sysctl interface for controlling
the CPUFreq,"userspace" governor. This is the same interface
as known from the 2.4.-kernel patches for CPUFreq, and offers
the same functionality as long as "userspace" is the
selected governor for the specified CPU.
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
config CPU_FREQ_GOV_ONDEMAND config CPU_FREQ_GOV_ONDEMAND
tristate "'ondemand' cpufreq policy governor" tristate "'ondemand' cpufreq policy governor"
depends on CPU_FREQ depends on CPU_FREQ
......
# CPUfreq core # CPUfreq core
obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o
# CPUfreq stats
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
# CPUfreq governors # CPUfreq governors
obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o
...@@ -9,5 +11,4 @@ obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o ...@@ -9,5 +11,4 @@ obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
# CPUfreq cross-arch helpers # CPUfreq cross-arch helpers
obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
obj-$(CONFIG_CPU_FREQ_PROC_INTF) += proc_intf.o
...@@ -63,7 +63,7 @@ static DECLARE_RWSEM (cpufreq_notifier_rwsem); ...@@ -63,7 +63,7 @@ static DECLARE_RWSEM (cpufreq_notifier_rwsem);
static LIST_HEAD(cpufreq_governor_list); static LIST_HEAD(cpufreq_governor_list);
static DECLARE_MUTEX (cpufreq_governor_sem); static DECLARE_MUTEX (cpufreq_governor_sem);
static struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu) struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu)
{ {
struct cpufreq_policy *data; struct cpufreq_policy *data;
unsigned long flags; unsigned long flags;
...@@ -102,12 +102,14 @@ static struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu) ...@@ -102,12 +102,14 @@ static struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu)
err_out: err_out:
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
static void cpufreq_cpu_put(struct cpufreq_policy *data) void cpufreq_cpu_put(struct cpufreq_policy *data)
{ {
kobject_put(&data->kobj); kobject_put(&data->kobj);
module_put(cpufreq_driver->owner); module_put(cpufreq_driver->owner);
} }
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
/********************************************************************* /*********************************************************************
...@@ -285,7 +287,7 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition); ...@@ -285,7 +287,7 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/** /**
* cpufreq_parse_governor - parse a governor string * cpufreq_parse_governor - parse a governor string
*/ */
int cpufreq_parse_governor (char *str_governor, unsigned int *policy, static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
struct cpufreq_governor **governor) struct cpufreq_governor **governor)
{ {
if (!cpufreq_driver) if (!cpufreq_driver)
...@@ -763,8 +765,11 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) ...@@ -763,8 +765,11 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif #endif
down(&data->lock);
if (cpufreq_driver->target) if (cpufreq_driver->target)
__cpufreq_governor(data, CPUFREQ_GOV_STOP); __cpufreq_governor(data, CPUFREQ_GOV_STOP);
cpufreq_driver->target = NULL;
up(&data->lock);
kobject_unregister(&data->kobj); kobject_unregister(&data->kobj);
...@@ -893,6 +898,13 @@ static int cpufreq_resume(struct sys_device * sysdev) ...@@ -893,6 +898,13 @@ static int cpufreq_resume(struct sys_device * sysdev)
return 0; return 0;
} }
if (cpufreq_driver->resume) {
ret = cpufreq_driver->resume(cpu_policy);
printk(KERN_ERR "cpufreq: resume failed in ->resume step on CPU %u\n", cpu_policy->cpu);
cpufreq_cpu_put(cpu_policy);
return (ret);
}
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
unsigned int cur_freq = 0; unsigned int cur_freq = 0;
...@@ -1018,7 +1030,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, ...@@ -1018,7 +1030,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
lock_cpu_hotplug(); lock_cpu_hotplug();
dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu, dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
target_freq, relation); target_freq, relation);
if (cpu_online(policy->cpu)) if (cpu_online(policy->cpu) && cpufreq_driver->target)
retval = cpufreq_driver->target(policy, target_freq, relation); retval = cpufreq_driver->target(policy, target_freq, relation);
unlock_cpu_hotplug(); unlock_cpu_hotplug();
return retval; return retval;
......
...@@ -229,10 +229,14 @@ static void dbs_check_cpu(int cpu) ...@@ -229,10 +229,14 @@ static void dbs_check_cpu(int cpu)
static int down_skip[NR_CPUS]; static int down_skip[NR_CPUS];
struct cpu_dbs_info_s *this_dbs_info; struct cpu_dbs_info_s *this_dbs_info;
struct cpufreq_policy *policy;
unsigned int j;
this_dbs_info = &per_cpu(cpu_dbs_info, cpu); this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
if (!this_dbs_info->enable) if (!this_dbs_info->enable)
return; return;
policy = this_dbs_info->cur_policy;
/* /*
* The default safe range is 20% to 80% * The default safe range is 20% to 80%
* Every sampling_rate, we check * Every sampling_rate, we check
...@@ -246,12 +250,33 @@ static void dbs_check_cpu(int cpu) ...@@ -246,12 +250,33 @@ static void dbs_check_cpu(int cpu)
* Frequency reduction happens at minimum steps of * Frequency reduction happens at minimum steps of
* 5% of max_frequency * 5% of max_frequency
*/ */
/* Check for frequency increase */ /* Check for frequency increase */
total_idle_ticks = kstat_cpu(cpu).cpustat.idle + total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
kstat_cpu(cpu).cpustat.iowait; kstat_cpu(cpu).cpustat.iowait;
idle_ticks = total_idle_ticks - idle_ticks = total_idle_ticks -
this_dbs_info->prev_cpu_idle_up; this_dbs_info->prev_cpu_idle_up;
this_dbs_info->prev_cpu_idle_up = total_idle_ticks; this_dbs_info->prev_cpu_idle_up = total_idle_ticks;
for_each_cpu_mask(j, policy->cpus) {
unsigned int tmp_idle_ticks;
struct cpu_dbs_info_s *j_dbs_info;
if (j == cpu)
continue;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
/* Check for frequency increase */
total_idle_ticks = kstat_cpu(j).cpustat.idle +
kstat_cpu(j).cpustat.iowait;
tmp_idle_ticks = total_idle_ticks -
j_dbs_info->prev_cpu_idle_up;
j_dbs_info->prev_cpu_idle_up = total_idle_ticks;
if (tmp_idle_ticks < idle_ticks)
idle_ticks = tmp_idle_ticks;
}
/* Scale idle ticks by 100 and compare with up and down ticks */ /* Scale idle ticks by 100 and compare with up and down ticks */
idle_ticks *= 100; idle_ticks *= 100;
...@@ -259,8 +284,7 @@ static void dbs_check_cpu(int cpu) ...@@ -259,8 +284,7 @@ static void dbs_check_cpu(int cpu)
sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate); sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate);
if (idle_ticks < up_idle_ticks) { if (idle_ticks < up_idle_ticks) {
__cpufreq_driver_target(this_dbs_info->cur_policy, __cpufreq_driver_target(policy, policy->max,
this_dbs_info->cur_policy->max,
CPUFREQ_RELATION_H); CPUFREQ_RELATION_H);
down_skip[cpu] = 0; down_skip[cpu] = 0;
this_dbs_info->prev_cpu_idle_down = total_idle_ticks; this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
...@@ -272,12 +296,34 @@ static void dbs_check_cpu(int cpu) ...@@ -272,12 +296,34 @@ static void dbs_check_cpu(int cpu)
if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor) if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
return; return;
total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
kstat_cpu(cpu).cpustat.iowait;
idle_ticks = total_idle_ticks - idle_ticks = total_idle_ticks -
this_dbs_info->prev_cpu_idle_down; this_dbs_info->prev_cpu_idle_down;
this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
for_each_cpu_mask(j, policy->cpus) {
unsigned int tmp_idle_ticks;
struct cpu_dbs_info_s *j_dbs_info;
if (j == cpu)
continue;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
/* Check for frequency increase */
total_idle_ticks = kstat_cpu(j).cpustat.idle +
kstat_cpu(j).cpustat.iowait;
tmp_idle_ticks = total_idle_ticks -
j_dbs_info->prev_cpu_idle_down;
j_dbs_info->prev_cpu_idle_down = total_idle_ticks;
if (tmp_idle_ticks < idle_ticks)
idle_ticks = tmp_idle_ticks;
}
/* Scale idle ticks by 100 and compare with up and down ticks */ /* Scale idle ticks by 100 and compare with up and down ticks */
idle_ticks *= 100; idle_ticks *= 100;
down_skip[cpu] = 0; down_skip[cpu] = 0;
this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
freq_down_sampling_rate = dbs_tuners_ins.sampling_rate * freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
dbs_tuners_ins.sampling_down_factor; dbs_tuners_ins.sampling_down_factor;
...@@ -285,14 +331,14 @@ static void dbs_check_cpu(int cpu) ...@@ -285,14 +331,14 @@ static void dbs_check_cpu(int cpu)
sampling_rate_in_HZ(freq_down_sampling_rate); sampling_rate_in_HZ(freq_down_sampling_rate);
if (idle_ticks > down_idle_ticks ) { if (idle_ticks > down_idle_ticks ) {
freq_down_step = (5 * this_dbs_info->cur_policy->max) / 100; freq_down_step = (5 * policy->max) / 100;
/* max freq cannot be less than 100. But who knows.... */ /* max freq cannot be less than 100. But who knows.... */
if (unlikely(freq_down_step == 0)) if (unlikely(freq_down_step == 0))
freq_down_step = 5; freq_down_step = 5;
__cpufreq_driver_target(this_dbs_info->cur_policy, __cpufreq_driver_target(policy,
this_dbs_info->cur_policy->cur - freq_down_step, policy->cur - freq_down_step,
CPUFREQ_RELATION_H); CPUFREQ_RELATION_H);
return; return;
} }
...@@ -313,7 +359,8 @@ static void do_dbs_timer(void *data) ...@@ -313,7 +359,8 @@ static void do_dbs_timer(void *data)
static inline void dbs_timer_init(void) static inline void dbs_timer_init(void)
{ {
INIT_WORK(&dbs_work, do_dbs_timer, NULL); INIT_WORK(&dbs_work, do_dbs_timer, NULL);
schedule_work(&dbs_work); schedule_delayed_work(&dbs_work,
sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate));
return; return;
} }
...@@ -328,6 +375,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, ...@@ -328,6 +375,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
{ {
unsigned int cpu = policy->cpu; unsigned int cpu = policy->cpu;
struct cpu_dbs_info_s *this_dbs_info; struct cpu_dbs_info_s *this_dbs_info;
unsigned int j;
this_dbs_info = &per_cpu(cpu_dbs_info, cpu); this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
...@@ -344,14 +392,18 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, ...@@ -344,14 +392,18 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
break; break;
down(&dbs_sem); down(&dbs_sem);
this_dbs_info->cur_policy = policy; for_each_cpu_mask(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
this_dbs_info->prev_cpu_idle_up = j_dbs_info->prev_cpu_idle_up =
kstat_cpu(cpu).cpustat.idle + kstat_cpu(j).cpustat.idle +
kstat_cpu(cpu).cpustat.iowait; kstat_cpu(j).cpustat.iowait;
this_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_down =
kstat_cpu(cpu).cpustat.idle + kstat_cpu(j).cpustat.idle +
kstat_cpu(cpu).cpustat.iowait; kstat_cpu(j).cpustat.iowait;
}
this_dbs_info->enable = 1; this_dbs_info->enable = 1;
sysfs_create_group(&policy->kobj, &dbs_attr_group); sysfs_create_group(&policy->kobj, &dbs_attr_group);
dbs_enable++; dbs_enable++;
......
/*
* drivers/cpufreq/cpufreq_stats.c
*
* Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
* (C) 2004 Zou Nan hai <nanhai.zou@intel.com>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sysdev.h>
#include <linux/cpu.h>
#include <linux/sysfs.h>
#include <linux/cpufreq.h>
#include <linux/jiffies.h>
#include <linux/percpu.h>
#include <linux/kobject.h>
#include <linux/spinlock.h>
static spinlock_t cpufreq_stats_lock;
#define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show) \
static struct freq_attr _attr_##_name = {\
.attr = {.name = __stringify(_name), .owner = THIS_MODULE, \
.mode = _mode, }, \
.show = _show,\
};
static unsigned long
delta_time(unsigned long old, unsigned long new)
{
return (old > new) ? (old - new): (new + ~old + 1);
}
struct cpufreq_stats {
unsigned int cpu;
unsigned int total_trans;
unsigned long long last_time;
unsigned int max_state;
unsigned int state_num;
unsigned int last_index;
unsigned long long *time_in_state;
unsigned int *freq_table;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
unsigned int *trans_table;
#endif
};
static struct cpufreq_stats *cpufreq_stats_table[NR_CPUS];
struct cpufreq_stats_attribute {
struct attribute attr;
ssize_t(*show) (struct cpufreq_stats *, char *);
};
static int
cpufreq_stats_update (unsigned int cpu)
{
struct cpufreq_stats *stat;
spin_lock(&cpufreq_stats_lock);
stat = cpufreq_stats_table[cpu];
if (stat->time_in_state)
stat->time_in_state[stat->last_index] +=
delta_time(stat->last_time, jiffies);
stat->last_time = jiffies;
spin_unlock(&cpufreq_stats_lock);
return 0;
}
static ssize_t
show_total_trans(struct cpufreq_policy *policy, char *buf)
{
struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu];
if(!stat)
return 0;
return sprintf(buf, "%d\n",
cpufreq_stats_table[stat->cpu]->total_trans);
}
static ssize_t
show_time_in_state(struct cpufreq_policy *policy, char *buf)
{
ssize_t len = 0;
int i;
struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu];
if(!stat)
return 0;
cpufreq_stats_update(stat->cpu);
for (i = 0; i < stat->state_num; i++) {
len += sprintf(buf + len, "%u %llu\n",
stat->freq_table[i], stat->time_in_state[i]);
}
return len;
}
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
static ssize_t
show_trans_table(struct cpufreq_policy *policy, char *buf)
{
ssize_t len = 0;
int i, j;
struct cpufreq_stats *stat = cpufreq_stats_table[policy->cpu];
if(!stat)
return 0;
cpufreq_stats_update(stat->cpu);
for (i = 0; i < stat->state_num; i++) {
if (len >= PAGE_SIZE)
break;
len += snprintf(buf + len, PAGE_SIZE - len, "%9u:\t",
stat->freq_table[i]);
for (j = 0; j < stat->state_num; j++) {
if (len >= PAGE_SIZE)
break;
len += snprintf(buf + len, PAGE_SIZE - len, "%u\t",
stat->trans_table[i*stat->max_state+j]);
}
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
}
return len;
}
CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table);
#endif
CPUFREQ_STATDEVICE_ATTR(total_trans,0444,show_total_trans);
CPUFREQ_STATDEVICE_ATTR(time_in_state,0444,show_time_in_state);
static struct attribute *default_attrs[] = {
&_attr_total_trans.attr,
&_attr_time_in_state.attr,
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
&_attr_trans_table.attr,
#endif
NULL
};
static struct attribute_group stats_attr_group = {
.attrs = default_attrs,
.name = "stats"
};
static int
freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
{
int index;
for (index = 0; index < stat->max_state; index++)
if (stat->freq_table[index] == freq)
return index;
return -1;
}
static void
cpufreq_stats_free_table (unsigned int cpu)
{
struct cpufreq_stats *stat = cpufreq_stats_table[cpu];
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
if (policy && policy->cpu == cpu)
sysfs_remove_group(&policy->kobj, &stats_attr_group);
if (stat) {
kfree(stat->time_in_state);
kfree(stat);
}
cpufreq_stats_table[cpu] = NULL;
if (policy)
cpufreq_cpu_put(policy);
}
static int
cpufreq_stats_create_table (struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
unsigned int i, j, count = 0, ret = 0;
struct cpufreq_stats *stat;
struct cpufreq_policy *data;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
if (cpufreq_stats_table[cpu])
return -EBUSY;
if ((stat = kmalloc(sizeof(struct cpufreq_stats), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(stat, 0, sizeof (struct cpufreq_stats));
data = cpufreq_cpu_get(cpu);
if ((ret = sysfs_create_group(&data->kobj, &stats_attr_group)))
goto error_out;
stat->cpu = cpu;
cpufreq_stats_table[cpu] = stat;
for (i=0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
count++;
}
alloc_size = count * sizeof(int) + count * sizeof(long long);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
alloc_size += count * count * sizeof(int);
#endif
stat->max_state = count;
stat->time_in_state = kmalloc(alloc_size, GFP_KERNEL);
if (!stat->time_in_state) {
ret = -ENOMEM;
goto error_out;
}
memset(stat->time_in_state, 0, alloc_size);
stat->freq_table = (unsigned int *)(stat->time_in_state + count);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
stat->trans_table = stat->freq_table + count;
#endif
j = 0;
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
if (freq_table_get_index(stat, freq) == -1)
stat->freq_table[j++] = freq;
}
stat->state_num = j;
spin_lock(&cpufreq_stats_lock);
stat->last_time = jiffies;
stat->last_index = freq_table_get_index(stat, policy->cur);
spin_unlock(&cpufreq_stats_lock);
cpufreq_cpu_put(data);
return 0;
error_out:
cpufreq_cpu_put(data);
kfree(stat);
cpufreq_stats_table[cpu] = NULL;
return ret;
}
static int
cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val,
void *data)
{
int ret;
struct cpufreq_policy *policy = data;
struct cpufreq_frequency_table *table;
unsigned int cpu = policy->cpu;
if (val != CPUFREQ_NOTIFY)
return 0;
table = cpufreq_frequency_get_table(cpu);
if (!table)
return 0;
if ((ret = cpufreq_stats_create_table(policy, table)))
return ret;
return 0;
}
static int
cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_freqs *freq = data;
struct cpufreq_stats *stat;
int old_index, new_index;
if (val != CPUFREQ_POSTCHANGE)
return 0;
stat = cpufreq_stats_table[freq->cpu];
if (!stat)
return 0;
old_index = freq_table_get_index(stat, freq->old);
new_index = freq_table_get_index(stat, freq->new);
cpufreq_stats_update(freq->cpu);
if (old_index == new_index)
return 0;
spin_lock(&cpufreq_stats_lock);
stat->last_index = new_index;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
stat->trans_table[old_index * stat->max_state + new_index]++;
#endif
stat->total_trans++;
spin_unlock(&cpufreq_stats_lock);
return 0;
}
static struct notifier_block notifier_policy_block = {
.notifier_call = cpufreq_stat_notifier_policy
};
static struct notifier_block notifier_trans_block = {
.notifier_call = cpufreq_stat_notifier_trans
};
static int
__init cpufreq_stats_init(void)
{
int ret;
unsigned int cpu;
spin_lock_init(&cpufreq_stats_lock);
if ((ret = cpufreq_register_notifier(&notifier_policy_block,
CPUFREQ_POLICY_NOTIFIER)))
return ret;
if ((ret = cpufreq_register_notifier(&notifier_trans_block,
CPUFREQ_TRANSITION_NOTIFIER))) {
cpufreq_unregister_notifier(&notifier_policy_block,
CPUFREQ_POLICY_NOTIFIER);
return ret;
}
for_each_cpu(cpu)
cpufreq_update_policy(cpu);
return 0;
}
static void
__exit cpufreq_stats_exit(void)
{
unsigned int cpu;
cpufreq_unregister_notifier(&notifier_policy_block,
CPUFREQ_POLICY_NOTIFIER);
cpufreq_unregister_notifier(&notifier_trans_block,
CPUFREQ_TRANSITION_NOTIFIER);
for_each_cpu(cpu)
cpufreq_stats_free_table(cpu);
}
MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats through sysfs filesystem");
MODULE_LICENSE ("GPL");
module_init(cpufreq_stats_init);
module_exit(cpufreq_stats_exit);
...@@ -17,51 +17,13 @@ ...@@ -17,51 +17,13 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/ctype.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/sysctl.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#define CTL_CPU_VARS_SPEED_MAX(cpunr) { \
.ctl_name = CPU_NR_FREQ_MAX, \
.data = &cpu_max_freq[cpunr], \
.procname = "speed-max", \
.maxlen = sizeof(cpu_max_freq[cpunr]),\
.mode = 0444, \
.proc_handler = proc_dointvec, }
#define CTL_CPU_VARS_SPEED_MIN(cpunr) { \
.ctl_name = CPU_NR_FREQ_MIN, \
.data = &cpu_min_freq[cpunr], \
.procname = "speed-min", \
.maxlen = sizeof(cpu_min_freq[cpunr]),\
.mode = 0444, \
.proc_handler = proc_dointvec, }
#define CTL_CPU_VARS_SPEED(cpunr) { \
.ctl_name = CPU_NR_FREQ, \
.procname = "speed", \
.mode = 0644, \
.proc_handler = cpufreq_procctl, \
.strategy = cpufreq_sysctl, \
.extra1 = (void*) (cpunr), }
#define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\
CTL_CPU_VARS_SPEED_MAX(cpunr), \
CTL_CPU_VARS_SPEED_MIN(cpunr), \
CTL_CPU_VARS_SPEED(cpunr), \
{ .ctl_name = 0, }, }
/* the ctl_table entry for each CPU */
#define CPU_ENUM(s) { \
.ctl_name = (CPU_NR + s), \
.procname = #s, \
.mode = 0555, \
.child = ctl_cpu_vars_##s }
/** /**
* A few values needed by the userspace governor * A few values needed by the userspace governor
...@@ -96,17 +58,17 @@ static struct notifier_block userspace_cpufreq_notifier_block = { ...@@ -96,17 +58,17 @@ static struct notifier_block userspace_cpufreq_notifier_block = {
/** /**
* _cpufreq_set - set the CPU frequency * cpufreq_set - set the CPU frequency
* @freq: target frequency in kHz * @freq: target frequency in kHz
* @cpu: CPU for which the frequency is to be set * @cpu: CPU for which the frequency is to be set
* *
* Sets the CPU frequency to freq. * Sets the CPU frequency to freq.
*/ */
static int _cpufreq_set(unsigned int freq, unsigned int cpu) static int cpufreq_set(unsigned int freq, unsigned int cpu)
{ {
int ret = -EINVAL; int ret = -EINVAL;
dprintk("_cpufreq_set for cpu %u, freq %u kHz\n", cpu, freq); dprintk("cpufreq_set for cpu %u, freq %u kHz\n", cpu, freq);
down(&userspace_sem); down(&userspace_sem);
if (!cpu_is_managed[cpu]) if (!cpu_is_managed[cpu])
...@@ -135,358 +97,6 @@ static int _cpufreq_set(unsigned int freq, unsigned int cpu) ...@@ -135,358 +97,6 @@ static int _cpufreq_set(unsigned int freq, unsigned int cpu)
} }
#ifdef CONFIG_CPU_FREQ_24_API
#warning The /proc/sys/cpu/ and sysctl interface to cpufreq will be removed from the 2.6. kernel series soon after 2005-01-01
static unsigned int warning_print = 0;
int __deprecated cpufreq_set(unsigned int freq, unsigned int cpu)
{
return _cpufreq_set(freq, cpu);
}
EXPORT_SYMBOL_GPL(cpufreq_set);
/**
* cpufreq_setmax - set the CPU to the maximum frequency
* @cpu - affected cpu;
*
* Sets the CPU frequency to the maximum frequency supported by
* this CPU.
*/
int __deprecated cpufreq_setmax(unsigned int cpu)
{
if (!cpu_is_managed[cpu] || !cpu_online(cpu))
return -EINVAL;
return _cpufreq_set(cpu_max_freq[cpu], cpu);
}
EXPORT_SYMBOL_GPL(cpufreq_setmax);
/*********************** cpufreq_sysctl interface ********************/
static int
cpufreq_procctl(ctl_table *ctl, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
char buf[16], *p;
int cpu = (long) ctl->extra1;
unsigned int len, left = *lenp;
if (!left || (*ppos && !write) || !cpu_online(cpu)) {
*lenp = 0;
return 0;
}
if (!warning_print) {
warning_print++;
printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and "
"will be removed from (new) 2.6. kernels soon "
"after 2005-01-01\n");
}
if (write) {
unsigned int freq;
len = left;
if (left > sizeof(buf))
left = sizeof(buf);
if (copy_from_user(buf, buffer, left))
return -EFAULT;
buf[sizeof(buf) - 1] = '\0';
freq = simple_strtoul(buf, &p, 0);
_cpufreq_set(freq, cpu);
} else {
len = sprintf(buf, "%d\n", cpufreq_get(cpu));
if (len > left)
len = left;
if (copy_to_user(buffer, buf, len))
return -EFAULT;
}
*lenp = len;
*ppos += len;
return 0;
}
static int
cpufreq_sysctl(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen, void **context)
{
int cpu = (long) table->extra1;
if (!cpu_online(cpu))
return -EINVAL;
if (!warning_print) {
warning_print++;
printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and "
"will be removed from (new) 2.6. kernels soon "
"after 2005-01-01\n");
}
if (oldval && oldlenp) {
size_t oldlen;
if (get_user(oldlen, oldlenp))
return -EFAULT;
if (oldlen != sizeof(unsigned int))
return -EINVAL;
if (put_user(cpufreq_get(cpu), (unsigned int __user *)oldval) ||
put_user(sizeof(unsigned int), oldlenp))
return -EFAULT;
}
if (newval && newlen) {
unsigned int freq;
if (newlen != sizeof(unsigned int))
return -EINVAL;
if (get_user(freq, (unsigned int __user *)newval))
return -EFAULT;
_cpufreq_set(freq, cpu);
}
return 1;
}
/* ctl_table ctl_cpu_vars_{0,1,...,(NR_CPUS-1)} */
/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
CTL_TABLE_CPU_VARS(0);
#if NR_CPUS > 1
CTL_TABLE_CPU_VARS(1);
#endif
#if NR_CPUS > 2
CTL_TABLE_CPU_VARS(2);
#endif
#if NR_CPUS > 3
CTL_TABLE_CPU_VARS(3);
#endif
#if NR_CPUS > 4
CTL_TABLE_CPU_VARS(4);
#endif
#if NR_CPUS > 5
CTL_TABLE_CPU_VARS(5);
#endif
#if NR_CPUS > 6
CTL_TABLE_CPU_VARS(6);
#endif
#if NR_CPUS > 7
CTL_TABLE_CPU_VARS(7);
#endif
#if NR_CPUS > 8
CTL_TABLE_CPU_VARS(8);
#endif
#if NR_CPUS > 9
CTL_TABLE_CPU_VARS(9);
#endif
#if NR_CPUS > 10
CTL_TABLE_CPU_VARS(10);
#endif
#if NR_CPUS > 11
CTL_TABLE_CPU_VARS(11);
#endif
#if NR_CPUS > 12
CTL_TABLE_CPU_VARS(12);
#endif
#if NR_CPUS > 13
CTL_TABLE_CPU_VARS(13);
#endif
#if NR_CPUS > 14
CTL_TABLE_CPU_VARS(14);
#endif
#if NR_CPUS > 15
CTL_TABLE_CPU_VARS(15);
#endif
#if NR_CPUS > 16
CTL_TABLE_CPU_VARS(16);
#endif
#if NR_CPUS > 17
CTL_TABLE_CPU_VARS(17);
#endif
#if NR_CPUS > 18
CTL_TABLE_CPU_VARS(18);
#endif
#if NR_CPUS > 19
CTL_TABLE_CPU_VARS(19);
#endif
#if NR_CPUS > 20
CTL_TABLE_CPU_VARS(20);
#endif
#if NR_CPUS > 21
CTL_TABLE_CPU_VARS(21);
#endif
#if NR_CPUS > 22
CTL_TABLE_CPU_VARS(22);
#endif
#if NR_CPUS > 23
CTL_TABLE_CPU_VARS(23);
#endif
#if NR_CPUS > 24
CTL_TABLE_CPU_VARS(24);
#endif
#if NR_CPUS > 25
CTL_TABLE_CPU_VARS(25);
#endif
#if NR_CPUS > 26
CTL_TABLE_CPU_VARS(26);
#endif
#if NR_CPUS > 27
CTL_TABLE_CPU_VARS(27);
#endif
#if NR_CPUS > 28
CTL_TABLE_CPU_VARS(28);
#endif
#if NR_CPUS > 29
CTL_TABLE_CPU_VARS(29);
#endif
#if NR_CPUS > 30
CTL_TABLE_CPU_VARS(30);
#endif
#if NR_CPUS > 31
CTL_TABLE_CPU_VARS(31);
#endif
#if NR_CPUS > 32
#error please extend CPU enumeration
#endif
/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
static ctl_table ctl_cpu_table[NR_CPUS + 1] = {
CPU_ENUM(0),
#if NR_CPUS > 1
CPU_ENUM(1),
#endif
#if NR_CPUS > 2
CPU_ENUM(2),
#endif
#if NR_CPUS > 3
CPU_ENUM(3),
#endif
#if NR_CPUS > 4
CPU_ENUM(4),
#endif
#if NR_CPUS > 5
CPU_ENUM(5),
#endif
#if NR_CPUS > 6
CPU_ENUM(6),
#endif
#if NR_CPUS > 7
CPU_ENUM(7),
#endif
#if NR_CPUS > 8
CPU_ENUM(8),
#endif
#if NR_CPUS > 9
CPU_ENUM(9),
#endif
#if NR_CPUS > 10
CPU_ENUM(10),
#endif
#if NR_CPUS > 11
CPU_ENUM(11),
#endif
#if NR_CPUS > 12
CPU_ENUM(12),
#endif
#if NR_CPUS > 13
CPU_ENUM(13),
#endif
#if NR_CPUS > 14
CPU_ENUM(14),
#endif
#if NR_CPUS > 15
CPU_ENUM(15),
#endif
#if NR_CPUS > 16
CPU_ENUM(16),
#endif
#if NR_CPUS > 17
CPU_ENUM(17),
#endif
#if NR_CPUS > 18
CPU_ENUM(18),
#endif
#if NR_CPUS > 19
CPU_ENUM(19),
#endif
#if NR_CPUS > 20
CPU_ENUM(20),
#endif
#if NR_CPUS > 21
CPU_ENUM(21),
#endif
#if NR_CPUS > 22
CPU_ENUM(22),
#endif
#if NR_CPUS > 23
CPU_ENUM(23),
#endif
#if NR_CPUS > 24
CPU_ENUM(24),
#endif
#if NR_CPUS > 25
CPU_ENUM(25),
#endif
#if NR_CPUS > 26
CPU_ENUM(26),
#endif
#if NR_CPUS > 27
CPU_ENUM(27),
#endif
#if NR_CPUS > 28
CPU_ENUM(28),
#endif
#if NR_CPUS > 29
CPU_ENUM(29),
#endif
#if NR_CPUS > 30
CPU_ENUM(30),
#endif
#if NR_CPUS > 31
CPU_ENUM(31),
#endif
#if NR_CPUS > 32
#error please extend CPU enumeration
#endif
{
.ctl_name = 0,
}
};
static ctl_table ctl_cpu[2] = {
{
.ctl_name = CTL_CPU,
.procname = "cpu",
.mode = 0555,
.child = ctl_cpu_table,
},
{
.ctl_name = 0,
}
};
static struct ctl_table_header *cpufreq_sysctl_table;
static inline void cpufreq_sysctl_init(void)
{
cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0);
}
static inline void cpufreq_sysctl_exit(void)
{
unregister_sysctl_table(cpufreq_sysctl_table);
}
#else
#define cpufreq_sysctl_init() do {} while(0)
#define cpufreq_sysctl_exit() do {} while(0)
#endif /* CONFIG_CPU_FREQ_24API */
/************************** sysfs interface ************************/ /************************** sysfs interface ************************/
static ssize_t show_speed (struct cpufreq_policy *policy, char *buf) static ssize_t show_speed (struct cpufreq_policy *policy, char *buf)
{ {
...@@ -503,7 +113,7 @@ store_speed (struct cpufreq_policy *policy, const char *buf, size_t count) ...@@ -503,7 +113,7 @@ store_speed (struct cpufreq_policy *policy, const char *buf, size_t count)
if (ret != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
_cpufreq_set(freq, policy->cpu); cpufreq_set(freq, policy->cpu);
return count; return count;
} }
...@@ -577,7 +187,6 @@ EXPORT_SYMBOL(cpufreq_gov_userspace); ...@@ -577,7 +187,6 @@ EXPORT_SYMBOL(cpufreq_gov_userspace);
static int __init cpufreq_gov_userspace_init(void) static int __init cpufreq_gov_userspace_init(void)
{ {
cpufreq_sysctl_init();
cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
return cpufreq_register_governor(&cpufreq_gov_userspace); return cpufreq_register_governor(&cpufreq_gov_userspace);
} }
...@@ -587,7 +196,6 @@ static void __exit cpufreq_gov_userspace_exit(void) ...@@ -587,7 +196,6 @@ static void __exit cpufreq_gov_userspace_exit(void)
{ {
cpufreq_unregister_governor(&cpufreq_gov_userspace); cpufreq_unregister_governor(&cpufreq_gov_userspace);
cpufreq_unregister_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); cpufreq_unregister_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
cpufreq_sysctl_exit();
} }
......
...@@ -214,6 +214,11 @@ void cpufreq_frequency_table_put_attr(unsigned int cpu) ...@@ -214,6 +214,11 @@ void cpufreq_frequency_table_put_attr(unsigned int cpu)
} }
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
{
return show_table[cpu];
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>"); MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION ("CPUfreq frequency table helpers"); MODULE_DESCRIPTION ("CPUfreq frequency table helpers");
......
/*
* linux/drivers/cpufreq/proc_intf.c
*
* Copyright (C) 2002 - 2003 Dominik Brodowski
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/ctype.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#warning This module will be removed from the 2.6. kernel series soon after 2005-01-01
#define CPUFREQ_ALL_CPUS ((NR_CPUS))
static unsigned int warning_print = 0;
/**
* cpufreq_parse_policy - parse a policy string
* @input_string: the string to parse.
* @policy: the policy written inside input_string
*
* This function parses a "policy string" - something the user echo'es into
* /proc/cpufreq or gives as boot parameter - into a struct cpufreq_policy.
* If there are invalid/missing entries, they are replaced with current
* cpufreq policy.
*/
static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *policy)
{
unsigned int min = 0;
unsigned int max = 0;
unsigned int cpu = 0;
char str_governor[16];
struct cpufreq_policy current_policy;
unsigned int result = -EFAULT;
if (!policy)
return -EINVAL;
policy->min = 0;
policy->max = 0;
policy->policy = 0;
policy->cpu = CPUFREQ_ALL_CPUS;
if (sscanf(input_string, "%d:%d:%d:%15s", &cpu, &min, &max, str_governor) == 4)
{
policy->min = min;
policy->max = max;
policy->cpu = cpu;
result = 0;
goto scan_policy;
}
if (sscanf(input_string, "%d%%%d%%%d%%%15s", &cpu, &min, &max, str_governor) == 4)
{
if (!cpufreq_get_policy(&current_policy, cpu)) {
policy->min = (min * current_policy.cpuinfo.max_freq) / 100;
policy->max = (max * current_policy.cpuinfo.max_freq) / 100;
policy->cpu = cpu;
result = 0;
goto scan_policy;
}
}
if (sscanf(input_string, "%d:%d:%15s", &min, &max, str_governor) == 3)
{
policy->min = min;
policy->max = max;
result = 0;
goto scan_policy;
}
if (sscanf(input_string, "%d%%%d%%%15s", &min, &max, str_governor) == 3)
{
if (!cpufreq_get_policy(&current_policy, cpu)) {
policy->min = (min * current_policy.cpuinfo.max_freq) / 100;
policy->max = (max * current_policy.cpuinfo.max_freq) / 100;
result = 0;
goto scan_policy;
}
}
return -EINVAL;
scan_policy:
result = cpufreq_parse_governor(str_governor, &policy->policy, &policy->governor);
return result;
}
/**
* cpufreq_proc_read - read /proc/cpufreq
*
* This function prints out the current cpufreq policy.
*/
static int cpufreq_proc_read (
char *page,
char **start,
off_t off,
int count,
int *eof,
void *data)
{
char *p = page;
int len = 0;
struct cpufreq_policy policy;
unsigned int min_pctg = 0;
unsigned int max_pctg = 0;
unsigned int i = 0;
if (off != 0)
goto end;
if (!warning_print) {
warning_print++;
printk(KERN_INFO "Access to /proc/cpufreq is deprecated and "
"will be removed from (new) 2.6. kernels soon "
"after 2005-01-01\n");
}
p += sprintf(p, " minimum CPU frequency - maximum CPU frequency - policy\n");
for (i=0;i<NR_CPUS;i++) {
if (!cpu_online(i))
continue;
if (cpufreq_get_policy(&policy, i))
continue;
if (!policy.cpuinfo.max_freq)
continue;
min_pctg = (policy.min * 100) / policy.cpuinfo.max_freq;
max_pctg = (policy.max * 100) / policy.cpuinfo.max_freq;
p += sprintf(p, "CPU%3d %9d kHz (%3d %%) - %9d kHz (%3d %%) - ",
i , policy.min, min_pctg, policy.max, max_pctg);
if (policy.policy) {
switch (policy.policy) {
case CPUFREQ_POLICY_POWERSAVE:
p += sprintf(p, "powersave\n");
break;
case CPUFREQ_POLICY_PERFORMANCE:
p += sprintf(p, "performance\n");
break;
default:
p += sprintf(p, "INVALID\n");
break;
}
} else
p += scnprintf(p, CPUFREQ_NAME_LEN, "%s\n", policy.governor->name);
}
end:
len = (p - page);
if (len <= off+count)
*eof = 1;
*start = page + off;
len -= off;
if (len>count)
len = count;
if (len<0)
len = 0;
return len;
}
/**
* cpufreq_proc_write - handles writing into /proc/cpufreq
*
* This function calls the parsing script and then sets the policy
* accordingly.
*/
static int cpufreq_proc_write (
struct file *file,
const char __user *buffer,
unsigned long count,
void *data)
{
int result = 0;
char proc_string[42] = {'\0'};
struct cpufreq_policy policy;
unsigned int i = 0;
if ((count > sizeof(proc_string) - 1))
return -EINVAL;
if (copy_from_user(proc_string, buffer, count))
return -EFAULT;
if (!warning_print) {
warning_print++;
printk(KERN_INFO "Access to /proc/cpufreq is deprecated and "
"will be removed from (new) 2.6. kernels soon "
"after 2005-01-01\n");
}
proc_string[count] = '\0';
result = cpufreq_parse_policy(proc_string, &policy);
if (result)
return -EFAULT;
if (policy.cpu == CPUFREQ_ALL_CPUS)
{
for (i=0; i<NR_CPUS; i++)
{
policy.cpu = i;
if (cpu_online(i))
cpufreq_set_policy(&policy);
}
}
else
cpufreq_set_policy(&policy);
return count;
}
/**
* cpufreq_proc_init - add "cpufreq" to the /proc root directory
*
* This function adds "cpufreq" to the /proc root directory.
*/
static int __init cpufreq_proc_init (void)
{
struct proc_dir_entry *entry = NULL;
/* are these acceptable values? */
entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR,
&proc_root);
if (!entry) {
printk(KERN_ERR "unable to create /proc/cpufreq entry\n");
return -EIO;
} else {
entry->read_proc = cpufreq_proc_read;
entry->write_proc = cpufreq_proc_write;
}
return 0;
}
/**
* cpufreq_proc_exit - removes "cpufreq" from the /proc root directory.
*
* This function removes "cpufreq" from the /proc root directory.
*/
static void __exit cpufreq_proc_exit (void)
{
remove_proc_entry("cpufreq", &proc_root);
return;
}
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION ("CPUfreq /proc/cpufreq interface");
MODULE_LICENSE ("GPL");
module_init(cpufreq_proc_init);
module_exit(cpufreq_proc_exit);
...@@ -252,65 +252,6 @@ int cpufreq_update_policy(unsigned int cpu); ...@@ -252,65 +252,6 @@ int cpufreq_update_policy(unsigned int cpu);
/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */ /* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
unsigned int cpufreq_get(unsigned int cpu); unsigned int cpufreq_get(unsigned int cpu);
/* the proc_intf.c needs this */
int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor);
/*********************************************************************
* CPUFREQ USERSPACE GOVERNOR *
*********************************************************************/
#ifdef CONFIG_CPU_FREQ_24_API
int __deprecated cpufreq_setmax(unsigned int cpu);
int __deprecated cpufreq_set(unsigned int kHz, unsigned int cpu);
/* /proc/sys/cpu */
enum {
CPU_NR = 1, /* compatibilty reasons */
CPU_NR_0 = 1,
CPU_NR_1 = 2,
CPU_NR_2 = 3,
CPU_NR_3 = 4,
CPU_NR_4 = 5,
CPU_NR_5 = 6,
CPU_NR_6 = 7,
CPU_NR_7 = 8,
CPU_NR_8 = 9,
CPU_NR_9 = 10,
CPU_NR_10 = 11,
CPU_NR_11 = 12,
CPU_NR_12 = 13,
CPU_NR_13 = 14,
CPU_NR_14 = 15,
CPU_NR_15 = 16,
CPU_NR_16 = 17,
CPU_NR_17 = 18,
CPU_NR_18 = 19,
CPU_NR_19 = 20,
CPU_NR_20 = 21,
CPU_NR_21 = 22,
CPU_NR_22 = 23,
CPU_NR_23 = 24,
CPU_NR_24 = 25,
CPU_NR_25 = 26,
CPU_NR_26 = 27,
CPU_NR_27 = 28,
CPU_NR_28 = 29,
CPU_NR_29 = 30,
CPU_NR_30 = 31,
CPU_NR_31 = 32,
};
/* /proc/sys/cpu/{0,1,...,(NR_CPUS-1)} */
enum {
CPU_NR_FREQ_MAX = 1,
CPU_NR_FREQ_MIN = 2,
CPU_NR_FREQ = 3,
};
#endif /* CONFIG_CPU_FREQ_24_API */
/********************************************************************* /*********************************************************************
* CPUFREQ DEFAULT GOVERNOR * * CPUFREQ DEFAULT GOVERNOR *
...@@ -351,6 +292,11 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, ...@@ -351,6 +292,11 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int relation, unsigned int relation,
unsigned int *index); unsigned int *index);
/* the following 3 funtions are for cpufreq core use only */
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu);
void cpufreq_cpu_put (struct cpufreq_policy *data);
/* the following are really really optional */ /* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs; extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment