blob: 15f7aed138d6572d87452f752ba89627559b760c [file] [log] [blame]
Anurag Singh6ec12062012-10-02 09:59:01 -07001/*
Anurag Singhfe93c1d2012-11-21 15:15:56 -08002 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Anurag Singh6ec12062012-10-02 09:59:01 -07003 *
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.
Duy Truong70222452013-02-10 06:35:11 -080013 * * Neither the name of The Linux Foundation nor the names of its
Anurag Singh6ec12062012-10-02 09:59:01 -070014 * 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 */
Anurag Singh6ec12062012-10-02 09:59:01 -070029#define LOG_NIDEBUG 0
30
31#include <dlfcn.h>
32#include <fcntl.h>
33#include <errno.h>
34
35#include "utils.h"
36#include "list.h"
37#include "hint-data.h"
Anurag Singh057806b2013-04-16 16:53:45 -070038#include "power-common.h"
Anurag Singh6ec12062012-10-02 09:59:01 -070039
40#define LOG_TAG "QCOM PowerHAL"
41#include <utils/Log.h>
42
Anurag Singh6ec12062012-10-02 09:59:01 -070043static void *qcopt_handle;
Anurag Singh6ec12062012-10-02 09:59:01 -070044static int (*perf_lock_acq)(unsigned long handle, int duration,
45 int list[], int numArgs);
Anurag Singh6ec12062012-10-02 09:59:01 -070046static int (*perf_lock_rel)(unsigned long handle);
Anurag Singh6ec12062012-10-02 09:59:01 -070047static struct list_node active_hint_list_head;
48
49static void *get_qcopt_handle()
50{
Anurag Singhfe93c1d2012-11-21 15:15:56 -080051 char qcopt_lib_path[PATH_MAX] = {0};
52 void *handle = NULL;
Anurag Singh6ec12062012-10-02 09:59:01 -070053
Anurag Singhfe93c1d2012-11-21 15:15:56 -080054 dlerror();
Anurag Singh6ec12062012-10-02 09:59:01 -070055
Anurag Singhfe93c1d2012-11-21 15:15:56 -080056 if (property_get("ro.vendor.extension_library", qcopt_lib_path,
57 NULL)) {
58 handle = dlopen(qcopt_lib_path, RTLD_NOW);
59 if (!handle) {
60 ALOGE("Unable to open %s: %s\n", qcopt_lib_path,
61 dlerror());
Anurag Singh6ec12062012-10-02 09:59:01 -070062 }
63 }
64
Anurag Singhfe93c1d2012-11-21 15:15:56 -080065 return handle;
66}
67
68static void __attribute__ ((constructor)) initialize(void)
69{
70 qcopt_handle = get_qcopt_handle();
71
72 if (!qcopt_handle) {
73 ALOGE("Failed to get qcopt handle.\n");
74 } else {
75 /*
76 * qc-opt handle obtained. Get the perflock acquire/release
77 * function pointers.
78 */
79 perf_lock_acq = dlsym(qcopt_handle, "perf_lock_acq");
80
81 if (!perf_lock_acq) {
82 ALOGE("Unable to get perf_lock_acq function handle.\n");
83 }
84
85 perf_lock_rel = dlsym(qcopt_handle, "perf_lock_rel");
86
87 if (!perf_lock_rel) {
88 ALOGE("Unable to get perf_lock_rel function handle.\n");
89 }
90 }
91}
92
93static void __attribute__ ((destructor)) cleanup(void)
94{
95 if (qcopt_handle) {
96 if (dlclose(qcopt_handle))
97 ALOGE("Error occurred while closing qc-opt library.");
98 }
Anurag Singh6ec12062012-10-02 09:59:01 -070099}
100
101int sysfs_read(char *path, char *s, int num_bytes)
102{
103 char buf[80];
104 int count;
105 int ret = 0;
106 int fd = open(path, O_RDONLY);
107
108 if (fd < 0) {
109 strerror_r(errno, buf, sizeof(buf));
110 ALOGE("Error opening %s: %s\n", path, buf);
111
112 return -1;
113 }
114
115 if ((count = read(fd, s, num_bytes - 1)) < 0) {
116 strerror_r(errno, buf, sizeof(buf));
117 ALOGE("Error writing to %s: %s\n", path, buf);
118
119 ret = -1;
120 } else {
121 s[count] = '\0';
122 }
123
124 close(fd);
125
126 return ret;
127}
128
129int sysfs_write(char *path, char *s)
130{
131 char buf[80];
132 int len;
133 int ret = 0;
134 int fd = open(path, O_WRONLY);
135
136 if (fd < 0) {
137 strerror_r(errno, buf, sizeof(buf));
138 ALOGE("Error opening %s: %s\n", path, buf);
139 return -1 ;
140 }
141
142 len = write(fd, s, strlen(s));
143 if (len < 0) {
144 strerror_r(errno, buf, sizeof(buf));
145 ALOGE("Error writing to %s: %s\n", path, buf);
146
147 ret = -1;
148 }
149
150 close(fd);
151
152 return ret;
153}
154
155int get_scaling_governor(char governor[], int size)
156{
157 if (sysfs_read(SCALING_GOVERNOR_PATH, governor,
158 size) == -1) {
159 // Can't obtain the scaling governor. Return.
160 return -1;
161 } else {
162 // Strip newline at the end.
163 int len = strlen(governor);
164
165 len--;
166
167 while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r'))
168 governor[len--] = '\0';
169 }
170
171 return 0;
172}
173
Vince Leung699c1bc2013-08-14 17:40:36 -0700174void interaction(int duration, int num_args, int opt_list[])
Vince Leung68574662013-07-16 16:47:00 -0700175{
176#ifdef INTERACTION_BOOST
177 static int lock_handle = 0;
Vince Leung699c1bc2013-08-14 17:40:36 -0700178
179 if (duration < 0 || num_args < 1 || opt_list[0] == NULL)
180 return;
181
Vince Leung68574662013-07-16 16:47:00 -0700182 if (qcopt_handle) {
183 if (perf_lock_acq) {
Vince Leung699c1bc2013-08-14 17:40:36 -0700184 lock_handle = perf_lock_acq(lock_handle, duration, opt_list, num_args);
Vince Leung68574662013-07-16 16:47:00 -0700185 if (lock_handle == -1)
186 ALOGE("Failed to acquire lock.");
187 }
188 }
189#endif
190}
191
Anurag Singh6ec12062012-10-02 09:59:01 -0700192void perform_hint_action(int hint_id, int resource_values[], int num_resources)
193{
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800194 if (qcopt_handle) {
195 if (perf_lock_acq) {
196 /* Acquire an indefinite lock for the requested resources. */
197 int lock_handle = perf_lock_acq(0, 0, resource_values,
Anurag Singh6ec12062012-10-02 09:59:01 -0700198 num_resources);
199
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800200 if (lock_handle == -1) {
201 ALOGE("Failed to acquire lock.");
202 } else {
203 /* Add this handle to our internal hint-list. */
204 struct hint_data *new_hint =
205 (struct hint_data *)malloc(sizeof(struct hint_data));
Anurag Singh6ec12062012-10-02 09:59:01 -0700206
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800207 if (new_hint) {
208 if (!active_hint_list_head.compare) {
209 active_hint_list_head.compare =
210 (int (*)(void *, void *))hint_compare;
211 active_hint_list_head.dump = (void (*)(void *))hint_dump;
212 }
Anurag Singh6ec12062012-10-02 09:59:01 -0700213
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800214 new_hint->hint_id = hint_id;
215 new_hint->perflock_handle = lock_handle;
Anurag Singh6ec12062012-10-02 09:59:01 -0700216
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800217 if (add_list_node(&active_hint_list_head, new_hint) == NULL) {
218 free(new_hint);
Anurag Singh6ec12062012-10-02 09:59:01 -0700219 /* Can't keep track of this lock. Release it. */
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800220 if (perf_lock_rel)
221 perf_lock_rel(lock_handle);
222
Anurag Singh6ec12062012-10-02 09:59:01 -0700223 ALOGE("Failed to process hint.");
224 }
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800225 } else {
226 /* Can't keep track of this lock. Release it. */
227 if (perf_lock_rel)
228 perf_lock_rel(lock_handle);
229
230 ALOGE("Failed to process hint.");
Anurag Singh6ec12062012-10-02 09:59:01 -0700231 }
Anurag Singh6ec12062012-10-02 09:59:01 -0700232 }
233 }
234 }
235}
236
237void undo_hint_action(int hint_id)
238{
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800239 if (qcopt_handle) {
240 if (perf_lock_rel) {
241 /* Get hint-data associated with this hint-id */
242 struct list_node *found_node;
243 struct hint_data temp_hint_data = {
244 .hint_id = hint_id
245 };
Anurag Singh6ec12062012-10-02 09:59:01 -0700246
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800247 found_node = find_node(&active_hint_list_head,
248 &temp_hint_data);
Anurag Singh6ec12062012-10-02 09:59:01 -0700249
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800250 if (found_node) {
251 /* Release this lock. */
252 struct hint_data *found_hint_data =
253 (struct hint_data *)(found_node->data);
Anurag Singh6ec12062012-10-02 09:59:01 -0700254
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800255 if (found_hint_data) {
256 if (perf_lock_rel(found_hint_data->perflock_handle) == -1)
Anurag Singh6ec12062012-10-02 09:59:01 -0700257 ALOGE("Perflock release failed.");
Anurag Singh6ec12062012-10-02 09:59:01 -0700258 }
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800259
260 if (found_node->data) {
261 /* We can free the hint-data for this node. */
262 free(found_node->data);
263 }
264
265 remove_list_node(&active_hint_list_head, found_node);
Anurag Singh6ec12062012-10-02 09:59:01 -0700266 } else {
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800267 ALOGE("Invalid hint ID.");
Anurag Singh6ec12062012-10-02 09:59:01 -0700268 }
269 }
270 }
271}