1 /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 *     * Redistributions of source code must retain the above copyright
7 *       notice, this list of conditions and the following disclaimer.
8 *     * Redistributions in binary form must reproduce the above
9 *       copyright notice, this list of conditions and the following
10 *       disclaimer in the documentation and/or other materials provided
11 *       with the distribution.
12 *     * Neither the name of The Linux Foundation nor the names of its
13 *       contributors may be used to endorse or promote products derived
14 *       from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29 
30 #define LOG_TAG "QCameraPerf"
31 
32 // To remove
33 #include <cutils/properties.h>
34 
35 // System dependencies
36 #include <stdlib.h>
37 #include <dlfcn.h>
38 
39 // Camera dependencies
40 #include "QCameraPerf.h"
41 #include "QCameraTrace.h"
42 
43 extern "C" {
44 #include "mm_camera_dbg.h"
45 }
46 
47 namespace qcamera {
48 
49 /*===========================================================================
50  * FUNCTION   : QCameraPerfLock constructor
51  *
52  * DESCRIPTION: initialize member variables
53  *
54  * PARAMETERS :
55  *   None
56  *
57  * RETURN     : void
58  *
59  *==========================================================================*/
QCameraPerfLock()60 QCameraPerfLock::QCameraPerfLock() :
61         perf_lock_acq(NULL),
62         perf_lock_rel(NULL),
63         mDlHandle(NULL),
64         mPerfLockEnable(0),
65         mPerfLockHandle(-1),
66         mPerfLockHandleTimed(-1),
67         mTimerSet(0),
68         mPerfLockTimeout(0),
69         mStartTimeofLock(0)
70 {
71 }
72 
73 /*===========================================================================
74  * FUNCTION   : QCameraPerfLock destructor
75  *
76  * DESCRIPTION: class desctructor
77  *
78  * PARAMETERS :
79  *   None
80  *
81  * RETURN     : void
82  *
83  *==========================================================================*/
~QCameraPerfLock()84 QCameraPerfLock::~QCameraPerfLock()
85 {
86     lock_deinit();
87 }
88 
89 
90 /*===========================================================================
91  * FUNCTION   : lock_init
92  *
93  * DESCRIPTION: opens the performance lib and initilizes the perf lock functions
94  *
95  * PARAMETERS :
96  *   None
97  *
98  * RETURN     : void
99  *
100  *==========================================================================*/
lock_init()101 void QCameraPerfLock::lock_init()
102 {
103     const char *rc;
104     char value[PROPERTY_VALUE_MAX];
105 
106     LOGD("E");
107     Mutex::Autolock lock(mLock);
108 
109     // Clear the list of active power hints
110     mActivePowerHints.clear();
111     mCurrentPowerHint       = static_cast<power_hint_t>(0);
112     mCurrentPowerHintEnable = false;
113 
114     property_get("persist.camera.perflock.enable", value, "1");
115     mPerfLockEnable = atoi(value);
116 #ifdef HAS_MULTIMEDIA_HINTS
117     if (hw_get_module(POWER_HARDWARE_MODULE_ID, (const hw_module_t **)&m_pPowerModule)) {
118         LOGE("%s module not found", POWER_HARDWARE_MODULE_ID);
119     }
120 #endif
121 
122     if (mPerfLockEnable) {
123         perf_lock_acq = NULL;
124         perf_lock_rel = NULL;
125         mPerfLockHandle = -1;
126         /* Retrieve name of vendor extension library */
127         if (property_get("ro.vendor.extension_library", value, NULL) <= 0) {
128             goto cleanup;
129         }
130 
131         mDlHandle = dlopen(value, RTLD_NOW | RTLD_LOCAL);
132         if (mDlHandle == NULL) {
133             goto cleanup;
134         }
135 
136         dlerror();
137 
138         perf_lock_acq = (int (*) (int, int, int[], int))dlsym(mDlHandle, "perf_lock_acq");
139         if ((rc = dlerror()) != NULL) {
140             LOGE("failed to perf_lock_acq function handle");
141             goto cleanup;
142         }
143 
144         perf_lock_rel = (int (*) (int))dlsym(mDlHandle, "perf_lock_rel");
145         if ((rc = dlerror()) != NULL) {
146             LOGE("failed to perf_lock_rel function handle");
147             goto cleanup;
148         }
149         LOGD("X");
150         return;
151 
152 cleanup:
153         perf_lock_acq  = NULL;
154         perf_lock_rel  = NULL;
155         mPerfLockEnable = 0;
156         if (mDlHandle) {
157             dlclose(mDlHandle);
158             mDlHandle = NULL;
159         }
160     }
161     LOGD("X");
162 }
163 
164 /*===========================================================================
165  * FUNCTION   : lock_deinit
166  *
167  * DESCRIPTION: deinitialize the perf lock parameters
168  *
169  * PARAMETERS :
170  *   None
171  *
172  * RETURN     : void
173  *
174  *==========================================================================*/
lock_deinit()175 void QCameraPerfLock::lock_deinit()
176 {
177     Mutex::Autolock lock(mLock);
178     if (mPerfLockEnable) {
179         LOGD("E");
180 
181         if (mActivePowerHints.empty() == false) {
182             // Disable the active power hint
183             mCurrentPowerHint = *mActivePowerHints.begin();
184             powerHintInternal(mCurrentPowerHint, false);
185             mActivePowerHints.clear();
186         }
187 
188         if ((NULL != perf_lock_rel) && (mPerfLockHandleTimed >= 0)) {
189             (*perf_lock_rel)(mPerfLockHandleTimed);
190         }
191 
192         if ((NULL != perf_lock_rel) && (mPerfLockHandle >= 0)) {
193             (*perf_lock_rel)(mPerfLockHandle);
194         }
195 
196         if (mDlHandle) {
197             perf_lock_acq  = NULL;
198             perf_lock_rel  = NULL;
199 
200             dlclose(mDlHandle);
201             mDlHandle       = NULL;
202         }
203         mPerfLockEnable = 0;
204         LOGD("X");
205     }
206 }
207 
208 /*===========================================================================
209  * FUNCTION   : isTimerReset
210  *
211  * DESCRIPTION: Check if timout duration is reached
212  *
213  * PARAMETERS : None
214  *
215  * RETURN     : true if timeout reached
216  *              false if timeout not reached
217  *
218  *==========================================================================*/
isTimerReset()219 bool QCameraPerfLock::isTimerReset()
220 {
221     Mutex::Autolock lock(mLock);
222     if (mPerfLockEnable && mTimerSet) {
223         nsecs_t timeDiff = systemTime() - mStartTimeofLock;
224         if (ns2ms(timeDiff) > (uint32_t)mPerfLockTimeout) {
225             resetTimer();
226             return true;
227         }
228     }
229     return false;
230 }
231 
232 /*===========================================================================
233  * FUNCTION   : resetTimer
234  *
235  * DESCRIPTION: Reset the timer used in timed perf lock
236  *
237  * PARAMETERS : None
238  *
239  * RETURN     : void
240  *
241  *==========================================================================*/
resetTimer()242 void QCameraPerfLock::resetTimer()
243 {
244     mPerfLockTimeout = 0;
245     mTimerSet = 0;
246 }
247 
248 /*===========================================================================
249  * FUNCTION   : start_timer
250  *
251  * DESCRIPTION: get the start of the timer
252  *
253  * PARAMETERS :
254  *  @timer_val: timer duration in milliseconds
255  *
256  * RETURN     : int32_t type of status
257  *              NO_ERROR  -- success
258  *              none-zero failure code
259  *
260  *==========================================================================*/
startTimer(uint32_t timer_val)261 void QCameraPerfLock::startTimer(uint32_t timer_val)
262 {
263     mStartTimeofLock = systemTime();
264     mTimerSet = 1;
265     mPerfLockTimeout = timer_val;
266 }
267 
268 /*===========================================================================
269  * FUNCTION   : lock_acq_timed
270  *
271  * DESCRIPTION: Acquire the performance lock for the specified duration.
272  *              If an existing lock timeout has not elapsed, extend the
273  *              lock further for the specified duration
274  *
275  * PARAMETERS :
276  *  @timer_val: lock duration
277  *
278  * RETURN     : int32_t type of status
279  *              NO_ERROR  -- success
280  *              none-zero failure code
281  *
282  *==========================================================================*/
lock_acq_timed(int32_t timer_val)283 int32_t QCameraPerfLock::lock_acq_timed(int32_t timer_val)
284 {
285     int32_t ret = -1;
286 
287     LOGD("E");
288     Mutex::Autolock lock(mLock);
289 
290     if (mPerfLockEnable) {
291         int32_t perf_lock_params[] = {
292                 ALL_CPUS_PWR_CLPS_DIS,
293                 CPU0_MIN_FREQ_TURBO_MAX,
294                 CPU4_MIN_FREQ_TURBO_MAX
295         };
296         if (mTimerSet) {
297             nsecs_t curElapsedTime = systemTime() - mStartTimeofLock;
298             int32_t pendingTimeout = mPerfLockTimeout - ns2ms(curElapsedTime);
299             timer_val += pendingTimeout;
300         }
301         startTimer(timer_val);
302 
303         // Disable power hint when acquiring the perf lock
304         if (mCurrentPowerHintEnable) {
305             LOGD("mCurrentPowerHintEnable %d" ,mCurrentPowerHintEnable);
306             powerHintInternal(mCurrentPowerHint, false);
307         }
308 
309         if ((NULL != perf_lock_acq) && (mPerfLockHandleTimed < 0)) {
310             ret = (*perf_lock_acq)(mPerfLockHandleTimed, timer_val, perf_lock_params,
311                     sizeof(perf_lock_params) / sizeof(int32_t));
312             LOGD("ret %d", ret);
313             if (ret < 0) {
314                 LOGE("failed to acquire lock");
315             } else {
316                 mPerfLockHandleTimed = ret;
317             }
318         }
319         LOGD("perf_handle_acq %d ", mPerfLockHandleTimed);
320     }
321 
322     LOGD("X");
323     return ret;
324 }
325 
326 /*===========================================================================
327  * FUNCTION   : lock_acq
328  *
329  * DESCRIPTION: acquire the performance lock
330  *
331  * PARAMETERS :
332  *   None
333  *
334  * RETURN     : int32_t type of status
335  *              NO_ERROR  -- success
336  *              none-zero failure code
337  *
338  *==========================================================================*/
lock_acq()339 int32_t QCameraPerfLock::lock_acq()
340 {
341     int32_t ret = -1;
342 
343     LOGD("E");
344     Mutex::Autolock lock(mLock);
345 
346     if (mPerfLockEnable) {
347         int32_t perf_lock_params[] = {
348                 ALL_CPUS_PWR_CLPS_DIS,
349                 CPU0_MIN_FREQ_TURBO_MAX,
350                 CPU4_MIN_FREQ_TURBO_MAX
351         };
352 
353         // Disable power hint when acquiring the perf lock
354         if (mCurrentPowerHintEnable) {
355             powerHintInternal(mCurrentPowerHint, false);
356         }
357 
358         if ((NULL != perf_lock_acq) && (mPerfLockHandle < 0)) {
359             ret = (*perf_lock_acq)(mPerfLockHandle, ONE_SEC, perf_lock_params,
360                     sizeof(perf_lock_params) / sizeof(int32_t));
361             LOGD("ret %d", ret);
362             if (ret < 0) {
363                 LOGE("failed to acquire lock");
364             } else {
365                 mPerfLockHandle = ret;
366             }
367         }
368         LOGD("perf_handle_acq %d ", mPerfLockHandle);
369     }
370 
371     LOGD("X");
372     return ret;
373 }
374 
375 /*===========================================================================
376  * FUNCTION   : lock_rel_timed
377  *
378  * DESCRIPTION: release the performance lock
379  *
380  * PARAMETERS :
381  *   None
382  *
383  * RETURN     : int32_t type of status
384  *              NO_ERROR  -- success
385  *              none-zero failure code
386  *
387  *==========================================================================*/
lock_rel_timed()388 int32_t QCameraPerfLock::lock_rel_timed()
389 {
390     int ret = -1;
391     Mutex::Autolock lock(mLock);
392     if (mPerfLockEnable) {
393         LOGD("E");
394         if (mPerfLockHandleTimed < 0) {
395             LOGW("mPerfLockHandle < 0,check if lock is acquired");
396             return ret;
397         }
398         LOGD("perf_handle_rel %d ", mPerfLockHandleTimed);
399 
400         if ((NULL != perf_lock_rel) && (0 <= mPerfLockHandleTimed)) {
401             ret = (*perf_lock_rel)(mPerfLockHandleTimed);
402             if (ret < 0) {
403                 LOGE("failed to release lock");
404             }
405             mPerfLockHandleTimed = -1;
406             resetTimer();
407         }
408 
409         if ((mCurrentPowerHintEnable == 1) && (mTimerSet == 0)) {
410             powerHintInternal(mCurrentPowerHint, mCurrentPowerHintEnable);
411         }
412         LOGD("X");
413     }
414     return ret;
415 }
416 
417 /*===========================================================================
418  * FUNCTION   : lock_rel
419  *
420  * DESCRIPTION: release the performance lock
421  *
422  * PARAMETERS :
423  *   None
424  *
425  * RETURN     : int32_t type of status
426  *              NO_ERROR  -- success
427  *              none-zero failure code
428  *
429  *==========================================================================*/
lock_rel()430 int32_t QCameraPerfLock::lock_rel()
431 {
432     int ret = -1;
433     Mutex::Autolock lock(mLock);
434     if (mPerfLockEnable) {
435         LOGD("E");
436         if (mPerfLockHandle < 0) {
437             LOGW("mPerfLockHandle < 0,check if lock is acquired");
438             return ret;
439         }
440         LOGD("perf_handle_rel %d ", mPerfLockHandle);
441 
442         if ((NULL != perf_lock_rel) && (0 <= mPerfLockHandle)) {
443             ret = (*perf_lock_rel)(mPerfLockHandle);
444             if (ret < 0) {
445                 LOGE("failed to release lock");
446             }
447             mPerfLockHandle = -1;
448         }
449 
450         if (mCurrentPowerHintEnable == 1) {
451             powerHintInternal(mCurrentPowerHint, mCurrentPowerHintEnable);
452         }
453         LOGD("X");
454     }
455     return ret;
456 }
457 
458 /*===========================================================================
459  * FUNCTION   : powerHintInternal
460  *
461  * DESCRIPTION: Sets the requested power hint and state to power HAL.
462  *
463  * PARAMETERS :
464  * hint       : Power hint
465  * enable     : Enable power hint if set to 1. Disable if set to 0.
466  * RETURN     : void
467  *
468  *==========================================================================*/
powerHintInternal(power_hint_t hint,bool enable)469 void QCameraPerfLock::powerHintInternal(power_hint_t hint, bool enable)
470 {
471 #ifdef HAS_MULTIMEDIA_HINTS
472     if (m_pPowerModule != NULL) {
473         if (enable == true) {
474             m_pPowerModule->powerHint(m_pPowerModule, hint, (void *)"state=1");
475         } else {
476             m_pPowerModule->powerHint(m_pPowerModule, hint, (void *)"state=0");
477         }
478     }
479 #endif
480 }
481 
482 /*===========================================================================
483  * FUNCTION   : powerHint
484  *
485  * DESCRIPTION: Updates the list containing active/enabled power hints.
486  *              If needed, calls the internal powerHint function with
487  *              requested power hint and state.
488  * PARAMETERS :
489  * hint       : Power hint
490  * enable     : Enable power hint if set to 1. Disable if set to 0.
491  * RETURN     : void
492  *
493  *==========================================================================*/
powerHint(power_hint_t hint,bool enable)494 void QCameraPerfLock::powerHint(power_hint_t hint, bool enable)
495 {
496 #ifdef HAS_MULTIMEDIA_HINTS
497     if (enable == true) {
498         if ((hint != mCurrentPowerHint) || (enable != mCurrentPowerHintEnable)) {
499             // Disable the current active power hint
500             if (mCurrentPowerHintEnable == true) {
501                 powerHintInternal(mCurrentPowerHint, false);
502             }
503             // Push the new power hint at the head of the active power hint list
504             mActivePowerHints.push_front(hint);
505 
506             // Set the new power hint
507             mCurrentPowerHint       = hint;
508             mCurrentPowerHintEnable = enable;
509             powerHintInternal(hint, enable);
510         }
511     } else {
512         // Remove the power hint from the list
513         for (List<power_hint_t>::iterator it = mActivePowerHints.begin();
514                 it != mActivePowerHints.end(); ++it) {
515             if (*it == hint) {
516                 if (it != mActivePowerHints.begin()) {
517                     LOGW("Request to remove the previous power hint: %d instead of "
518                             "currently active power hint: %d", static_cast<int>(hint),
519                                                             static_cast<int>(mCurrentPowerHint));
520                 }
521                 mActivePowerHints.erase(it);
522                 break;
523             }
524         }
525 
526         if (hint == mCurrentPowerHint) {
527             // Disable the power hint
528             powerHintInternal(hint, false);
529 
530             // If the active power hint list is not empty,
531             // restore the previous power hint from the head of the list
532             if (mActivePowerHints.empty() == false) {
533                 mCurrentPowerHint       = *mActivePowerHints.begin();
534                 mCurrentPowerHintEnable = true;
535                 powerHintInternal(mCurrentPowerHint, true);
536             } else {
537                 mCurrentPowerHint       = static_cast<power_hint_t>(0);
538                 mCurrentPowerHintEnable = false;
539             }
540         }
541     }
542 #endif
543 }
544 
545 }; // namespace qcamera
546