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