power_hikey: Add schedtune boosting and fallback
Add logic to use the EAS schedtune interface to
do interactive boosting, as well as setting back
to non-boosted mode.
Change-Id: I47c2e43135a707a88000cb495e0330ea1e02afa4
Signed-off-by: John Stultz <john.stultz@linaro.org>
diff --git a/power/power_hikey.c b/power/power_hikey.c
index 9b28e73..2dfe76d 100644
--- a/power/power_hikey.c
+++ b/power/power_hikey.c
@@ -25,6 +25,8 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
+#include <pthread.h>
+#include <semaphore.h>
#include <cutils/properties.h>
//#define LOG_NDEBUG 0
@@ -34,6 +36,10 @@
#include <hardware/hardware.h>
#include <hardware/power.h>
+#define SCHEDTUNE_BOOST_PATH "/sys/fs/cgroup/stune/foreground/schedtune.boost"
+#define SCHEDTUNE_BOOST_NORM "10"
+#define SCHEDTUNE_BOOST_INTERACTIVE "40"
+#define SCHEDTUNE_BOOST_TIME_NS 1000000000LL
#define INTERACTIVE_BOOSTPULSE_PATH "/sys/devices/system/cpu/cpufreq/interactive/boostpulse"
#define INTERACTIVE_IO_IS_BUSY_PATH "/sys/devices/system/cpu/cpufreq/interactive/io_is_busy"
#define CPU_MAX_FREQ_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
@@ -46,8 +52,13 @@
struct hikey_power_module {
struct power_module base;
pthread_mutex_t lock;
+ /* interactive gov boost values */
int boostpulse_fd;
int boostpulse_warned;
+ /* EAS schedtune values */
+ int schedtune_boost_fd;
+ long long deboost_time;
+ sem_t signal_lock;
};
static bool low_power_mode = false;
@@ -81,6 +92,23 @@
close(fd);
}
+#define NSEC_PER_SEC 1000000000LL
+static long long gettime_ns(void)
+{
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
+}
+
+static void nanosleep_ns(long long ns)
+{
+ struct timespec ts;
+ ts.tv_sec = ns/NSEC_PER_SEC;
+ ts.tv_nsec = ns%NSEC_PER_SEC;
+ nanosleep(&ts, NULL);
+}
+
/*[interactive cpufreq gov funcs]*********************************************/
static void interactive_power_init(struct hikey_power_module __unused *hikey)
{
@@ -157,13 +185,103 @@
return 0;
}
-/*[generic functions]*********************************************************/
+/*[schedtune functions]*******************************************************/
+int schedtune_sysfs_boost(struct hikey_power_module *hikey, char* booststr)
+{
+ char buf[80];
+ int len;
+
+ if (hikey->schedtune_boost_fd < 0)
+ return hikey->schedtune_boost_fd;
+
+ len = write(hikey->schedtune_boost_fd, booststr, 2);
+ if (len < 0) {
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGE("Error writing to %s: %s\n", SCHEDTUNE_BOOST_PATH, buf);
+ }
+ return len;
+}
+
+static void* schedtune_deboost_thread(void* arg)
+{
+ struct hikey_power_module *hikey = (struct hikey_power_module *)arg;
+
+ while(1) {
+ sem_wait(&hikey->signal_lock);
+ while(1) {
+ long long now, sleeptime = 0;
+
+ pthread_mutex_lock(&hikey->lock);
+ now = gettime_ns();
+ if (hikey->deboost_time > now) {
+ sleeptime = hikey->deboost_time - now;
+ pthread_mutex_unlock(&hikey->lock);
+ nanosleep_ns(sleeptime);
+ continue;
+ }
+
+ schedtune_sysfs_boost(hikey, SCHEDTUNE_BOOST_NORM);
+ hikey->deboost_time = 0;
+ pthread_mutex_unlock(&hikey->lock);
+ break;
+ }
+ }
+ return NULL;
+}
+
+static int schedtune_boost(struct hikey_power_module *hikey)
+{
+ long long now;
+
+ if (hikey->schedtune_boost_fd < 0)
+ return hikey->schedtune_boost_fd;
+
+ now = gettime_ns();
+ if (!hikey->deboost_time) {
+ schedtune_sysfs_boost(hikey, SCHEDTUNE_BOOST_INTERACTIVE);
+ sem_post(&hikey->signal_lock);
+ }
+ hikey->deboost_time = now + SCHEDTUNE_BOOST_TIME_NS;
+
+ return 0;
+}
+
+static void schedtune_power_init(struct hikey_power_module *hikey)
+{
+ char buf[50];
+ pthread_t tid;
+
+
+ hikey->deboost_time = 0;
+ sem_init(&hikey->signal_lock, 0, 1);
+
+ hikey->schedtune_boost_fd = open(SCHEDTUNE_BOOST_PATH, O_WRONLY);
+ if (hikey->schedtune_boost_fd < 0) {
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGE("Error opening %s: %s\n", SCHEDTUNE_BOOST_PATH, buf);
+ }
+
+ pthread_create(&tid, NULL, schedtune_deboost_thread, hikey);
+}
+
+/*[generic functions]*********************************************************/
static void hikey_power_init(struct power_module __unused *module)
{
struct hikey_power_module *hikey = container_of(module,
struct hikey_power_module, base);
interactive_power_init(hikey);
+ schedtune_power_init(hikey);
+}
+
+static void hikey_hint_interaction(struct hikey_power_module *mod)
+{
+ /* Try interactive cpufreq boosting first */
+ if(!interactive_boostpulse(mod))
+ return;
+ /* Then try EAS schedtune boosting */
+ if(!schedtune_boost(mod))
+ return;
}
static void hikey_power_hint(struct power_module *module, power_hint_t hint,
@@ -175,7 +293,7 @@
pthread_mutex_lock(&hikey->lock);
switch (hint) {
case POWER_HINT_INTERACTION:
- interactive_boostpulse(hikey);
+ hikey_hint_interaction(hikey);
break;
case POWER_HINT_VSYNC: