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