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