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_NDEBUG 1
     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 #include <cutils/properties.h>
     45 
     46 #include "utils.h"
     47 #include "metadata-defs.h"
     48 #include "hint-data.h"
     49 #include "performance.h"
     50 #include "power-common.h"
     51 #include "power-helper.h"
     52 
     53 #define USINSEC 1000000L
     54 #define NSINUS 1000L
     55 
     56 #ifndef RPM_STAT
     57 #define RPM_STAT "/d/rpm_stats"
     58 #endif
     59 
     60 #ifndef RPM_MASTER_STAT
     61 #define RPM_MASTER_STAT "/d/rpm_master_stats"
     62 #endif
     63 
     64 #ifndef WLAN_POWER_STAT
     65 #define WLAN_POWER_STAT "/d/wlan_wcnss/power_stats"
     66 #endif
     67 
     68 static const char *rpm_param_names[] = {
     69     "vlow_count",
     70     "accumulated_vlow_time",
     71     "vmin_count",
     72     "accumulated_vmin_time"
     73 };
     74 
     75 static const char *rpm_master_param_names[] = {
     76     "xo_accumulated_duration",
     77     "xo_count",
     78     "xo_accumulated_duration",
     79     "xo_count",
     80     "xo_accumulated_duration",
     81     "xo_count",
     82     "xo_accumulated_duration",
     83     "xo_count"
     84 };
     85 
     86 static const char *wlan_param_names[] = {
     87     "cumulative_sleep_time_ms",
     88     "cumulative_total_on_time_ms",
     89     "deep_sleep_enter_counter",
     90     "last_deep_sleep_enter_tstamp_ms"
     91 };
     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 int display_boost;
    102 static int sustained_mode_handle = 0;
    103 static int vr_mode_handle = 0;
    104 int sustained_performance_mode = 0;
    105 int vr_mode = 0;
    106 
    107 //interaction boost global variables
    108 static struct timespec s_previous_boost_timespec;
    109 static int s_previous_duration;
    110 
    111 void power_init(void)
    112 {
    113     ALOGV("QCOM power HAL initing.");
    114 
    115     int fd;
    116     char buf[10] = {0};
    117 
    118     fd = open("/sys/devices/soc0/soc_id", O_RDONLY);
    119     if (fd >= 0) {
    120         if (read(fd, buf, sizeof(buf) - 1) == -1) {
    121             ALOGW("Unable to read soc_id");
    122         } else {
    123             int soc_id = atoi(buf);
    124             if (soc_id == 194 || (soc_id >= 208 && soc_id <= 218) || soc_id == 178) {
    125                 display_boost = 1;
    126             }
    127         }
    128         close(fd);
    129     }
    130 }
    131 
    132 static void process_video_decode_hint(void *metadata)
    133 {
    134     char governor[80];
    135     struct video_decode_metadata_t video_decode_metadata;
    136 
    137     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    138         ALOGE("Can't obtain scaling governor.");
    139 
    140         return;
    141     }
    142 
    143     if (metadata) {
    144         ALOGV("Processing video decode hint. Metadata: %s", (char *)metadata);
    145     }
    146 
    147     /* Initialize encode metadata struct fields. */
    148     memset(&video_decode_metadata, 0, sizeof(struct video_decode_metadata_t));
    149     video_decode_metadata.state = -1;
    150     video_decode_metadata.hint_id = DEFAULT_VIDEO_DECODE_HINT_ID;
    151 
    152     if (metadata) {
    153         if (parse_video_decode_metadata((char *)metadata, &video_decode_metadata) ==
    154             -1) {
    155             ALOGE("Error occurred while parsing metadata.");
    156             return;
    157         }
    158     } else {
    159         return;
    160     }
    161 
    162     if (video_decode_metadata.state == 1) {
    163         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    164                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    165             int resource_values[] = {THREAD_MIGRATION_SYNC_OFF};
    166 
    167             perform_hint_action(video_decode_metadata.hint_id,
    168                     resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    169         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    170                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    171             int resource_values[] = {TR_MS_30, HISPEED_LOAD_90, HS_FREQ_1026, THREAD_MIGRATION_SYNC_OFF};
    172 
    173             perform_hint_action(video_decode_metadata.hint_id,
    174                     resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    175         }
    176     } else if (video_decode_metadata.state == 0) {
    177         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    178                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    179         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    180                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    181             undo_hint_action(video_decode_metadata.hint_id);
    182         }
    183     }
    184 }
    185 
    186 static void process_video_encode_hint(void *metadata)
    187 {
    188     char governor[80];
    189     struct video_encode_metadata_t video_encode_metadata;
    190 
    191     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    192         ALOGE("Can't obtain scaling governor.");
    193 
    194         return;
    195     }
    196 
    197     /* Initialize encode metadata struct fields. */
    198     memset(&video_encode_metadata, 0, sizeof(struct video_encode_metadata_t));
    199     video_encode_metadata.state = -1;
    200     video_encode_metadata.hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID;
    201 
    202     if (metadata) {
    203         if (parse_video_encode_metadata((char *)metadata, &video_encode_metadata) ==
    204             -1) {
    205             ALOGE("Error occurred while parsing metadata.");
    206             return;
    207         }
    208     } else {
    209         return;
    210     }
    211 
    212     if (video_encode_metadata.state == 1) {
    213         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    214                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    215             int resource_values[] = {IO_BUSY_OFF, SAMPLING_DOWN_FACTOR_1, THREAD_MIGRATION_SYNC_OFF};
    216 
    217             perform_hint_action(video_encode_metadata.hint_id,
    218                 resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    219         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    220                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    221             int resource_values[] = {TR_MS_30, HISPEED_LOAD_90, HS_FREQ_1026, THREAD_MIGRATION_SYNC_OFF,
    222                 INTERACTIVE_IO_BUSY_OFF};
    223 
    224             perform_hint_action(video_encode_metadata.hint_id,
    225                     resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    226         }
    227     } else if (video_encode_metadata.state == 0) {
    228         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    229                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    230             undo_hint_action(video_encode_metadata.hint_id);
    231         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    232                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    233             undo_hint_action(video_encode_metadata.hint_id);
    234         }
    235     }
    236 }
    237 
    238 int __attribute__ ((weak)) power_hint_override(power_hint_t UNUSED(hint),
    239         void * UNUSED(data))
    240 {
    241     return HINT_NONE;
    242 }
    243 
    244 /* Declare function before use */
    245 void interaction(int duration, int num_args, int opt_list[]);
    246 void release_request(int lock_handle);
    247 
    248 static long long calc_timespan_us(struct timespec start, struct timespec end) {
    249     long long diff_in_us = 0;
    250     diff_in_us += (end.tv_sec - start.tv_sec) * USINSEC;
    251     diff_in_us += (end.tv_nsec - start.tv_nsec) / NSINUS;
    252     return diff_in_us;
    253 }
    254 
    255 void power_hint(power_hint_t hint, void *data)
    256 {
    257     /* Check if this hint has been overridden. */
    258     if (power_hint_override(hint, data) == HINT_HANDLED) {
    259         /* The power_hint has been handled. We can skip the rest. */
    260         return;
    261     }
    262 
    263     switch(hint) {
    264         case POWER_HINT_VSYNC:
    265         break;
    266         /* Sustained performance mode:
    267          * All CPUs are capped to ~1.2GHz
    268          * GPU frequency is capped to 315MHz
    269          */
    270         /* VR+Sustained performance mode:
    271          * All CPUs are locked to ~1.2GHz
    272          * GPU frequency is locked to 315MHz
    273          * GPU BW min_freq is raised to 775MHz
    274          */
    275         case POWER_HINT_SUSTAINED_PERFORMANCE:
    276         {
    277             int duration = 0;
    278             if (data && sustained_performance_mode == 0) {
    279                 int* resources;
    280                 if (vr_mode == 0) { // Sustained mode only.
    281                     // Ensure that POWER_HINT_LAUNCH is not in progress.
    282                     if (launch_mode == 1) {
    283                         release_request(launch_handle);
    284                         launch_mode = 0;
    285                     }
    286                     // 0x40804000: cpu0 max freq
    287                     // 0x40804100: cpu2 max freq
    288                     // 0x42C20000: gpu max freq
    289                     // 0x42C24000: gpu min freq
    290                     // 0x42C28000: gpu bus min freq
    291                     int resources[] = {0x40804000, 1209, 0x40804100, 1209,
    292                                        0x42C24000, 133,  0x42C20000, 315,
    293                                        0x42C28000, 7759};
    294                     sustained_mode_handle = interaction_with_handle(
    295                         sustained_mode_handle, duration,
    296                         sizeof(resources) / sizeof(resources[0]), resources);
    297                 } else if (vr_mode == 1) { // Sustained + VR mode.
    298                     release_request(vr_mode_handle);
    299                     // 0x40804000: cpu0 max freq
    300                     // 0x40804100: cpu2 max freq
    301                     // 0x40800000: cpu0 min freq
    302                     // 0x40800100: cpu2 min freq
    303                     // 0x42C20000: gpu max freq
    304                     // 0x42C24000: gpu min freq
    305                     // 0x42C28000: gpu bus min freq
    306                     int resources[] = {0x40800000, 1209, 0x40800100, 1209,
    307                                        0x40804000, 1209, 0x40804100, 1209,
    308                                        0x42C24000, 315,  0x42C20000, 315,
    309                                        0x42C28000, 7759};
    310                     sustained_mode_handle = interaction_with_handle(
    311                         sustained_mode_handle, duration,
    312                         sizeof(resources) / sizeof(resources[0]), resources);
    313                 }
    314                 sustained_performance_mode = 1;
    315             } else if (sustained_performance_mode == 1) {
    316                 release_request(sustained_mode_handle);
    317                 if (vr_mode == 1) { // Switch back to VR Mode.
    318                     // 0x40804000: cpu0 max freq
    319                     // 0x40804100: cpu2 max freq
    320                     // 0x40800000: cpu0 min freq
    321                     // 0x40800100: cpu2 min freq
    322                     // 0x42C20000: gpu max freq
    323                     // 0x42C24000: gpu min freq
    324                     // 0x42C28000: gpu bus min freq
    325                     int resources[] = {0x40804000, 1440, 0x40804100, 1440,
    326                                        0x40800000, 1440, 0x40800100, 1440,
    327                                        0x42C20000, 510,  0x42C24000, 510,
    328                                        0x42C28000, 7759};
    329                     vr_mode_handle = interaction_with_handle(
    330                         vr_mode_handle, duration,
    331                         sizeof(resources) / sizeof(resources[0]), resources);
    332                 }
    333                 sustained_performance_mode = 0;
    334             }
    335         }
    336         break;
    337         /* VR mode:
    338          * All CPUs are locked at ~1.4GHz
    339          * GPU frequency is locked  to 510MHz
    340          * GPU BW min_freq is raised to 775MHz
    341          */
    342         case POWER_HINT_VR_MODE:
    343         {
    344             int duration = 0;
    345             if (data && vr_mode == 0) {
    346                 if (sustained_performance_mode == 0) { // VR mode only.
    347                     // Ensure that POWER_HINT_LAUNCH is not in progress.
    348                     if (launch_mode == 1) {
    349                         release_request(launch_handle);
    350                         launch_mode = 0;
    351                     }
    352                     // 0x40804000: cpu0 max freq
    353                     // 0x40804100: cpu2 max freq
    354                     // 0x40800000: cpu0 min freq
    355                     // 0x40800100: cpu2 min freq
    356                     // 0x42C20000: gpu max freq
    357                     // 0x42C24000: gpu min freq
    358                     // 0x42C28000: gpu bus min freq
    359                     int resources[] = {0x40800000, 1440, 0x40800100, 1440,
    360                                        0x40804000, 1440, 0x40804100, 1440,
    361                                        0x42C20000, 510,  0x42C24000, 510,
    362                                        0x42C28000, 7759};
    363                     vr_mode_handle = interaction_with_handle(
    364                         vr_mode_handle, duration,
    365                         sizeof(resources) / sizeof(resources[0]), resources);
    366                 } else if (sustained_performance_mode == 1) { // Sustained + VR mode.
    367                     release_request(sustained_mode_handle);
    368                     // 0x40804000: cpu0 max freq
    369                     // 0x40804100: cpu2 max freq
    370                     // 0x40800000: cpu0 min freq
    371                     // 0x40800100: cpu2 min freq
    372                     // 0x42C20000: gpu max freq
    373                     // 0x42C24000: gpu min freq
    374                     // 0x42C28000: gpu bus min freq
    375                     int resources[] = {0x40800000, 1209, 0x40800100, 1209,
    376                                        0x40804000, 1209, 0x40804100, 1209,
    377                                        0x42C24000, 315,  0x42C20000, 315,
    378                                        0x42C28000, 7759};
    379 
    380                     vr_mode_handle = interaction_with_handle(
    381                         vr_mode_handle, duration,
    382                         sizeof(resources) / sizeof(resources[0]), resources);
    383                 }
    384                 vr_mode = 1;
    385             } else if (vr_mode == 1) {
    386                 release_request(vr_mode_handle);
    387                 if (sustained_performance_mode == 1) { // Switch back to sustained Mode.
    388                     // 0x40804000: cpu0 max freq
    389                     // 0x40804100: cpu2 max freq
    390                     // 0x40800000: cpu0 min freq
    391                     // 0x40800100: cpu2 min freq
    392                     // 0x42C20000: gpu max freq
    393                     // 0x42C24000: gpu min freq
    394                     // 0x42C28000: gpu bus min freq
    395                     int resources[] = {0x40800000, 0,    0x40800100, 0,
    396                                        0x40804000, 1209, 0x40804100, 1209,
    397                                        0x42C24000, 133,  0x42C20000, 315,
    398                                        0x42C28000, 0};
    399                     sustained_mode_handle = interaction_with_handle(
    400                         sustained_mode_handle, duration,
    401                         sizeof(resources) / sizeof(resources[0]), resources);
    402                 }
    403                 vr_mode = 0;
    404             }
    405         }
    406         break;
    407         case POWER_HINT_INTERACTION:
    408         {
    409             char governor[80];
    410 
    411             if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    412                 ALOGE("Can't obtain scaling governor.");
    413                 return;
    414             }
    415 
    416             if (sustained_performance_mode || vr_mode) {
    417                 return;
    418             }
    419 
    420             int duration = 1500; // 1.5s by default
    421             if (data) {
    422                 int input_duration = *((int*)data) + 750;
    423                 if (input_duration > duration) {
    424                     duration = (input_duration > 5750) ? 5750 : input_duration;
    425                 }
    426             }
    427 
    428             struct timespec cur_boost_timespec;
    429             clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
    430 
    431             long long elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
    432             // don't hint if previous hint's duration covers this hint's duration
    433             if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
    434                 return;
    435             }
    436             s_previous_boost_timespec = cur_boost_timespec;
    437             s_previous_duration = duration;
    438 
    439             // Scheduler is EAS.
    440             if (true || strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) {
    441                 // Setting the value of foreground schedtune boost to 50 and
    442                 // scaling_min_freq to 1100MHz.
    443                 int resources[] = {0x40800000, 1100, 0x40800100, 1100, 0x42C0C000, 0x32, 0x41800000, 0x33};
    444                 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
    445             } else { // Scheduler is HMP.
    446                 int resources[] = {0x41800000, 0x33, 0x40800000, 1000, 0x40800100, 1000, 0x40C00000, 0x1};
    447                 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
    448             }
    449         }
    450         break;
    451         case POWER_HINT_VIDEO_ENCODE:
    452             process_video_encode_hint(data);
    453         break;
    454         case POWER_HINT_VIDEO_DECODE:
    455             process_video_decode_hint(data);
    456         break;
    457         default:
    458         break;
    459     }
    460 }
    461 
    462 int __attribute__ ((weak)) set_interactive_override(int UNUSED(on))
    463 {
    464     return HINT_NONE;
    465 }
    466 
    467 void power_set_interactive(int on)
    468 {
    469     char governor[80];
    470     char tmp_str[NODE_MAX];
    471     struct video_encode_metadata_t video_encode_metadata;
    472     int rc = 0;
    473 
    474     if (set_interactive_override(on) == HINT_HANDLED) {
    475         return;
    476     }
    477 
    478     ALOGV("Got set_interactive hint");
    479 
    480     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    481         ALOGE("Can't obtain scaling governor.");
    482 
    483         return;
    484     }
    485 
    486     if (!on) {
    487         /* Display off. */
    488         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    489                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    490             int resource_values[] = {DISPLAY_OFF, MS_500, THREAD_MIGRATION_SYNC_OFF};
    491 
    492             if (!display_hint_sent) {
    493                 perform_hint_action(DISPLAY_STATE_HINT_ID,
    494                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    495                 display_hint_sent = 1;
    496             }
    497         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    498                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    499             int resource_values[] = {TR_MS_50, THREAD_MIGRATION_SYNC_OFF};
    500 
    501             if (!display_hint_sent) {
    502                 perform_hint_action(DISPLAY_STATE_HINT_ID,
    503                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    504                 display_hint_sent = 1;
    505             }
    506         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
    507                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
    508             if (saved_interactive_mode == 1){
    509                 /* Display turned off. */
    510                 if (sysfs_read(DCVS_CPU0_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
    511                     if (!slack_node_rw_failed) {
    512                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MAX_NODE);
    513                     }
    514 
    515                     rc = 1;
    516                 } else {
    517                     saved_dcvs_cpu0_slack_max = atoi(tmp_str);
    518                 }
    519 
    520                 if (sysfs_read(DCVS_CPU0_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
    521                     if (!slack_node_rw_failed) {
    522                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MIN_NODE);
    523                     }
    524 
    525                     rc = 1;
    526                 } else {
    527                     saved_dcvs_cpu0_slack_min = atoi(tmp_str);
    528                 }
    529 
    530                 if (sysfs_read(MPDECISION_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
    531                     if (!slack_node_rw_failed) {
    532                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MAX_NODE);
    533                     }
    534 
    535                     rc = 1;
    536                 } else {
    537                     saved_mpdecision_slack_max = atoi(tmp_str);
    538                 }
    539 
    540                 if (sysfs_read(MPDECISION_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
    541                     if(!slack_node_rw_failed) {
    542                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MIN_NODE);
    543                     }
    544 
    545                     rc = 1;
    546                 } else {
    547                     saved_mpdecision_slack_min = atoi(tmp_str);
    548                 }
    549 
    550                 /* Write new values. */
    551                 if (saved_dcvs_cpu0_slack_max != -1) {
    552                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_max);
    553 
    554                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
    555                         if (!slack_node_rw_failed) {
    556                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
    557                         }
    558 
    559                         rc = 1;
    560                     }
    561                 }
    562 
    563                 if (saved_dcvs_cpu0_slack_min != -1) {
    564                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_min);
    565 
    566                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
    567                         if(!slack_node_rw_failed) {
    568                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
    569                         }
    570 
    571                         rc = 1;
    572                     }
    573                 }
    574 
    575                 if (saved_mpdecision_slack_max != -1) {
    576                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_max);
    577 
    578                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
    579                         if(!slack_node_rw_failed) {
    580                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
    581                         }
    582 
    583                         rc = 1;
    584                     }
    585                 }
    586 
    587                 if (saved_mpdecision_slack_min != -1) {
    588                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_min);
    589 
    590                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
    591                         if(!slack_node_rw_failed) {
    592                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
    593                         }
    594 
    595                         rc = 1;
    596                     }
    597                 }
    598             }
    599 
    600             slack_node_rw_failed = rc;
    601         }
    602     } else {
    603         /* Display on. */
    604         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    605                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    606             undo_hint_action(DISPLAY_STATE_HINT_ID);
    607             display_hint_sent = 0;
    608         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    609                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    610             undo_hint_action(DISPLAY_STATE_HINT_ID);
    611             display_hint_sent = 0;
    612         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
    613                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
    614             if (saved_interactive_mode == -1 || saved_interactive_mode == 0) {
    615                 /* Display turned on. Restore if possible. */
    616                 if (saved_dcvs_cpu0_slack_max != -1) {
    617                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_max);
    618 
    619                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
    620                         if (!slack_node_rw_failed) {
    621                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
    622                         }
    623 
    624                         rc = 1;
    625                     }
    626                 }
    627 
    628                 if (saved_dcvs_cpu0_slack_min != -1) {
    629                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_min);
    630 
    631                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
    632                         if (!slack_node_rw_failed) {
    633                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
    634                         }
    635 
    636                         rc = 1;
    637                     }
    638                 }
    639 
    640                 if (saved_mpdecision_slack_max != -1) {
    641                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_max);
    642 
    643                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
    644                         if (!slack_node_rw_failed) {
    645                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
    646                         }
    647 
    648                         rc = 1;
    649                     }
    650                 }
    651 
    652                 if (saved_mpdecision_slack_min != -1) {
    653                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_min);
    654 
    655                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
    656                         if (!slack_node_rw_failed) {
    657                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
    658                         }
    659 
    660                         rc = 1;
    661                     }
    662                 }
    663             }
    664 
    665             slack_node_rw_failed = rc;
    666         }
    667     }
    668 
    669     saved_interactive_mode = !!on;
    670 }
    671 
    672 
    673 static int extract_stats(uint64_t *list, char *file, const char**param_names,
    674                          unsigned int num_parameters, int isHex) {
    675     FILE *fp;
    676     ssize_t read;
    677     size_t len;
    678     size_t index = 0;
    679     char *line;
    680     int ret;
    681 
    682     fp = fopen(file, "r");
    683     if (fp == NULL) {
    684         ret = -errno;
    685         ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
    686         return ret;
    687     }
    688 
    689     for (line = NULL, len = 0;
    690          ((read = getline(&line, &len, fp) != -1) && (index < num_parameters));
    691          free(line), line = NULL, len = 0) {
    692         uint64_t value;
    693         char* offset;
    694 
    695         size_t begin = strspn(line, " \t");
    696         if (strncmp(line + begin, param_names[index], strlen(param_names[index]))) {
    697             continue;
    698         }
    699 
    700         offset = memchr(line, ':', len);
    701         if (!offset) {
    702             continue;
    703         }
    704 
    705         if (isHex) {
    706             sscanf(offset, ":%" SCNx64, &value);
    707         } else {
    708             sscanf(offset, ":%" SCNu64, &value);
    709         }
    710         list[index] = value;
    711         index++;
    712     }
    713 
    714     free(line);
    715     fclose(fp);
    716 
    717     return 0;
    718 }
    719 
    720 
    721 int extract_platform_stats(uint64_t *list) {
    722 
    723     int ret;
    724 
    725     //Data is located in two files
    726 
    727     ret = extract_stats(list, RPM_STAT, rpm_param_names, RPM_PARAM_COUNT, false);
    728     if (ret) {
    729         for (size_t i=0; i < RPM_PARAM_COUNT; i++)
    730             list[i] = 0;
    731     }
    732 
    733     ret = extract_stats(list + RPM_PARAM_COUNT, RPM_MASTER_STAT,
    734                         rpm_master_param_names, PLATFORM_PARAM_COUNT - RPM_PARAM_COUNT, true);
    735     if (ret) {
    736         for (size_t i=RPM_PARAM_COUNT; i < PLATFORM_PARAM_COUNT; i++)
    737         list[i] = 0;
    738     }
    739 
    740     return 0;
    741 }
    742 
    743 int extract_wlan_stats(uint64_t *list) {
    744 
    745     int ret;
    746 
    747     ret = extract_stats(list, WLAN_POWER_STAT, wlan_param_names, WLAN_PARAM_COUNT, false);
    748     if (ret) {
    749         for (size_t i=0; i < WLAN_PARAM_COUNT; i++)
    750             list[i] = 0;
    751     }
    752 
    753     return 0;
    754 }
    755