diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 8045a55..f8507bf 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -44,6 +44,20 @@ enum sched_tunable_scaling {
 };
 extern enum sched_tunable_scaling sysctl_sched_tunable_scaling;
 
+#ifdef CONFIG_SMP
+enum sched_balance_option {
+	SCHED_BALANCE_OPTION_PERFORMANCE,
+	SCHED_BALANCE_OPTION_POWER,
+	SCHED_BALANCE_OPTION_AUTO,
+	SCHED_BALANCE_OPTION_END,
+};
+extern enum sched_balance_option sysctl_sched_balance_option;
+
+int sched_proc_balance_option_handler(struct ctl_table *table, int write,
+		void __user *buffer, size_t *length,
+		loff_t *ppos);
+#endif
+
 extern unsigned int sysctl_numa_balancing_scan_delay;
 extern unsigned int sysctl_numa_balancing_scan_period_min;
 extern unsigned int sysctl_numa_balancing_scan_period_max;
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 7570dd9..7b8e93d 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -29,7 +29,7 @@
 #include <linux/mempolicy.h>
 #include <linux/migrate.h>
 #include <linux/task_work.h>
-
+#include <linux/power_supply.h>
 #include <trace/events/sched.h>
 
 #include "sched.h"
@@ -61,6 +61,24 @@ unsigned int normalized_sysctl_sched_latency = 6000000ULL;
 enum sched_tunable_scaling sysctl_sched_tunable_scaling
 	= SCHED_TUNABLESCALING_LOG;
 
+#ifdef CONFIG_SMP
+/*
+ * Scheduler balancing policy:
+ *
+ * Options are:
+ * SCHED_BALANCE_OPTION_PERFORMANCE - full performance
+ * SCHED_BALANCE_OPTION_POWER - power saving aggressive
+ * SCHED_BALANCE_OPTION_AUTO - switches to 'performance' when plugged
+ *                             on or 'power' on battery
+ */
+enum sched_balance_option sysctl_sched_balance_option
+	= SCHED_BALANCE_OPTION_AUTO;
+
+static int sched_current_balance_option
+	= SCHED_BALANCE_OPTION_PERFORMANCE;
+
+#endif
+
 /*
  * Minimal preemption granularity for CPU-bound tasks:
  * (default: 0.75 msec * (1 + ilog(ncpus)), units: nanoseconds)
@@ -555,6 +573,76 @@ static struct sched_entity *__pick_next_entity(struct sched_entity *se)
 	return rb_entry(next, struct sched_entity, run_node);
 }
 
+#ifdef CONFIG_SMP
+static int sched_balance_option_update(void)
+{
+	int ret;
+
+	/*
+	 * Copy the current balance option
+	 */
+	if (sysctl_sched_balance_option != SCHED_BALANCE_OPTION_AUTO) {
+		sched_current_balance_option = sysctl_sched_balance_option;
+		return 0;
+	}
+
+	/*
+	 * This call may fail if the kernel is not compiled with
+	 * the POWER_SUPPLY option.
+	 */
+	ret = power_supply_is_system_supplied();
+	if (ret < 0) {
+		sysctl_sched_balance_option = sched_current_balance_option;
+		return ret;
+	}
+
+	/*
+	 * When in 'auto' mode, switch to 'performance if the system
+	 * is plugged on the wall, to 'power' if we are on battery
+	 */
+	sched_current_balance_option = ret ?
+		SCHED_BALANCE_OPTION_PERFORMANCE :
+		SCHED_BALANCE_OPTION_POWER;
+
+	return 0;
+}
+
+int sched_proc_balance_option_handler(struct ctl_table *table, int write,
+		void __user *buffer, size_t *length,
+		loff_t *ppos)
+{
+	int ret;
+
+	ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+	if (ret)
+		return ret;
+
+	return sched_balance_option_update();
+}
+
+static int sched_power_supply_notifier(struct notifier_block *b,
+				       unsigned long l, void *v)
+{
+	sched_balance_option_update();
+	return NOTIFY_OK;
+}
+
+static struct notifier_block power_supply_notifier_nb = {
+	.notifier_call = sched_power_supply_notifier,
+};
+
+static int sched_balance_option_init(void)
+{
+	int ret;
+
+	ret = sched_balance_option_update();
+	if (ret)
+		return ret;
+
+	return power_supply_reg_notifier(&power_supply_notifier_nb);
+}
+#endif
+
 #ifdef CONFIG_SCHED_DEBUG
 struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
 {
@@ -7695,7 +7783,7 @@ __init void init_sched_fair_class(void)
 {
 #ifdef CONFIG_SMP
 	open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);
-
+	sched_balance_option_init();
 #ifdef CONFIG_NO_HZ_COMMON
 	nohz.next_balance = jiffies;
 	zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 74f5b58..e4ecc7d 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -282,6 +282,17 @@ static struct ctl_table kern_table[] = {
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
+#ifdef CONFIG_SMP
+	{
+		.procname	= "sched_balance_option",
+		.data		= &sysctl_sched_balance_option,
+		.maxlen		= sizeof(enum sched_balance_option),
+		.mode		= 0644,
+		.proc_handler	= sched_proc_balance_option_handler,
+		.extra1		= &zero, /* SCHED_BALANCE_OPTION_AUTO */
+		.extra2		= &two,  /* SCHED_BALANCE_OPTION_POWER */
+	},
+#endif
 #ifdef CONFIG_SCHED_DEBUG
 	{
 		.procname	= "sched_min_granularity_ns",
