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
release_request(int lock_handle)213 void release_request(int lock_handle) {
214 if (qcopt_handle && perf_lock_rel)
215 perf_lock_rel(lock_handle);
216 }
217
perform_hint_action(int hint_id,int resource_values[],int num_resources)218 void perform_hint_action(int hint_id, int resource_values[], int num_resources)
219 {
220 if (qcopt_handle) {
221 if (perf_lock_acq) {
222 /* Acquire an indefinite lock for the requested resources. */
223 int lock_handle = perf_lock_acq(0, 0, resource_values,
224 num_resources);
225
226 if (lock_handle == -1) {
227 ALOGE("Failed to acquire lock.");
228 } else {
229 /* Add this handle to our internal hint-list. */
230 struct hint_data *new_hint =
231 (struct hint_data *)malloc(sizeof(struct hint_data));
232
233 if (new_hint) {
234 if (!active_hint_list_head.compare) {
235 active_hint_list_head.compare =
236 (int (*)(void *, void *))hint_compare;
237 active_hint_list_head.dump = (void (*)(void *))hint_dump;
238 }
239
240 new_hint->hint_id = hint_id;
241 new_hint->perflock_handle = lock_handle;
242
243 if (add_list_node(&active_hint_list_head, new_hint) == NULL) {
244 free(new_hint);
245 /* Can't keep track of this lock. Release it. */
246 if (perf_lock_rel)
247 perf_lock_rel(lock_handle);
248
249 ALOGE("Failed to process hint.");
250 }
251 } else {
252 /* Can't keep track of this lock. Release it. */
253 if (perf_lock_rel)
254 perf_lock_rel(lock_handle);
255
256 ALOGE("Failed to process hint.");
257 }
258 }
259 }
260 }
261 }
262
undo_hint_action(int hint_id)263 void undo_hint_action(int hint_id)
264 {
265 if (qcopt_handle) {
266 if (perf_lock_rel) {
267 /* Get hint-data associated with this hint-id */
268 struct list_node *found_node;
269 struct hint_data temp_hint_data = {
270 .hint_id = hint_id
271 };
272
273 found_node = find_node(&active_hint_list_head,
274 &temp_hint_data);
275
276 if (found_node) {
277 /* Release this lock. */
278 struct hint_data *found_hint_data =
279 (struct hint_data *)(found_node->data);
280
281 if (found_hint_data) {
282 if (perf_lock_rel(found_hint_data->perflock_handle) == -1)
283 ALOGE("Perflock release failed.");
284 }
285
286 if (found_node->data) {
287 /* We can free the hint-data for this node. */
288 free(found_node->data);
289 }
290
291 remove_list_node(&active_hint_list_head, found_node);
292 } else {
293 ALOGE("Invalid hint ID.");
294 }
295 }
296 }
297 }
298
299 /*
300 * Used to release initial lock holding
301 * two cores online when the display is on
302 */
undo_initial_hint_action()303 void undo_initial_hint_action()
304 {
305 if (qcopt_handle) {
306 if (perf_lock_rel) {
307 perf_lock_rel(1);
308 }
309 }
310 }
311