19 #include <kernel/kpower.h> |
19 #include <kernel/kpower.h> |
20 #include <kernel/kern_priv.h> |
20 #include <kernel/kern_priv.h> |
21 #include "execs.h" |
21 #include "execs.h" |
22 #include "msgqueue.h" |
22 #include "msgqueue.h" |
23 |
23 |
24 // #define _DEBUG_POWER |
24 #ifdef _DEBUG |
25 |
25 #include <nkern/nk_trace.h> |
|
26 //#define _DEBUG_POWER |
|
27 #endif |
26 |
28 |
27 /****************************************************************************** |
29 /****************************************************************************** |
28 * Power Manager - a Power Model implementation |
30 * Power Manager - a Power Model implementation |
29 ******************************************************************************/ |
31 ******************************************************************************/ |
30 #ifndef __X86__ |
32 #ifndef __X86__ |
87 // used in assertions only |
98 // used in assertions only |
88 // { return iFeatureLock->iCleanup.iThread == TheCurrentThread; } |
99 // { return iFeatureLock->iCleanup.iThread == TheCurrentThread; } |
89 // #endif |
100 // #endif |
90 |
101 |
91 void NotifyWakeupEvent(TInt aReason); |
102 void NotifyWakeupEvent(TInt aReason); |
|
103 |
|
104 static void ShutDownTimeoutFn(TAny* aArg); |
92 |
105 |
93 DMutex* iFeatureLock; |
106 DMutex* iFeatureLock; |
94 DThread* iClient; // protected by the system lock |
107 DThread* iClient; // protected by the system lock |
95 TClientRequest* iRequest; // protected by the system lock |
108 TClientRequest* iRequest; // protected by the system lock |
96 DPowerHandler* iHandlers; // protected by the feature lock |
109 DPowerHandler* iHandlers; // protected by the feature lock |
326 NKern::ThreadEnterCS(); |
339 NKern::ThreadEnterCS(); |
327 NotifyWakeupEvent(KErrCancel); |
340 NotifyWakeupEvent(KErrCancel); |
328 NKern::ThreadLeaveCS(); |
341 NKern::ThreadLeaveCS(); |
329 } |
342 } |
330 |
343 |
331 // Called in CS |
344 |
|
345 void DPowerManager::ShutDownTimeoutFn(TAny* aArg) |
|
346 { |
|
347 __KTRACE_OPT(KPOWER,Kern::Printf(">DPowerManager::ShutDownTimeoutFn")); |
|
348 NFastSemaphore* sem = (NFastSemaphore*)aArg; |
|
349 #ifdef _DEBUG_POWER |
|
350 NKern::FSSignal(sem); |
|
351 #else |
|
352 TUint SignalCount = __e32_atomic_load_acq32(&(PowerManager->iPendingShutdownCount)); |
|
353 DPowerHandler* ph = PowerManager->iHandlers; |
|
354 do |
|
355 { |
|
356 ph->iSem = NULL; |
|
357 ph = ph->iPrev; |
|
358 }while(ph != PowerManager->iHandlers); |
|
359 |
|
360 __e32_atomic_store_rel32(&(PowerManager->iPendingShutdownCount), (TUint)ESHUTDOWN_TIMEOUT); // = -1 |
|
361 NKern::FSSignalN(sem,SignalCount); |
|
362 |
|
363 __KTRACE_OPT(KPOWER,Kern::Printf("<DPowerManager::ShutDownTimeoutFn")); |
|
364 #endif |
|
365 } |
|
366 |
332 TInt DPowerManager::PowerDown() |
367 TInt DPowerManager::PowerDown() |
333 { // called by ExecHandler |
368 { // called by ExecHandler |
334 __KTRACE_OPT(KPOWER,Kern::Printf(">PowerManger::PowerDown(0x%x) Enter", iPowerController->iTargetState)); |
369 __KTRACE_OPT(KPOWER,Kern::Printf(">PowerManger::PowerDown(0x%x) Enter", iPowerController->iTargetState)); |
335 __ASSERT_CRITICAL; |
370 __ASSERT_CRITICAL; |
336 |
371 |
342 Unlock(); |
377 Unlock(); |
343 return KErrNotReady; |
378 return KErrNotReady; |
344 } |
379 } |
345 |
380 |
346 __PM_ASSERT(iHandlers); |
381 __PM_ASSERT(iHandlers); |
347 NFastSemaphore sem(0); |
382 NFastSemaphore shutdownSem(0); |
|
383 NTimer ntimer; |
|
384 TDfc dfc(ShutDownTimeoutFn, &shutdownSem); |
|
385 #ifndef _DEBUG_POWER |
|
386 iPendingShutdownCount = 0; |
|
387 #endif |
348 DPowerHandler* ph = iHandlers; |
388 DPowerHandler* ph = iHandlers; |
349 //Power down in reverse order of handle registration. |
389 //Power down in reverse order of handle registration. |
350 do |
390 do |
351 { |
391 { |
352 #ifdef _DEBUG_POWER |
392 #ifdef _DEBUG_POWER |
353 __PM_ASSERT(!(ph->iStatus & DPowerHandler::EDone)); |
393 __PM_ASSERT(!(ph->iStatus & DPowerHandler::EDone)); |
354 #endif |
394 #endif |
355 ph->iSem = &sem; |
395 ph->iSem = &shutdownSem; |
356 ph->PowerDown(iPowerController->iTargetState); |
396 ph->PowerDown(iPowerController->iTargetState); |
357 #ifdef _DEBUG_POWER |
397 #ifndef _DEBUG_POWER |
358 __PM_ASSERT(!(ph->iStatus & DPowerHandler::EDone)); |
398 iPendingShutdownCount++; |
359 NKern::FSWait(&sem); // power down drivers one after another to simplify debug |
399 #else |
360 __PM_ASSERT(!ph->iSem); |
400 if(iPslShutdownTimeoutMs>0) |
361 __PM_ASSERT(ph->iStatus & EDone); |
401 { |
362 ph->iStatus &= ~EDone; |
402 // Fire shut down timeout timer |
363 #endif |
403 ntimer.OneShot(iPslShutdownTimeoutMs, dfc); |
|
404 } |
|
405 |
|
406 NKern::FSWait(&shutdownSem); // power down drivers one after another to simplify debug |
|
407 __e32_atomic_and_ord32(&(ph->iStatus), ~DPowerHandler::EDone); |
|
408 |
|
409 // timeout condition |
|
410 if(iPslShutdownTimeoutMs>0 && ph->iSem) |
|
411 { |
|
412 __e32_atomic_store_ord_ptr(&ph->iSem, 0); |
|
413 } |
|
414 ntimer.Cancel(); |
|
415 #endif |
364 ph = ph->iPrev; |
416 ph = ph->iPrev; |
365 }while(ph != iHandlers); |
417 }while(ph != iHandlers); |
366 |
418 |
367 #ifndef _DEBUG_POWER |
419 #ifndef _DEBUG_POWER |
|
420 if(iPslShutdownTimeoutMs>0) |
|
421 { |
|
422 // Fire shut down timeout timer |
|
423 ntimer.OneShot(iPslShutdownTimeoutMs, dfc); |
|
424 } |
|
425 |
368 ph = iHandlers; |
426 ph = iHandlers; |
369 do |
427 do |
370 { |
428 { |
371 NKern::FSWait(&sem); |
429 NKern::FSWait(&shutdownSem); |
|
430 if(__e32_atomic_load_acq32(&iPendingShutdownCount)==ESHUTDOWN_TIMEOUT) |
|
431 { |
|
432 iPendingShutdownCount = 0; |
|
433 NKern::Lock(); |
|
434 shutdownSem.Reset(); // iPendingShutdownCount could be altered while ShutDownTimeoutFn is running |
|
435 // reset it to make sure shutdownSem is completely clean. |
|
436 NKern::Unlock(); |
|
437 break; |
|
438 } |
|
439 __e32_atomic_add_ord32(&iPendingShutdownCount, (TUint)(~0x0)); // iPendingShutDownCount--; |
372 ph = ph->iPrev; |
440 ph = ph->iPrev; |
373 }while(ph != iHandlers); |
441 }while(ph != iHandlers); |
|
442 |
|
443 ntimer.Cancel(); |
|
444 |
374 #endif |
445 #endif |
375 |
446 |
376 TTickQ::Wait(); |
447 TTickQ::Wait(); |
377 |
448 |
378 iPowerController->PowerDown(K::SecondQ->WakeupTime()); |
449 iPowerController->PowerDown(K::SecondQ->WakeupTime()); |
380 iPowerController->iTargetState = EPwActive; |
451 iPowerController->iTargetState = EPwActive; |
381 |
452 |
382 K::SecondQ->WakeUp(); |
453 K::SecondQ->WakeUp(); |
383 TTickQ::Signal(); |
454 TTickQ::Signal(); |
384 |
455 |
|
456 NFastSemaphore powerupSem(0); |
|
457 |
385 ph = iHandlers->iNext; |
458 ph = iHandlers->iNext; |
386 //Power up in same order of handle registration. |
459 //Power up in same order of handle registration. |
387 do |
460 do |
388 { |
461 { |
389 #ifdef _DEBUG_POWER |
462 #ifdef _DEBUG_POWER |
390 __PM_ASSERT(!(ph->iStatus & DPowerHandler::EDone)); |
463 __PM_ASSERT(!(ph->iStatus & DPowerHandler::EDone)); |
391 #endif |
464 #endif |
392 ph->iSem = &sem; |
465 ph->iSem = &powerupSem; |
393 ph->PowerUp(); |
466 ph->PowerUp(); |
394 #ifdef _DEBUG_POWER |
467 #ifdef _DEBUG_POWER |
395 __PM_ASSERT(!(ph->iStatus & DPowerHandler::EDone)); |
468 NKern::FSWait(&powerupSem); // power down drivers one after another to simplify debug |
396 NKern::FSWait(&sem); // power down drivers one after another to simplify debug |
|
397 __PM_ASSERT(!ph->iSem); |
469 __PM_ASSERT(!ph->iSem); |
398 __PM_ASSERT(ph->iStatus & EDone); |
470 __PM_ASSERT(ph->iStatus & DPowerHandler::EDone); |
399 ph->iStatus &= ~EDone; |
471 ph->iStatus &= ~DPowerHandler::EDone; |
400 #endif |
472 #endif |
401 ph = ph->iNext; |
473 ph = ph->iNext; |
402 }while(ph != iHandlers->iNext); |
474 }while(ph != iHandlers->iNext); |
403 |
475 |
404 #ifndef _DEBUG_POWER |
476 #ifndef _DEBUG_POWER |
405 ph = iHandlers->iNext; |
477 ph = iHandlers->iNext; |
406 do |
478 do |
407 { |
479 { |
408 NKern::FSWait(&sem); |
480 NKern::FSWait(&powerupSem); |
409 ph = ph->iNext; |
481 ph = ph->iNext; |
410 }while(ph != iHandlers->iNext); |
482 }while(ph != iHandlers->iNext); |
411 #endif |
483 #endif |
412 |
484 |
413 // complete wakeup notification request if any |
485 // complete wakeup notification request if any |
576 } |
649 } |
577 |
650 |
578 |
651 |
579 |
652 |
580 /** @deprecated, no replacement */ |
653 /** @deprecated, no replacement */ |
581 EXPORT_C void DPowerHandler::DeltaCurrentConsumption(TInt aDelta) |
654 EXPORT_C void DPowerHandler::DeltaCurrentConsumption(TInt /* aDelta */) |
582 { |
655 { |
583 __e32_atomic_add_ord32(&iCurrent, aDelta); |
|
584 __PM_ASSERT(iCurrent >= 0); |
|
585 __e32_atomic_add_ord32(&PowerManager->iTotalCurrent, aDelta); |
|
586 __PM_ASSERT(PowerManager->iTotalCurrent >= 0); |
|
587 } |
656 } |
588 |
657 |
589 /** @deprecated, no replacement */ |
658 /** @deprecated, no replacement */ |
590 EXPORT_C void DPowerHandler::SetCurrentConsumption(TInt aCurrent) |
659 EXPORT_C void DPowerHandler::SetCurrentConsumption(TInt /* aCurrent */) |
591 { |
660 { |
592 __PM_ASSERT(aCurrent >= 0); |
|
593 TInt old = (TInt)__e32_atomic_swp_ord32(&iCurrent, aCurrent); |
|
594 TInt delta = aCurrent - old; |
|
595 __e32_atomic_add_ord32(&PowerManager->iTotalCurrent, delta); |
|
596 __PM_ASSERT(PowerManager->iTotalCurrent >= 0); |
|
597 } |
661 } |
598 |
662 |
599 /****************************************************************************** |
663 /****************************************************************************** |
600 * Power Controller |
664 * Power Controller |
601 ******************************************************************************/ |
665 ******************************************************************************/ |
648 PowerManager->iPowerController = this; |
712 PowerManager->iPowerController = this; |
649 #ifndef __X86__ |
713 #ifndef __X86__ |
650 TPowerController::ThePowerController = this; |
714 TPowerController::ThePowerController = this; |
651 #endif |
715 #endif |
652 K::PowerModel = PowerManager; |
716 K::PowerModel = PowerManager; |
|
717 } |
|
718 |
|
719 /** |
|
720 Registers this power controller object with the power manager. |
|
721 |
|
722 The power manager can only use the power controller after registration. |
|
723 |
|
724 @param aShutdownTimeoutMs The kernel shut down time out value in msec. |
|
725 |
|
726 @pre Calling thread must be in a critical section. |
|
727 @pre No fast mutex can be held. |
|
728 @pre Call in a thread context. |
|
729 @pre Kernel must be unlocked |
|
730 @pre interrupts enabled |
|
731 */ |
|
732 EXPORT_C void DPowerController::Register(TUint aShutdownTimeoutMs) |
|
733 { |
|
734 PowerManager->iPslShutdownTimeoutMs = aShutdownTimeoutMs; |
|
735 Register(); |
653 } |
736 } |
654 |
737 |
655 #ifndef __X86__ |
738 #ifndef __X86__ |
656 /** |
739 /** |
657 Registers resource controller with power controller |
740 Registers resource controller with power controller |