summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@nvidia.com>2013-09-14 01:34:19 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 01:34:19 -0700
commitb805ce72d78083eb58a9aaca52ea6618ffaed789 (patch)
tree8cdb14cde5a219476706824e22393bfb836a1414 /kernel
parenta4d2ac80e12e3cbb30109417570e5c04a21fd7ac (diff)
parent5ec1068d47f8c22eacaee450424a1158dc4f440d (diff)
Merge branch 'buckets/pm_qos' into after-buckets
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/qos.c128
1 files changed, 124 insertions, 4 deletions
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 25cf89bc659e..8e662c3dc2ef 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -41,7 +41,7 @@
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/kernel.h>
-
+#include <linux/moduleparam.h>
#include <linux/uaccess.h>
#include <linux/export.h>
@@ -101,11 +101,72 @@ static struct pm_qos_object network_throughput_pm_qos = {
};
+static BLOCKING_NOTIFIER_HEAD(min_online_cpus_notifier);
+static struct pm_qos_constraints min_online_cpus_constraints = {
+ .list = PLIST_HEAD_INIT(min_online_cpus_constraints.list),
+ .target_value = PM_QOS_MIN_ONLINE_CPUS_DEFAULT_VALUE,
+ .default_value = PM_QOS_MIN_ONLINE_CPUS_DEFAULT_VALUE,
+ .type = PM_QOS_MAX,
+ .notifiers = &min_online_cpus_notifier,
+};
+static struct pm_qos_object min_online_cpus_pm_qos = {
+ .constraints = &min_online_cpus_constraints,
+ .name = "min_online_cpus",
+};
+
+
+static BLOCKING_NOTIFIER_HEAD(max_online_cpus_notifier);
+static struct pm_qos_constraints max_online_cpus_constraints = {
+ .list = PLIST_HEAD_INIT(max_online_cpus_constraints.list),
+ .target_value = PM_QOS_MAX_ONLINE_CPUS_DEFAULT_VALUE,
+ .default_value = PM_QOS_MAX_ONLINE_CPUS_DEFAULT_VALUE,
+ .type = PM_QOS_MIN,
+ .notifiers = &max_online_cpus_notifier,
+};
+static struct pm_qos_object max_online_cpus_pm_qos = {
+ .constraints = &max_online_cpus_constraints,
+ .name = "max_online_cpus",
+
+};
+
+
+static BLOCKING_NOTIFIER_HEAD(cpu_freq_min_notifier);
+static struct pm_qos_constraints cpu_freq_min_constraints = {
+ .list = PLIST_HEAD_INIT(cpu_freq_min_constraints.list),
+ .target_value = PM_QOS_CPU_FREQ_MIN_DEFAULT_VALUE,
+ .default_value = PM_QOS_CPU_FREQ_MIN_DEFAULT_VALUE,
+ .type = PM_QOS_MAX,
+ .notifiers = &cpu_freq_min_notifier,
+};
+static struct pm_qos_object cpu_freq_min_pm_qos = {
+ .constraints = &cpu_freq_min_constraints,
+ .name = "cpu_freq_min",
+};
+
+
+static BLOCKING_NOTIFIER_HEAD(cpu_freq_max_notifier);
+static struct pm_qos_constraints cpu_freq_max_constraints = {
+ .list = PLIST_HEAD_INIT(cpu_freq_max_constraints.list),
+ .target_value = PM_QOS_CPU_FREQ_MAX_DEFAULT_VALUE,
+ .default_value = PM_QOS_CPU_FREQ_MAX_DEFAULT_VALUE,
+ .type = PM_QOS_MIN,
+ .notifiers = &cpu_freq_max_notifier,
+};
+static struct pm_qos_object cpu_freq_max_pm_qos = {
+ .constraints = &cpu_freq_max_constraints,
+ .name = "cpu_freq_max",
+};
+
+
static struct pm_qos_object *pm_qos_array[] = {
&null_pm_qos,
&cpu_dma_pm_qos,
&network_lat_pm_qos,
- &network_throughput_pm_qos
+ &network_throughput_pm_qos,
+ &min_online_cpus_pm_qos,
+ &max_online_cpus_pm_qos,
+ &cpu_freq_min_pm_qos,
+ &cpu_freq_max_pm_qos
};
static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
@@ -123,6 +184,8 @@ static const struct file_operations pm_qos_power_fops = {
.llseek = noop_llseek,
};
+static bool pm_qos_enabled __read_mostly = true;
+
/* unlocked internal variant */
static inline int pm_qos_get_value(struct pm_qos_constraints *c)
{
@@ -197,8 +260,12 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
;
}
- curr_value = pm_qos_get_value(c);
- pm_qos_set_value(c, curr_value);
+ if (pm_qos_enabled) {
+ curr_value = pm_qos_get_value(c);
+ pm_qos_set_value(c, curr_value);
+ } else {
+ curr_value = c->default_value;
+ }
spin_unlock_irqrestore(&pm_qos_lock, flags);
@@ -434,6 +501,59 @@ void pm_qos_remove_request(struct pm_qos_request *req)
}
EXPORT_SYMBOL_GPL(pm_qos_remove_request);
+static int pm_qos_enabled_set(const char *arg, const struct kernel_param *kp)
+{
+ unsigned long flags;
+ bool old;
+ s32 prev[PM_QOS_NUM_CLASSES], curr[PM_QOS_NUM_CLASSES];
+ int ret, i;
+
+ old = pm_qos_enabled;
+ ret = param_set_bool(arg, kp);
+ if (ret != 0) {
+ pr_warn("%s: cannot set PM QoS enable to %s\n",
+ __FUNCTION__, arg);
+ return ret;
+ }
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ for (i = 1; i < PM_QOS_NUM_CLASSES; i++)
+ prev[i] = pm_qos_read_value(pm_qos_array[i]->constraints);
+ if (old && !pm_qos_enabled) {
+ /* got disabled */
+ for (i = 1; i < PM_QOS_NUM_CLASSES; i++) {
+ curr[i] = pm_qos_array[i]->constraints->default_value;
+ pm_qos_set_value(pm_qos_array[i]->constraints, curr[i]);
+ }
+ } else if (!old && pm_qos_enabled) {
+ /* got enabled */
+ for (i = 1; i < PM_QOS_NUM_CLASSES; i++) {
+ curr[i] = pm_qos_get_value(pm_qos_array[i]->constraints);
+ pm_qos_set_value(pm_qos_array[i]->constraints, curr[i]);
+ }
+ }
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+ for (i = 1; i < PM_QOS_NUM_CLASSES; i++)
+ if (prev[i] != curr[i])
+ blocking_notifier_call_chain(
+ pm_qos_array[i]->constraints->notifiers,
+ (unsigned long)curr[i],
+ NULL);
+
+ return ret;
+}
+
+static int pm_qos_enabled_get(char *buffer, const struct kernel_param *kp)
+{
+ return param_get_bool(buffer, kp);
+}
+
+static struct kernel_param_ops pm_qos_enabled_ops = {
+ .set = pm_qos_enabled_set,
+ .get = pm_qos_enabled_get,
+};
+
+module_param_cb(enable, &pm_qos_enabled_ops, &pm_qos_enabled, 0644);
+
/**
* pm_qos_add_notifier - sets notification entry for changes to target value
* @pm_qos_class: identifies which qos target changes should be notified.