• 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 
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