1 // 2 // Copyright (C) Microsoft. All rights reserved. 3 // 4 #ifndef _FXPOWERIDLESTATEMACHINE_H_ 5 #define _FXPOWERIDLESTATEMACHINE_H_ 6 7 // 8 // This is a magical number based on inspection. If the queue overflows, 9 // it is OK to increase these numbers without fear of either dependencies or 10 // weird side affects. 11 // 12 const UCHAR FxPowerIdleEventQueueDepth = 8; 13 14 enum FxPowerIdleEvents { 15 // CAN BE REUSED = 0x0001, 16 PowerIdleEventPowerUpFailed = 0x0002, 17 PowerIdleEventPowerUpComplete = 0x0004, 18 PowerIdleEventPowerDown = 0x0008, 19 PowerIdleEventPowerDownFailed = 0x0010, 20 PowerIdleEventTimerExpired = 0x0020, 21 PowerIdleEventEnabled = 0x0040, 22 PowerIdleEventDisabled = 0x0080, 23 PowerIdleEventIoDecrement = 0x0100, 24 PowerIdleEventIoIncrement = 0x0200, 25 PowerIdleEventStart = 0x0400, 26 PowerIdleEventStop = 0x0800, 27 PowerIdleNull = 0x0000, 28 }; 29 30 // begin_wpp config 31 // CUSTOM_TYPE(FxPowerIdleEvents, ItemEnum(FxPowerIdleEvents)); 32 // end_wpp 33 34 enum FxPowerIdleStates { 35 FxIdleStopped = 1, 36 FxIdleStarted, 37 FxIdleStartedPowerUp, 38 FxIdleStartedPowerFailed, 39 FxIdleDisabled, 40 FxIdleCheckIoCount, 41 FxIdleBusy, 42 FxIdleDecrementIo, 43 FxIdleStartTimer, 44 FxIdleTimerRunning, 45 FxIdleTimingOut, 46 FxIdleTimedOut, 47 FxIdleTimedOutIoIncrement, 48 FxIdleTimedOutPowerDown, 49 FxIdleTimedOutPowerDownFailed, 50 FxIdleGoingToDx, 51 FxIdleInDx, 52 FxIdleInDxIoIncrement, 53 FxIdleInDxPowerUpFailure, 54 FxIdleInDxStopped, 55 FxIdleInDxDisabled, 56 FxIdleInDxEnabled, 57 FxIdlePowerUp, 58 FxIdlePowerUpComplete, 59 FxIdleTimedOutDisabled, 60 FxIdleTimedOutEnabled, 61 FxIdleCancelTimer, 62 FxIdleWaitForTimeout, 63 FxIdleTimerExpired, 64 FxIdleDisabling, 65 FxIdleDisablingWaitForTimeout, 66 FxIdleDisablingTimerExpired, 67 FxIdlePowerFailedWaitForTimeout, 68 FxIdlePowerFailed, 69 FxIdleMax, 70 }; 71 72 // 73 // NOTE: if you change these flags (order, values, etc), you must also modify 74 // m_FlagsByName to match your changes. 75 // 76 enum FxPowerIdleFlags { 77 FxPowerIdleTimerEnabled = 0x01, 78 FxPowerIdleInDx = 0x02, 79 FxPowerIdleTimerCanceled = 0x04, 80 FxPowerIdleTimerStarted = 0x08, 81 FxPowerIdlePowerFailed = 0x10, 82 FxPowerIdleIsStarted = 0x20, 83 FxPowerIdleIoPresentSent = 0x40, 84 FxPowerIdleSendPnpPowerUpEvent = 0x80, 85 }; 86 87 enum FxPowerReferenceFlags { 88 FxPowerReferenceDefault = 0x0, 89 FxPowerReferenceSendPnpPowerUpEvent = 0x1 90 }; 91 92 typedef 93 FxPowerIdleStates 94 (*PFN_POWER_IDLE_STATE_ENTRY_FUNCTION)( 95 FxPowerIdleMachine* 96 ); 97 98 struct FxPowerIdleTargetState { 99 FxPowerIdleEvents PowerIdleEvent; 100 101 FxPowerIdleStates PowerIdleState; 102 103 #if FX_SUPER_DBG 104 BOOLEAN EventDebugged; 105 #endif 106 }; 107 108 struct FxIdleStateTable { 109 PFN_POWER_IDLE_STATE_ENTRY_FUNCTION StateFunc; 110 111 const FxPowerIdleTargetState* TargetStates; 112 113 ULONG TargetStatesCount; 114 }; 115 116 class FxPowerIdleMachine : public FxStump { 117 118 public: 119 FxPowerIdleMachine( 120 VOID 121 ); 122 123 ~FxPowerIdleMachine( 124 VOID 125 ); 126 127 _Must_inspect_result_ 128 NTSTATUS 129 Init( 130 VOID 131 ); 132 133 VOID 134 EnableTimer( 135 VOID 136 ); 137 138 BOOLEAN 139 DisableTimer( 140 VOID 141 ); 142 143 VOID 144 Start( 145 VOID 146 ); 147 148 VOID 149 Stop( 150 VOID 151 ); 152 153 VOID 154 Reset( 155 VOID 156 ); 157 158 _Must_inspect_result_ 159 NTSTATUS 160 IoIncrement( 161 VOID 162 ); 163 164 _Must_inspect_result_ 165 NTSTATUS 166 IoIncrementWithFlags( 167 __in FxPowerReferenceFlags Flags, 168 __out_opt PULONG Count = NULL 169 ); 170 171 VOID 172 IoDecrement( 173 __in_opt PVOID Tag = NULL, 174 __in_opt LONG Line = 0, 175 __in_opt PSTR File = NULL 176 ); 177 178 BOOLEAN 179 QueryReturnToIdle( 180 VOID 181 ); 182 183 VOID WaitForD0(VOID)184 WaitForD0( 185 VOID 186 ) 187 { 188 m_D0NotificationEvent.EnterCRAndWaitAndLeave(); 189 } 190 191 _Must_inspect_result_ 192 NTSTATUS PowerReference(__in BOOLEAN WaitForD0,__in_opt PVOID Tag=NULL,__in_opt LONG Line=0,__in_opt PSTR File=NULL)193 PowerReference( 194 __in BOOLEAN WaitForD0, 195 __in_opt PVOID Tag = NULL, 196 __in_opt LONG Line = 0, 197 __in_opt PSTR File = NULL 198 ) 199 { 200 return PowerReferenceWorker(WaitForD0, FxPowerReferenceDefault, Tag, Line, File); 201 } 202 203 _Must_inspect_result_ 204 NTSTATUS PowerReferenceWithFlags(__in FxPowerReferenceFlags Flags)205 PowerReferenceWithFlags( 206 __in FxPowerReferenceFlags Flags 207 ) 208 { 209 return PowerReferenceWorker(FALSE, // WaitForD0 210 Flags); 211 } 212 213 VOID 214 ProcessPowerEvent( 215 __in FxPowerIdleEvents Event 216 ); 217 218 protected: 219 220 VOID 221 ProcessEventLocked( 222 __in FxPowerIdleEvents Event 223 ); 224 225 BOOLEAN IsTransitioning(VOID)226 IsTransitioning( 227 VOID 228 ) 229 { 230 return m_D0NotificationEvent.ReadState() ? FALSE : TRUE; 231 } 232 233 BOOLEAN CancelIdleTimer(VOID)234 CancelIdleTimer( 235 VOID 236 ) 237 { 238 // 239 // If we are canceling the timer, be well sure it is started 240 // 241 ASSERT(m_Flags & FxPowerIdleTimerStarted); 242 243 if (m_PowerTimeoutTimer.Stop()) { 244 m_Flags &= ~FxPowerIdleTimerStarted; 245 return TRUE; 246 } 247 else { 248 return FALSE; 249 } 250 } 251 252 BOOLEAN InD0Locked(VOID)253 InD0Locked( 254 VOID 255 ) 256 { 257 return m_D0NotificationEvent.ReadState() ? TRUE : FALSE; 258 } 259 260 VOID 261 SendD0Notification( 262 VOID 263 ); 264 265 _Must_inspect_result_ 266 NTSTATUS 267 PowerReferenceWorker( 268 __in BOOLEAN WaitForD0, 269 __in FxPowerReferenceFlags Flags, 270 __in_opt PVOID Tag = NULL, 271 __in_opt LONG Line = 0, 272 __in_opt PSTR File = NULL 273 ); 274 275 static 276 MdDeferredRoutineType 277 _PowerTimeoutDpcRoutine; 278 279 static 280 FxPowerIdleStates 281 Stopped( 282 __inout FxPowerIdleMachine* This 283 ); 284 285 static 286 FxPowerIdleStates 287 Started( 288 __inout FxPowerIdleMachine* This 289 ); 290 291 static 292 FxPowerIdleStates 293 StartedPowerUp( 294 __inout FxPowerIdleMachine* This 295 ); 296 297 static 298 FxPowerIdleStates 299 StartedPowerFailed( 300 __inout FxPowerIdleMachine* This 301 ); 302 303 static 304 FxPowerIdleStates 305 Disabled( 306 __inout FxPowerIdleMachine* This 307 ); 308 309 static 310 FxPowerIdleStates 311 CheckIoCount( 312 __inout FxPowerIdleMachine* This 313 ); 314 315 static 316 FxPowerIdleStates 317 DecrementIo( 318 __inout FxPowerIdleMachine* This 319 ); 320 321 static 322 FxPowerIdleStates 323 StartTimer( 324 __inout FxPowerIdleMachine* This 325 ); 326 327 static 328 FxPowerIdleStates 329 TimingOut( 330 __inout FxPowerIdleMachine* This 331 ); 332 333 static 334 FxPowerIdleStates 335 TimedOutIoIncrement( 336 __inout FxPowerIdleMachine* This 337 ); 338 339 static 340 FxPowerIdleStates 341 TimedOutPowerDown( 342 __inout FxPowerIdleMachine* This 343 ); 344 345 static 346 FxPowerIdleStates 347 TimedOutPowerDownFailed( 348 __inout FxPowerIdleMachine* This 349 ); 350 351 static 352 FxPowerIdleStates 353 GoingToDx( 354 __inout FxPowerIdleMachine* This 355 ); 356 357 static 358 FxPowerIdleStates 359 InDx( 360 __inout FxPowerIdleMachine* This 361 ); 362 363 static 364 FxPowerIdleStates 365 InDxIoIncrement( 366 __inout FxPowerIdleMachine* This 367 ); 368 369 static 370 FxPowerIdleStates 371 InDxPowerUpFailure( 372 __inout FxPowerIdleMachine* This 373 ); 374 375 static 376 FxPowerIdleStates 377 InDxStopped( 378 __inout FxPowerIdleMachine* This 379 ); 380 381 static 382 FxPowerIdleStates 383 InDxDisabled( 384 __inout FxPowerIdleMachine* This 385 ); 386 387 static 388 FxPowerIdleStates 389 InDxEnabled( 390 __inout FxPowerIdleMachine* This 391 ); 392 393 static 394 FxPowerIdleStates 395 PowerUp( 396 __inout FxPowerIdleMachine* This 397 ); 398 399 static 400 FxPowerIdleStates 401 PowerUpComplete( 402 __inout FxPowerIdleMachine* This 403 ); 404 405 static 406 FxPowerIdleStates 407 TimedOutDisabled( 408 __inout FxPowerIdleMachine* This 409 ); 410 411 static 412 FxPowerIdleStates 413 TimedOutEnabled( 414 __inout FxPowerIdleMachine* This 415 ); 416 417 static 418 FxPowerIdleStates 419 CancelTimer( 420 __inout FxPowerIdleMachine* This 421 ); 422 423 static 424 FxPowerIdleStates 425 TimerExpired( 426 __inout FxPowerIdleMachine* This 427 ); 428 429 static 430 FxPowerIdleStates 431 Disabling( 432 __inout FxPowerIdleMachine* This 433 ); 434 435 static 436 FxPowerIdleStates 437 DisablingTimerExpired( 438 __inout FxPowerIdleMachine* This 439 ); 440 441 static 442 FxPowerIdleStates 443 PowerFailed( 444 __inout FxPowerIdleMachine* This 445 ); 446 447 private: 448 VOID 449 CheckAssumptions( 450 VOID 451 ); 452 453 public: 454 LARGE_INTEGER m_PowerTimeout; 455 456 protected: 457 // 458 // Lock which guards state 459 // 460 MxLock m_Lock; 461 462 // 463 // Number of pending requests which require being in D0 464 // 465 ULONG m_IoCount; 466 467 // 468 // Tracks power references and releases. 469 // 470 FxTagTracker* m_TagTracker; 471 472 // 473 // Timer which will be set when the I/O count goes to zero 474 // 475 MxTimer m_PowerTimeoutTimer; 476 477 // 478 // Event to wait on when transitioning from Dx to D0 479 // 480 FxCREvent m_D0NotificationEvent; 481 482 union { 483 // 484 // Combintaion of FxPowerIdleFlags enum values 485 // 486 UCHAR m_Flags; 487 488 // 489 // Not used in the code. Here so that you can easily decode m_Flags in 490 // the debugger without needing the enum definition. 491 // 492 struct { 493 UCHAR TimerEnabled : 1; 494 UCHAR InDx : 1; 495 UCHAR TimerCanceled : 1; 496 UCHAR TimerStarted : 1; 497 UCHAR TimerPowerFailed : 1; 498 UCHAR IsStarted : 1; 499 UCHAR IoPresentSent : 1; 500 UCHAR SendPnpPowerUpEvent : 1; 501 } m_FlagsByName; 502 }; 503 504 // 505 // Index into m_EventHistory where to place the next value 506 // 507 UCHAR m_EventHistoryIndex; 508 509 // 510 // Index into m_StateHistory where to place the next value 511 UCHAR m_StateHistoryIndex; 512 513 // 514 // our current state 515 // 516 FxPowerIdleStates m_CurrentIdleState; 517 518 // 519 // Circular history of events fed into this state machine 520 // 521 FxPowerIdleEvents m_EventHistory[FxPowerIdleEventQueueDepth]; 522 523 // 524 // Circular history of states the state machine was in 525 // 526 FxPowerIdleStates m_StateHistory[FxPowerIdleEventQueueDepth]; 527 528 static const FxPowerIdleTargetState m_StoppedStates[]; 529 static const FxPowerIdleTargetState m_StartedStates[]; 530 static const FxPowerIdleTargetState m_DisabledStates[]; 531 static const FxPowerIdleTargetState m_BusyStates[]; 532 static const FxPowerIdleTargetState m_TimerRunningStates[]; 533 static const FxPowerIdleTargetState m_TimedOutStates[]; 534 static const FxPowerIdleTargetState m_InDxStates[]; 535 static const FxPowerIdleTargetState m_WaitForTimeoutStates[]; 536 static const FxPowerIdleTargetState m_DisablingWaitForTimeoutStates[]; 537 static const FxPowerIdleTargetState m_PowerFailedWaitForTimeoutStates[]; 538 539 static const FxIdleStateTable m_StateTable[]; 540 541 // 542 // We use a coalescable timer for idle timeout. The tolerable delay for the 543 // idle timer is defined below. The value below is an arbitrary choice and 544 // can be changed if necessary. MSDN documentation suggests 100 ms as being 545 // a reasonable choice. 546 // 547 static const ULONG m_IdleTimerTolerableDelayMS = 100; 548 }; 549 550 #endif // _FXPOWERIDLESTATEMACHINE_H_ 551