Add cpufreq governors: performance, powersave, userspace
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 10 Dec 2008 13:27:14 +0000 (13:27 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 10 Dec 2008 13:27:14 +0000 (13:27 +0000)
This patch add 3 more governors beside original running ondemand
cpufreq governor.
performance governor is with best performance, keeping cpu always
running at highest freq;
powersave governor is with best power save effect, keeping cpu always
running at lowest freq;
userspace governor provide user setting freq ability;

Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com>
xen/drivers/cpufreq/Makefile
xen/drivers/cpufreq/cpufreq.c
xen/drivers/cpufreq/cpufreq_misc_governors.c [new file with mode: 0644]
xen/drivers/cpufreq/cpufreq_ondemand.c
xen/include/acpi/cpufreq/cpufreq.h

index c91c25b715c2abf616c2f566567920887539104e..b87d12777fa8a93fe616d37a5edb86aa793b8bb8 100644 (file)
@@ -1,3 +1,4 @@
 obj-y += cpufreq.o
 obj-y += cpufreq_ondemand.o
+obj-y += cpufreq_misc_governors.o
 obj-y += utility.o
index 8777a8a822e9c4893ecae4e90f6b7dc43125c8d3..185b0343d75288aef050f106c3a09e9dc2648f0e 100644 (file)
@@ -33,6 +33,7 @@
 #include <xen/cpumask.h>
 #include <xen/list.h>
 #include <xen/sched.h>
+#include <xen/string.h>
 #include <xen/timer.h>
 #include <xen/xmalloc.h>
 #include <xen/guest_access.h>
@@ -52,6 +53,53 @@ struct cpufreq_dom {
 };
 static LIST_HEAD(cpufreq_dom_list_head);
 
+static LIST_HEAD(cpufreq_governor_list);
+
+static struct cpufreq_governor *__find_governor(const char *governor)
+{
+    struct cpufreq_governor *t;
+
+    if (!governor)
+        return NULL;
+
+    list_for_each_entry(t, &cpufreq_governor_list, governor_list)
+        if (!strnicmp(governor, t->name, CPUFREQ_NAME_LEN))
+            return t;
+
+    return NULL;
+}
+
+int cpufreq_register_governor(struct cpufreq_governor *governor)
+{
+    if (!governor)
+        return -EINVAL;
+
+    if (__find_governor(governor->name) != NULL)
+        return -EEXIST;
+
+    list_add(&governor->governor_list, &cpufreq_governor_list);
+    return 0;
+}
+
+int cpufreq_unregister_governor(struct cpufreq_governor *governor)
+{
+    int cpu = smp_processor_id();
+    struct cpufreq_policy *policy = cpufreq_cpu_policy[cpu];
+
+    if (!governor || !policy)
+        return -EINVAL;
+
+    /* error if unregister current cpufreq governor */
+    if (governor == policy->governor)
+        return -EBUSY;
+
+    if (__find_governor(governor->name) == NULL)
+        return -ENOENT;
+
+    list_del(&governor->governor_list);
+    return 0;
+}
+
 int cpufreq_limit_change(unsigned int cpu)
 {
     struct processor_performance *perf = &processor_pminfo[cpu]->perf;
diff --git a/xen/drivers/cpufreq/cpufreq_misc_governors.c b/xen/drivers/cpufreq/cpufreq_misc_governors.c
new file mode 100644 (file)
index 0000000..8b391d3
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ *  xen/drivers/cpufreq/cpufreq_misc_gov.c
+ *
+ *  Copyright (C)  2001 Russell King
+ *            (C)  2002 - 2004 Dominik Brodowski <linux@brodo.de>
+ *
+ *     Nov 2008 Liu Jinsong <jinsong.liu@intel.com>
+ *     Porting cpufreq_userspace.c, cpufreq_performance.c, and 
+ *     cpufreq_powersave.c from Liunx 2.6.23 to Xen hypervisor
+ *
+ * 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 <xen/init.h>
+#include <xen/sched.h>
+#include <acpi/cpufreq/cpufreq.h>
+
+
+/*
+ * cpufreq userspace governor
+ */
+static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
+                                      unsigned int event)
+{
+    int ret = 0;
+
+    if (!policy)
+        return -EINVAL;
+
+    switch (event) {
+    case CPUFREQ_GOV_START:
+    case CPUFREQ_GOV_STOP:
+        break;
+    case CPUFREQ_GOV_LIMITS:
+        if (policy->max < policy->cur)
+            ret = __cpufreq_driver_target(policy, policy->max,
+                        CPUFREQ_RELATION_H);
+        else if (policy->min > policy->cur)
+            ret = __cpufreq_driver_target(policy, policy->min,
+                        CPUFREQ_RELATION_L);
+        break;
+    default:
+        ret = -EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+struct cpufreq_governor cpufreq_gov_userspace = {
+    .name = "userspace",
+    .governor = cpufreq_governor_userspace,
+};
+
+static int __init cpufreq_gov_userspace_init(void)
+{
+    return cpufreq_register_governor(&cpufreq_gov_userspace);
+}
+__initcall(cpufreq_gov_userspace_init);
+
+static void cpufreq_gov_userspace_exit(void)
+{
+    cpufreq_unregister_governor(&cpufreq_gov_userspace);
+}
+__exitcall(cpufreq_gov_userspace_exit);
+
+
+/*
+ * cpufreq performance governor
+ */
+static int cpufreq_governor_performance(struct cpufreq_policy *policy,
+                                      unsigned int event)
+{
+    int ret = 0;
+
+    if (!policy)
+        return -EINVAL;
+
+    switch (event) {
+    case CPUFREQ_GOV_START:
+    case CPUFREQ_GOV_STOP:
+        break;
+    case CPUFREQ_GOV_LIMITS:
+        ret = __cpufreq_driver_target(policy, policy->max,
+                        CPUFREQ_RELATION_H);
+        break;
+    default:
+        ret = -EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+struct cpufreq_governor cpufreq_gov_performance = {
+    .name = "performance",
+    .governor = cpufreq_governor_performance,
+};
+
+static int __init cpufreq_gov_performance_init(void)
+{
+    return cpufreq_register_governor(&cpufreq_gov_performance);
+}
+__initcall(cpufreq_gov_performance_init);
+
+static void cpufreq_gov_performance_exit(void)
+{
+    cpufreq_unregister_governor(&cpufreq_gov_performance);
+}
+__exitcall(cpufreq_gov_performance_exit);
+
+
+/*
+ * cpufreq powersave governor
+ */
+static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
+                                      unsigned int event)
+{
+    int ret = 0;
+
+    if (!policy)
+        return -EINVAL;
+
+    switch (event) {
+    case CPUFREQ_GOV_START:
+    case CPUFREQ_GOV_STOP:
+        break;
+    case CPUFREQ_GOV_LIMITS:
+        ret = __cpufreq_driver_target(policy, policy->min,
+                        CPUFREQ_RELATION_L);
+        break;
+    default:
+        ret = -EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+struct cpufreq_governor cpufreq_gov_powersave = {
+    .name = "powersave",
+    .governor = cpufreq_governor_powersave,
+};
+
+static int __init cpufreq_gov_powersave_init(void)
+{
+    return cpufreq_register_governor(&cpufreq_gov_powersave);
+}
+__initcall(cpufreq_gov_powersave_init);
+
+static void cpufreq_gov_powersave_exit(void)
+{
+    cpufreq_unregister_governor(&cpufreq_gov_powersave);
+}
+__exitcall(cpufreq_gov_powersave_exit);
index d860407fca8c5bcf381b709b91b78b6d31317200..655edc79e9488e08308b61b6d70d05133c4aedf7 100644 (file)
@@ -263,6 +263,18 @@ struct cpufreq_governor cpufreq_gov_dbs = {
     .governor = cpufreq_governor_dbs,
 };
 
+static int __init cpufreq_gov_dbs_init(void)
+{
+    return cpufreq_register_governor(&cpufreq_gov_dbs);
+}
+__initcall(cpufreq_gov_dbs_init);
+
+static void cpufreq_gov_dbs_exit(void)
+{
+    cpufreq_unregister_governor(&cpufreq_gov_dbs);
+}
+__exitcall(cpufreq_gov_dbs_exit);
+
 void __init cpufreq_cmdline_parse(char *str)
 {
     do {
index 25b6ce7316e7572fd2d9e1c07cd8b164c23a53e8..9e3e9477a0bbe1a5b25a08fa050f3a71d6a300eb 100644 (file)
@@ -84,9 +84,12 @@ struct cpufreq_governor {
     char    name[CPUFREQ_NAME_LEN];
     int     (*governor)(struct cpufreq_policy *policy,
                         unsigned int event);
+    struct list_head governor_list;
 };
 
 extern struct cpufreq_governor cpufreq_gov_dbs;
+extern int cpufreq_register_governor(struct cpufreq_governor *governor);
+extern int cpufreq_unregister_governor(struct cpufreq_governor *governor);
 #define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_dbs
 
 /* pass a target to the cpufreq driver */