CPUFreq 24-API add-on patch for 2.5.35:
kernel/cpufreq.c cpufreq-24-API
include/linux/cpufreq.h cpufreq-24-API
arch/i386/config.in Transmeta LongRun does not work well with cpufreq-24-API
arch/i386/Config.help help text for CONFIG_CPU_FREQ_24_API
diff -ruN linux-2535original/arch/i386/Config.help linux/arch/i386/Config.help
--- linux-2535original/arch/i386/Config.help Tue Sep 17 10:35:43 2002
+++ linux/arch/i386/Config.help Tue Sep 17 10:36:23 2002
@@ -850,6 +850,19 @@
If in doubt, say N.
+CONFIG_CPU_FREQ_24_API
+ This enables the /proc/sys/cpu/ sysctl interface for controlling
+ CPUFreq, as known from the 2.4.-kernel patches for CPUFreq. Note
+ that some drivers do not support this interface or offer less
+ functionality.
+
+ If you say N here, you'll be able to control CPUFreq using the
+ new /proc/cpufreq interface.
+
+ For details, take a look at linux/Documentation/cpufreq.
+
+ If in doubt, say N.
+
CONFIG_X86_POWERNOW_K6
This adds the CPUFreq driver for mobile AMD K6-2+ and mobile
AMD K6-3+ processors.
diff -ruN linux-2535original/arch/i386/config.in linux/arch/i386/config.in
--- linux-2535original/arch/i386/config.in Tue Sep 17 10:35:43 2002
+++ linux/arch/i386/config.in Tue Sep 17 10:36:16 2002
@@ -192,7 +192,10 @@
bool 'CPU Frequency scaling' CONFIG_CPU_FREQ
if [ "$CONFIG_CPU_FREQ" = "y" ]; then
- define_bool CONFIG_CPU_FREQ_26_API y
+ bool ' /proc/sys/cpu/ interface (2.4.)' CONFIG_CPU_FREQ_24_API
+ if [ "$CONFIG_CPU_FREQ_24_API" = "n" ]; then
+ define_bool CONFIG_CPU_FREQ_26_API y
+ fi
tristate ' AMD Mobile K6-2/K6-3 PowerNow!' CONFIG_X86_POWERNOW_K6
if [ "$CONFIG_MELAN" = "y" ]; then
tristate ' AMD Elan' CONFIG_ELAN_CPUFREQ
@@ -200,7 +203,9 @@
tristate ' VIA Cyrix III Longhaul' CONFIG_X86_LONGHAUL
tristate ' Intel Speedstep' CONFIG_X86_SPEEDSTEP
tristate ' Intel Pentium 4 clock modulation' CONFIG_X86_P4_CLOCKMOD
- tristate ' Transmeta LongRun' CONFIG_X86_LONGRUN
+ if [ "$CONFIG_CPU_FREQ_24_API" = "n" ]; then
+ tristate ' Transmeta LongRun' CONFIG_X86_LONGRUN
+ fi
fi
tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
diff -ruN linux-2535original/include/linux/cpufreq.h linux/include/linux/cpufreq.h
--- linux-2535original/include/linux/cpufreq.h Tue Sep 17 10:35:43 2002
+++ linux/include/linux/cpufreq.h Tue Sep 17 10:35:57 2002
@@ -155,4 +155,98 @@
#endif
+#ifdef CONFIG_CPU_FREQ_24_API
+/*********************************************************************
+ * CPUFREQ 2.4. INTERFACE *
+ *********************************************************************/
+int cpufreq_setmax(unsigned int cpu);
+#ifdef CONFIG_PM
+int cpufreq_restore(void);
+#endif
+int cpufreq_set(unsigned int kHz, unsigned int cpu);
+unsigned int cpufreq_get(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,
+};
+
+#define CTL_CPU_VARS_SPEED_MAX { \
+ ctl_name: CPU_NR_FREQ_MAX, \
+ data: &cpu_max_freq, \
+ procname: "speed-max", \
+ maxlen: sizeof(cpu_max_freq),\
+ mode: 0444, \
+ proc_handler: proc_dointvec, }
+
+#define CTL_CPU_VARS_SPEED_MIN { \
+ ctl_name: CPU_NR_FREQ_MIN, \
+ data: &cpu_min_freq, \
+ procname: "speed-min", \
+ maxlen: sizeof(cpu_min_freq),\
+ 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, \
+ CTL_CPU_VARS_SPEED_MIN, \
+ 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 }
+
+#endif /* CONFIG_CPU_FREQ_24_API */
+
#endif /* _LINUX_CPUFREQ_H */
diff -ruN linux-2535original/kernel/cpufreq.c linux/kernel/cpufreq.c
--- linux-2535original/kernel/cpufreq.c Tue Sep 17 10:35:43 2002
+++ linux/kernel/cpufreq.c Tue Sep 17 10:36:02 2002
@@ -28,6 +28,9 @@
#include <linux/proc_fs.h>
#endif
+#ifdef CONFIG_CPU_FREQ_24_API
+#include <linux/sysctl.h>
+#endif
/**
@@ -65,6 +68,16 @@
};
+#ifdef CONFIG_CPU_FREQ_24_API
+/**
+ * A few values needed by the 2.4.-compatible API
+ */
+static unsigned int cpu_max_freq;
+static unsigned int cpu_min_freq;
+static unsigned int cpu_cur_freq[NR_CPUS];
+#endif
+
+
/*********************************************************************
* 2.6. API *
@@ -327,6 +340,389 @@
/*********************************************************************
+ * 2.4. COMPATIBLE API *
+ *********************************************************************/
+
+#ifdef CONFIG_CPU_FREQ_24_API
+/* NOTE #1: when you use this API, you may not use any other calls,
+ * except cpufreq_[un]register_notifier, of course.
+ */
+
+/**
+ * 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.
+ */
+int cpufreq_set(unsigned int freq, unsigned int cpu)
+{
+ struct cpufreq_policy policy;
+ down(&cpufreq_driver_sem);
+ if (!cpufreq_driver || !cpu_max_freq) {
+ up(&cpufreq_driver_sem);
+ return -EINVAL;
+ }
+
+ policy.min = freq;
+ policy.max = freq;
+ policy.policy = CPUFREQ_POLICY_POWERSAVE;
+ policy.cpu = cpu;
+
+ up(&cpufreq_driver_sem);
+
+ return cpufreq_set_policy(&policy);
+}
+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 cpufreq_setmax(unsigned int cpu)
+{
+ if (!cpu_online(cpu) && (cpu != CPUFREQ_ALL_CPUS))
+ return -EINVAL;
+ return cpufreq_set(cpu_max_freq, cpu);
+}
+EXPORT_SYMBOL_GPL(cpufreq_setmax);
+
+
+/**
+ * cpufreq_get - get the current CPU frequency (in kHz)
+ * @cpu: CPU number - currently without effect.
+ *
+ * Get the CPU current (static) CPU frequency
+ */
+unsigned int cpufreq_get(unsigned int cpu)
+{
+ if (!cpu_online(cpu))
+ return -EINVAL;
+ return cpu_cur_freq[cpu];
+}
+EXPORT_SYMBOL(cpufreq_get);
+
+
+#ifdef CONFIG_SYSCTL
+
+
+/*********************** cpufreq_sysctl interface ********************/
+static int
+cpufreq_procctl(ctl_table *ctl, int write, struct file *filp,
+ void *buffer, size_t *lenp)
+{
+ char buf[16], *p;
+ int cpu = (int) ctl->extra1;
+ int len, left = *lenp;
+
+ if (!left || (filp->f_pos && !write) || !cpu_online(cpu)) {
+ *lenp = 0;
+ return 0;
+ }
+
+ 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;
+ filp->f_pos += len;
+ return 0;
+}
+
+static int
+cpufreq_sysctl(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen, void **context)
+{
+ int cpu = (int) table->extra1;
+
+ if (!cpu_online(cpu))
+ return -EINVAL;
+
+ 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 *)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 *)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,
+ }
+};
+
+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()
+#define cpufreq_sysctl_exit()
+#endif /* CONFIG_SYSCTL */
+#endif /* CONFIG_CPU_FREQ_24_API */
+
+
+
+/*********************************************************************
* NOTIFIER LISTS INTERFACE *
*********************************************************************/
@@ -484,6 +880,14 @@
cpufreq_driver->policy[policy->cpu].policy = policy->policy;
}
+#ifdef CONFIG_CPU_FREQ_24_API
+ if (policy->cpu == CPUFREQ_ALL_CPUS) {
+ for (i=0;i<NR_CPUS;i++)
+ cpu_cur_freq[i] = policy->max;
+ } else
+ cpu_cur_freq[policy->cpu] = policy->max;
+#endif
+
cpufreq_driver->setpolicy(policy);
up(&cpufreq_driver_sem);
@@ -592,6 +996,20 @@
cpufreq_proc_init();
#endif
+#ifdef CONFIG_CPU_FREQ_24_API
+ down(&cpufreq_driver_sem);
+ cpu_min_freq = driver_data->cpu_min_freq;
+ cpu_max_freq = driver_data->policy[0].max_cpu_freq;
+ {
+ unsigned int i;
+ for (i=0; i<NR_CPUS; i++) {
+ cpu_cur_freq[i] = driver_data->cpu_cur_freq[i];
+ }
+ }
+ up(&cpufreq_driver_sem);
+
+ cpufreq_sysctl_init();
+#endif
if (ret) {
down(&cpufreq_driver_sem);
cpufreq_driver = NULL;
@@ -628,6 +1046,10 @@
cpufreq_proc_exit();
#endif
+#ifdef CONFIG_CPU_FREQ_24_API
+ cpufreq_sysctl_exit();
+#endif
+
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_unregister);
@@ -666,6 +1088,10 @@
#ifdef CONFIG_CPU_FREQ_26_API
cpufreq_set_policy(&policy);
+#endif
+
+#ifdef CONFIG_CPU_FREQ_24_API
+ cpufreq_set(cpu_cur_freq[i], i);
#endif
}