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