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