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/hardware.h>
     44 #include <hardware/power.h>
     45 #include <cutils/properties.h>
     46 
     47 #include "utils.h"
     48 #include "metadata-defs.h"
     49 #include "hint-data.h"
     50 #include "performance.h"
     51 #include "power-common.h"
     52 
     53 #define USINSEC 1000000L
     54 #define NSINUS 1000L
     55 
     56 #define PLATFORM_SLEEP_MODES 2
     57 #define XO_VOTERS 4
     58 #define VMIN_VOTERS 0
     59 
     60 #define RPM_PARAMETERS 4
     61 #define NUM_PARAMETERS 12
     62 
     63 #ifndef RPM_STAT
     64 #define RPM_STAT "/d/rpm_stats"
     65 #endif
     66 
     67 #ifndef RPM_MASTER_STAT
     68 #define RPM_MASTER_STAT "/d/rpm_master_stats"
     69 #endif
     70 
     71 /* RPM runs at 19.2Mhz. Divide by 19200 for msec */
     72 #define RPM_CLK 19200
     73 
     74 const char *parameter_names[] = {
     75     "vlow_count",
     76     "accumulated_vlow_time",
     77     "vmin_count",
     78     "accumulated_vmin_time",
     79     "xo_accumulated_duration",
     80     "xo_count",
     81     "xo_accumulated_duration",
     82     "xo_count",
     83     "xo_accumulated_duration",
     84     "xo_count",
     85     "xo_accumulated_duration",
     86     "xo_count"
     87 };
     88 
     89 static int saved_dcvs_cpu0_slack_max = -1;
     90 static int saved_dcvs_cpu0_slack_min = -1;
     91 static int saved_mpdecision_slack_max = -1;
     92 static int saved_mpdecision_slack_min = -1;
     93 static int saved_interactive_mode = -1;
     94 static int slack_node_rw_failed = 0;
     95 static int display_hint_sent;
     96 int display_boost;
     97 static int sustained_mode_handle = 0;
     98 static int vr_mode_handle = 0;
     99 int sustained_performance_mode = 0;
    100 int vr_mode = 0;
    101 
    102 //interaction boost global variables
    103 static pthread_mutex_t s_interaction_lock = PTHREAD_MUTEX_INITIALIZER;
    104 static struct timespec s_previous_boost_timespec;
    105 static int s_previous_duration;
    106 
    107 static void power_init(struct power_module *module)
    108 {
    109     ALOGV("QCOM power HAL initing.");
    110 
    111     int fd;
    112     char buf[10] = {0};
    113 
    114     fd = open("/sys/devices/soc0/soc_id", O_RDONLY);
    115     if (fd >= 0) {
    116         if (read(fd, buf, sizeof(buf) - 1) == -1) {
    117             ALOGW("Unable to read soc_id");
    118         } else {
    119             int soc_id = atoi(buf);
    120             if (soc_id == 194 || (soc_id >= 208 && soc_id <= 218) || soc_id == 178) {
    121                 display_boost = 1;
    122             }
    123         }
    124         close(fd);
    125     }
    126 }
    127 
    128 static void process_video_decode_hint(void *metadata)
    129 {
    130     char governor[80];
    131     struct video_decode_metadata_t video_decode_metadata;
    132 
    133     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    134         ALOGE("Can't obtain scaling governor.");
    135 
    136         return;
    137     }
    138 
    139     if (metadata) {
    140         ALOGV("Processing video decode hint. Metadata: %s", (char *)metadata);
    141     }
    142 
    143     /* Initialize encode metadata struct fields. */
    144     memset(&video_decode_metadata, 0, sizeof(struct video_decode_metadata_t));
    145     video_decode_metadata.state = -1;
    146     video_decode_metadata.hint_id = DEFAULT_VIDEO_DECODE_HINT_ID;
    147 
    148     if (metadata) {
    149         if (parse_video_decode_metadata((char *)metadata, &video_decode_metadata) ==
    150             -1) {
    151             ALOGE("Error occurred while parsing metadata.");
    152             return;
    153         }
    154     } else {
    155         return;
    156     }
    157 
    158     if (video_decode_metadata.state == 1) {
    159         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    160                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    161             int resource_values[] = {THREAD_MIGRATION_SYNC_OFF};
    162 
    163             perform_hint_action(video_decode_metadata.hint_id,
    164                     resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    165         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    166                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    167             int resource_values[] = {TR_MS_30, HISPEED_LOAD_90, HS_FREQ_1026, THREAD_MIGRATION_SYNC_OFF};
    168 
    169             perform_hint_action(video_decode_metadata.hint_id,
    170                     resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    171         }
    172     } else if (video_decode_metadata.state == 0) {
    173         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    174                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    175         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    176                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    177             undo_hint_action(video_decode_metadata.hint_id);
    178         }
    179     }
    180 }
    181 
    182 static void process_video_encode_hint(void *metadata)
    183 {
    184     char governor[80];
    185     struct video_encode_metadata_t video_encode_metadata;
    186 
    187     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    188         ALOGE("Can't obtain scaling governor.");
    189 
    190         return;
    191     }
    192 
    193     /* Initialize encode metadata struct fields. */
    194     memset(&video_encode_metadata, 0, sizeof(struct video_encode_metadata_t));
    195     video_encode_metadata.state = -1;
    196     video_encode_metadata.hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID;
    197 
    198     if (metadata) {
    199         if (parse_video_encode_metadata((char *)metadata, &video_encode_metadata) ==
    200             -1) {
    201             ALOGE("Error occurred while parsing metadata.");
    202             return;
    203         }
    204     } else {
    205         return;
    206     }
    207 
    208     if (video_encode_metadata.state == 1) {
    209         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    210                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    211             int resource_values[] = {IO_BUSY_OFF, SAMPLING_DOWN_FACTOR_1, THREAD_MIGRATION_SYNC_OFF};
    212 
    213             perform_hint_action(video_encode_metadata.hint_id,
    214                 resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    215         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    216                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    217             int resource_values[] = {TR_MS_30, HISPEED_LOAD_90, HS_FREQ_1026, THREAD_MIGRATION_SYNC_OFF,
    218                 INTERACTIVE_IO_BUSY_OFF};
    219 
    220             perform_hint_action(video_encode_metadata.hint_id,
    221                     resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    222         }
    223     } else if (video_encode_metadata.state == 0) {
    224         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    225                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    226             undo_hint_action(video_encode_metadata.hint_id);
    227         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    228                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    229             undo_hint_action(video_encode_metadata.hint_id);
    230         }
    231     }
    232 }
    233 
    234 int __attribute__ ((weak)) power_hint_override(struct power_module *module, power_hint_t hint,
    235         void *data)
    236 {
    237     return HINT_NONE;
    238 }
    239 
    240 /* Declare function before use */
    241 void interaction(int duration, int num_args, int opt_list[]);
    242 void release_request(int lock_handle);
    243 
    244 static long long calc_timespan_us(struct timespec start, struct timespec end) {
    245     long long diff_in_us = 0;
    246     diff_in_us += (end.tv_sec - start.tv_sec) * USINSEC;
    247     diff_in_us += (end.tv_nsec - start.tv_nsec) / NSINUS;
    248     return diff_in_us;
    249 }
    250 
    251 static void power_hint(struct power_module *module, power_hint_t hint,
    252         void *data)
    253 {
    254     /* Check if this hint has been overridden. */
    255     if (power_hint_override(module, hint, data) == HINT_HANDLED) {
    256         /* The power_hint has been handled. We can skip the rest. */
    257         return;
    258     }
    259 
    260     switch(hint) {
    261         case POWER_HINT_VSYNC:
    262         break;
    263         /* Sustained performance mode:
    264          * All CPUs are capped to ~1.2GHz
    265          * GPU frequency is capped to 315MHz
    266          */
    267         /* VR+Sustained performance mode:
    268          * All CPUs are locked to ~1.2GHz
    269          * GPU frequency is locked to 315MHz
    270          * GPU BW min_freq is raised to 775MHz
    271          */
    272         case POWER_HINT_SUSTAINED_PERFORMANCE:
    273         {
    274             int duration = 0;
    275             pthread_mutex_lock(&s_interaction_lock);
    276             if (data && sustained_performance_mode == 0) {
    277                 int* resources;
    278                 if (vr_mode == 0) { // Sustained mode only.
    279                     // Ensure that POWER_HINT_LAUNCH is not in progress.
    280                     if (launch_mode == 1) {
    281                         release_request(launch_handle);
    282                         launch_mode = 0;
    283                     }
    284                     // 0x40804000: cpu0 max freq
    285                     // 0x40804100: cpu2 max freq
    286                     // 0x42C20000: gpu max freq
    287                     // 0x42C24000: gpu min freq
    288                     // 0x42C28000: gpu bus min freq
    289                     int resources[] = {0x40804000, 1209, 0x40804100, 1209,
    290                                        0x42C24000, 133,  0x42C20000, 315,
    291                                        0x42C28000, 7759};
    292                     sustained_mode_handle = interaction_with_handle(
    293                         sustained_mode_handle, duration,
    294                         sizeof(resources) / sizeof(resources[0]), resources);
    295                 } else if (vr_mode == 1) { // Sustained + VR mode.
    296                     release_request(vr_mode_handle);
    297                     // 0x40804000: cpu0 max freq
    298                     // 0x40804100: cpu2 max freq
    299                     // 0x40800000: cpu0 min freq
    300                     // 0x40800100: cpu2 min freq
    301                     // 0x42C20000: gpu max freq
    302                     // 0x42C24000: gpu min freq
    303                     // 0x42C28000: gpu bus min freq
    304                     int resources[] = {0x40800000, 1209, 0x40800100, 1209,
    305                                        0x40804000, 1209, 0x40804100, 1209,
    306                                        0x42C24000, 315,  0x42C20000, 315,
    307                                        0x42C28000, 7759};
    308                     sustained_mode_handle = interaction_with_handle(
    309                         sustained_mode_handle, duration,
    310                         sizeof(resources) / sizeof(resources[0]), resources);
    311                 }
    312                 sustained_performance_mode = 1;
    313             } else if (sustained_performance_mode == 1) {
    314                 release_request(sustained_mode_handle);
    315                 if (vr_mode == 1) { // Switch back to VR Mode.
    316                     // 0x40804000: cpu0 max freq
    317                     // 0x40804100: cpu2 max freq
    318                     // 0x40800000: cpu0 min freq
    319                     // 0x40800100: cpu2 min freq
    320                     // 0x42C20000: gpu max freq
    321                     // 0x42C24000: gpu min freq
    322                     // 0x42C28000: gpu bus min freq
    323                     int resources[] = {0x40804000, 1440, 0x40804100, 1440,
    324                                        0x40800000, 1440, 0x40800100, 1440,
    325                                        0x42C20000, 510,  0x42C24000, 510,
    326                                        0x42C28000, 7759};
    327                     vr_mode_handle = interaction_with_handle(
    328                         vr_mode_handle, duration,
    329                         sizeof(resources) / sizeof(resources[0]), resources);
    330                 }
    331                 sustained_performance_mode = 0;
    332             }
    333             pthread_mutex_unlock(&s_interaction_lock);
    334         }
    335         break;
    336         /* VR mode:
    337          * All CPUs are locked at ~1.4GHz
    338          * GPU frequency is locked  to 510MHz
    339          * GPU BW min_freq is raised to 775MHz
    340          */
    341         case POWER_HINT_VR_MODE:
    342         {
    343             int duration = 0;
    344             pthread_mutex_lock(&s_interaction_lock);
    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             pthread_mutex_unlock(&s_interaction_lock);
    406         }
    407         break;
    408         case POWER_HINT_INTERACTION:
    409         {
    410             char governor[80];
    411 
    412             if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    413                 ALOGE("Can't obtain scaling governor.");
    414                 return;
    415             }
    416 
    417             pthread_mutex_lock(&s_interaction_lock);
    418             if (sustained_performance_mode || vr_mode) {
    419                 pthread_mutex_unlock(&s_interaction_lock);
    420                 return;
    421             }
    422 
    423             int duration = 1500; // 1.5s by default
    424             if (data) {
    425                 int input_duration = *((int*)data) + 750;
    426                 if (input_duration > duration) {
    427                     duration = (input_duration > 5750) ? 5750 : input_duration;
    428                 }
    429             }
    430 
    431             struct timespec cur_boost_timespec;
    432             clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
    433 
    434             long long elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
    435             // don't hint if previous hint's duration covers this hint's duration
    436             if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
    437                 pthread_mutex_unlock(&s_interaction_lock);
    438                 return;
    439             }
    440             s_previous_boost_timespec = cur_boost_timespec;
    441             s_previous_duration = duration;
    442 
    443             // Scheduler is EAS.
    444             if (true || strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) {
    445                 // Setting the value of foreground schedtune boost to 50 and
    446                 // scaling_min_freq to 1100MHz.
    447                 int resources[] = {0x40800000, 1100, 0x40800100, 1100, 0x42C0C000, 0x32, 0x41800000, 0x33};
    448                 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
    449             } else { // Scheduler is HMP.
    450                 int resources[] = {0x41800000, 0x33, 0x40800000, 1000, 0x40800100, 1000, 0x40C00000, 0x1};
    451                 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
    452             }
    453             pthread_mutex_unlock(&s_interaction_lock);
    454         }
    455         break;
    456         case POWER_HINT_VIDEO_ENCODE:
    457             process_video_encode_hint(data);
    458         break;
    459         case POWER_HINT_VIDEO_DECODE:
    460             process_video_decode_hint(data);
    461         break;
    462 	default:
    463 	break;
    464     }
    465 }
    466 
    467 int __attribute__ ((weak)) set_interactive_override(struct power_module *module, int on)
    468 {
    469     return HINT_NONE;
    470 }
    471 
    472 void set_interactive(struct power_module *module, int on)
    473 {
    474     char governor[80];
    475     char tmp_str[NODE_MAX];
    476     struct video_encode_metadata_t video_encode_metadata;
    477     int rc = 0;
    478 
    479     if (set_interactive_override(module, on) == HINT_HANDLED) {
    480         return;
    481     }
    482 
    483     ALOGV("Got set_interactive hint");
    484 
    485     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    486         ALOGE("Can't obtain scaling governor.");
    487 
    488         return;
    489     }
    490 
    491     if (!on) {
    492         /* Display off. */
    493         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    494                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    495             int resource_values[] = {DISPLAY_OFF, MS_500, THREAD_MIGRATION_SYNC_OFF};
    496 
    497             if (!display_hint_sent) {
    498                 perform_hint_action(DISPLAY_STATE_HINT_ID,
    499                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    500                 display_hint_sent = 1;
    501             }
    502         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    503                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    504             int resource_values[] = {TR_MS_50, THREAD_MIGRATION_SYNC_OFF};
    505 
    506             if (!display_hint_sent) {
    507                 perform_hint_action(DISPLAY_STATE_HINT_ID,
    508                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    509                 display_hint_sent = 1;
    510             }
    511         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
    512                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
    513             if (saved_interactive_mode == 1){
    514                 /* Display turned off. */
    515                 if (sysfs_read(DCVS_CPU0_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
    516                     if (!slack_node_rw_failed) {
    517                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MAX_NODE);
    518                     }
    519 
    520                     rc = 1;
    521                 } else {
    522                     saved_dcvs_cpu0_slack_max = atoi(tmp_str);
    523                 }
    524 
    525                 if (sysfs_read(DCVS_CPU0_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
    526                     if (!slack_node_rw_failed) {
    527                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MIN_NODE);
    528                     }
    529 
    530                     rc = 1;
    531                 } else {
    532                     saved_dcvs_cpu0_slack_min = atoi(tmp_str);
    533                 }
    534 
    535                 if (sysfs_read(MPDECISION_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
    536                     if (!slack_node_rw_failed) {
    537                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MAX_NODE);
    538                     }
    539 
    540                     rc = 1;
    541                 } else {
    542                     saved_mpdecision_slack_max = atoi(tmp_str);
    543                 }
    544 
    545                 if (sysfs_read(MPDECISION_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
    546                     if(!slack_node_rw_failed) {
    547                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MIN_NODE);
    548                     }
    549 
    550                     rc = 1;
    551                 } else {
    552                     saved_mpdecision_slack_min = atoi(tmp_str);
    553                 }
    554 
    555                 /* Write new values. */
    556                 if (saved_dcvs_cpu0_slack_max != -1) {
    557                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_max);
    558 
    559                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
    560                         if (!slack_node_rw_failed) {
    561                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
    562                         }
    563 
    564                         rc = 1;
    565                     }
    566                 }
    567 
    568                 if (saved_dcvs_cpu0_slack_min != -1) {
    569                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_min);
    570 
    571                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
    572                         if(!slack_node_rw_failed) {
    573                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
    574                         }
    575 
    576                         rc = 1;
    577                     }
    578                 }
    579 
    580                 if (saved_mpdecision_slack_max != -1) {
    581                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_max);
    582 
    583                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
    584                         if(!slack_node_rw_failed) {
    585                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
    586                         }
    587 
    588                         rc = 1;
    589                     }
    590                 }
    591 
    592                 if (saved_mpdecision_slack_min != -1) {
    593                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_min);
    594 
    595                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
    596                         if(!slack_node_rw_failed) {
    597                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
    598                         }
    599 
    600                         rc = 1;
    601                     }
    602                 }
    603             }
    604 
    605             slack_node_rw_failed = rc;
    606         }
    607     } else {
    608         /* Display on. */
    609         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    610                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    611             undo_hint_action(DISPLAY_STATE_HINT_ID);
    612             display_hint_sent = 0;
    613         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    614                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    615             undo_hint_action(DISPLAY_STATE_HINT_ID);
    616             display_hint_sent = 0;
    617         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
    618                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
    619             if (saved_interactive_mode == -1 || saved_interactive_mode == 0) {
    620                 /* Display turned on. Restore if possible. */
    621                 if (saved_dcvs_cpu0_slack_max != -1) {
    622                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_max);
    623 
    624                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
    625                         if (!slack_node_rw_failed) {
    626                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
    627                         }
    628 
    629                         rc = 1;
    630                     }
    631                 }
    632 
    633                 if (saved_dcvs_cpu0_slack_min != -1) {
    634                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_min);
    635 
    636                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
    637                         if (!slack_node_rw_failed) {
    638                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
    639                         }
    640 
    641                         rc = 1;
    642                     }
    643                 }
    644 
    645                 if (saved_mpdecision_slack_max != -1) {
    646                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_max);
    647 
    648                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
    649                         if (!slack_node_rw_failed) {
    650                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
    651                         }
    652 
    653                         rc = 1;
    654                     }
    655                 }
    656 
    657                 if (saved_mpdecision_slack_min != -1) {
    658                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_min);
    659 
    660                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
    661                         if (!slack_node_rw_failed) {
    662                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
    663                         }
    664 
    665                         rc = 1;
    666                     }
    667                 }
    668             }
    669 
    670             slack_node_rw_failed = rc;
    671         }
    672     }
    673 
    674     saved_interactive_mode = !!on;
    675 }
    676 
    677 static ssize_t get_number_of_platform_modes(struct power_module *module) {
    678    return PLATFORM_SLEEP_MODES;
    679 }
    680 
    681 static int get_voter_list(struct power_module *module, size_t *voter) {
    682    voter[0] = XO_VOTERS;
    683    voter[1] = VMIN_VOTERS;
    684 
    685    return 0;
    686 }
    687 
    688 static int extract_stats(uint64_t *list, char *file,
    689     unsigned int num_parameters, unsigned int index) {
    690     FILE *fp;
    691     ssize_t read;
    692     size_t len;
    693     char *line;
    694     int ret;
    695 
    696     fp = fopen(file, "r");
    697     if (fp == NULL) {
    698         ret = -errno;
    699         ALOGE("%s: failed to open: %s", __func__, strerror(errno));
    700         return ret;
    701     }
    702 
    703     for (line = NULL, len = 0;
    704          ((read = getline(&line, &len, fp) != -1) && (index < num_parameters));
    705          free(line), line = NULL, len = 0) {
    706         uint64_t value;
    707         char* offset;
    708 
    709         size_t begin = strspn(line, " \t");
    710         if (strncmp(line + begin, parameter_names[index], strlen(parameter_names[index]))) {
    711             continue;
    712         }
    713 
    714         offset = memchr(line, ':', len);
    715         if (!offset) {
    716             continue;
    717         }
    718 
    719         if (!strcmp(file, RPM_MASTER_STAT)) {
    720             /* RPM_MASTER_STAT is reported in hex */
    721             sscanf(offset, ":%" SCNx64, &value);
    722             /* Duration is reported in rpm SLEEP TICKS */
    723             if (!strcmp(parameter_names[index], "xo_accumulated_duration")) {
    724                 value /= RPM_CLK;
    725             }
    726         } else {
    727             /* RPM_STAT is reported in decimal */
    728             sscanf(offset, ":%" SCNu64, &value);
    729         }
    730         list[index] = value;
    731         index++;
    732     }
    733     free(line);
    734 
    735     fclose(fp);
    736     return 0;
    737 }
    738 
    739 static int get_platform_low_power_stats(struct power_module *module,
    740     power_state_platform_sleep_state_t *list) {
    741     uint64_t stats[sizeof(parameter_names)] = {0};
    742     int ret;
    743 
    744     if (!list) {
    745         return -EINVAL;
    746     }
    747 
    748     ret = extract_stats(stats, RPM_STAT, RPM_PARAMETERS, 0);
    749 
    750     if (ret) {
    751         return ret;
    752     }
    753 
    754     ret = extract_stats(stats, RPM_MASTER_STAT, NUM_PARAMETERS, RPM_PARAMETERS);
    755 
    756     if (ret) {
    757         return ret;
    758     }
    759 
    760     /* Update statistics for XO_shutdown */
    761     strcpy(list[0].name, "XO_shutdown");
    762     list[0].total_transitions = stats[0];
    763     list[0].residency_in_msec_since_boot = stats[1];
    764     list[0].supported_only_in_suspend = false;
    765     list[0].number_of_voters = XO_VOTERS;
    766 
    767     /* Update statistics for APSS voter */
    768     strcpy(list[0].voters[0].name, "APSS");
    769     list[0].voters[0].total_time_in_msec_voted_for_since_boot = stats[4];
    770     list[0].voters[0].total_number_of_times_voted_since_boot = stats[5];
    771 
    772     /* Update statistics for MPSS voter */
    773     strcpy(list[0].voters[1].name, "MPSS");
    774     list[0].voters[1].total_time_in_msec_voted_for_since_boot = stats[6];
    775     list[0].voters[1].total_number_of_times_voted_since_boot = stats[7];
    776 
    777     /* Update statistics for ADSP voter */
    778     strcpy(list[0].voters[2].name, "ADSP");
    779     list[0].voters[2].total_time_in_msec_voted_for_since_boot = stats[8];
    780     list[0].voters[2].total_number_of_times_voted_since_boot = stats[9];
    781 
    782     /* Update statistics for SLPI voter */
    783     strcpy(list[0].voters[3].name, "SLPI");
    784     list[0].voters[3].total_time_in_msec_voted_for_since_boot = stats[10];
    785     list[0].voters[3].total_number_of_times_voted_since_boot = stats[11];
    786 
    787     /* Update statistics for VMIN state */
    788     strcpy(list[1].name, "VMIN");
    789     list[1].total_transitions = stats[2];
    790     list[1].residency_in_msec_since_boot = stats[3];
    791     list[1].supported_only_in_suspend = false;
    792     list[1].number_of_voters = VMIN_VOTERS;
    793 
    794     return 0;
    795 }
    796 
    797 static int power_open(const hw_module_t* module, const char* name,
    798                     hw_device_t** device)
    799 {
    800     ALOGV("%s: enter; name=%s", __FUNCTION__, name);
    801     int retval = 0; /* 0 is ok; -1 is error */
    802 
    803     if (strcmp(name, POWER_HARDWARE_MODULE_ID) == 0) {
    804         power_module_t *dev = (power_module_t *)calloc(1,
    805                 sizeof(power_module_t));
    806 
    807         if (dev) {
    808             /* Common hw_device_t fields */
    809             dev->common.tag = HARDWARE_MODULE_TAG;
    810             dev->common.module_api_version = POWER_MODULE_API_VERSION_0_5;
    811             dev->common.module_api_version = HARDWARE_HAL_API_VERSION;
    812 
    813             dev->init = power_init;
    814             dev->powerHint = power_hint;
    815             dev->setInteractive = set_interactive;
    816             dev->get_number_of_platform_modes = get_number_of_platform_modes;
    817             dev->get_platform_low_power_stats = get_platform_low_power_stats;
    818             dev->get_voter_list = get_voter_list;
    819 
    820             *device = (hw_device_t*)dev;
    821         } else
    822             retval = -ENOMEM;
    823     } else {
    824         retval = -EINVAL;
    825     }
    826 
    827     ALOGV("%s: exit %d", __FUNCTION__, retval);
    828     return retval;
    829 }
    830 
    831 static struct hw_module_methods_t power_module_methods = {
    832     .open = power_open,
    833 };
    834 
    835 struct power_module HAL_MODULE_INFO_SYM = {
    836     .common = {
    837         .tag = HARDWARE_MODULE_TAG,
    838         .module_api_version = POWER_MODULE_API_VERSION_0_5,
    839         .hal_api_version = HARDWARE_HAL_API_VERSION,
    840         .id = POWER_HARDWARE_MODULE_ID,
    841         .name = "QCOM Power HAL",
    842         .author = "Qualcomm",
    843         .methods = &power_module_methods,
    844     },
    845 
    846     .init = power_init,
    847     .powerHint = power_hint,
    848     .setInteractive = set_interactive,
    849     .get_number_of_platform_modes = get_number_of_platform_modes,
    850     .get_platform_low_power_stats = get_platform_low_power_stats,
    851     .get_voter_list = get_voter_list
    852 };
    853