diff -purN linux-2.6.0-test7/drivers/cpufreq/cpufreq_dbs.c linux-2.6.0-test7-dbs/drivers/cpufreq/cpufreq_dbs.c --- linux-2.6.0-test7/drivers/cpufreq/cpufreq_dbs.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.0-test7-dbs/drivers/cpufreq/cpufreq_dbs.c 2003-10-20 17:38:05.000000000 -0700 @@ -0,0 +1,214 @@ +/* + * drivers/cpufreq/cpufreq_dbs.c + * + * Copyright (C) 2001 Russell King + * (C) 2002 - 2003 Dominik Brodowski + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * + * $Id:$ + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DBS_RATE (HZ/4) /* timer rate is 250ms */ +#define LOW_LATENCY_FREQUENCY_CHANGE_LIMIT 100 /* in uS */ + +static void do_dbs_timer(void *data); + +typedef struct { + struct cpufreq_policy *cur_policy; + unsigned int prev_cpu_idle; + unsigned int enable; +} ____cacheline_aligned cpu_dbs_info_t; +static cpu_dbs_info_t cpu_dbs_info[NR_CPUS]; + +static unsigned int dbs_enable; /* number of CPUs using DBS policy */ + +static DECLARE_MUTEX (dbs_sem); +static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); + +static void dbs_check_cpu(int cpu) +{ + unsigned int idle_ticks; + + if (!cpu_dbs_info[cpu].enable) + return; + + idle_ticks = kstat_cpu(cpu).cpustat.idle - + cpu_dbs_info[cpu].prev_cpu_idle; + cpu_dbs_info[cpu].prev_cpu_idle = kstat_cpu(cpu).cpustat.idle; + + /* + * The current safe range is 20% to 80% + * - If current idle time is less than 20%, then we try to + * increase frequency + * - If current idle time is more than 80%, then we try to + * decrease frequency + */ + if (idle_ticks < (DBS_RATE / 5)) + cpufreq_driver_target(cpu_dbs_info[cpu].cur_policy, + cpu_dbs_info[cpu].cur_policy->cur + 1, + CPUFREQ_RELATION_L); + else if (idle_ticks > (4 * DBS_RATE / 5)) + cpufreq_driver_target(cpu_dbs_info[cpu].cur_policy, + cpu_dbs_info[cpu].cur_policy->cur - 1, + CPUFREQ_RELATION_H); +} + +static void do_dbs_timer(void *data) +{ + int i; + down(&dbs_sem); + for (i = 0; i < NR_CPUS; i++) + if (cpu_online(i)) + dbs_check_cpu(i); + schedule_delayed_work(&dbs_work, DBS_RATE); + up(&dbs_sem); +} + +static inline int dbs_timer_init(void) +{ + schedule_work(&dbs_work); + return 0; +} + +static inline void dbs_timer_exit(void) +{ + cancel_delayed_work(&dbs_work); + return; +} + +/************************** sysfs interface ************************/ +static ssize_t show_speed (struct cpufreq_policy *policy, char *buf) +{ + return sprintf (buf, "%u\n", policy->cur); +} + +static struct freq_attr freq_attr_scaling_getspeed = { + .attr = { .name = "scaling_getspeed", .mode = 0444 }, + .show = show_speed, +}; + +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu = policy->cpu; + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!try_module_get(THIS_MODULE)) || + !policy->cur) + return -EINVAL; + if (policy->cpuinfo.transition_latency > + LOW_LATENCY_FREQUENCY_CHANGE_LIMIT) + return -EINVAL; + if (cpu_dbs_info[cpu].enable) /* Already enabled */ + break; + + printk(KERN_DEBUG "DBS START: cpu %d, max %d, min %d, cur %d\n", + policy->cpu, policy->max, + policy->min, policy->cur); + down(&dbs_sem); + cpu_dbs_info[cpu].cur_policy = policy; + cpu_dbs_info[cpu].prev_cpu_idle = kstat_cpu(cpu).cpustat.idle; + cpu_dbs_info[cpu].enable = 1; + sysfs_create_file(&policy->kobj, + &freq_attr_scaling_getspeed.attr); + dbs_enable++; + /* + * Start the timerschedule work, when this governer + * is used for first time + */ + if (dbs_enable == 1) + dbs_timer_init(); + + up(&dbs_sem); + break; + + case CPUFREQ_GOV_STOP: + printk(KERN_DEBUG "DBS STOP: cpu %d, max %d, min %d, cur %d\n", + policy->cpu, policy->max, + policy->min, policy->cur); + down(&dbs_sem); + sysfs_remove_file(&policy->kobj, + &freq_attr_scaling_getspeed.attr); + cpu_dbs_info[cpu].enable = 0; + dbs_enable--; + /* + * Start the timerschedule work, when this governer + * is used for first time + */ + if (dbs_enable == 0) + dbs_timer_exit(); + + up(&dbs_sem); + module_put(THIS_MODULE); + break; + + case CPUFREQ_GOV_LIMITS: + printk(KERN_DEBUG "DBS LIMIT: cpu %d, max %d, min %d, cur %d\n", + policy->cpu, policy->max, + policy->min, policy->cur); + down(&dbs_sem); + if (policy->max < cpu_dbs_info[cpu].cur_policy->cur) + __cpufreq_driver_target(cpu_dbs_info[cpu].cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > cpu_dbs_info[cpu].cur_policy->cur) + __cpufreq_driver_target(cpu_dbs_info[cpu].cur_policy, + policy->min, CPUFREQ_RELATION_L); + up(&dbs_sem); + break; + } + return 0; +} + +struct cpufreq_governor cpufreq_gov_dbs = { + .name = "demandbased", + .governor = cpufreq_governor_dbs, + .owner = THIS_MODULE, +}; +EXPORT_SYMBOL(cpufreq_gov_dbs); + +static int __init cpufreq_gov_dbs_init(void) +{ + return cpufreq_register_governor(&cpufreq_gov_dbs); +} + +static void __exit cpufreq_gov_dbs_exit(void) +{ + /* Make sure that the scheduled work is indeed not running */ + flush_scheduled_work(); + cpufreq_unregister_governor(&cpufreq_gov_dbs); +} + + +MODULE_AUTHOR ("Venkatesh Pallipadi "); +MODULE_DESCRIPTION ("DBS(Demand Based Switching)- " + "A dynamic processor frequency governor for " + "Low Latency Frequency Transition capable processors"); +MODULE_LICENSE ("GPL"); + +module_init(cpufreq_gov_dbs_init); +module_exit(cpufreq_gov_dbs_exit); diff -purN linux-2.6.0-test7/drivers/cpufreq/Kconfig linux-2.6.0-test7-dbs/drivers/cpufreq/Kconfig --- linux-2.6.0-test7/drivers/cpufreq/Kconfig 2003-10-20 00:24:33.000000000 -0700 +++ linux-2.6.0-test7-dbs/drivers/cpufreq/Kconfig 2003-10-20 17:27:57.000000000 -0700 @@ -35,6 +35,16 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE programm shall be able to set the CPU dynamically without having to enable the userspace governor manually. +config CPU_FREQ_DEFAULT_GOV_DEMANDBASED + bool "demandbased" + select CPU_FREQ_GOV_DEMANDBASED + help + Use the CPUFreq governor 'demandbased' as default. This enables + kernel to dynamically motnitor the CPU usage and adjust the + CPU frequency accordingly, with no manual intervenation. + This will be enabled only if CPU supports 'Low Latency + Frequency Transitions' + endchoice config CPU_FREQ_GOV_PERFORMANCE @@ -68,6 +78,21 @@ config CPU_FREQ_GOV_USERSPACE If in doubt, say Y. +config CPU_FREQ_GOV_DEMANDBASED + tristate "Demand Based Switching - Dynamic cpufreq policy governer" + depends on CPU_FREQ + help + This driver adds a cpufreq policy governer called Demand Based + Switching. The driver does a periodic polling and dynamically + changes frequency based on the processor utilization. + The policy depends on processor capability to + do fast frequency switching (i.e, very low latency frequency + transitions). + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + config CPU_FREQ_24_API bool "/proc/sys/cpu/ interface (2.4. / OLD)" depends on CPU_FREQ && SYSCTL && CPU_FREQ_GOV_USERSPACE diff -purN linux-2.6.0-test7/drivers/cpufreq/Makefile linux-2.6.0-test7-dbs/drivers/cpufreq/Makefile --- linux-2.6.0-test7/drivers/cpufreq/Makefile 2003-10-20 00:24:33.000000000 -0700 +++ linux-2.6.0-test7-dbs/drivers/cpufreq/Makefile 2003-10-20 17:06:05.000000000 -0700 @@ -5,6 +5,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o +obj-$(CONFIG_CPU_FREQ_GOV_DEMANDBASED) += cpufreq_dbs.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o diff -purN linux-2.6.0-test7/include/linux/cpufreq.h linux-2.6.0-test7-dbs/include/linux/cpufreq.h --- linux-2.6.0-test7/include/linux/cpufreq.h 2003-10-08 12:24:16.000000000 -0700 +++ linux-2.6.0-test7-dbs/include/linux/cpufreq.h 2003-10-20 17:36:34.000000000 -0700 @@ -303,6 +303,9 @@ extern struct cpufreq_governor cpufreq_g #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE) extern struct cpufreq_governor cpufreq_gov_userspace; #define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_userspace +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_DEMANDBASED) +extern struct cpufreq_governor cpufreq_gov_dbs; +#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_dbs #endif /*********************************************************************