• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012-2013,2015-2016, 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 #define LOG_NIDEBUG 0
30 
31 #include <dlfcn.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include "utils.h"
39 #include "list.h"
40 #include "hint-data.h"
41 #include "power-common.h"
42 
43 #define LOG_TAG "QCOM PowerHAL"
44 #include <utils/Log.h>
45 
46 static void *qcopt_handle;
47 static int (*perf_lock_acq)(unsigned long handle, int duration,
48     int list[], int numArgs);
49 static int (*perf_lock_rel)(unsigned long handle);
50 static struct list_node active_hint_list_head;
51 
get_qcopt_handle()52 static void *get_qcopt_handle()
53 {
54     char qcopt_lib_path[PATH_MAX] = {0};
55     void *handle = NULL;
56 
57     dlerror();
58 
59     if (property_get("ro.vendor.extension_library", qcopt_lib_path,
60                 NULL)) {
61         handle = dlopen(qcopt_lib_path, RTLD_NOW);
62         if (!handle) {
63             ALOGE("Unable to open %s: %s\n", qcopt_lib_path,
64                     dlerror());
65         }
66     }
67 
68     return handle;
69 }
70 
initialize(void)71 static void __attribute__ ((constructor)) initialize(void)
72 {
73     qcopt_handle = get_qcopt_handle();
74 
75     if (!qcopt_handle) {
76         ALOGE("Failed to get qcopt handle.\n");
77     } else {
78         /*
79          * qc-opt handle obtained. Get the perflock acquire/release
80          * function pointers.
81          */
82         perf_lock_acq = dlsym(qcopt_handle, "perf_lock_acq");
83 
84         if (!perf_lock_acq) {
85             ALOGE("Unable to get perf_lock_acq function handle.\n");
86         }
87 
88         perf_lock_rel = dlsym(qcopt_handle, "perf_lock_rel");
89 
90         if (!perf_lock_rel) {
91             ALOGE("Unable to get perf_lock_rel function handle.\n");
92         }
93     }
94 }
95 
cleanup(void)96 static void __attribute__ ((destructor)) cleanup(void)
97 {
98     if (qcopt_handle) {
99         if (dlclose(qcopt_handle))
100             ALOGE("Error occurred while closing qc-opt library.");
101     }
102 }
103 
sysfs_read(char * path,char * s,int num_bytes)104 int sysfs_read(char *path, char *s, int num_bytes)
105 {
106     char buf[80];
107     int count;
108     int ret = 0;
109     int fd = open(path, O_RDONLY);
110 
111     if (fd < 0) {
112         strerror_r(errno, buf, sizeof(buf));
113         ALOGE("Error opening %s: %s\n", path, buf);
114 
115         return -1;
116     }
117 
118     if ((count = read(fd, s, num_bytes - 1)) < 0) {
119         strerror_r(errno, buf, sizeof(buf));
120         ALOGE("Error writing to %s: %s\n", path, buf);
121 
122         ret = -1;
123     } else {
124         s[count] = '\0';
125     }
126 
127     close(fd);
128 
129     return ret;
130 }
131 
sysfs_write(char * path,char * s)132 int sysfs_write(char *path, char *s)
133 {
134     char buf[80];
135     int len;
136     int ret = 0;
137     int fd = open(path, O_WRONLY);
138 
139     if (fd < 0) {
140         strerror_r(errno, buf, sizeof(buf));
141         ALOGE("Error opening %s: %s\n", path, buf);
142         return -1 ;
143     }
144 
145     len = write(fd, s, strlen(s));
146     if (len < 0) {
147         strerror_r(errno, buf, sizeof(buf));
148         ALOGE("Error writing to %s: %s\n", path, buf);
149 
150         ret = -1;
151     }
152 
153     close(fd);
154 
155     return ret;
156 }
157 
get_scaling_governor(char governor[],int size)158 int get_scaling_governor(char governor[], int size)
159 {
160     if (sysfs_read(SCALING_GOVERNOR_PATH, governor,
161                 size) == -1) {
162         // Can't obtain the scaling governor. Return.
163         return -1;
164     } else {
165         // Strip newline at the end.
166         int len = strlen(governor);
167 
168         len--;
169 
170         while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r'))
171             governor[len--] = '\0';
172     }
173 
174     return 0;
175 }
176 
is_interactive_governor(char * governor)177 int is_interactive_governor(char* governor) {
178    if (strncmp(governor, INTERACTIVE_GOVERNOR, (strlen(INTERACTIVE_GOVERNOR)+1)) == 0)
179       return 1;
180    return 0;
181 }
182 
interaction(int duration,int num_args,int opt_list[])183 void interaction(int duration, int num_args, int opt_list[])
184 {
185 #ifdef INTERACTION_BOOST
186     static int lock_handle = 0;
187 
188     if (duration < 0 || num_args < 1 || opt_list[0] == 0)
189         return;
190 
191     if (qcopt_handle) {
192         if (perf_lock_acq) {
193             lock_handle = perf_lock_acq(lock_handle, duration, opt_list, num_args);
194             if (lock_handle == -1)
195                 ALOGE("Failed to acquire lock.");
196         }
197     }
198 #endif
199 }
200 
interaction_with_handle(int lock_handle,int duration,int num_args,int opt_list[])201 int interaction_with_handle(int lock_handle, int duration, int num_args, int opt_list[])
202 {
203 #ifdef INTERACTION_BOOST
204     if (duration < 0 || num_args < 1 || opt_list[0] == 0)
205         return 0;
206 
207     if (qcopt_handle) {
208         if (perf_lock_acq) {
209             lock_handle = perf_lock_acq(lock_handle, duration, opt_list, num_args);
210             if (lock_handle == -1)
211                 ALOGE("Failed to acquire lock.");
212         }
213     }
214     return lock_handle;
215 #else
216     return 0;
217 #endif
218 }
219 
release_request(int lock_handle)220 void release_request(int lock_handle) {
221     if (qcopt_handle && perf_lock_rel)
222         perf_lock_rel(lock_handle);
223 }
224 
perform_hint_action(int hint_id,int resource_values[],int num_resources)225 void perform_hint_action(int hint_id, int resource_values[], int num_resources)
226 {
227     if (qcopt_handle) {
228         struct hint_data temp_hint_data = {
229             .hint_id = hint_id
230         };
231         struct list_node *found_node = find_node(&active_hint_list_head,
232                                                  &temp_hint_data);
233         if (found_node) {
234             ALOGE("hint ID %d already active", hint_id);
235             return;
236         }
237         if (perf_lock_acq) {
238             /* Acquire an indefinite lock for the requested resources. */
239             int lock_handle = perf_lock_acq(0, 0, resource_values,
240                     num_resources);
241 
242             if (lock_handle == -1) {
243                 ALOGE("%s: Failed to acquire lock.", __func__);
244             } else {
245                 /* Add this handle to our internal hint-list. */
246                 struct hint_data *new_hint =
247                     (struct hint_data *)malloc(sizeof(struct hint_data));
248 
249                 if (new_hint) {
250                     if (!active_hint_list_head.compare) {
251                         active_hint_list_head.compare =
252                             (int (*)(void *, void *))hint_compare;
253                         active_hint_list_head.dump = (void (*)(void *))hint_dump;
254                     }
255 
256                     new_hint->hint_id = hint_id;
257                     new_hint->perflock_handle = lock_handle;
258 
259                     if (add_list_node(&active_hint_list_head, new_hint) == NULL) {
260                         free(new_hint);
261                         /* Can't keep track of this lock. Release it. */
262                         if (perf_lock_rel)
263                             perf_lock_rel(lock_handle);
264 
265                         ALOGE("Failed to process hint.");
266                     }
267                 } else {
268                     /* Can't keep track of this lock. Release it. */
269                     if (perf_lock_rel)
270                         perf_lock_rel(lock_handle);
271 
272                     ALOGE("Failed to process hint.");
273                 }
274             }
275         }
276     }
277 }
278 
undo_hint_action(int hint_id)279 void undo_hint_action(int hint_id)
280 {
281     if (qcopt_handle) {
282         if (perf_lock_rel) {
283             /* Get hint-data associated with this hint-id */
284             struct list_node *found_node;
285             struct hint_data temp_hint_data = {
286                 .hint_id = hint_id
287             };
288 
289             found_node = find_node(&active_hint_list_head,
290                     &temp_hint_data);
291 
292             if (found_node) {
293                 /* Release this lock. */
294                 struct hint_data *found_hint_data =
295                     (struct hint_data *)(found_node->data);
296 
297                 if (found_hint_data) {
298                     if (perf_lock_rel(found_hint_data->perflock_handle) == -1)
299                         ALOGE("Perflock release failed: %d", hint_id);
300                 }
301 
302                 if (found_node->data) {
303                     /* We can free the hint-data for this node. */
304                     free(found_node->data);
305                 }
306 
307                 remove_list_node(&active_hint_list_head, found_node);
308                 ALOGV("Undo of hint ID %d succeeded", hint_id);
309             } else {
310                 ALOGE("Invalid hint ID: %d", hint_id);
311             }
312         }
313     }
314 }
315 
316 /*
317  * Used to release initial lock holding
318  * two cores online when the display is on
319  */
undo_initial_hint_action()320 void undo_initial_hint_action()
321 {
322     if (qcopt_handle) {
323         if (perf_lock_rel) {
324             perf_lock_rel(1);
325         }
326     }
327 }
328