Home | History | Annotate | Download | only in power
      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