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 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 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 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 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 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 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 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 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 213 void release_request(int lock_handle) { 214 if (qcopt_handle && perf_lock_rel) 215 perf_lock_rel(lock_handle); 216 } 217 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 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 */ 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