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
------------
There is a CPU frequency changing CVS commit and general list where
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
http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the
send an email to cpufreq@lists.linux.org.uk, to subscribe go to
http://lists.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the
mailing list are available to subscribers at
http://www.linux.org.uk/mailman/private/cpufreq/.
http://lists.linux.org.uk/mailman/private/cpufreq/.
Links
......@@ -50,7 +50,7 @@ how to access the CVS repository:
* http://cvs.arm.linux.org.uk/
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:
* http://www.lart.tudelft.nl/projects/scaling
......@@ -575,7 +575,7 @@ S: Maintained
CPU FREQUENCY DRIVERS
P: Dave Jones
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/
S: Maintained
......
......@@ -38,6 +38,8 @@
#include <linux/acpi.h>
#include <acpi/processor.h>
#include "speedstep-est-common.h"
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
......@@ -48,10 +50,12 @@ MODULE_LICENSE("GPL");
struct cpufreq_acpi_io {
struct acpi_processor_performance acpi_data;
struct cpufreq_frequency_table *freq_table;
unsigned int resume;
};
static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS];
static struct cpufreq_driver acpi_cpufreq_driver;
static int
acpi_processor_write_port(
......@@ -119,9 +123,14 @@ acpi_processor_set_performance (
}
if (state == data->acpi_data.state) {
dprintk("Already at target state (P%d)\n", state);
retval = 0;
goto migrate_end;
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);
retval = 0;
goto migrate_end;
}
}
dprintk("Transitioning from P%d to P%d\n",
......@@ -368,6 +377,10 @@ acpi_cpufreq_cpu_init (
if (result)
goto err_free;
if (is_const_loops_cpu(cpu)) {
acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
}
/* capability check */
if (data->acpi_data.state_count <= 1) {
dprintk("No P-States\n");
......@@ -462,6 +475,20 @@ acpi_cpufreq_cpu_exit (
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[] = {
&cpufreq_freq_attr_scaling_available_freqs,
......@@ -473,6 +500,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.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,
......
......@@ -55,16 +55,7 @@ MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
MODULE_PARM_DESC(min_fsb,
"Minimum FSB to use, if not defined: current FSB - 50");
/* DEBUG
* 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
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-nforce2", msg)
/*
* nforce2_calc_fsb - calculate FSB
......
......@@ -209,7 +209,7 @@ static unsigned int gx_get_cpuspeed(unsigned int cpu)
if ((gx_params->pci_suscfg & SUSMOD) == 0)
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);
}
......
......@@ -171,7 +171,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
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) */
printk(KERN_WARNING PFX "Warning: Pentium M detected. "
"The speedstep_centrino module offers voltage scaling"
......
......@@ -635,6 +635,17 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
static int powernow_cpu_exit (struct cpufreq_policy *policy) {
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;
}
......@@ -664,15 +675,7 @@ static int __init powernow_init (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);
if (powernow_table)
kfree(powernow_table);
}
module_param(acpi_force, int, 0444);
......
......@@ -18,6 +18,9 @@
* 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
* 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>
......@@ -65,7 +68,12 @@ static u32 find_millivolts_from_vid(struct powernow_k8_data *data, u32 vid)
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)
{
if (fid < HI_FID_TABLE_BOTTOM) {
......@@ -278,7 +286,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
return 1;
}
while (rvosteps > 0) {
while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) {
if (data->currvid == 0) {
rvosteps = 0;
} else {
......@@ -307,10 +315,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
/* Phase 2 - core frequency transition */
static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
{
u32 vcoreqfid;
u32 vcocurrfid;
u32 vcofiddiff;
u32 savevid = data->currvid;
u32 vcoreqfid, vcocurrfid, vcofiddiff, savevid = data->currvid;
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",
......@@ -498,7 +503,7 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8
|| (pst[j].fid & 1)
|| (j && (pst[j].fid < HI_FID_TABLE_BOTTOM))) {
/* 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;
}
if (pst[j].fid < lastfid)
......@@ -618,7 +623,7 @@ static int find_psb_table(struct powernow_k8_data *data)
return -ENODEV;
}
data->vstable = psb->voltagestabilizationtime;
data->vstable = psb->vstable;
dprintk("voltage stabilization time: %d(*20us)\n", data->vstable);
dprintk("flags2: 0x%x\n", psb->flags2);
......@@ -632,8 +637,8 @@ static int find_psb_table(struct powernow_k8_data *data)
dprintk("isochronous relief time: %d\n", data->irt);
dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs);
dprintk("numpst: 0x%x\n", psb->numpst);
cpst = psb->numpst;
dprintk("numpst: 0x%x\n", psb->num_tables);
cpst = psb->num_tables;
if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0) ){
thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) {
......@@ -651,7 +656,7 @@ static int find_psb_table(struct powernow_k8_data *data)
dprintk("maxvid: 0x%x\n", psb->maxvid);
maxvid = psb->maxvid;
data->numps = psb->numpstates;
data->numps = psb->numps;
dprintk("numpstates: 0x%x\n", data->numps);
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)
/* min/max the cpu is capable of */
if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) {
printk(KERN_ERR PFX "invalid powernow_table\n");
powernow_k8_cpu_exit_acpi(data);
kfree(data->powernow_table);
kfree(data);
return -EINVAL;
......@@ -1027,6 +1033,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol)
err_out:
set_cpus_allowed(current, oldmask);
schedule();
powernow_k8_cpu_exit_acpi(data);
kfree(data);
return -ENODEV;
......
......@@ -21,8 +21,7 @@ struct powernow_k8_data {
u32 plllock; /* pll lock time, units 1 us */
/* keep track of the current fid / vid */
u32 currvid;
u32 currfid;
u32 currvid, currfid;
/* 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.
......@@ -152,14 +151,14 @@ struct psb_s {
u8 signature[10];
u8 tableversion;
u8 flags1;
u16 voltagestabilizationtime;
u16 vstable;
u8 flags2;
u8 numpst;
u8 num_tables;
u32 cpuid;
u8 plllocktime;
u8 maxfid;
u8 maxvid;
u8 numpstates;
u8 numps;
};
/* Pairs of fid/vid values are appended to the version 1.4 PSB table. */
......
/*
* 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
2 to activate CPUfreq drivers debugging, and
4 to activate CPUfreq governor debugging
config CPU_FREQ_PROC_INTF
tristate "/proc/cpufreq interface (deprecated)"
depends on CPU_FREQ && PROC_FS
help
This enables the /proc/cpufreq interface for controlling
CPUFreq. Please note that it is recommended to use the sysfs
interface instead (which is built automatically).
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
config CPU_FREQ_STAT
tristate "CPU frequency translation statistics"
depends on CPU_FREQ && CPU_FREQ_TABLE
default y
help
This driver exports CPU frequency statistics information through sysfs
file system
config CPU_FREQ_STAT_DETAILS
bool "CPU frequency translation statistics details"
depends on CPU_FREQ && CPU_FREQ_STAT
default n
help
This will show detail CPU frequency translation table in sysfs file
system
choice
prompt "Default CPUFreq governor"
......@@ -98,21 +102,6 @@ config CPU_FREQ_GOV_USERSPACE
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
tristate "'ondemand' cpufreq policy governor"
depends on CPU_FREQ
......
# CPUfreq core
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
# CPUfreq stats
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
# CPUfreq governors
obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o
......@@ -9,5 +11,4 @@ obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
# CPUfreq cross-arch helpers
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);
static LIST_HEAD(cpufreq_governor_list);
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;
unsigned long flags;
......@@ -102,12 +102,14 @@ static struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu)
err_out:
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);
module_put(cpufreq_driver->owner);
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
/*********************************************************************
......@@ -285,7 +287,7 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/**
* 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)
{
if (!cpufreq_driver)
......@@ -763,8 +765,11 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
down(&data->lock);
if (cpufreq_driver->target)
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
cpufreq_driver->target = NULL;
up(&data->lock);
kobject_unregister(&data->kobj);
......@@ -893,6 +898,13 @@ static int cpufreq_resume(struct sys_device * sysdev)
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)) {
unsigned int cur_freq = 0;
......@@ -1018,7 +1030,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
lock_cpu_hotplug();
dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
target_freq, relation);
if (cpu_online(policy->cpu))
if (cpu_online(policy->cpu) && cpufreq_driver->target)
retval = cpufreq_driver->target(policy, target_freq, relation);
unlock_cpu_hotplug();
return retval;
......
......@@ -229,10 +229,14 @@ static void dbs_check_cpu(int cpu)
static int down_skip[NR_CPUS];
struct cpu_dbs_info_s *this_dbs_info;
struct cpufreq_policy *policy;
unsigned int j;
this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
if (!this_dbs_info->enable)
return;
policy = this_dbs_info->cur_policy;
/*
* The default safe range is 20% to 80%
* Every sampling_rate, we check
......@@ -246,12 +250,33 @@ static void dbs_check_cpu(int cpu)
* Frequency reduction happens at minimum steps of
* 5% of max_frequency
*/
/* Check for frequency increase */
total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
kstat_cpu(cpu).cpustat.iowait;
idle_ticks = total_idle_ticks -
this_dbs_info->prev_cpu_idle_up;
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 */
idle_ticks *= 100;
......@@ -259,8 +284,7 @@ static void dbs_check_cpu(int cpu)
sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate);
if (idle_ticks < up_idle_ticks) {
__cpufreq_driver_target(this_dbs_info->cur_policy,
this_dbs_info->cur_policy->max,
__cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_H);
down_skip[cpu] = 0;
this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
......@@ -272,12 +296,34 @@ static void dbs_check_cpu(int cpu)
if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
return;
total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
kstat_cpu(cpu).cpustat.iowait;
idle_ticks = total_idle_ticks -
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 */
idle_ticks *= 100;
down_skip[cpu] = 0;
this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
dbs_tuners_ins.sampling_down_factor;
......@@ -285,14 +331,14 @@ static void dbs_check_cpu(int cpu)
sampling_rate_in_HZ(freq_down_sampling_rate);
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.... */
if (unlikely(freq_down_step == 0))
freq_down_step = 5;
__cpufreq_driver_target(this_dbs_info->cur_policy,
this_dbs_info->cur_policy->cur - freq_down_step,
__cpufreq_driver_target(policy,
policy->cur - freq_down_step,
CPUFREQ_RELATION_H);
return;
}
......@@ -313,7 +359,8 @@ static void do_dbs_timer(void *data)
static inline void dbs_timer_init(void)
{
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;
}
......@@ -328,6 +375,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
{
unsigned int cpu = policy->cpu;
struct cpu_dbs_info_s *this_dbs_info;
unsigned int j;
this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
......@@ -344,14 +392,18 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
break;
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 =
kstat_cpu(cpu).cpustat.idle +
kstat_cpu(cpu).cpustat.iowait;
this_dbs_info->prev_cpu_idle_down =
kstat_cpu(cpu).cpustat.idle +
kstat_cpu(cpu).cpustat.iowait;
j_dbs_info->prev_cpu_idle_up =
kstat_cpu(j).cpustat.idle +
kstat_cpu(j).cpustat.iowait;
j_dbs_info->prev_cpu_idle_down =
kstat_cpu(j).cpustat.idle +
kstat_cpu(j).cpustat.iowait;
}
this_dbs_info->enable = 1;
sysfs_create_group(&policy->kobj, &dbs_attr_group);
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 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/ctype.h>
#include <linux/cpufreq.h>
#include <linux/sysctl.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/sysfs.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
......@@ -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
* @cpu: CPU for which the frequency is to be set
*
* 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;
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);
if (!cpu_is_managed[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 ************************/
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)
if (ret != 1)
return -EINVAL;
_cpufreq_set(freq, policy->cpu);
cpufreq_set(freq, policy->cpu);
return count;
}
......@@ -577,7 +187,6 @@ EXPORT_SYMBOL(cpufreq_gov_userspace);
static int __init cpufreq_gov_userspace_init(void)
{
cpufreq_sysctl_init();
cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
return cpufreq_register_governor(&cpufreq_gov_userspace);
}
......@@ -587,7 +196,6 @@ static void __exit cpufreq_gov_userspace_exit(void)
{
cpufreq_unregister_governor(&cpufreq_gov_userspace);
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)
}
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_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);
/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
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 *
......@@ -351,6 +292,11 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int relation,
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 */
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