• 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/power.h>
44 
45 #include "utils.h"
46 #include "metadata-defs.h"
47 #include "hint-data.h"
48 #include "performance.h"
49 #include "power-common.h"
50 #include "power-helper.h"
51 
52 #ifndef RPM_SYSTEM_STAT
53 #define RPM_SYSTEM_STAT "/d/system_stats"
54 #endif
55 
56 #ifndef WLAN_POWER_STAT
57 #define WLAN_POWER_STAT "/d/wlan0/power_stats"
58 #endif
59 
60 #define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0]))
61 #define LINE_SIZE 128
62 
63 const char *rpm_stat_params[MAX_RPM_PARAMS] = {
64     "count",
65     "actual last sleep(msec)",
66 };
67 
68 const char *master_stat_params[MAX_RPM_PARAMS] = {
69     "Accumulated XO duration",
70     "XO Count",
71 };
72 
73 struct stat_pair rpm_stat_map[] = {
74     { RPM_MODE_XO,   "RPM Mode:vlow", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) },
75     { RPM_MODE_VMIN, "RPM Mode:vmin", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) },
76     { VOTER_APSS,    "APSS",    master_stat_params, ARRAY_SIZE(master_stat_params) },
77     { VOTER_MPSS,    "MPSS",    master_stat_params, ARRAY_SIZE(master_stat_params) },
78     { VOTER_ADSP,    "ADSP",    master_stat_params, ARRAY_SIZE(master_stat_params) },
79     { VOTER_SLPI,    "SLPI",    master_stat_params, ARRAY_SIZE(master_stat_params) },
80 };
81 
82 
83 const char *wlan_power_stat_params[] = {
84     "cumulative_sleep_time_ms",
85     "cumulative_total_on_time_ms",
86     "deep_sleep_enter_counter",
87     "last_deep_sleep_enter_tstamp_ms"
88 };
89 
90 struct stat_pair wlan_stat_map[] = {
91     { WLAN_POWER_DEBUG_STATS, "POWER DEBUG STATS", wlan_power_stat_params, ARRAY_SIZE(wlan_power_stat_params) },
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 
power_init(void)102 void power_init(void)
103 {
104     ALOGI("QCOM power HAL initing.");
105 }
106 
power_hint_override(power_hint_t UNUSED (hint),void * UNUSED (data))107 int __attribute__ ((weak)) power_hint_override(power_hint_t UNUSED(hint),
108                                                void *UNUSED(data))
109 {
110     return HINT_NONE;
111 }
112 
113 /* Declare function before use */
114 void interaction(int duration, int num_args, int opt_list[]);
115 
power_hint(power_hint_t hint,void * data)116 void power_hint(power_hint_t hint, void *data)
117 {
118     /* Check if this hint has been overridden. */
119     if (power_hint_override(hint, data) == HINT_HANDLED) {
120         /* The power_hint has been handled. We can skip the rest. */
121         return;
122     }
123 
124     switch(hint) {
125         case POWER_HINT_VSYNC:
126         break;
127         case POWER_HINT_SUSTAINED_PERFORMANCE:
128             ALOGD("Sustained perf power hint not handled in power_hint_override");
129             break;
130         case POWER_HINT_VR_MODE:
131             ALOGD("VR mode power hint not handled in power_hint_override");
132             break;
133         case POWER_HINT_INTERACTION:
134         {
135             int resources[] = {0x702, 0x20F, 0x30F};
136             int duration = 3000;
137 
138             interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
139         }
140             break;
141         default:
142         break;
143     }
144 }
145 
is_perf_hint_active(int UNUSED (hint))146 int __attribute__ ((weak)) is_perf_hint_active(int UNUSED(hint))
147 {
148     return 0;
149 }
150 
set_interactive_override(int UNUSED (on))151 int __attribute__ ((weak)) set_interactive_override(int UNUSED(on))
152 {
153     return HINT_NONE;
154 }
155 
power_set_interactive(int on)156 void power_set_interactive(int on)
157 {
158     char governor[80];
159     char tmp_str[NODE_MAX];
160     struct video_encode_metadata_t video_encode_metadata;
161     int rc = 0;
162 
163     if (set_interactive_override(on) == HINT_HANDLED) {
164         return;
165     }
166 
167     ALOGD("Got set_interactive hint");
168 
169     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
170         ALOGE("Can't obtain scaling governor.");
171 
172         return;
173     }
174 
175     if (!on) {
176         /* Display off. */
177         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
178                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
179             int resource_values[] = {DISPLAY_OFF, MS_500, THREAD_MIGRATION_SYNC_OFF};
180 
181             if (!display_hint_sent) {
182                 perform_hint_action(DISPLAY_STATE_HINT_ID,
183                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
184                 display_hint_sent = 1;
185             }
186         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
187                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
188             int resource_values[] = {TR_MS_50, THREAD_MIGRATION_SYNC_OFF};
189 
190             if (!display_hint_sent) {
191                 perform_hint_action(DISPLAY_STATE_HINT_ID,
192                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
193                 display_hint_sent = 1;
194             }
195         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
196                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
197             if (saved_interactive_mode == 1){
198                 /* Display turned off. */
199                 if (sysfs_read(DCVS_CPU0_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
200                     if (!slack_node_rw_failed) {
201                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MAX_NODE);
202                     }
203 
204                     rc = 1;
205                 } else {
206                     saved_dcvs_cpu0_slack_max = atoi(tmp_str);
207                 }
208 
209                 if (sysfs_read(DCVS_CPU0_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
210                     if (!slack_node_rw_failed) {
211                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MIN_NODE);
212                     }
213 
214                     rc = 1;
215                 } else {
216                     saved_dcvs_cpu0_slack_min = atoi(tmp_str);
217                 }
218 
219                 if (sysfs_read(MPDECISION_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
220                     if (!slack_node_rw_failed) {
221                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MAX_NODE);
222                     }
223 
224                     rc = 1;
225                 } else {
226                     saved_mpdecision_slack_max = atoi(tmp_str);
227                 }
228 
229                 if (sysfs_read(MPDECISION_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
230                     if(!slack_node_rw_failed) {
231                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MIN_NODE);
232                     }
233 
234                     rc = 1;
235                 } else {
236                     saved_mpdecision_slack_min = atoi(tmp_str);
237                 }
238 
239                 /* Write new values. */
240                 if (saved_dcvs_cpu0_slack_max != -1) {
241                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_max);
242 
243                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
244                         if (!slack_node_rw_failed) {
245                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
246                         }
247 
248                         rc = 1;
249                     }
250                 }
251 
252                 if (saved_dcvs_cpu0_slack_min != -1) {
253                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_min);
254 
255                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
256                         if(!slack_node_rw_failed) {
257                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
258                         }
259 
260                         rc = 1;
261                     }
262                 }
263 
264                 if (saved_mpdecision_slack_max != -1) {
265                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_max);
266 
267                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
268                         if(!slack_node_rw_failed) {
269                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
270                         }
271 
272                         rc = 1;
273                     }
274                 }
275 
276                 if (saved_mpdecision_slack_min != -1) {
277                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_min);
278 
279                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
280                         if(!slack_node_rw_failed) {
281                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
282                         }
283 
284                         rc = 1;
285                     }
286                 }
287             }
288 
289             slack_node_rw_failed = rc;
290         }
291     } else {
292         /* Display on. */
293         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
294                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
295             undo_hint_action(DISPLAY_STATE_HINT_ID);
296             display_hint_sent = 0;
297         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
298                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
299             undo_hint_action(DISPLAY_STATE_HINT_ID);
300             display_hint_sent = 0;
301         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
302                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
303             if (saved_interactive_mode == -1 || saved_interactive_mode == 0) {
304                 /* Display turned on. Restore if possible. */
305                 if (saved_dcvs_cpu0_slack_max != -1) {
306                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_max);
307 
308                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
309                         if (!slack_node_rw_failed) {
310                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
311                         }
312 
313                         rc = 1;
314                     }
315                 }
316 
317                 if (saved_dcvs_cpu0_slack_min != -1) {
318                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_min);
319 
320                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
321                         if (!slack_node_rw_failed) {
322                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
323                         }
324 
325                         rc = 1;
326                     }
327                 }
328 
329                 if (saved_mpdecision_slack_max != -1) {
330                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_max);
331 
332                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
333                         if (!slack_node_rw_failed) {
334                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
335                         }
336 
337                         rc = 1;
338                     }
339                 }
340 
341                 if (saved_mpdecision_slack_min != -1) {
342                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_min);
343 
344                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
345                         if (!slack_node_rw_failed) {
346                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
347                         }
348 
349                         rc = 1;
350                     }
351                 }
352             }
353 
354             slack_node_rw_failed = rc;
355         }
356     }
357 
358     saved_interactive_mode = !!on;
359 }
360 
361 
parse_stats(const char ** params,size_t params_size,uint64_t * list,FILE * fp)362 static int parse_stats(const char **params, size_t params_size,
363                        uint64_t *list, FILE *fp) {
364     ssize_t nread;
365     size_t len = LINE_SIZE;
366     char *line;
367     size_t params_read = 0;
368     size_t i;
369 
370     line = malloc(len);
371     if (!line) {
372         ALOGE("%s: no memory to hold line", __func__);
373         return -ENOMEM;
374     }
375 
376     while ((params_read < params_size) &&
377         (nread = getline(&line, &len, fp) > 0)) {
378         char *key = line + strspn(line, " \t");
379         char *value = strchr(key, ':');
380         if (!value || (value > (line + len)))
381             continue;
382         *value++ = '\0';
383 
384         for (i = 0; i < params_size; i++) {
385             if (!strcmp(key, params[i])) {
386                 list[i] = strtoull(value, NULL, 0);
387                 params_read++;
388                 break;
389             }
390         }
391     }
392     free(line);
393 
394     return 0;
395 }
396 
397 
extract_stats(uint64_t * list,char * file,struct stat_pair * map,size_t map_size)398 static int extract_stats(uint64_t *list, char *file,
399                          struct stat_pair *map, size_t map_size) {
400     FILE *fp;
401     ssize_t read;
402     size_t len = LINE_SIZE;
403     char *line;
404     size_t i, stats_read = 0;
405     int ret = 0;
406 
407     fp = fopen(file, "re");
408     if (fp == NULL) {
409         ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
410         return -errno;
411     }
412 
413     line = malloc(len);
414     if (!line) {
415         ALOGE("%s: no memory to hold line", __func__);
416         fclose(fp);
417         return -ENOMEM;
418     }
419 
420     while ((stats_read < map_size) && (read = getline(&line, &len, fp) != -1)) {
421         size_t begin = strspn(line, " \t");
422 
423         for (i = 0; i < map_size; i++) {
424             if (!strncmp(line + begin, map[i].label, strlen(map[i].label))) {
425                 stats_read++;
426                 break;
427             }
428         }
429 
430         if (i == map_size)
431             continue;
432 
433         ret = parse_stats(map[i].parameters, map[i].num_parameters,
434                           &list[map[i].stat * MAX_RPM_PARAMS], fp);
435         if (ret < 0)
436             break;
437     }
438     free(line);
439     fclose(fp);
440 
441     return ret;
442 }
443 
extract_platform_stats(uint64_t * list)444 int extract_platform_stats(uint64_t *list) {
445     return extract_stats(list, RPM_SYSTEM_STAT, rpm_stat_map, ARRAY_SIZE(rpm_stat_map));
446 }
447 
extract_wlan_stats(uint64_t * list)448 int extract_wlan_stats(uint64_t *list) {
449     return extract_stats(list, WLAN_POWER_STAT, wlan_stat_map, ARRAY_SIZE(wlan_stat_map));
450 }
451