Home | History | Annotate | Download | only in power
      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 
     32 #include <errno.h>
     33 #include <inttypes.h>
     34 #include <string.h>
     35 #include <sys/types.h>
     36 #include <sys/stat.h>
     37 #include <fcntl.h>
     38 #include <dlfcn.h>
     39 #include <stdlib.h>
     40 
     41 #define LOG_TAG "QCOM PowerHAL"
     42 #include <utils/Log.h>
     43 #include <hardware/power.h>
     44 
     45 #include "utils.h"
     46 #include "metadata-defs.h"
     47 #include "hint-data.h"
     48 #include "performance.h"
     49 #include "power-common.h"
     50 #include "power-helper.h"
     51 
     52 #ifndef RPM_SYSTEM_STAT
     53 #define RPM_SYSTEM_STAT "/d/system_stats"
     54 #endif
     55 
     56 #ifndef WLAN_POWER_STAT
     57 #define WLAN_POWER_STAT "/d/wlan0/power_stats"
     58 #endif
     59 
     60 #define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0]))
     61 #define LINE_SIZE 128
     62 
     63 const char *rpm_stat_params[MAX_RPM_PARAMS] = {
     64     "count",
     65     "actual last sleep(msec)",
     66 };
     67 
     68 const char *master_stat_params[MAX_RPM_PARAMS] = {
     69     "Accumulated XO duration",
     70     "XO Count",
     71 };
     72 
     73 struct stat_pair rpm_stat_map[] = {
     74     { RPM_MODE_XO,   "RPM Mode:vlow", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) },
     75     { RPM_MODE_VMIN, "RPM Mode:vmin", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) },
     76     { VOTER_APSS,    "APSS",    master_stat_params, ARRAY_SIZE(master_stat_params) },
     77     { VOTER_MPSS,    "MPSS",    master_stat_params, ARRAY_SIZE(master_stat_params) },
     78     { VOTER_ADSP,    "ADSP",    master_stat_params, ARRAY_SIZE(master_stat_params) },
     79     { VOTER_SLPI,    "SLPI",    master_stat_params, ARRAY_SIZE(master_stat_params) },
     80 };
     81 
     82 
     83 const char *wlan_power_stat_params[] = {
     84     "cumulative_sleep_time_ms",
     85     "cumulative_total_on_time_ms",
     86     "deep_sleep_enter_counter",
     87     "last_deep_sleep_enter_tstamp_ms"
     88 };
     89 
     90 struct stat_pair wlan_stat_map[] = {
     91     { WLAN_POWER_DEBUG_STATS, "POWER DEBUG STATS", wlan_power_stat_params, ARRAY_SIZE(wlan_power_stat_params) },
     92 };
     93 
     94 static int saved_dcvs_cpu0_slack_max = -1;
     95 static int saved_dcvs_cpu0_slack_min = -1;
     96 static int saved_mpdecision_slack_max = -1;
     97 static int saved_mpdecision_slack_min = -1;
     98 static int saved_interactive_mode = -1;
     99 static int slack_node_rw_failed = 0;
    100 static int display_hint_sent;
    101 
    102 void power_init(void)
    103 {
    104     ALOGI("QCOM power HAL initing.");
    105 }
    106 
    107 int __attribute__ ((weak)) power_hint_override(power_hint_t UNUSED(hint),
    108                                                void *UNUSED(data))
    109 {
    110     return HINT_NONE;
    111 }
    112 
    113 /* Declare function before use */
    114 void interaction(int duration, int num_args, int opt_list[]);
    115 
    116 void power_hint(power_hint_t hint, void *data)
    117 {
    118     /* Check if this hint has been overridden. */
    119     if (power_hint_override(hint, data) == HINT_HANDLED) {
    120         /* The power_hint has been handled. We can skip the rest. */
    121         return;
    122     }
    123 
    124     switch(hint) {
    125         case POWER_HINT_VSYNC:
    126         break;
    127         case POWER_HINT_SUSTAINED_PERFORMANCE:
    128             ALOGD("Sustained perf power hint not handled in power_hint_override");
    129             break;
    130         case POWER_HINT_VR_MODE:
    131             ALOGD("VR mode power hint not handled in power_hint_override");
    132             break;
    133         case POWER_HINT_INTERACTION:
    134         {
    135             int resources[] = {0x702, 0x20F, 0x30F};
    136             int duration = 3000;
    137 
    138             interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
    139         }
    140             break;
    141         default:
    142         break;
    143     }
    144 }
    145 
    146 int __attribute__ ((weak)) is_perf_hint_active(int UNUSED(hint))
    147 {
    148     return 0;
    149 }
    150 
    151 int __attribute__ ((weak)) set_interactive_override(int UNUSED(on))
    152 {
    153     return HINT_NONE;
    154 }
    155 
    156 void power_set_interactive(int on)
    157 {
    158     char governor[80];
    159     char tmp_str[NODE_MAX];
    160     struct video_encode_metadata_t video_encode_metadata;
    161     int rc = 0;
    162 
    163     if (set_interactive_override(on) == HINT_HANDLED) {
    164         return;
    165     }
    166 
    167     ALOGD("Got set_interactive hint");
    168 
    169     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    170         ALOGE("Can't obtain scaling governor.");
    171 
    172         return;
    173     }
    174 
    175     if (!on) {
    176         /* Display off. */
    177         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    178                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    179             int resource_values[] = {DISPLAY_OFF, MS_500, THREAD_MIGRATION_SYNC_OFF};
    180 
    181             if (!display_hint_sent) {
    182                 perform_hint_action(DISPLAY_STATE_HINT_ID,
    183                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    184                 display_hint_sent = 1;
    185             }
    186         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    187                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    188             int resource_values[] = {TR_MS_50, THREAD_MIGRATION_SYNC_OFF};
    189 
    190             if (!display_hint_sent) {
    191                 perform_hint_action(DISPLAY_STATE_HINT_ID,
    192                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    193                 display_hint_sent = 1;
    194             }
    195         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
    196                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
    197             if (saved_interactive_mode == 1){
    198                 /* Display turned off. */
    199                 if (sysfs_read(DCVS_CPU0_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
    200                     if (!slack_node_rw_failed) {
    201                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MAX_NODE);
    202                     }
    203 
    204                     rc = 1;
    205                 } else {
    206                     saved_dcvs_cpu0_slack_max = atoi(tmp_str);
    207                 }
    208 
    209                 if (sysfs_read(DCVS_CPU0_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
    210                     if (!slack_node_rw_failed) {
    211                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MIN_NODE);
    212                     }
    213 
    214                     rc = 1;
    215                 } else {
    216                     saved_dcvs_cpu0_slack_min = atoi(tmp_str);
    217                 }
    218 
    219                 if (sysfs_read(MPDECISION_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
    220                     if (!slack_node_rw_failed) {
    221                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MAX_NODE);
    222                     }
    223 
    224                     rc = 1;
    225                 } else {
    226                     saved_mpdecision_slack_max = atoi(tmp_str);
    227                 }
    228 
    229                 if (sysfs_read(MPDECISION_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
    230                     if(!slack_node_rw_failed) {
    231                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MIN_NODE);
    232                     }
    233 
    234                     rc = 1;
    235                 } else {
    236                     saved_mpdecision_slack_min = atoi(tmp_str);
    237                 }
    238 
    239                 /* Write new values. */
    240                 if (saved_dcvs_cpu0_slack_max != -1) {
    241                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_max);
    242 
    243                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
    244                         if (!slack_node_rw_failed) {
    245                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
    246                         }
    247 
    248                         rc = 1;
    249                     }
    250                 }
    251 
    252                 if (saved_dcvs_cpu0_slack_min != -1) {
    253                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_min);
    254 
    255                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
    256                         if(!slack_node_rw_failed) {
    257                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
    258                         }
    259 
    260                         rc = 1;
    261                     }
    262                 }
    263 
    264                 if (saved_mpdecision_slack_max != -1) {
    265                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_max);
    266 
    267                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
    268                         if(!slack_node_rw_failed) {
    269                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
    270                         }
    271 
    272                         rc = 1;
    273                     }
    274                 }
    275 
    276                 if (saved_mpdecision_slack_min != -1) {
    277                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_min);
    278 
    279                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
    280                         if(!slack_node_rw_failed) {
    281                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
    282                         }
    283 
    284                         rc = 1;
    285                     }
    286                 }
    287             }
    288 
    289             slack_node_rw_failed = rc;
    290         }
    291     } else {
    292         /* Display on. */
    293         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    294                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    295             undo_hint_action(DISPLAY_STATE_HINT_ID);
    296             display_hint_sent = 0;
    297         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    298                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    299             undo_hint_action(DISPLAY_STATE_HINT_ID);
    300             display_hint_sent = 0;
    301         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
    302                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
    303             if (saved_interactive_mode == -1 || saved_interactive_mode == 0) {
    304                 /* Display turned on. Restore if possible. */
    305                 if (saved_dcvs_cpu0_slack_max != -1) {
    306                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_max);
    307 
    308                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
    309                         if (!slack_node_rw_failed) {
    310                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
    311                         }
    312 
    313                         rc = 1;
    314                     }
    315                 }
    316 
    317                 if (saved_dcvs_cpu0_slack_min != -1) {
    318                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_min);
    319 
    320                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
    321                         if (!slack_node_rw_failed) {
    322                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
    323                         }
    324 
    325                         rc = 1;
    326                     }
    327                 }
    328 
    329                 if (saved_mpdecision_slack_max != -1) {
    330                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_max);
    331 
    332                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
    333                         if (!slack_node_rw_failed) {
    334                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
    335                         }
    336 
    337                         rc = 1;
    338                     }
    339                 }
    340 
    341                 if (saved_mpdecision_slack_min != -1) {
    342                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_min);
    343 
    344                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
    345                         if (!slack_node_rw_failed) {
    346                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
    347                         }
    348 
    349                         rc = 1;
    350                     }
    351                 }
    352             }
    353 
    354             slack_node_rw_failed = rc;
    355         }
    356     }
    357 
    358     saved_interactive_mode = !!on;
    359 }
    360 
    361 
    362 static int parse_stats(const char **params, size_t params_size,
    363                        uint64_t *list, FILE *fp) {
    364     ssize_t nread;
    365     size_t len = LINE_SIZE;
    366     char *line;
    367     size_t params_read = 0;
    368     size_t i;
    369 
    370     line = malloc(len);
    371     if (!line) {
    372         ALOGE("%s: no memory to hold line", __func__);
    373         return -ENOMEM;
    374     }
    375 
    376     while ((params_read < params_size) &&
    377         (nread = getline(&line, &len, fp) > 0)) {
    378         char *key = line + strspn(line, " \t");
    379         char *value = strchr(key, ':');
    380         if (!value || (value > (line + len)))
    381             continue;
    382         *value++ = '\0';
    383 
    384         for (i = 0; i < params_size; i++) {
    385             if (!strcmp(key, params[i])) {
    386                 list[i] = strtoull(value, NULL, 0);
    387                 params_read++;
    388                 break;
    389             }
    390         }
    391     }
    392     free(line);
    393 
    394     return 0;
    395 }
    396 
    397 
    398 static int extract_stats(uint64_t *list, char *file,
    399                          struct stat_pair *map, size_t map_size) {
    400     FILE *fp;
    401     ssize_t read;
    402     size_t len = LINE_SIZE;
    403     char *line;
    404     size_t i, stats_read = 0;
    405     int ret = 0;
    406 
    407     fp = fopen(file, "re");
    408     if (fp == NULL) {
    409         ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
    410         return -errno;
    411     }
    412 
    413     line = malloc(len);
    414     if (!line) {
    415         ALOGE("%s: no memory to hold line", __func__);
    416         fclose(fp);
    417         return -ENOMEM;
    418     }
    419 
    420     while ((stats_read < map_size) && (read = getline(&line, &len, fp) != -1)) {
    421         size_t begin = strspn(line, " \t");
    422 
    423         for (i = 0; i < map_size; i++) {
    424             if (!strncmp(line + begin, map[i].label, strlen(map[i].label))) {
    425                 stats_read++;
    426                 break;
    427             }
    428         }
    429 
    430         if (i == map_size)
    431             continue;
    432 
    433         ret = parse_stats(map[i].parameters, map[i].num_parameters,
    434                           &list[map[i].stat * MAX_RPM_PARAMS], fp);
    435         if (ret < 0)
    436             break;
    437     }
    438     free(line);
    439     fclose(fp);
    440 
    441     return ret;
    442 }
    443 
    444 int extract_platform_stats(uint64_t *list) {
    445     return extract_stats(list, RPM_SYSTEM_STAT, rpm_stat_map, ARRAY_SIZE(rpm_stat_map));
    446 }
    447 
    448 int extract_wlan_stats(uint64_t *list) {
    449     return extract_stats(list, WLAN_POWER_STAT, wlan_stat_map, ARRAY_SIZE(wlan_stat_map));
    450 }
    451