1 /* 2 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above 10 * copyright notice, this list of conditions and the following 11 * disclaimer in the documentation and/or other materials provided 12 * with the distribution. 13 * * Neither the name of The Linux Foundation nor the names of its 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #define LOG_NIDEBUG 0 31 #define LOG_TAG "android.hardware.power (at) 1.2-service.wahoo-libperfmgr" 32 33 #include <errno.h> 34 #include <inttypes.h> 35 #include <string.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <fcntl.h> 39 #include <dlfcn.h> 40 #include <stdlib.h> 41 42 #include <log/log.h> 43 44 #include "power-helper.h" 45 46 #ifndef RPM_SYSTEM_STAT 47 #define RPM_SYSTEM_STAT "/d/system_stats" 48 #endif 49 50 #ifndef WLAN_POWER_STAT 51 #define WLAN_POWER_STAT "/d/wlan0/power_stats" 52 #endif 53 54 #ifndef EASEL_STATE_FILE 55 #define EASEL_STATE_FILE "/sys/devices/virtual/misc/mnh_sm/state" 56 #endif 57 58 #define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0])) 59 #define LINE_SIZE 128 60 61 const char *rpm_stat_params[MAX_RPM_PARAMS] = { 62 "count", 63 "actual last sleep(msec)", 64 }; 65 66 const char *master_stat_params[MAX_RPM_PARAMS] = { 67 "Accumulated XO duration", 68 "XO Count", 69 }; 70 71 struct stat_pair rpm_stat_map[] = { 72 { RPM_MODE_XO, "RPM Mode:vlow", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) }, 73 { RPM_MODE_VMIN, "RPM Mode:vmin", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) }, 74 { VOTER_APSS, "APSS", master_stat_params, ARRAY_SIZE(master_stat_params) }, 75 { VOTER_MPSS, "MPSS", master_stat_params, ARRAY_SIZE(master_stat_params) }, 76 { VOTER_ADSP, "ADSP", master_stat_params, ARRAY_SIZE(master_stat_params) }, 77 { VOTER_SLPI, "SLPI", master_stat_params, ARRAY_SIZE(master_stat_params) }, 78 }; 79 80 81 const char *wlan_power_stat_params[] = { 82 "cumulative_sleep_time_ms", 83 "cumulative_total_on_time_ms", 84 "deep_sleep_enter_counter", 85 "last_deep_sleep_enter_tstamp_ms" 86 }; 87 88 struct stat_pair wlan_stat_map[] = { 89 { WLAN_POWER_DEBUG_STATS, "POWER DEBUG STATS", wlan_power_stat_params, ARRAY_SIZE(wlan_power_stat_params) }, 90 }; 91 92 static int parse_stats(const char **params, size_t params_size, 93 uint64_t *list, FILE *fp) { 94 ssize_t nread; 95 size_t len = LINE_SIZE; 96 char *line; 97 size_t params_read = 0; 98 size_t i; 99 100 line = malloc(len); 101 if (!line) { 102 ALOGE("%s: no memory to hold line", __func__); 103 return -ENOMEM; 104 } 105 106 while ((params_read < params_size) && 107 (nread = getline(&line, &len, fp) > 0)) { 108 char *key = line + strspn(line, " \t"); 109 char *value = strchr(key, ':'); 110 if (!value || (value > (line + len))) 111 continue; 112 *value++ = '\0'; 113 114 for (i = 0; i < params_size; i++) { 115 if (!strcmp(key, params[i])) { 116 list[i] = strtoull(value, NULL, 0); 117 params_read++; 118 break; 119 } 120 } 121 } 122 free(line); 123 124 return 0; 125 } 126 127 128 static int extract_stats(uint64_t *list, char *file, 129 struct stat_pair *map, size_t map_size) { 130 FILE *fp; 131 ssize_t read; 132 size_t len = LINE_SIZE; 133 char *line; 134 size_t i, stats_read = 0; 135 int ret = 0; 136 137 fp = fopen(file, "re"); 138 if (fp == NULL) { 139 ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno)); 140 return -errno; 141 } 142 143 line = malloc(len); 144 if (!line) { 145 ALOGE("%s: no memory to hold line", __func__); 146 fclose(fp); 147 return -ENOMEM; 148 } 149 150 while ((stats_read < map_size) && (read = getline(&line, &len, fp) != -1)) { 151 size_t begin = strspn(line, " \t"); 152 153 for (i = 0; i < map_size; i++) { 154 if (!strncmp(line + begin, map[i].label, strlen(map[i].label))) { 155 stats_read++; 156 break; 157 } 158 } 159 160 if (i == map_size) 161 continue; 162 163 ret = parse_stats(map[i].parameters, map[i].num_parameters, 164 &list[map[i].stat * MAX_RPM_PARAMS], fp); 165 if (ret < 0) 166 break; 167 } 168 free(line); 169 fclose(fp); 170 171 return ret; 172 } 173 174 int extract_platform_stats(uint64_t *list) { 175 return extract_stats(list, RPM_SYSTEM_STAT, rpm_stat_map, ARRAY_SIZE(rpm_stat_map)); 176 } 177 178 int extract_wlan_stats(uint64_t *list) { 179 return extract_stats(list, WLAN_POWER_STAT, wlan_stat_map, ARRAY_SIZE(wlan_stat_map)); 180 } 181 182 int get_easel_state(unsigned long *current_state) { 183 FILE *fp = NULL; 184 static const size_t EASEL_STATE_LINE_SIZE = 16; 185 char buffer[EASEL_STATE_LINE_SIZE]; 186 char *parse_end = buffer; 187 unsigned long state; 188 189 if (current_state == NULL) { 190 ALOGD("%s: null current_state pointer from caller", __func__); 191 return -1; 192 } 193 194 fp = fopen(EASEL_STATE_FILE, "re"); 195 if (fp == NULL) { 196 ALOGE("%s: failed to open: %s Error = %s", __func__, EASEL_STATE_FILE, 197 strerror(errno)); 198 return -errno; 199 } 200 201 if (fgets(buffer, EASEL_STATE_LINE_SIZE, fp) == NULL) { 202 fclose(fp); 203 ALOGE("%s: failed to read: %s", __func__, EASEL_STATE_FILE); 204 return -1; 205 } 206 207 fclose(fp); 208 209 parse_end = buffer; 210 state = strtoul(buffer, &parse_end, 10); 211 if ((parse_end == buffer) || (state > 2)) { 212 ALOGE("%s: unrecognized format: %s '%s'", __func__, EASEL_STATE_FILE, 213 buffer); 214 return -1; 215 } 216 217 *current_state = state; 218 219 return 0; 220 } 221 222