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