From: "Eugeny S. Mints" <eugeny.mints@gmail.com>
To: pm list <linux-pm@lists.osdl.org>
Cc: Matthew Locke <matt@nomadgs.com>,
Amit Kucheria <amit.kucheria@nokia.com>,
Igor Stoppa <igor.stoppa@nokia.com>,
kernel list <linux-kernel@vger.kernel.org>
Subject: [RFC] CPUFreq PowerOP integratoin, CPUFreq core 1/3
Date: Thu, 14 Sep 2006 18:43:07 +0400 [thread overview]
Message-ID: <45096A7B.2070007@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 48 bytes --]
This patch touches cpufreq.c and freq_tables.c
[-- Attachment #2: cpufreq.powerop.integration.patch --]
[-- Type: text/x-patch, Size: 50262 bytes --]
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 71fc3b4..73f2e37 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -1,5 +1,5 @@
# CPUfreq core
-obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_helpers.o
# CPUfreq stats
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
@@ -10,6 +10,3 @@ obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) +=
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
-# CPUfreq cross-arch helpers
-obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
-
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index b3df613..28d71f2 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -9,6 +9,13 @@
* Feb 2006 - Jacob Shin <jacob.shin@amd.com>
* Fix handling for CPU hotplug -- affected CPUs
*
+ * Aug 2006 - Eugeny S. Mints <eugeny.@nomad.com>
+ * splitting original cpufreq code on functional layers, integration with
+ * PowerOP, got rid of cpufreq driver
+ *
+ *
+ * 2006 (C) Nomad Global Solutions, Inc.
+ *
* 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.
@@ -28,17 +35,17 @@ #include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/completion.h>
#include <linux/mutex.h>
+#include <linux/powerop.h>
+
+#include "freq_helpers.h"
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "cpufreq-core", msg)
-/**
- * The "cpufreq driver" - the arch- or hardware-dependend low
- * level driver of CPUFreq support, and its spinlock. This lock
- * also protects the cpufreq_cpu_data array.
- */
-static struct cpufreq_driver *cpufreq_driver;
+/* if defined CPUFreq uses set_policy instead of target method */
+static unsigned int smart_cpu = 0;
+
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
-static DEFINE_SPINLOCK(cpufreq_driver_lock);
+static DEFINE_SPINLOCK(cpufreq_cpu_data_lock);
/* internal prototypes */
static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
@@ -67,31 +74,22 @@ struct cpufreq_policy *cpufreq_cpu_get(u
goto err_out;
/* get the cpufreq driver */
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
-
- if (!cpufreq_driver)
- goto err_out_unlock;
-
- if (!try_module_get(cpufreq_driver->owner))
- goto err_out_unlock;
-
+ spin_lock_irqsave(&cpufreq_cpu_data_lock, flags);
/* get the CPU */
data = cpufreq_cpu_data[cpu];
if (!data)
- goto err_out_put_module;
+ goto err_out_unlock;
if (!kobject_get(&data->kobj))
- goto err_out_put_module;
+ goto err_out_unlock;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_unlock_irqrestore(&cpufreq_cpu_data_lock, flags);
return data;
-err_out_put_module:
- module_put(cpufreq_driver->owner);
err_out_unlock:
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_unlock_irqrestore(&cpufreq_cpu_data_lock, flags);
err_out:
return NULL;
}
@@ -101,7 +99,6 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
void cpufreq_cpu_put(struct cpufreq_policy *data)
{
kobject_put(&data->kobj);
- module_put(cpufreq_driver->owner);
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
@@ -241,10 +238,10 @@ void cpufreq_notify_transition(struct cp
BUG_ON(irqs_disabled());
- freqs->flags = cpufreq_driver->flags;
dprintk("notification %u of frequency transition to %u kHz\n",
state, freqs->new);
+ /* FIXME: don't we need a lock here? */
policy = cpufreq_cpu_data[freqs->cpu];
switch (state) {
@@ -253,14 +250,12 @@ void cpufreq_notify_transition(struct cp
* which is not equal to what the cpufreq core thinks is
* "old frequency".
*/
- if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
- if ((policy) && (policy->cpu == freqs->cpu) &&
- (policy->cur) && (policy->cur != freqs->old)) {
- dprintk("Warning: CPU frequency is"
- " %u, cpufreq assumed %u kHz.\n",
- freqs->old, policy->cur);
- freqs->old = policy->cur;
- }
+ if ((policy) && (policy->cpu == freqs->cpu) &&
+ (policy->cur) && (policy->cur != freqs->old)) {
+ dprintk("Warning: CPU frequency is"
+ " %u, cpufreq assumed %u kHz.\n",
+ freqs->old, policy->cur);
+ freqs->old = policy->cur;
}
blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_PRECHANGE, freqs);
@@ -303,10 +298,7 @@ static int cpufreq_parse_governor (char
{
int err = -EINVAL;
- if (!cpufreq_driver)
- goto out;
-
- if (cpufreq_driver->setpolicy) {
+ if (smart_cpu) {
if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
*policy = CPUFREQ_POLICY_PERFORMANCE;
err = 0;
@@ -314,7 +306,7 @@ static int cpufreq_parse_governor (char
*policy = CPUFREQ_POLICY_POWERSAVE;
err = 0;
}
- } else if (cpufreq_driver->target) {
+ } else {
struct cpufreq_governor *t;
mutex_lock(&cpufreq_governor_mutex);
@@ -345,7 +337,6 @@ static int cpufreq_parse_governor (char
mutex_unlock(&cpufreq_governor_mutex);
}
- out:
return err;
}
@@ -433,6 +424,40 @@ static ssize_t show_scaling_governor (st
return -EINVAL;
}
+/**
+ * show_scaling_governor - show the current policy for the specified CPU
+ */
+static ssize_t
+show_available_freqs(struct cpufreq_policy *policy, char *buf)
+{
+ int rc = 0;
+ unsigned int i = 0, freq = 0;
+ ssize_t count = 0;
+ char freq_n[CPUFREQ_FREQ_STR_SIZE];
+ char **opt_names_list;
+ int opt_names_list_size;
+
+ CPUFREQ_CPU_N_FREQ(freq_n, policy->cpu);
+
+ rc = powerop_get_registered_opt_names(opt_names_list,
+ &opt_names_list_size);
+ if (rc != 0)
+ return rc;
+
+ for (i = 0; i < opt_names_list_size; i++) {
+ if (powerop_get_point(opt_names_list[i], freq_n, &freq))
+ continue;
+
+ if (freq == CPUFREQ_ENTRY_INVALID)
+ continue;
+ count += sprintf(&buf[count], "%d ", freq);
+ }
+ powerop_put_registered_opt_names(opt_names_list);
+
+ count += sprintf(&buf[count], "\n");
+
+ return count;
+}
/**
* store_scaling_governor - store policy for the specified CPU
@@ -472,14 +497,6 @@ static ssize_t store_scaling_governor (s
}
/**
- * show_scaling_driver - show the cpufreq driver currently loaded
- */
-static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf)
-{
- return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name);
-}
-
-/**
* show_scaling_available_governors - show the available CPUfreq governors
*/
static ssize_t show_scaling_available_governors (struct cpufreq_policy * policy,
@@ -488,7 +505,7 @@ static ssize_t show_scaling_available_go
ssize_t i = 0;
struct cpufreq_governor *t;
- if (!cpufreq_driver->target) {
+ if (smart_cpu) {
i += sprintf(buf, "performance powersave");
goto out;
}
@@ -538,12 +555,12 @@ define_one_ro0400(cpuinfo_cur_freq);
define_one_ro(cpuinfo_min_freq);
define_one_ro(cpuinfo_max_freq);
define_one_ro(scaling_available_governors);
-define_one_ro(scaling_driver);
define_one_ro(scaling_cur_freq);
define_one_ro(affected_cpus);
define_one_rw(scaling_min_freq);
define_one_rw(scaling_max_freq);
define_one_rw(scaling_governor);
+define_one_ro(available_freqs);
static struct attribute * default_attrs[] = {
&cpuinfo_min_freq.attr,
@@ -552,8 +569,8 @@ static struct attribute * default_attrs[
&scaling_max_freq.attr,
&affected_cpus.attr,
&scaling_governor.attr,
- &scaling_driver.attr,
&scaling_available_governors.attr,
+ &available_freqs.attr,
NULL
};
@@ -605,6 +622,7 @@ static struct kobj_type ktype_cpufreq =
.release = cpufreq_sysfs_release,
};
+extern cpumask_t arch_get_dependent_cpus_mask(int cpu);
/**
* cpufreq_add_dev - add a CPU device
@@ -617,10 +635,10 @@ static int cpufreq_add_dev (struct sys_d
int ret = 0;
struct cpufreq_policy new_policy;
struct cpufreq_policy *policy;
- struct freq_attr **drv_attr;
struct sys_device *cpu_sys_dev;
unsigned long flags;
unsigned int j;
+ char freq_n[CPUFREQ_FREQ_STR_SIZE];
#ifdef CONFIG_SMP
struct cpufreq_policy *managed_policy;
#endif
@@ -630,7 +648,7 @@ #endif
cpufreq_debug_disable_ratelimit();
dprintk("adding CPU %u\n", cpu);
-
+
#ifdef CONFIG_SMP
/* check whether a different CPU already registered this
* CPU because it is in the same boat. */
@@ -638,15 +656,9 @@ #ifdef CONFIG_SMP
if (unlikely(policy)) {
cpufreq_cpu_put(policy);
cpufreq_debug_enable_ratelimit();
- return 0;
+ return ret;
}
#endif
-
- if (!try_module_get(cpufreq_driver->owner)) {
- ret = -EINVAL;
- goto module_out;
- }
-
policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!policy) {
ret = -ENOMEM;
@@ -654,23 +666,38 @@ #endif
}
policy->cpu = cpu;
- policy->cpus = cpumask_of_cpu(cpu);
+
+ /*
+ * FIXME: this will go away once notifications moved to lower layers
+ * presumably to clock/voltage framework level
+ */
+ policy->cpus = arch_get_dependent_cpus_mask(cpu);
mutex_init(&policy->lock);
mutex_lock(&policy->lock);
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update, (void *)(long)cpu);
- /* call driver. From then on the cpufreq must be able
- * to accept all calls to ->verify and ->setpolicy for this CPU
- */
- ret = cpufreq_driver->init(policy);
- if (ret) {
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ /* FIXME: soon this will come from PowerOP Core as well */
+ policy->cpuinfo.transition_latency = 10000; /* 10uS latency */
+
+ CPUFREQ_CPU_N_FREQ(freq_n, cpu);
+ ret = powerop_get_point(NULL, freq_n, &policy->cur);
+ if (ret != 0) {
dprintk("initialization failed\n");
mutex_unlock(&policy->lock);
goto err_out;
}
+ ret = cpufreq_cpuinfo(policy);
+ if (ret) {
+ dprintk("cpuinfo initialization failed\n");
+ mutex_unlock(&policy->lock);
+ goto err_out;
+ }
+
#ifdef CONFIG_SMP
for_each_cpu_mask(j, policy->cpus) {
if (cpu == j)
@@ -681,10 +708,10 @@ #ifdef CONFIG_SMP
*/
managed_policy = cpufreq_cpu_get(j);
if (unlikely(managed_policy)) {
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ spin_lock_irqsave(&cpufreq_cpu_data_lock, flags);
managed_policy->cpus = policy->cpus;
cpufreq_cpu_data[cpu] = managed_policy;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_unlock_irqrestore(&cpufreq_cpu_data_lock, flags);
dprintk("CPU already managed, adding link\n");
sysfs_create_link(&sys_dev->kobj,
@@ -692,8 +719,16 @@ #ifdef CONFIG_SMP
cpufreq_debug_enable_ratelimit();
mutex_unlock(&policy->lock);
- ret = 0;
- goto err_out_driver_exit; /* call driver->exit() */
+ /*
+ * FIXME: interesting... cpufreq handles one policy
+ * entry for all affected CPUs... it works since
+ * currently same set of freq/voltage pairs are always
+ * registered for all CPUs. That bacomes not the case
+ * with PowerOP approach when we can have different
+ * set of operating points even for affected CPUs
+ */
+ kfree(policy);
+ return 0;
}
}
#endif
@@ -707,23 +742,16 @@ #endif
ret = kobject_register(&policy->kobj);
if (ret) {
mutex_unlock(&policy->lock);
- goto err_out_driver_exit;
- }
- /* set up files for this cpu device */
- drv_attr = cpufreq_driver->attr;
- while ((drv_attr) && (*drv_attr)) {
- sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
- drv_attr++;
+ goto err_out;
}
- if (cpufreq_driver->get)
- sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
- if (cpufreq_driver->target)
- sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
+ sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
+
+ spin_lock_irqsave(&cpufreq_cpu_data_lock, flags);
for_each_cpu_mask(j, policy->cpus)
cpufreq_cpu_data[j] = policy;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_unlock_irqrestore(&cpufreq_cpu_data_lock, flags);
/* symlink affected CPUs */
for_each_cpu_mask(j, policy->cpus) {
@@ -750,32 +778,25 @@ #endif
goto err_out_unregister;
}
- module_put(cpufreq_driver->owner);
dprintk("initialization complete\n");
cpufreq_debug_enable_ratelimit();
return 0;
-
err_out_unregister:
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ /* FIXME: original CPUFreq bug: sysfs is not cleaned up properly */
+ spin_lock_irqsave(&cpufreq_cpu_data_lock, flags);
for_each_cpu_mask(j, policy->cpus)
cpufreq_cpu_data[j] = NULL;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_unlock_irqrestore(&cpufreq_cpu_data_lock, flags);
kobject_unregister(&policy->kobj);
wait_for_completion(&policy->kobj_unregister);
-err_out_driver_exit:
- if (cpufreq_driver->exit)
- cpufreq_driver->exit(policy);
-
err_out:
kfree(policy);
nomem_out:
- module_put(cpufreq_driver->owner);
-module_out:
cpufreq_debug_enable_ratelimit();
return ret;
}
@@ -785,6 +806,11 @@ module_out:
* cpufreq_remove_dev - remove a CPU device
*
* Removes the cpufreq interface for a CPU device.
+ *
+ * FIXME: are sysdev driver/device infrastructure for cpus and hotplug
+ * notification redundant? It's important question for PowerOP since for a cpu
+ * [core] suspend (which iiuc now is handled via hotplug] we most probably
+ * don't want unregister operating points
*/
static int cpufreq_remove_dev (struct sys_device * sys_dev)
{
@@ -799,11 +825,11 @@ #endif
cpufreq_debug_disable_ratelimit();
dprintk("unregistering CPU %u\n", cpu);
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ spin_lock_irqsave(&cpufreq_cpu_data_lock, flags);
data = cpufreq_cpu_data[cpu];
if (!data) {
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_unlock_irqrestore(&cpufreq_cpu_data_lock, flags);
cpufreq_debug_enable_ratelimit();
return -EINVAL;
}
@@ -817,7 +843,7 @@ #ifdef CONFIG_SMP
if (unlikely(cpu != data->cpu)) {
dprintk("removing link\n");
cpu_clear(cpu, data->cpus);
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_unlock_irqrestore(&cpufreq_cpu_data_lock, flags);
sysfs_remove_link(&sys_dev->kobj, "cpufreq");
cpufreq_cpu_put(data);
cpufreq_debug_enable_ratelimit();
@@ -825,9 +851,8 @@ #ifdef CONFIG_SMP
}
#endif
-
if (!kobject_get(&data->kobj)) {
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_unlock_irqrestore(&cpufreq_cpu_data_lock, flags);
cpufreq_debug_enable_ratelimit();
return -EFAULT;
}
@@ -842,11 +867,18 @@ #ifdef CONFIG_SMP
for_each_cpu_mask(j, data->cpus) {
if (j == cpu)
continue;
+ /*
+ * FIXME: hmm, we "remove" affected CPUs once a
+ * "leader" CPU is down...is it hw limitation?
+ * why not just cpufreq_cpu_data[cpu] = NULL ?
+ * ...so far unregister operating points for affected
+ * CPUs
+ */
cpufreq_cpu_data[j] = NULL;
}
}
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_unlock_irqrestore(&cpufreq_cpu_data_lock, flags);
if (unlikely(cpus_weight(data->cpus) > 1)) {
for_each_cpu_mask(j, data->cpus) {
@@ -859,11 +891,11 @@ #ifdef CONFIG_SMP
}
}
#else
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_unlock_irqrestore(&cpufreq_cpu_data_lock, flags);
#endif
mutex_lock(&data->lock);
- if (cpufreq_driver->target)
+ if (!smart_cpu)
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
mutex_unlock(&data->lock);
@@ -879,11 +911,7 @@ #endif
wait_for_completion(&data->kobj_unregister);
dprintk("wait complete\n");
- if (cpufreq_driver->exit)
- cpufreq_driver->exit(data);
-
kfree(data);
-
cpufreq_debug_enable_ratelimit();
return 0;
}
@@ -944,6 +972,7 @@ unsigned int cpufreq_quick_get(unsigned
EXPORT_SYMBOL(cpufreq_quick_get);
+/* FIXME: REVISIT: this routine returns 0 on error! */
/**
* cpufreq_get - get the current CPU frequency (in kHz)
* @cpu: CPU number
@@ -954,45 +983,52 @@ unsigned int cpufreq_get(unsigned int cp
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
unsigned int ret = 0;
+ int clock_freq = 0;
+ char freq_n[CPUFREQ_FREQ_STR_SIZE];
if (!policy)
return 0;
- if (!cpufreq_driver->get)
- goto out;
-
mutex_lock(&policy->lock);
- ret = cpufreq_driver->get(cpu);
+ CPUFREQ_CPU_N_FREQ(freq_n, cpu);
+ ret = powerop_get_point(NULL, freq_n, &clock_freq);
+ if (ret != 0) {
+ mutex_unlock(&policy->lock);
+ cpufreq_cpu_put(policy);
+ return 0;
+ }
- if (ret && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
- /* verify no discrepancy between actual and saved value exists */
- if (unlikely(ret != policy->cur)) {
- cpufreq_out_of_sync(cpu, policy->cur, ret);
- schedule_work(&policy->update);
- }
+ if (clock_freq && policy->cur && unlikely(clock_freq != policy->cur)) {
+ /*
+ * verify no discrepancy between actual and saved
+ * value exists
+ */
+ cpufreq_out_of_sync(cpu, policy->cur, clock_freq);
+ schedule_work(&policy->update);
}
mutex_unlock(&policy->lock);
-out:
cpufreq_cpu_put(policy);
- return (ret);
+ return clock_freq;
}
EXPORT_SYMBOL(cpufreq_get);
/**
* cpufreq_suspend - let the low level driver prepare for suspend
+ * with PowerOP cpufreq_suspend() handles internal cpufreq core
+ * needs only. PM Core handles all low layer needs
*/
static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
{
int cpu = sysdev->id;
- unsigned int ret = 0;
unsigned int cur_freq = 0;
struct cpufreq_policy *cpu_policy;
+ char freq_n[CPUFREQ_FREQ_STR_SIZE];
dprintk("resuming cpu %u\n", cpu);
@@ -1014,23 +1050,10 @@ static int cpufreq_suspend(struct sys_de
return 0;
}
- if (cpufreq_driver->suspend) {
- ret = cpufreq_driver->suspend(cpu_policy, pmsg);
- if (ret) {
- printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
- "step on CPU %u\n", cpu_policy->cpu);
- cpufreq_cpu_put(cpu_policy);
- return ret;
- }
- }
-
-
- if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)
+ CPUFREQ_CPU_N_FREQ(freq_n, cpu);
+ if (powerop_get_point(NULL, freq_n, &cur_freq))
goto out;
- if (cpufreq_driver->get)
- cur_freq = cpufreq_driver->get(cpu_policy->cpu);
-
if (!cur_freq || !cpu_policy->cur) {
printk(KERN_ERR "cpufreq: suspend failed to assert current "
"frequency is what timing core thinks it is.\n");
@@ -1040,10 +1063,9 @@ static int cpufreq_suspend(struct sys_de
if (unlikely(cur_freq != cpu_policy->cur)) {
struct cpufreq_freqs freqs;
- if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
- dprintk("Warning: CPU frequency is %u, "
- "cpufreq assumed %u kHz.\n",
- cur_freq, cpu_policy->cur);
+ dprintk("Warning: CPU frequency is %u, "
+ "cpufreq assumed %u kHz.\n",
+ cur_freq, cpu_policy->cur);
freqs.cpu = cpu;
freqs.old = cpu_policy->cur;
@@ -1063,8 +1085,9 @@ out:
/**
* cpufreq_resume - restore proper CPU frequency handling after resume
- *
- * 1.) resume CPUfreq hardware support (cpufreq_driver->resume())
+ *
+ * with PowerOP cpufreq_resume() handles internal cpufreq core
+ * needs only. PM Core handles all low layer needs
* 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync
* 3.) schedule call cpufreq_update_policy() ASAP as interrupts are
* restored.
@@ -1074,6 +1097,9 @@ static int cpufreq_resume(struct sys_dev
int cpu = sysdev->id;
unsigned int ret = 0;
struct cpufreq_policy *cpu_policy;
+ unsigned int cur_freq = 0;
+ char freq_n[CPUFREQ_FREQ_STR_SIZE];
+
dprintk("resuming cpu %u\n", cpu);
@@ -1095,50 +1121,34 @@ static int cpufreq_resume(struct sys_dev
return 0;
}
- if (cpufreq_driver->resume) {
- ret = cpufreq_driver->resume(cpu_policy);
- if (ret) {
- 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;
- if (cpufreq_driver->get)
- cur_freq = cpufreq_driver->get(cpu_policy->cpu);
-
- if (!cur_freq || !cpu_policy->cur) {
- printk(KERN_ERR "cpufreq: resume failed to assert "
- "current frequency is what timing core "
- "thinks it is.\n");
- goto out;
- }
+ CPUFREQ_CPU_N_FREQ(freq_n, cpu);
+ if (powerop_get_point(NULL, freq_n, &cur_freq))
+ goto out;
- if (unlikely(cur_freq != cpu_policy->cur)) {
- struct cpufreq_freqs freqs;
+ if (!cur_freq || !cpu_policy->cur) {
+ printk(KERN_ERR "cpufreq: resume failed to assert "
+ "current frequency is what timing core "
+ "thinks it is.\n");
+ goto out;
+ }
- if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
- dprintk("Warning: CPU frequency"
- "is %u, cpufreq assumed %u kHz.\n",
- cur_freq, cpu_policy->cur);
+ if (unlikely(cur_freq != cpu_policy->cur)) {
+ struct cpufreq_freqs freqs;
- freqs.cpu = cpu;
- freqs.old = cpu_policy->cur;
- freqs.new = cur_freq;
+ dprintk("Warning: CPU frequency"
+ "is %u, cpufreq assumed %u kHz.\n",
+ cur_freq, cpu_policy->cur);
- blocking_notifier_call_chain(
- &cpufreq_transition_notifier_list,
- CPUFREQ_RESUMECHANGE, &freqs);
- adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
+ freqs.cpu = cpu;
+ freqs.old = cpu_policy->cur;
+ freqs.new = cur_freq;
- cpu_policy->cur = cur_freq;
- }
+ blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+ CPUFREQ_RESUMECHANGE, &freqs);
+ adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
+ cpu_policy->cur = cur_freq;
}
-
out:
schedule_work(&cpu_policy->update);
cpufreq_cpu_put(cpu_policy);
@@ -1238,8 +1248,9 @@ int __cpufreq_driver_target(struct cpufr
dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
target_freq, relation);
- if (cpu_online(policy->cpu) && cpufreq_driver->target)
- retval = cpufreq_driver->target(policy, target_freq, relation);
+ if (cpu_online(policy->cpu))
+ retval = cpufreq_target(policy, target_freq,
+ relation);
return retval;
}
@@ -1377,7 +1388,7 @@ static int __cpufreq_set_policy(struct c
}
/* verify the cpu speed can be set within this limit */
- ret = cpufreq_driver->verify(policy);
+ ret = cpufreq_verify(policy);
if (ret)
goto error_out;
@@ -1391,7 +1402,7 @@ static int __cpufreq_set_policy(struct c
/* verify the cpu speed can be set within this limit,
which might be different to the first one */
- ret = cpufreq_driver->verify(policy);
+ ret = cpufreq_verify(policy);
if (ret)
goto error_out;
@@ -1404,10 +1415,10 @@ static int __cpufreq_set_policy(struct c
dprintk("new min and max freqs are %u - %u kHz\n", data->min, data->max);
- if (cpufreq_driver->setpolicy) {
+ if (smart_cpu) {
data->policy = policy->policy;
dprintk("setting range\n");
- ret = cpufreq_driver->setpolicy(policy);
+ ret = cpufreq_setpolicy(policy);
} else {
if (policy->governor != data->governor) {
/* save old, working values */
@@ -1492,6 +1503,7 @@ int cpufreq_update_policy(unsigned int c
{
struct cpufreq_policy *data = cpufreq_cpu_get(cpu);
struct cpufreq_policy policy;
+ char freq_n[CPUFREQ_FREQ_STR_SIZE];
int ret = 0;
if (!data)
@@ -1509,26 +1521,35 @@ int cpufreq_update_policy(unsigned int c
/* BIOS might change freq behind our back
-> ask driver for current freq and notify governors about a change */
- if (cpufreq_driver->get) {
- policy.cur = cpufreq_driver->get(cpu);
- if (!data->cur) {
- dprintk("Driver did not initialize current freq");
- data->cur = policy.cur;
- } else {
- if (data->cur != policy.cur)
- cpufreq_out_of_sync(cpu, data->cur, policy.cur);
- }
+ CPUFREQ_CPU_N_FREQ(freq_n, cpu);
+ ret = powerop_get_point(NULL, freq_n, &policy.cur);
+ if (ret != 0)
+ goto out_failed;
+
+ if (!data->cur) {
+ dprintk("Driver did not initialize current freq");
+ data->cur = policy.cur;
+ } else {
+ if (data->cur != policy.cur)
+ cpufreq_out_of_sync(cpu, data->cur, policy.cur);
}
ret = __cpufreq_set_policy(data, &policy);
+out_failed:
mutex_unlock(&data->lock);
unlock_cpu_hotplug();
cpufreq_cpu_put(data);
return ret;
}
EXPORT_SYMBOL(cpufreq_update_policy);
-
+/*
+ * FIXME: why do we need separate hotplug callback and sysdev_driver->add()
+ * routine is not enough? Doesn't acpi call arch_register_cpu() and trigger
+ * sysdev_driver->add() in case of ACPI is enabled (CONFIG_ACPI_HOTPLUG_CPU)?
+ * Seems hotplug code does not ever (indirectly) call register_cpu() from
+ * drivers/base/cpu.c . Why? Am I missing something?
+ */
#ifdef CONFIG_HOTPLUG_CPU
static int cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
@@ -1551,10 +1572,11 @@ static int cpufreq_cpu_callback(struct n
* hardware-managed P-State to switch other related
* threads to min or higher speeds if possible.
*/
+ /* FIXME: no any locking here? */
policy = cpufreq_cpu_data[cpu];
if (policy) {
- cpufreq_driver_target(policy, policy->min,
- CPUFREQ_RELATION_H);
+ cpufreq_target(policy, policy->min,
+ CPUFREQ_RELATION_H);
}
break;
case CPU_DEAD:
@@ -1571,6 +1593,49 @@ static struct notifier_block __cpuinitda
};
#endif /* CONFIG_HOTPLUG_CPU */
+static int
+cpufreq_powerop_callback(struct notifier_block *nfb, unsigned long action,
+ void *name)
+{
+ char freq_n[CPUFREQ_FREQ_STR_SIZE];
+ int freq = 0, i, rc = 0;
+ struct cpufreq_policy *policy;
+
+ switch (action) {
+ case POWEROP_REGISTER_EVENT:
+ for (i = 0; i < NR_CPUS; i++) {
+ CPUFREQ_CPU_N_FREQ(freq_n, i);
+ rc = powerop_get_point(name, freq_n, &freq);
+ if (rc != 0)
+ break;
+ if (freq != -1) {
+ policy = cpufreq_cpu_get(i);
+ if (freq < policy->min)
+ policy->min = freq;
+ if (freq > policy->max)
+ policy->max = freq;
+ if (policy->max >
+ policy->cpuinfo.max_freq)
+ policy->cpuinfo.max_freq =
+ policy->max;
+ if (policy->min <
+ policy->cpuinfo.min_freq)
+ policy->cpuinfo.min_freq =
+ policy->min;
+ schedule_work(&policy->update);
+ cpufreq_cpu_put(policy);
+ }
+ }
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block cpufreq_powerop_notifier =
+{
+ .notifier_call = cpufreq_powerop_callback,
+};
+
/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
@@ -1585,89 +1650,36 @@ #endif /* CONFIG_HOTPLUG_CPU */
* (and isn't unregistered in the meantime).
*
*/
-int cpufreq_register_driver(struct cpufreq_driver *driver_data)
+int cpufreq_core_init(void)
{
- unsigned long flags;
int ret;
- if (!driver_data || !driver_data->verify || !driver_data->init ||
- ((!driver_data->setpolicy) && (!driver_data->target)))
- return -EINVAL;
-
- dprintk("trying to register driver %s\n", driver_data->name);
-
- if (driver_data->setpolicy)
- driver_data->flags |= CPUFREQ_CONST_LOOPS;
-
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
- if (cpufreq_driver) {
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- return -EBUSY;
- }
- cpufreq_driver = driver_data;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
ret = sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver);
+ if (ret != 0)
+ return ret;
- if ((!ret) && !(cpufreq_driver->flags & CPUFREQ_STICKY)) {
- int i;
- ret = -ENODEV;
-
- /* check for at least one working CPU */
- for (i=0; i<NR_CPUS; i++)
- if (cpufreq_cpu_data[i])
- ret = 0;
-
- /* if all ->init() calls failed, unregister */
- if (ret) {
- dprintk("no CPU initialized for driver %s\n", driver_data->name);
- sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
-
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
- cpufreq_driver = NULL;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- }
- }
-
- if (!ret) {
- register_hotcpu_notifier(&cpufreq_cpu_notifier);
- dprintk("driver %s up and running\n", driver_data->name);
- cpufreq_debug_enable_ratelimit();
- }
+ powerop_register_notifier(&cpufreq_powerop_notifier);
+ register_hotcpu_notifier(&cpufreq_cpu_notifier);
+ dprintk("driver %s up and running\n", driver_data->name);
+ cpufreq_debug_enable_ratelimit();
return (ret);
}
-EXPORT_SYMBOL_GPL(cpufreq_register_driver);
-
-/**
- * cpufreq_unregister_driver - unregister the current CPUFreq driver
- *
- * Unregister the current CPUFreq driver. Only call this if you have
- * the right to do so, i.e. if you have succeeded in initialising before!
- * Returns zero if successful, and -EINVAL if the cpufreq_driver is
- * currently not initialised.
- */
-int cpufreq_unregister_driver(struct cpufreq_driver *driver)
+void
+cpufreq_core_exit(void)
{
- unsigned long flags;
-
cpufreq_debug_disable_ratelimit();
-
- if (!cpufreq_driver || (driver != cpufreq_driver)) {
- cpufreq_debug_enable_ratelimit();
- return -EINVAL;
- }
-
dprintk("unregistering driver %s\n", driver->name);
+ powerop_unregister_notifier(&cpufreq_powerop_notifier);
sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
+}
+module_init(cpufreq_core_init);
+module_exit(cpufreq_core_exit);
+
+module_param(smart_cpu, uint, 0644);
+MODULE_PARM_DESC(smart_cpu, "Define if cpu handles frequency intervals insted oftarget frequencies");
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
- cpufreq_driver = NULL;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- return 0;
-}
-EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
diff --git a/drivers/cpufreq/freq_helpers.c b/drivers/cpufreq/freq_helpers.c
new file mode 100644
index 0000000..3e631f3
--- /dev/null
+++ b/drivers/cpufreq/freq_helpers.c
@@ -0,0 +1,317 @@
+/*
+ * linux/drivers/cpufreq/freq_heplers.c
+ * CPUFreq Core helpers
+ *
+ * Modified for PowerOP by Eugeny S. Mints <eugeny@nomadgs.com>
+ *
+ * Copyright (C) 2006 Nomad Global Solutions, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Based on code by
+ * Copyright (C) 2002 - 2003 Dominik Brodowski
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/powerop.h>
+#include "freq_helpers.h"
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg)
+
+/*********************************************************************
+ * CPUFREQ HELPERS *
+ *********************************************************************/
+
+int cpufreq_cpuinfo(struct cpufreq_policy *policy)
+{
+ int rc = 0;
+ unsigned int min_freq = ~0;
+ unsigned int max_freq = 0;
+ unsigned int i;
+ unsigned int freq;
+ char freq_n[CPUFREQ_FREQ_STR_SIZE];
+ char **opt_names_list = NULL;
+ int opt_names_list_size = 0;
+
+ /*
+ * generate parameter name we are looking for. For CPU N name is
+ * "freqN"
+ */
+ CPUFREQ_CPU_N_FREQ(freq_n, policy->cpu);
+
+ rc = powerop_get_registered_opt_names(opt_names_list,
+ &opt_names_list_size);
+ if (rc != 0)
+ return rc;
+
+ for (i = 0; i < opt_names_list_size; i++) {
+ rc = powerop_get_point(opt_names_list[i], freq_n, &freq);
+ if (rc != 0) {
+ powerop_put_registered_opt_names(opt_names_list);
+ return rc;
+ }
+
+ if (freq == CPUFREQ_ENTRY_INVALID) {
+ dprintk("table entry %u is invalid, skipping\n", i);
+ continue;
+ }
+
+ dprintk("point %s: %u kHz\n", opt_names_list[i], freq);
+ if (freq < min_freq)
+ min_freq = freq;
+ if (freq > max_freq)
+ max_freq = freq;
+ }
+ powerop_put_registered_opt_names(opt_names_list);
+
+ policy->min = policy->cpuinfo.min_freq = min_freq;
+ policy->max = policy->cpuinfo.max_freq = max_freq;
+
+ if (policy->min == ~0)
+ return -EINVAL;
+ else
+ return 0;
+}
+
+
+int cpufreq_verify(struct cpufreq_policy *policy)
+{
+ int rc = -EINVAL;
+ unsigned int next_larger = ~0;
+ unsigned int i;
+ unsigned int count = 0;
+ unsigned int freq;
+ char freq_n[CPUFREQ_FREQ_STR_SIZE];
+ char **opt_names_list = NULL;
+ int opt_names_list_size = 0;
+
+
+ CPUFREQ_CPU_N_FREQ(freq_n, policy->cpu);
+
+ dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu);
+
+ if (!cpu_online(policy->cpu))
+ return rc;
+
+ cpufreq_verify_within_limits(policy,
+ policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
+
+ rc = powerop_get_registered_opt_names(opt_names_list,
+ &opt_names_list_size);
+ if (rc != 0)
+ return rc;
+
+ for (i = 0; i < opt_names_list_size; i++) {
+ rc = powerop_get_point(opt_names_list[i], freq_n, &freq);
+ if (rc != 0) {
+ powerop_put_registered_opt_names(opt_names_list);
+ return rc;
+ }
+
+ if (freq == CPUFREQ_ENTRY_INVALID)
+ continue;
+ if ((freq >= policy->min) && (freq <= policy->max))
+ count++;
+ else if ((next_larger > freq) && (freq > policy->max))
+ next_larger = freq;
+ }
+
+ powerop_put_registered_opt_names(opt_names_list);
+
+ if (!count)
+ policy->max = next_larger;
+
+ cpufreq_verify_within_limits(policy,
+ policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
+
+ dprintk("verification lead to (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu);
+
+ return 0;
+}
+
+
+int
+cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ /* FIXME: hide 3 fields in a structure */
+ int rc = -EINVAL;
+ unsigned int optimal = 0;
+ unsigned int optimal_found = 0;
+ char *optimal_name = NULL;
+ unsigned int suboptimal = 0;
+ unsigned int suboptimal_found = 0;
+ char *suboptimal_name = NULL;
+ unsigned int i, j;
+ char **opt_names_list = NULL;
+ unsigned int opt_names_list_size = 0;
+ char *target_opt_name;
+ char freq_n[CPUFREQ_FREQ_STR_SIZE];
+ struct cpufreq_freqs freqs;
+ cpumask_t online_policy_cpus;
+
+ dprintk("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu);
+
+ CPUFREQ_CPU_N_FREQ(freq_n, policy->cpu);
+
+ switch (relation) {
+ case CPUFREQ_RELATION_H:
+ suboptimal = ~0;
+ break;
+ case CPUFREQ_RELATION_L:
+ optimal = ~0;
+ break;
+ }
+
+ if (!cpu_online(policy->cpu))
+ return rc;
+
+ if (powerop_get_registered_opt_names(opt_names_list,
+ &opt_names_list_size))
+ return rc;
+
+ for (i = 0; i < opt_names_list_size; i++) {
+ unsigned int freq;
+
+ rc = powerop_get_point(opt_names_list[i], freq_n, &freq);
+ if (rc != 0) {
+ powerop_put_registered_opt_names(opt_names_list);
+ return rc;
+ }
+
+ if (freq == CPUFREQ_ENTRY_INVALID)
+ continue;
+ if ((freq < policy->min) || (freq > policy->max))
+ continue;
+ switch(relation) {
+ case CPUFREQ_RELATION_H:
+ if (freq <= target_freq) {
+ if (freq >= optimal) {
+ optimal = freq;
+ optimal_found = 1;
+ optimal_name = opt_names_list[i];
+ }
+ } else {
+ if (freq <= suboptimal) {
+ suboptimal = freq;
+ suboptimal_found = 1;
+ suboptimal_name = opt_names_list[i];
+ }
+ }
+ break;
+ case CPUFREQ_RELATION_L:
+ if (freq >= target_freq) {
+ if (freq <= optimal) {
+ optimal = freq;
+ optimal_found = 1;
+ optimal_name = opt_names_list[i];
+ }
+ } else {
+ if (freq >= suboptimal) {
+ suboptimal = freq;
+ suboptimal_found = 1;
+ suboptimal_name = opt_names_list[i];
+ }
+ }
+ break;
+ }
+ }
+ powerop_put_registered_opt_names(opt_names_list);
+
+ if (!optimal_found) {
+ if (!suboptimal_found)
+ return -EINVAL;
+ target_opt_name = suboptimal_name;
+ } else
+ target_opt_name = optimal_name;
+
+ rc = powerop_get_point(NULL, freq_n, &freqs.old);
+ if (rc != 0)
+ return rc;
+
+ rc = powerop_get_point(target_opt_name, freq_n, &freqs.new);
+ if (rc != 0)
+ return rc;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ /* cpufreq holds the hotplug lock, so we are safe from here on */
+ cpus_and(online_policy_cpus, cpu_online_map, policy->cpus);
+#else
+ online_policy_cpus = policy->cpus;
+#endif
+
+ for_each_cpu_mask(j, online_policy_cpus) {
+ freqs.cpu = j;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ }
+
+ rc = powerop_set_point(target_opt_name);
+ if (rc != 0) {
+ int tmp;
+ tmp = freqs.new;
+ freqs.new = freqs.old;
+ freqs.old = tmp;
+ for_each_cpu_mask(j, online_policy_cpus) {
+ freqs.cpu = j;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+ } else {
+ for_each_cpu_mask(j, online_policy_cpus) {
+ freqs.cpu = j;
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+ }
+
+ return rc;
+}
+
+int
+cpufreq_setpolicy(struct cpufreq_policy *policy)
+{
+ char lfreq_hfreq[20];
+ int cpu = policy->cpu;
+ int i, rc;
+ char **opt_names_list = NULL;
+ int opt_names_list_size = 0;
+
+ /*
+ * FIXME: just reference code
+ * if you specify smart_cpu cpufreq expects your PM Core
+ * support the following power parameter names:
+ * "lfreqN", "hfreqN"
+ */
+ powerop_get_registered_opt_names(opt_names_list,
+ &opt_names_list_size);
+ sprintf(lfreq_hfreq, "lfreq%d hfreq%d ", cpu, cpu);
+ for (i = 0; i < opt_names_list_size; i++) {
+ unsigned int lfreq, hfreq;
+
+ rc = powerop_get_point(opt_names_list[i], lfreq_hfreq, &lfreq,
+ &hfreq);
+ if (rc != 0) {
+ powerop_put_registered_opt_names(opt_names_list);
+ return rc;
+ }
+
+ if ((lfreq == CPUFREQ_ENTRY_INVALID) ||
+ (hfreq == CPUFREQ_ENTRY_INVALID))
+ continue;
+ if ((lfreq > policy->min) && (hfreq < policy->max)) {
+ /* point fits */
+ powerop_set_point(opt_names_list[i]);
+ break;
+ }
+ }
+ return 0;
+}
+
+MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION ("CPUfreq core helpers");
+MODULE_LICENSE ("GPL");
+
diff --git a/drivers/cpufreq/freq_helpers.h b/drivers/cpufreq/freq_helpers.h
new file mode 100644
index 0000000..78780ef
--- /dev/null
+++ b/drivers/cpufreq/freq_helpers.h
@@ -0,0 +1,22 @@
+/*
+ * cpufreq core helpers
+ *
+ * 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.
+ */
+#ifndef __LINUX_CPUFREQ_HELPERS_H__
+#define __LINUX_CPUFREQ_HELPERS_H__
+
+#include <linux/cpufreq.h>
+
+#define CPUFREQ_ENTRY_INVALID ~0
+
+int cpufreq_cpuinfo(struct cpufreq_policy *policy);
+int cpufreq_verify(struct cpufreq_policy *policy);
+int cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq,
+ unsigned int relation);
+int cpufreq_setpolicy(struct cpufreq_policy *policy);
+
+#endif /* __LINUX_CPUFREQ_POWEROP_H__ */
+
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
deleted file mode 100644
index 551f4cc..0000000
--- a/drivers/cpufreq/freq_table.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * linux/drivers/cpufreq/freq_table.c
- *
- * Copyright (C) 2002 - 2003 Dominik Brodowski
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg)
-
-/*********************************************************************
- * FREQUENCY TABLE HELPERS *
- *********************************************************************/
-
-int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
- struct cpufreq_frequency_table *table)
-{
- unsigned int min_freq = ~0;
- unsigned int max_freq = 0;
- unsigned int i;
-
- for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
- unsigned int freq = table[i].frequency;
- if (freq == CPUFREQ_ENTRY_INVALID) {
- dprintk("table entry %u is invalid, skipping\n", i);
-
- continue;
- }
- dprintk("table entry %u: %u kHz, %u index\n", i, freq, table[i].index);
- if (freq < min_freq)
- min_freq = freq;
- if (freq > max_freq)
- max_freq = freq;
- }
-
- policy->min = policy->cpuinfo.min_freq = min_freq;
- policy->max = policy->cpuinfo.max_freq = max_freq;
-
- if (policy->min == ~0)
- return -EINVAL;
- else
- return 0;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
-
-
-int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
- struct cpufreq_frequency_table *table)
-{
- unsigned int next_larger = ~0;
- unsigned int i;
- unsigned int count = 0;
-
- dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu);
-
- if (!cpu_online(policy->cpu))
- return -EINVAL;
-
- cpufreq_verify_within_limits(policy,
- policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
-
- for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
- unsigned int freq = table[i].frequency;
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
- if ((freq >= policy->min) && (freq <= policy->max))
- count++;
- else if ((next_larger > freq) && (freq > policy->max))
- next_larger = freq;
- }
-
- if (!count)
- policy->max = next_larger;
-
- cpufreq_verify_within_limits(policy,
- policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
-
- dprintk("verification lead to (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
-
-
-int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
- struct cpufreq_frequency_table *table,
- unsigned int target_freq,
- unsigned int relation,
- unsigned int *index)
-{
- struct cpufreq_frequency_table optimal = {
- .index = ~0,
- .frequency = 0,
- };
- struct cpufreq_frequency_table suboptimal = {
- .index = ~0,
- .frequency = 0,
- };
- unsigned int i;
-
- dprintk("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu);
-
- switch (relation) {
- case CPUFREQ_RELATION_H:
- suboptimal.frequency = ~0;
- break;
- case CPUFREQ_RELATION_L:
- optimal.frequency = ~0;
- break;
- }
-
- if (!cpu_online(policy->cpu))
- return -EINVAL;
-
- for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
- unsigned int freq = table[i].frequency;
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
- if ((freq < policy->min) || (freq > policy->max))
- continue;
- switch(relation) {
- case CPUFREQ_RELATION_H:
- if (freq <= target_freq) {
- if (freq >= optimal.frequency) {
- optimal.frequency = freq;
- optimal.index = i;
- }
- } else {
- if (freq <= suboptimal.frequency) {
- suboptimal.frequency = freq;
- suboptimal.index = i;
- }
- }
- break;
- case CPUFREQ_RELATION_L:
- if (freq >= target_freq) {
- if (freq <= optimal.frequency) {
- optimal.frequency = freq;
- optimal.index = i;
- }
- } else {
- if (freq >= suboptimal.frequency) {
- suboptimal.frequency = freq;
- suboptimal.index = i;
- }
- }
- break;
- }
- }
- if (optimal.index > i) {
- if (suboptimal.index > i)
- return -EINVAL;
- *index = suboptimal.index;
- } else
- *index = optimal.index;
-
- dprintk("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
- table[*index].index);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
-
-static struct cpufreq_frequency_table *show_table[NR_CPUS];
-/**
- * show_scaling_governor - show the current policy for the specified CPU
- */
-static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
-{
- unsigned int i = 0;
- unsigned int cpu = policy->cpu;
- ssize_t count = 0;
- struct cpufreq_frequency_table *table;
-
- if (!show_table[cpu])
- return -ENODEV;
-
- table = show_table[cpu];
-
- for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
- if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
- continue;
- count += sprintf(&buf[count], "%d ", table[i].frequency);
- }
- count += sprintf(&buf[count], "\n");
-
- return count;
-
-}
-
-struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
- .attr = { .name = "scaling_available_frequencies", .mode = 0444, .owner=THIS_MODULE },
- .show = show_available_freqs,
-};
-EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
-
-/*
- * if you use these, you must assure that the frequency table is valid
- * all the time between get_attr and put_attr!
- */
-void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
- unsigned int cpu)
-{
- dprintk("setting show_table for cpu %u to %p\n", cpu, table);
- show_table[cpu] = table;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
-
-void cpufreq_frequency_table_put_attr(unsigned int cpu)
-{
- dprintk("clearing show_table for cpu %u\n", cpu);
- show_table[cpu] = NULL;
-}
-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");
-MODULE_LICENSE ("GPL");
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 4ea39fe..6e85cb4 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -3,7 +3,10 @@
*
* Copyright (C) 2001 Russell King
* (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
- *
+ *
+ * Eugeny S. Mints <eugeny@nomadgs.com>
+ *
+ * Interface update (get rid of cpufreq driver, integation with PowerOP
*
* $Id: cpufreq.h,v 1.36 2003/01/20 17:31:48 db Exp $
*
@@ -27,7 +30,20 @@ #include <asm/div64.h>
#define CPUFREQ_NAME_LEN 16
-
+/*********************************************************************
+ * cpufreq PowerOP glue for multi cpu support
+ *
+ * cpufreq layer refers to frequency and voltage of cpuN by "vN", "freqN"
+ * string when calls powerop_regiter/get_point()
+ ********************************************************************/
+/* FIXME: request review */
+#define CPUFREQ_FREQ_STR_SIZE 8
+#define CPUFREQ_FREQ_OP_SIZE 20
+#define CPUFREQ_OP_NAME_SIZE 12
+#define CPUFREQ_CPU_N_FREQ(freq, n) sprintf((freq), "freq%d ", (n))
+#define CPUFREQ_CPU_N_FREQ_V(op, n) sprintf((op), "v%d freq%d ", (n), (n))
+#define CPUFREQ_CPU_N_GNRT_OP_NAME(res, cpu, idx) \
+ sprintf((res), "cpu%d_opt%d", (cpu), (idx))
/*********************************************************************
* CPUFREQ NOTIFIER INTERFACE *
*********************************************************************/
@@ -100,11 +116,6 @@ #define CPUFREQ_ADJUST (0)
#define CPUFREQ_INCOMPATIBLE (1)
#define CPUFREQ_NOTIFY (2)
-#define CPUFREQ_SHARED_TYPE_NONE (0) /* None */
-#define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */
-#define CPUFREQ_SHARED_TYPE_ALL (2) /* All dependent CPUs should set freq */
-#define CPUFREQ_SHARED_TYPE_ANY (3) /* Freq can be set from any dependent CPU*/
-
/******************** cpufreq transition notifiers *******************/
#define CPUFREQ_PRECHANGE (0)
@@ -185,31 +196,6 @@ #define CPUFREQ_RELATION_H 1 /* highest
struct freq_attr;
-struct cpufreq_driver {
- struct module *owner;
- char name[CPUFREQ_NAME_LEN];
- u8 flags;
-
- /* needed by all drivers */
- int (*init) (struct cpufreq_policy *policy);
- int (*verify) (struct cpufreq_policy *policy);
-
- /* define one out of two */
- int (*setpolicy) (struct cpufreq_policy *policy);
- int (*target) (struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation);
-
- /* should be defined, if possible */
- unsigned int (*get) (unsigned int cpu);
-
- /* optional */
- int (*exit) (struct cpufreq_policy *policy);
- int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg);
- int (*resume) (struct cpufreq_policy *policy);
- struct freq_attr **attr;
-};
-
/* flags */
#define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if
@@ -220,10 +206,6 @@ #define CPUFREQ_CONST_LOOPS 0x02 /* loo
#define CPUFREQ_PM_NO_WARN 0x04 /* don't warn on suspend/resume speed
* mismatches */
-int cpufreq_register_driver(struct cpufreq_driver *driver_data);
-int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
-
-
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
@@ -284,45 +266,9 @@ #define CPUFREQ_DEFAULT_GOVERNOR &cpufre
#endif
-/*********************************************************************
- * FREQUENCY TABLE HELPERS *
- *********************************************************************/
-
-#define CPUFREQ_ENTRY_INVALID ~0
-#define CPUFREQ_TABLE_END ~1
-
-struct cpufreq_frequency_table {
- unsigned int index; /* any */
- unsigned int frequency; /* kHz - doesn't need to be in ascending
- * order */
-};
-
-int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
- struct cpufreq_frequency_table *table);
-
-int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
- struct cpufreq_frequency_table *table);
-
-int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
- struct cpufreq_frequency_table *table,
- unsigned int target_freq,
- 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;
-
-void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
- unsigned int cpu);
-
-void cpufreq_frequency_table_put_attr(unsigned int cpu);
-
-
/*********************************************************************
* UNIFIED DEBUG HELPERS *
*********************************************************************/
next reply other threads:[~2006-09-14 14:43 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-09-14 14:43 Eugeny S. Mints [this message]
2006-10-07 3:19 ` [RFC] CPUFreq PowerOP integratoin, CPUFreq core 1/3 Dominik Brodowski
-- strict thread matches above, loose matches on Subject: below --
2006-08-24 1:26 Eugeny S. Mints
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=45096A7B.2070007@gmail.com \
--to=eugeny.mints@gmail.com \
--cc=amit.kucheria@nokia.com \
--cc=igor.stoppa@nokia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@lists.osdl.org \
--cc=matt@nomadgs.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.