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