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 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 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 */ 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