Home | History | Annotate | Download | only in power
      1 /*
      2  * Copyright (c) 2012-2013,2015-2016, 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 #include <unistd.h>
     37 
     38 #include "utils.h"
     39 #include "list.h"
     40 #include "hint-data.h"
     41 #include "power-common.h"
     42 
     43 #define LOG_TAG "QCOM PowerHAL"
     44 #include <utils/Log.h>
     45 
     46 static void *qcopt_handle;
     47 static int (*perf_lock_acq)(unsigned long handle, int duration,
     48     int list[], int numArgs);
     49 static int (*perf_lock_rel)(unsigned long handle);
     50 static struct list_node active_hint_list_head;
     51 
     52 static void *get_qcopt_handle()
     53 {
     54     char qcopt_lib_path[PATH_MAX] = {0};
     55     void *handle = NULL;
     56 
     57     dlerror();
     58 
     59     if (property_get("ro.vendor.extension_library", qcopt_lib_path,
     60                 NULL)) {
     61         handle = dlopen(qcopt_lib_path, RTLD_NOW);
     62         if (!handle) {
     63             ALOGE("Unable to open %s: %s\n", qcopt_lib_path,
     64                     dlerror());
     65         }
     66     }
     67 
     68     return handle;
     69 }
     70 
     71 static void __attribute__ ((constructor)) initialize(void)
     72 {
     73     qcopt_handle = get_qcopt_handle();
     74 
     75     if (!qcopt_handle) {
     76         ALOGE("Failed to get qcopt handle.\n");
     77     } else {
     78         /*
     79          * qc-opt handle obtained. Get the perflock acquire/release
     80          * function pointers.
     81          */
     82         perf_lock_acq = dlsym(qcopt_handle, "perf_lock_acq");
     83 
     84         if (!perf_lock_acq) {
     85             ALOGE("Unable to get perf_lock_acq function handle.\n");
     86         }
     87 
     88         perf_lock_rel = dlsym(qcopt_handle, "perf_lock_rel");
     89 
     90         if (!perf_lock_rel) {
     91             ALOGE("Unable to get perf_lock_rel function handle.\n");
     92         }
     93     }
     94 }
     95 
     96 static void __attribute__ ((destructor)) cleanup(void)
     97 {
     98     if (qcopt_handle) {
     99         if (dlclose(qcopt_handle))
    100             ALOGE("Error occurred while closing qc-opt library.");
    101     }
    102 }
    103 
    104 int sysfs_read(char *path, char *s, int num_bytes)
    105 {
    106     char buf[80];
    107     int count;
    108     int ret = 0;
    109     int fd = open(path, O_RDONLY);
    110 
    111     if (fd < 0) {
    112         strerror_r(errno, buf, sizeof(buf));
    113         ALOGE("Error opening %s: %s\n", path, buf);
    114 
    115         return -1;
    116     }
    117 
    118     if ((count = read(fd, s, num_bytes - 1)) < 0) {
    119         strerror_r(errno, buf, sizeof(buf));
    120         ALOGE("Error writing to %s: %s\n", path, buf);
    121 
    122         ret = -1;
    123     } else {
    124         s[count] = '\0';
    125     }
    126 
    127     close(fd);
    128 
    129     return ret;
    130 }
    131 
    132 int sysfs_write(char *path, char *s)
    133 {
    134     char buf[80];
    135     int len;
    136     int ret = 0;
    137     int fd = open(path, O_WRONLY);
    138 
    139     if (fd < 0) {
    140         strerror_r(errno, buf, sizeof(buf));
    141         ALOGE("Error opening %s: %s\n", path, buf);
    142         return -1 ;
    143     }
    144 
    145     len = write(fd, s, strlen(s));
    146     if (len < 0) {
    147         strerror_r(errno, buf, sizeof(buf));
    148         ALOGE("Error writing to %s: %s\n", path, buf);
    149 
    150         ret = -1;
    151     }
    152 
    153     close(fd);
    154 
    155     return ret;
    156 }
    157 
    158 int get_scaling_governor(char governor[], int size)
    159 {
    160     if (sysfs_read(SCALING_GOVERNOR_PATH, governor,
    161                 size) == -1) {
    162         // Can't obtain the scaling governor. Return.
    163         return -1;
    164     } else {
    165         // Strip newline at the end.
    166         int len = strlen(governor);
    167 
    168         len--;
    169 
    170         while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r'))
    171             governor[len--] = '\0';
    172     }
    173 
    174     return 0;
    175 }
    176 
    177 int is_interactive_governor(char* governor) {
    178    if (strncmp(governor, INTERACTIVE_GOVERNOR, (strlen(INTERACTIVE_GOVERNOR)+1)) == 0)
    179       return 1;
    180    return 0;
    181 }
    182 
    183 void interaction(int duration, int num_args, int opt_list[])
    184 {
    185 #ifdef INTERACTION_BOOST
    186     static int lock_handle = 0;
    187 
    188     if (duration < 0 || num_args < 1 || opt_list[0] == 0)
    189         return;
    190 
    191     if (qcopt_handle) {
    192         if (perf_lock_acq) {
    193             lock_handle = perf_lock_acq(lock_handle, duration, opt_list, num_args);
    194             if (lock_handle == -1)
    195                 ALOGE("Failed to acquire lock.");
    196         }
    197     }
    198 #endif
    199 }
    200 
    201 int interaction_with_handle(int lock_handle, int duration, int num_args, int opt_list[])
    202 {
    203 #ifdef INTERACTION_BOOST
    204     if (duration < 0 || num_args < 1 || opt_list[0] == 0)
    205         return 0;
    206 
    207     if (qcopt_handle) {
    208         if (perf_lock_acq) {
    209             lock_handle = perf_lock_acq(lock_handle, duration, opt_list, num_args);
    210             if (lock_handle == -1)
    211                 ALOGE("Failed to acquire lock.");
    212         }
    213     }
    214     return lock_handle;
    215 #else
    216     return 0;
    217 #endif
    218 }
    219 
    220 void release_request(int lock_handle) {
    221     if (qcopt_handle && perf_lock_rel)
    222         perf_lock_rel(lock_handle);
    223 }
    224 
    225 void perform_hint_action(int hint_id, int resource_values[], int num_resources)
    226 {
    227     if (qcopt_handle) {
    228         struct hint_data temp_hint_data = {
    229             .hint_id = hint_id
    230         };
    231         struct list_node *found_node = find_node(&active_hint_list_head,
    232                                                  &temp_hint_data);
    233         if (found_node) {
    234             ALOGE("hint ID %d already active", hint_id);
    235             return;
    236         }
    237         if (perf_lock_acq) {
    238             /* Acquire an indefinite lock for the requested resources. */
    239             int lock_handle = perf_lock_acq(0, 0, resource_values,
    240                     num_resources);
    241 
    242             if (lock_handle == -1) {
    243                 ALOGE("%s: Failed to acquire lock.", __func__);
    244             } else {
    245                 /* Add this handle to our internal hint-list. */
    246                 struct hint_data *new_hint =
    247                     (struct hint_data *)malloc(sizeof(struct hint_data));
    248 
    249                 if (new_hint) {
    250                     if (!active_hint_list_head.compare) {
    251                         active_hint_list_head.compare =
    252                             (int (*)(void *, void *))hint_compare;
    253                         active_hint_list_head.dump = (void (*)(void *))hint_dump;
    254                     }
    255 
    256                     new_hint->hint_id = hint_id;
    257                     new_hint->perflock_handle = lock_handle;
    258 
    259                     if (add_list_node(&active_hint_list_head, new_hint) == NULL) {
    260                         free(new_hint);
    261                         /* Can't keep track of this lock. Release it. */
    262                         if (perf_lock_rel)
    263                             perf_lock_rel(lock_handle);
    264 
    265                         ALOGE("Failed to process hint.");
    266                     }
    267                 } else {
    268                     /* Can't keep track of this lock. Release it. */
    269                     if (perf_lock_rel)
    270                         perf_lock_rel(lock_handle);
    271 
    272                     ALOGE("Failed to process hint.");
    273                 }
    274             }
    275         }
    276     }
    277 }
    278 
    279 void undo_hint_action(int hint_id)
    280 {
    281     if (qcopt_handle) {
    282         if (perf_lock_rel) {
    283             /* Get hint-data associated with this hint-id */
    284             struct list_node *found_node;
    285             struct hint_data temp_hint_data = {
    286                 .hint_id = hint_id
    287             };
    288 
    289             found_node = find_node(&active_hint_list_head,
    290                     &temp_hint_data);
    291 
    292             if (found_node) {
    293                 /* Release this lock. */
    294                 struct hint_data *found_hint_data =
    295                     (struct hint_data *)(found_node->data);
    296 
    297                 if (found_hint_data) {
    298                     if (perf_lock_rel(found_hint_data->perflock_handle) == -1)
    299                         ALOGE("Perflock release failed: %d", hint_id);
    300                 }
    301 
    302                 if (found_node->data) {
    303                     /* We can free the hint-data for this node. */
    304                     free(found_node->data);
    305                 }
    306 
    307                 remove_list_node(&active_hint_list_head, found_node);
    308                 ALOGV("Undo of hint ID %d succeeded", hint_id);
    309             } else {
    310                 ALOGE("Invalid hint ID: %d", hint_id);
    311             }
    312         }
    313     }
    314 }
    315 
    316 /*
    317  * Used to release initial lock holding
    318  * two cores online when the display is on
    319  */
    320 void undo_initial_hint_action()
    321 {
    322     if (qcopt_handle) {
    323         if (perf_lock_rel) {
    324             perf_lock_rel(1);
    325         }
    326     }
    327 }
    328