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 
power_init(struct power_module * module)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 
process_video_decode_hint(void * metadata)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 
process_video_encode_hint(void * metadata)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 
power_hint_override(struct power_module * module,power_hint_t hint,void * data)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 
calc_timespan_us(struct timespec start,struct timespec end)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 
power_hint(struct power_module * module,power_hint_t hint,void * data)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 
set_interactive_override(struct power_module * module,int on)467 int __attribute__ ((weak)) set_interactive_override(struct power_module *module, int on)
468 {
469     return HINT_NONE;
470 }
471 
set_interactive(struct power_module * module,int on)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 
get_number_of_platform_modes(struct power_module * module)677 static ssize_t get_number_of_platform_modes(struct power_module *module) {
678    return PLATFORM_SLEEP_MODES;
679 }
680 
get_voter_list(struct power_module * module,size_t * voter)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 
extract_stats(uint64_t * list,char * file,unsigned int num_parameters,unsigned int index)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 
get_platform_low_power_stats(struct power_module * module,power_state_platform_sleep_state_t * list)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 
power_open(const hw_module_t * module,const char * name,hw_device_t ** device)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