• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * *    * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above
10  *       copyright notice, this list of conditions and the following
11  *       disclaimer in the documentation and/or other materials provided
12  *       with the distribution.
13  *     * Neither the name of The Linux Foundation nor the names of its
14  *       contributors may be used to endorse or promote products derived
15  *       from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #define LOG_NIDEBUG 0
31 
32 #include <errno.h>
33 #include <inttypes.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <dlfcn.h>
39 #include <stdlib.h>
40 
41 #define LOG_TAG "QCOM PowerHAL"
42 #include <utils/Log.h>
43 #include <hardware/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 struct hw_module_methods_t power_module_methods = {
108     .open = NULL,
109 };
110 
power_init(struct power_module * module)111 static void power_init(struct power_module *module)
112 {
113     ALOGI("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 
process_video_decode_hint(void * metadata)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         ALOGI("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 
process_video_encode_hint(void * metadata)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 
power_hint_override(struct power_module * module,power_hint_t hint,void * data)238 int __attribute__ ((weak)) power_hint_override(struct power_module *module, power_hint_t hint,
239         void *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 
calc_timespan_us(struct timespec start,struct timespec end)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 
power_hint(struct power_module * module,power_hint_t hint,void * data)255 static void power_hint(struct power_module *module, power_hint_t hint,
256         void *data)
257 {
258     /* Check if this hint has been overridden. */
259     if (power_hint_override(module, hint, data) == HINT_HANDLED) {
260         /* The power_hint has been handled. We can skip the rest. */
261         return;
262     }
263 
264     switch(hint) {
265         case POWER_HINT_VSYNC:
266         break;
267         /* Sustained performance mode:
268          * All CPUs are capped to ~1.2GHz
269          * GPU frequency is capped to 315MHz
270          */
271         /* VR+Sustained performance mode:
272          * All CPUs are locked to ~1.2GHz
273          * GPU frequency is locked to 315MHz
274          * GPU BW min_freq is raised to 775MHz
275          */
276         case POWER_HINT_SUSTAINED_PERFORMANCE:
277         {
278             int duration = 0;
279             pthread_mutex_lock(&s_interaction_lock);
280             if (data && sustained_performance_mode == 0) {
281                 int* resources;
282                 if (vr_mode == 0) { // Sustained mode only.
283                     // Ensure that POWER_HINT_LAUNCH is not in progress.
284                     if (launch_mode == 1) {
285                         release_request(launch_handle);
286                         launch_mode = 0;
287                     }
288                     // 0x40804000: cpu0 max freq
289                     // 0x40804100: cpu2 max freq
290                     // 0x42C20000: gpu max freq
291                     // 0x42C24000: gpu min freq
292                     // 0x42C28000: gpu bus min freq
293                     int resources[] = {0x40804000, 1209, 0x40804100, 1209,
294                                        0x42C24000, 133,  0x42C20000, 315,
295                                        0x42C28000, 7759};
296                     sustained_mode_handle = interaction_with_handle(
297                         sustained_mode_handle, duration,
298                         sizeof(resources) / sizeof(resources[0]), resources);
299                 } else if (vr_mode == 1) { // Sustained + VR mode.
300                     release_request(vr_mode_handle);
301                     // 0x40804000: cpu0 max freq
302                     // 0x40804100: cpu2 max freq
303                     // 0x40800000: cpu0 min freq
304                     // 0x40800100: cpu2 min freq
305                     // 0x42C20000: gpu max freq
306                     // 0x42C24000: gpu min freq
307                     // 0x42C28000: gpu bus min freq
308                     int resources[] = {0x40800000, 1209, 0x40800100, 1209,
309                                        0x40804000, 1209, 0x40804100, 1209,
310                                        0x42C24000, 315,  0x42C20000, 315,
311                                        0x42C28000, 7759};
312                     sustained_mode_handle = interaction_with_handle(
313                         sustained_mode_handle, duration,
314                         sizeof(resources) / sizeof(resources[0]), resources);
315                 }
316                 sustained_performance_mode = 1;
317             } else if (sustained_performance_mode == 1) {
318                 release_request(sustained_mode_handle);
319                 if (vr_mode == 1) { // Switch back to VR Mode.
320                     // 0x40804000: cpu0 max freq
321                     // 0x40804100: cpu2 max freq
322                     // 0x40800000: cpu0 min freq
323                     // 0x40800100: cpu2 min freq
324                     // 0x42C20000: gpu max freq
325                     // 0x42C24000: gpu min freq
326                     // 0x42C28000: gpu bus min freq
327                     int resources[] = {0x40804000, 1440, 0x40804100, 1440,
328                                        0x40800000, 1440, 0x40800100, 1440,
329                                        0x42C20000, 510,  0x42C24000, 510,
330                                        0x42C28000, 7759};
331                     vr_mode_handle = interaction_with_handle(
332                         vr_mode_handle, duration,
333                         sizeof(resources) / sizeof(resources[0]), resources);
334                 }
335                 sustained_performance_mode = 0;
336             }
337             pthread_mutex_unlock(&s_interaction_lock);
338         }
339         break;
340         /* VR mode:
341          * All CPUs are locked at ~1.4GHz
342          * GPU frequency is locked  to 510MHz
343          * GPU BW min_freq is raised to 775MHz
344          */
345         case POWER_HINT_VR_MODE:
346         {
347             int duration = 0;
348             pthread_mutex_lock(&s_interaction_lock);
349             if (data && vr_mode == 0) {
350                 if (sustained_performance_mode == 0) { // VR mode only.
351                     // Ensure that POWER_HINT_LAUNCH is not in progress.
352                     if (launch_mode == 1) {
353                         release_request(launch_handle);
354                         launch_mode = 0;
355                     }
356                     // 0x40804000: cpu0 max freq
357                     // 0x40804100: cpu2 max freq
358                     // 0x40800000: cpu0 min freq
359                     // 0x40800100: cpu2 min freq
360                     // 0x42C20000: gpu max freq
361                     // 0x42C24000: gpu min freq
362                     // 0x42C28000: gpu bus min freq
363                     int resources[] = {0x40800000, 1440, 0x40800100, 1440,
364                                        0x40804000, 1440, 0x40804100, 1440,
365                                        0x42C20000, 510,  0x42C24000, 510,
366                                        0x42C28000, 7759};
367                     vr_mode_handle = interaction_with_handle(
368                         vr_mode_handle, duration,
369                         sizeof(resources) / sizeof(resources[0]), resources);
370                 } else if (sustained_performance_mode == 1) { // Sustained + VR mode.
371                     release_request(sustained_mode_handle);
372                     // 0x40800000: cpu0 min freq
373                     // 0x40800100: cpu2 min freq
374                     // 0x42C24000: gpu min freq
375                     // 0x42C28000: gpu bus min freq
376                     int resources[] = {0x40800000, 1209, 0x40800100, 1209,
377                                        0x42C24000, 315,  0x42C28000, 7759};
378                     vr_mode_handle = interaction_with_handle(
379                         vr_mode_handle, duration,
380                         sizeof(resources) / sizeof(resources[0]), resources);
381                 }
382                 vr_mode = 1;
383             } else if (vr_mode == 1) {
384                 release_request(vr_mode_handle);
385                 if (sustained_performance_mode == 1) { // Switch back to sustained Mode.
386                     // 0x40804000: cpu0 max freq
387                     // 0x40804100: cpu2 max freq
388                     // 0x40800000: cpu0 min freq
389                     // 0x40800100: cpu2 min freq
390                     // 0x42C20000: gpu max freq
391                     // 0x42C24000: gpu min freq
392                     // 0x42C28000: gpu bus min freq
393                     int resources[] = {0x40800000, 0,    0x40800100, 0,
394                                        0x40804000, 1209, 0x40804100, 1209,
395                                        0x42C24000, 133,  0x42C20000, 315,
396                                        0x42C28000, 0};
397                     sustained_mode_handle = interaction_with_handle(
398                         sustained_mode_handle, duration,
399                         sizeof(resources) / sizeof(resources[0]), resources);
400                 }
401                 vr_mode = 0;
402             }
403             pthread_mutex_unlock(&s_interaction_lock);
404         }
405         break;
406         case POWER_HINT_INTERACTION:
407         {
408             char governor[80];
409 
410             if (get_scaling_governor(governor, sizeof(governor)) == -1) {
411                 ALOGE("Can't obtain scaling governor.");
412                 return;
413             }
414 
415             pthread_mutex_lock(&s_interaction_lock);
416             if (sustained_performance_mode || vr_mode) {
417                 pthread_mutex_unlock(&s_interaction_lock);
418                 return;
419             }
420             pthread_mutex_unlock(&s_interaction_lock);
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             pthread_mutex_lock(&s_interaction_lock);
435             long long elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
436             // don't hint if previous hint's duration covers this hint's duration
437             if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
438                 pthread_mutex_unlock(&s_interaction_lock);
439                 return;
440             }
441             s_previous_boost_timespec = cur_boost_timespec;
442             s_previous_duration = duration;
443             pthread_mutex_unlock(&s_interaction_lock);
444 
445             // Scheduler is EAS.
446             if (true || strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) {
447                 // Setting the value of foreground schedtune boost to 50 and
448                 // scaling_min_freq to 1100MHz.
449                 int resources[] = {0x40800000, 1100, 0x40800100, 1100, 0x42C0C000, 0x32, 0x41800000, 0x33};
450                 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
451             } else { // Scheduler is HMP.
452                 int resources[] = {0x41800000, 0x33, 0x40800000, 1000, 0x40800100, 1000, 0x40C00000, 0x1};
453                 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
454             }
455         }
456         break;
457         case POWER_HINT_VIDEO_ENCODE:
458             process_video_encode_hint(data);
459         break;
460         case POWER_HINT_VIDEO_DECODE:
461             process_video_decode_hint(data);
462         break;
463     }
464 }
465 
set_interactive_override(struct power_module * module,int on)466 int __attribute__ ((weak)) set_interactive_override(struct power_module *module, int on)
467 {
468     return HINT_NONE;
469 }
470 
set_interactive(struct power_module * module,int on)471 void set_interactive(struct power_module *module, int on)
472 {
473     char governor[80];
474     char tmp_str[NODE_MAX];
475     struct video_encode_metadata_t video_encode_metadata;
476     int rc = 0;
477 
478     if (set_interactive_override(module, on) == HINT_HANDLED) {
479         return;
480     }
481 
482     ALOGI("Got set_interactive hint");
483 
484     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
485         ALOGE("Can't obtain scaling governor.");
486 
487         return;
488     }
489 
490     if (!on) {
491         /* Display off. */
492         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
493                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
494             int resource_values[] = {DISPLAY_OFF, MS_500, THREAD_MIGRATION_SYNC_OFF};
495 
496             if (!display_hint_sent) {
497                 perform_hint_action(DISPLAY_STATE_HINT_ID,
498                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
499                 display_hint_sent = 1;
500             }
501         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
502                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
503             int resource_values[] = {TR_MS_50, THREAD_MIGRATION_SYNC_OFF};
504 
505             if (!display_hint_sent) {
506                 perform_hint_action(DISPLAY_STATE_HINT_ID,
507                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
508                 display_hint_sent = 1;
509             }
510         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
511                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
512             if (saved_interactive_mode == 1){
513                 /* Display turned off. */
514                 if (sysfs_read(DCVS_CPU0_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
515                     if (!slack_node_rw_failed) {
516                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MAX_NODE);
517                     }
518 
519                     rc = 1;
520                 } else {
521                     saved_dcvs_cpu0_slack_max = atoi(tmp_str);
522                 }
523 
524                 if (sysfs_read(DCVS_CPU0_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
525                     if (!slack_node_rw_failed) {
526                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MIN_NODE);
527                     }
528 
529                     rc = 1;
530                 } else {
531                     saved_dcvs_cpu0_slack_min = atoi(tmp_str);
532                 }
533 
534                 if (sysfs_read(MPDECISION_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
535                     if (!slack_node_rw_failed) {
536                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MAX_NODE);
537                     }
538 
539                     rc = 1;
540                 } else {
541                     saved_mpdecision_slack_max = atoi(tmp_str);
542                 }
543 
544                 if (sysfs_read(MPDECISION_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
545                     if(!slack_node_rw_failed) {
546                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MIN_NODE);
547                     }
548 
549                     rc = 1;
550                 } else {
551                     saved_mpdecision_slack_min = atoi(tmp_str);
552                 }
553 
554                 /* Write new values. */
555                 if (saved_dcvs_cpu0_slack_max != -1) {
556                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_max);
557 
558                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
559                         if (!slack_node_rw_failed) {
560                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
561                         }
562 
563                         rc = 1;
564                     }
565                 }
566 
567                 if (saved_dcvs_cpu0_slack_min != -1) {
568                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_min);
569 
570                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
571                         if(!slack_node_rw_failed) {
572                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
573                         }
574 
575                         rc = 1;
576                     }
577                 }
578 
579                 if (saved_mpdecision_slack_max != -1) {
580                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_max);
581 
582                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
583                         if(!slack_node_rw_failed) {
584                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
585                         }
586 
587                         rc = 1;
588                     }
589                 }
590 
591                 if (saved_mpdecision_slack_min != -1) {
592                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_min);
593 
594                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
595                         if(!slack_node_rw_failed) {
596                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
597                         }
598 
599                         rc = 1;
600                     }
601                 }
602             }
603 
604             slack_node_rw_failed = rc;
605         }
606     } else {
607         /* Display on. */
608         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
609                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
610             undo_hint_action(DISPLAY_STATE_HINT_ID);
611             display_hint_sent = 0;
612         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
613                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
614             undo_hint_action(DISPLAY_STATE_HINT_ID);
615             display_hint_sent = 0;
616         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
617                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
618             if (saved_interactive_mode == -1 || saved_interactive_mode == 0) {
619                 /* Display turned on. Restore if possible. */
620                 if (saved_dcvs_cpu0_slack_max != -1) {
621                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_max);
622 
623                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
624                         if (!slack_node_rw_failed) {
625                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
626                         }
627 
628                         rc = 1;
629                     }
630                 }
631 
632                 if (saved_dcvs_cpu0_slack_min != -1) {
633                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_min);
634 
635                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
636                         if (!slack_node_rw_failed) {
637                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
638                         }
639 
640                         rc = 1;
641                     }
642                 }
643 
644                 if (saved_mpdecision_slack_max != -1) {
645                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_max);
646 
647                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
648                         if (!slack_node_rw_failed) {
649                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
650                         }
651 
652                         rc = 1;
653                     }
654                 }
655 
656                 if (saved_mpdecision_slack_min != -1) {
657                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_min);
658 
659                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
660                         if (!slack_node_rw_failed) {
661                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
662                         }
663 
664                         rc = 1;
665                     }
666                 }
667             }
668 
669             slack_node_rw_failed = rc;
670         }
671     }
672 
673     saved_interactive_mode = !!on;
674 }
675 
get_number_of_platform_modes(struct power_module * module)676 static ssize_t get_number_of_platform_modes(struct power_module *module) {
677    return PLATFORM_SLEEP_MODES;
678 }
679 
get_voter_list(struct power_module * module,size_t * voter)680 static int get_voter_list(struct power_module *module, size_t *voter) {
681    voter[0] = XO_VOTERS;
682    voter[1] = VMIN_VOTERS;
683 
684    return 0;
685 }
686 
extract_stats(uint64_t * list,char * file,unsigned int num_parameters,unsigned int index)687 static int extract_stats(uint64_t *list, char *file,
688     unsigned int num_parameters, unsigned int index) {
689     FILE *fp;
690     ssize_t read;
691     size_t len;
692     char *line;
693     int ret;
694 
695     fp = fopen(file, "r");
696     if (fp == NULL) {
697         ret = -errno;
698         ALOGE("%s: failed to open: %s", __func__, strerror(errno));
699         return ret;
700     }
701 
702     for (line = NULL, len = 0;
703          ((read = getline(&line, &len, fp) != -1) && (index < num_parameters));
704          free(line), line = NULL, len = 0) {
705         uint64_t value;
706         char* offset;
707 
708         size_t begin = strspn(line, " \t");
709         if (strncmp(line + begin, parameter_names[index], strlen(parameter_names[index]))) {
710             continue;
711         }
712 
713         offset = memchr(line, ':', len);
714         if (!offset) {
715             continue;
716         }
717 
718         if (!strcmp(file, RPM_MASTER_STAT)) {
719             /* RPM_MASTER_STAT is reported in hex */
720             sscanf(offset, ":%" SCNx64, &value);
721             /* Duration is reported in rpm SLEEP TICKS */
722             if (!strcmp(parameter_names[index], "xo_accumulated_duration")) {
723                 value /= RPM_CLK;
724             }
725         } else {
726             /* RPM_STAT is reported in decimal */
727             sscanf(offset, ":%" SCNu64, &value);
728         }
729         list[index] = value;
730         index++;
731     }
732     free(line);
733 
734     fclose(fp);
735     return 0;
736 }
737 
get_platform_low_power_stats(struct power_module * module,power_state_platform_sleep_state_t * list)738 static int get_platform_low_power_stats(struct power_module *module,
739     power_state_platform_sleep_state_t *list) {
740     uint64_t stats[sizeof(parameter_names)] = {0};
741     int ret;
742 
743     if (!list) {
744         return -EINVAL;
745     }
746 
747     ret = extract_stats(stats, RPM_STAT, RPM_PARAMETERS, 0);
748 
749     if (ret) {
750         return ret;
751     }
752 
753     ret = extract_stats(stats, RPM_MASTER_STAT, NUM_PARAMETERS, RPM_PARAMETERS);
754 
755     if (ret) {
756         return ret;
757     }
758 
759     /* Update statistics for XO_shutdown */
760     strcpy(list[0].name, "XO_shutdown");
761     list[0].total_transitions = stats[0];
762     list[0].residency_in_msec_since_boot = stats[1];
763     list[0].supported_only_in_suspend = false;
764     list[0].number_of_voters = XO_VOTERS;
765 
766     /* Update statistics for APSS voter */
767     strcpy(list[0].voters[0].name, "APSS");
768     list[0].voters[0].total_time_in_msec_voted_for_since_boot = stats[4];
769     list[0].voters[0].total_number_of_times_voted_since_boot = stats[5];
770 
771     /* Update statistics for MPSS voter */
772     strcpy(list[0].voters[1].name, "MPSS");
773     list[0].voters[1].total_time_in_msec_voted_for_since_boot = stats[6];
774     list[0].voters[1].total_number_of_times_voted_since_boot = stats[7];
775 
776     /* Update statistics for ADSP voter */
777     strcpy(list[0].voters[2].name, "ADSP");
778     list[0].voters[2].total_time_in_msec_voted_for_since_boot = stats[8];
779     list[0].voters[2].total_number_of_times_voted_since_boot = stats[9];
780 
781     /* Update statistics for SLPI voter */
782     strcpy(list[0].voters[3].name, "SLPI");
783     list[0].voters[3].total_time_in_msec_voted_for_since_boot = stats[10];
784     list[0].voters[3].total_number_of_times_voted_since_boot = stats[11];
785 
786     /* Update statistics for VMIN state */
787     strcpy(list[1].name, "VMIN");
788     list[1].total_transitions = stats[2];
789     list[1].residency_in_msec_since_boot = stats[3];
790     list[1].supported_only_in_suspend = false;
791     list[1].number_of_voters = VMIN_VOTERS;
792 
793     return 0;
794 }
795 
796 struct power_module HAL_MODULE_INFO_SYM = {
797     .common = {
798         .tag = HARDWARE_MODULE_TAG,
799         .module_api_version = POWER_MODULE_API_VERSION_0_5,
800         .hal_api_version = HARDWARE_HAL_API_VERSION,
801         .id = POWER_HARDWARE_MODULE_ID,
802         .name = "QCOM Power HAL",
803         .author = "Qualcomm",
804         .methods = &power_module_methods,
805     },
806 
807     .init = power_init,
808     .powerHint = power_hint,
809     .setInteractive = set_interactive,
810     .get_number_of_platform_modes = get_number_of_platform_modes,
811     .get_platform_low_power_stats = get_platform_low_power_stats,
812     .get_voter_list = get_voter_list
813 };
814