blob: 787aa93537f808537b9f31388e1c061a33bee558 [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>
Ajay Dudani5e676802015-04-07 23:56:52 -070034#include <stdlib.h>
35#include <string.h>
Anurag Singh6ec12062012-10-02 09:59:01 -070036
37#include "utils.h"
38#include "list.h"
39#include "hint-data.h"
Anurag Singh057806b2013-04-16 16:53:45 -070040#include "power-common.h"
Anurag Singh6ec12062012-10-02 09:59:01 -070041
42#define LOG_TAG "QCOM PowerHAL"
43#include <utils/Log.h>
44
Anurag Singh6ec12062012-10-02 09:59:01 -070045static void *qcopt_handle;
Anurag Singh6ec12062012-10-02 09:59:01 -070046static int (*perf_lock_acq)(unsigned long handle, int duration,
47 int list[], int numArgs);
Anurag Singh6ec12062012-10-02 09:59:01 -070048static int (*perf_lock_rel)(unsigned long handle);
Anurag Singh6ec12062012-10-02 09:59:01 -070049static struct list_node active_hint_list_head;
50
51static void *get_qcopt_handle()
52{
Anurag Singhfe93c1d2012-11-21 15:15:56 -080053 char qcopt_lib_path[PATH_MAX] = {0};
54 void *handle = NULL;
Anurag Singh6ec12062012-10-02 09:59:01 -070055
Anurag Singhfe93c1d2012-11-21 15:15:56 -080056 dlerror();
Anurag Singh6ec12062012-10-02 09:59:01 -070057
Anurag Singhfe93c1d2012-11-21 15:15:56 -080058 if (property_get("ro.vendor.extension_library", qcopt_lib_path,
59 NULL)) {
60 handle = dlopen(qcopt_lib_path, RTLD_NOW);
61 if (!handle) {
62 ALOGE("Unable to open %s: %s\n", qcopt_lib_path,
63 dlerror());
Anurag Singh6ec12062012-10-02 09:59:01 -070064 }
65 }
66
Anurag Singhfe93c1d2012-11-21 15:15:56 -080067 return handle;
68}
69
70static void __attribute__ ((constructor)) initialize(void)
71{
72 qcopt_handle = get_qcopt_handle();
73
74 if (!qcopt_handle) {
75 ALOGE("Failed to get qcopt handle.\n");
76 } else {
77 /*
78 * qc-opt handle obtained. Get the perflock acquire/release
79 * function pointers.
80 */
81 perf_lock_acq = dlsym(qcopt_handle, "perf_lock_acq");
82
83 if (!perf_lock_acq) {
84 ALOGE("Unable to get perf_lock_acq function handle.\n");
85 }
86
87 perf_lock_rel = dlsym(qcopt_handle, "perf_lock_rel");
88
89 if (!perf_lock_rel) {
90 ALOGE("Unable to get perf_lock_rel function handle.\n");
91 }
92 }
93}
94
95static void __attribute__ ((destructor)) cleanup(void)
96{
97 if (qcopt_handle) {
98 if (dlclose(qcopt_handle))
99 ALOGE("Error occurred while closing qc-opt library.");
100 }
Anurag Singh6ec12062012-10-02 09:59:01 -0700101}
102
103int sysfs_read(char *path, char *s, int num_bytes)
104{
105 char buf[80];
106 int count;
107 int ret = 0;
108 int fd = open(path, O_RDONLY);
109
110 if (fd < 0) {
111 strerror_r(errno, buf, sizeof(buf));
112 ALOGE("Error opening %s: %s\n", path, buf);
113
114 return -1;
115 }
116
117 if ((count = read(fd, s, num_bytes - 1)) < 0) {
118 strerror_r(errno, buf, sizeof(buf));
119 ALOGE("Error writing to %s: %s\n", path, buf);
120
121 ret = -1;
122 } else {
123 s[count] = '\0';
124 }
125
126 close(fd);
127
128 return ret;
129}
130
131int sysfs_write(char *path, char *s)
132{
133 char buf[80];
134 int len;
135 int ret = 0;
136 int fd = open(path, O_WRONLY);
137
138 if (fd < 0) {
139 strerror_r(errno, buf, sizeof(buf));
140 ALOGE("Error opening %s: %s\n", path, buf);
141 return -1 ;
142 }
143
144 len = write(fd, s, strlen(s));
145 if (len < 0) {
146 strerror_r(errno, buf, sizeof(buf));
147 ALOGE("Error writing to %s: %s\n", path, buf);
148
149 ret = -1;
150 }
151
152 close(fd);
153
154 return ret;
155}
156
157int get_scaling_governor(char governor[], int size)
158{
159 if (sysfs_read(SCALING_GOVERNOR_PATH, governor,
160 size) == -1) {
161 // Can't obtain the scaling governor. Return.
162 return -1;
163 } else {
164 // Strip newline at the end.
165 int len = strlen(governor);
166
167 len--;
168
169 while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r'))
170 governor[len--] = '\0';
171 }
172
173 return 0;
174}
175
Vince Leung699c1bc2013-08-14 17:40:36 -0700176void interaction(int duration, int num_args, int opt_list[])
Vince Leung68574662013-07-16 16:47:00 -0700177{
178#ifdef INTERACTION_BOOST
179 static int lock_handle = 0;
Vince Leung699c1bc2013-08-14 17:40:36 -0700180
181 if (duration < 0 || num_args < 1 || opt_list[0] == NULL)
182 return;
183
Vince Leung68574662013-07-16 16:47:00 -0700184 if (qcopt_handle) {
185 if (perf_lock_acq) {
Vince Leung699c1bc2013-08-14 17:40:36 -0700186 lock_handle = perf_lock_acq(lock_handle, duration, opt_list, num_args);
Vince Leung68574662013-07-16 16:47:00 -0700187 if (lock_handle == -1)
188 ALOGE("Failed to acquire lock.");
189 }
190 }
191#endif
192}
193
Anurag Singh6ec12062012-10-02 09:59:01 -0700194void perform_hint_action(int hint_id, int resource_values[], int num_resources)
195{
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800196 if (qcopt_handle) {
197 if (perf_lock_acq) {
198 /* Acquire an indefinite lock for the requested resources. */
199 int lock_handle = perf_lock_acq(0, 0, resource_values,
Anurag Singh6ec12062012-10-02 09:59:01 -0700200 num_resources);
201
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800202 if (lock_handle == -1) {
203 ALOGE("Failed to acquire lock.");
204 } else {
205 /* Add this handle to our internal hint-list. */
206 struct hint_data *new_hint =
207 (struct hint_data *)malloc(sizeof(struct hint_data));
Anurag Singh6ec12062012-10-02 09:59:01 -0700208
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800209 if (new_hint) {
210 if (!active_hint_list_head.compare) {
211 active_hint_list_head.compare =
212 (int (*)(void *, void *))hint_compare;
213 active_hint_list_head.dump = (void (*)(void *))hint_dump;
214 }
Anurag Singh6ec12062012-10-02 09:59:01 -0700215
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800216 new_hint->hint_id = hint_id;
217 new_hint->perflock_handle = lock_handle;
Anurag Singh6ec12062012-10-02 09:59:01 -0700218
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800219 if (add_list_node(&active_hint_list_head, new_hint) == NULL) {
220 free(new_hint);
Anurag Singh6ec12062012-10-02 09:59:01 -0700221 /* Can't keep track of this lock. Release it. */
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800222 if (perf_lock_rel)
223 perf_lock_rel(lock_handle);
224
Anurag Singh6ec12062012-10-02 09:59:01 -0700225 ALOGE("Failed to process hint.");
226 }
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800227 } else {
228 /* Can't keep track of this lock. Release it. */
229 if (perf_lock_rel)
230 perf_lock_rel(lock_handle);
231
232 ALOGE("Failed to process hint.");
Anurag Singh6ec12062012-10-02 09:59:01 -0700233 }
Anurag Singh6ec12062012-10-02 09:59:01 -0700234 }
235 }
236 }
237}
238
239void undo_hint_action(int hint_id)
240{
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800241 if (qcopt_handle) {
242 if (perf_lock_rel) {
243 /* Get hint-data associated with this hint-id */
244 struct list_node *found_node;
245 struct hint_data temp_hint_data = {
246 .hint_id = hint_id
247 };
Anurag Singh6ec12062012-10-02 09:59:01 -0700248
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800249 found_node = find_node(&active_hint_list_head,
250 &temp_hint_data);
Anurag Singh6ec12062012-10-02 09:59:01 -0700251
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800252 if (found_node) {
253 /* Release this lock. */
254 struct hint_data *found_hint_data =
255 (struct hint_data *)(found_node->data);
Anurag Singh6ec12062012-10-02 09:59:01 -0700256
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800257 if (found_hint_data) {
258 if (perf_lock_rel(found_hint_data->perflock_handle) == -1)
Anurag Singh6ec12062012-10-02 09:59:01 -0700259 ALOGE("Perflock release failed.");
Anurag Singh6ec12062012-10-02 09:59:01 -0700260 }
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800261
262 if (found_node->data) {
263 /* We can free the hint-data for this node. */
264 free(found_node->data);
265 }
266
267 remove_list_node(&active_hint_list_head, found_node);
Anurag Singh6ec12062012-10-02 09:59:01 -0700268 } else {
Anurag Singhfe93c1d2012-11-21 15:15:56 -0800269 ALOGE("Invalid hint ID.");
Anurag Singh6ec12062012-10-02 09:59:01 -0700270 }
271 }
272 }
273}
Zhoulu Luo3b1fbdb2013-12-06 16:32:10 -0800274
275/*
276 * Used to release initial lock holding
277 * two cores online when the display is on
278 */
279void undo_initial_hint_action()
280{
281 if (qcopt_handle) {
282 if (perf_lock_rel) {
283 perf_lock_rel(1);
284 }
285 }
286}