power: Add 1.0 HAL for devices that don't have WiFi stats
Some devices (cough Broadcom cough) don't have nodes that return WiFi
stats, so add a 1.0 HAL that devices can build. Also actually enable
the system power stats code and use it. Also add a legacy stats option
for devices that use an old RPM driver
Change-Id: If946b81b589ce11b0bde46437396bb4be74a731a
diff --git a/power-helper.c b/power-helper.c
index 1e19c7d..db864a9 100644
--- a/power-helper.c
+++ b/power-helper.c
@@ -1,5 +1,7 @@
/*
* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2017 The LineageOS Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -35,6 +37,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <dlfcn.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <unistd.h>
@@ -50,13 +53,79 @@
#include "power-feature.h"
#include "power-helper.h"
+#define USINSEC 1000000L
+#define NSINUS 1000L
+
+#ifndef RPM_STAT
+#define RPM_STAT "/d/rpm_stats"
+#endif
+
+#ifndef RPM_MASTER_STAT
+#define RPM_MASTER_STAT "/d/rpm_master_stats"
+#endif
+
+#ifndef RPM_SYSTEM_STAT
+#define RPM_SYSTEM_STAT "/d/system_stats"
+#endif
+
+/*
+ Set with TARGET_WLAN_POWER_STAT in BoardConfig.mk
+ Defaults to QCACLD3 path
+ Path for QCACLD3: /d/wlan0/power_stats
+ Path for QCACLD2 and Prima: /d/wlan_wcnss/power_stats
+ */
+
+#ifndef V1_0_HAL
#ifndef WLAN_POWER_STAT
#define WLAN_POWER_STAT "/d/wlan0/power_stats"
#endif
+#endif
#define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0]))
#define LINE_SIZE 128
+#ifdef LEGACY_STATS
+/* Use these stats on pre-nougat qualcomm kernels */
+static const char *rpm_param_names[] = {
+ "vlow_count",
+ "accumulated_vlow_time",
+ "vmin_count",
+ "accumulated_vmin_time"
+};
+
+static const char *rpm_master_param_names[] = {
+ "xo_accumulated_duration",
+ "xo_count",
+ "xo_accumulated_duration",
+ "xo_count",
+ "xo_accumulated_duration",
+ "xo_count",
+ "xo_accumulated_duration",
+ "xo_count"
+};
+#else
+/* Use these stats on nougat and forward */
+const char *rpm_stat_params[MAX_RPM_PARAMS] = {
+ "count",
+ "actual last sleep(msec)",
+};
+
+const char *master_stat_params[MAX_RPM_PARAMS] = {
+ "Accumulated XO duration",
+ "XO Count",
+};
+
+struct stat_pair rpm_stat_map[] = {
+ { RPM_MODE_XO, "RPM Mode:vlow", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) },
+ { RPM_MODE_VMIN, "RPM Mode:vmin", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) },
+ { VOTER_APSS, "APSS", master_stat_params, ARRAY_SIZE(master_stat_params) },
+ { VOTER_MPSS, "MPSS", master_stat_params, ARRAY_SIZE(master_stat_params) },
+ { VOTER_ADSP, "ADSP", master_stat_params, ARRAY_SIZE(master_stat_params) },
+ { VOTER_SLPI, "SLPI", master_stat_params, ARRAY_SIZE(master_stat_params) },
+};
+#endif
+
+#ifndef V1_0_HAL
const char *wlan_power_stat_params[] = {
"cumulative_sleep_time_ms",
"cumulative_total_on_time_ms",
@@ -67,6 +136,7 @@
struct stat_pair wlan_stat_map[] = {
{ WLAN_POWER_DEBUG_STATS, "POWER DEBUG STATS", wlan_power_stat_params, ARRAY_SIZE(wlan_power_stat_params) },
};
+#endif
static int saved_dcvs_cpu0_slack_max = -1;
static int saved_dcvs_cpu0_slack_min = -1;
@@ -405,7 +475,7 @@
(strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
undo_hint_action(DISPLAY_STATE_HINT_ID);
display_hint_sent = 0;
- } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
+ } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
(strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
if (saved_interactive_mode == -1 || saved_interactive_mode == 0) {
/* Display turned on. Restore if possible. */
@@ -514,6 +584,84 @@
return 0;
}
+#ifdef LEGACY_STATS
+static int extract_stats(uint64_t *list, char *file, const char**param_names,
+ unsigned int num_parameters, int isHex) {
+ FILE *fp;
+ ssize_t read;
+ size_t len;
+ size_t index = 0;
+ char *line;
+ int ret;
+
+ fp = fopen(file, "r");
+ if (fp == NULL) {
+ ret = -errno;
+ ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
+ return ret;
+ }
+
+ for (line = NULL, len = 0;
+ ((read = getline(&line, &len, fp) != -1) && (index < num_parameters));
+ free(line), line = NULL, len = 0) {
+ uint64_t value;
+ char* offset;
+
+ size_t begin = strspn(line, " \t");
+ if (strncmp(line + begin, param_names[index], strlen(param_names[index]))) {
+ continue;
+ }
+
+ offset = memchr(line, ':', len);
+ if (!offset) {
+ continue;
+ }
+
+ if (isHex) {
+ sscanf(offset, ":%" SCNx64, &value);
+ } else {
+ sscanf(offset, ":%" SCNu64, &value);
+ }
+ list[index] = value;
+ index++;
+ }
+
+ free(line);
+ fclose(fp);
+
+ return 0;
+}
+
+int extract_platform_stats(uint64_t *list) {
+ int ret;
+ //Data is located in two files
+ ret = extract_stats(list, RPM_STAT, rpm_param_names, RPM_PARAM_COUNT, false);
+ if (ret) {
+ for (size_t i=0; i < RPM_PARAM_COUNT; i++)
+ list[i] = 0;
+ }
+ ret = extract_stats(list + RPM_PARAM_COUNT, RPM_MASTER_STAT,
+ rpm_master_param_names, PLATFORM_PARAM_COUNT - RPM_PARAM_COUNT, true);
+ if (ret) {
+ for (size_t i=RPM_PARAM_COUNT; i < PLATFORM_PARAM_COUNT; i++)
+ list[i] = 0;
+ }
+ return 0;
+}
+
+#ifndef V1_0_HAL
+int extract_wlan_stats(uint64_t *list) {
+ int ret;
+ ret = extract_stats(list, WLAN_POWER_STAT, wlan_param_names, WLAN_PARAM_COUNT, false);
+ if (ret) {
+ for (size_t i=0; i < WLAN_PARAM_COUNT; i++)
+ list[i] = 0;
+ }
+ return 0;
+}
+#endif
+#else
+
static int extract_stats(uint64_t *list, char *file,
struct stat_pair *map, size_t map_size) {
FILE *fp;
@@ -522,27 +670,33 @@
char *line;
size_t i, stats_read = 0;
int ret = 0;
+
fp = fopen(file, "re");
if (fp == NULL) {
ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
return -errno;
}
+
line = malloc(len);
if (!line) {
ALOGE("%s: no memory to hold line", __func__);
fclose(fp);
return -ENOMEM;
}
+
while ((stats_read < map_size) && (read = getline(&line, &len, fp) != -1)) {
size_t begin = strspn(line, " \t");
+
for (i = 0; i < map_size; i++) {
if (!strncmp(line + begin, map[i].label, strlen(map[i].label))) {
stats_read++;
break;
}
}
+
if (i == map_size)
continue;
+
ret = parse_stats(map[i].parameters, map[i].num_parameters,
&list[map[i].stat * MAX_RPM_PARAMS], fp);
if (ret < 0)
@@ -550,9 +704,17 @@
}
free(line);
fclose(fp);
+
return ret;
}
+int extract_platform_stats(uint64_t *list) {
+ return extract_stats(list, RPM_SYSTEM_STAT, rpm_stat_map, ARRAY_SIZE(rpm_stat_map));
+}
+
+#ifndef V1_0_HAL
int extract_wlan_stats(uint64_t *list) {
return extract_stats(list, WLAN_POWER_STAT, wlan_stat_map, ARRAY_SIZE(wlan_stat_map));
}
+#endif
+#endif