1 /*++ 2 3 Copyright (c) Microsoft. All rights reserved. 4 5 Module Name: 6 7 PowerIdleStateMachine.cpp 8 9 Abstract: 10 11 This module implements the Power Policy idle state machine for the driver 12 framework. 13 14 Author: 15 16 17 18 Environment: 19 20 Both kernel and user mode 21 22 Revision History: 23 24 25 26 --*/ 27 28 #include "pnppriv.hpp" 29 30 extern "C" { 31 #if defined(EVENT_TRACING) 32 #include "PowerIdleStateMachine.tmh" 33 #endif 34 } 35 36 const FxPowerIdleTargetState FxPowerIdleMachine::m_StoppedStates[] = 37 { 38 { PowerIdleEventStart, FxIdleStarted DEBUGGED_EVENT }, 39 }; 40 41 const FxPowerIdleTargetState FxPowerIdleMachine::m_StartedStates[] = 42 { 43 { PowerIdleEventPowerUpComplete, FxIdleStartedPowerUp DEBUGGED_EVENT }, 44 { PowerIdleEventPowerUpFailed, FxIdleStartedPowerFailed DEBUGGED_EVENT }, 45 { PowerIdleEventStop, FxIdleStopped DEBUGGED_EVENT }, 46 }; 47 48 const FxPowerIdleTargetState FxPowerIdleMachine::m_DisabledStates[] = 49 { 50 { PowerIdleEventEnabled, FxIdleCheckIoCount DEBUGGED_EVENT }, 51 { PowerIdleEventDisabled, FxIdleDisabled DEBUGGED_EVENT }, 52 { PowerIdleEventPowerDown, FxIdleGoingToDx DEBUGGED_EVENT }, 53 { PowerIdleEventPowerDownFailed, FxIdlePowerFailed DEBUGGED_EVENT }, 54 { PowerIdleEventPowerUpFailed, FxIdlePowerFailed DEBUGGED_EVENT }, 55 { PowerIdleEventStop, FxIdleStopped DEBUGGED_EVENT }, 56 }; 57 58 const FxPowerIdleTargetState FxPowerIdleMachine::m_BusyStates[] = 59 { 60 { PowerIdleEventIoDecrement, FxIdleDecrementIo DEBUGGED_EVENT }, 61 { PowerIdleEventDisabled, FxIdleDisabled DEBUGGED_EVENT }, 62 { PowerIdleEventPowerDown, FxIdleGoingToDx TRAP_ON_EVENT }, 63 { PowerIdleEventPowerDownFailed, FxIdlePowerFailed TRAP_ON_EVENT }, 64 }; 65 66 const FxPowerIdleTargetState FxPowerIdleMachine::m_TimerRunningStates[] = 67 { 68 { PowerIdleEventDisabled, FxIdleDisabling DEBUGGED_EVENT }, 69 { PowerIdleEventIoIncrement, FxIdleCancelTimer DEBUGGED_EVENT }, 70 { PowerIdleEventEnabled, FxIdleCancelTimer DEBUGGED_EVENT }, 71 { PowerIdleEventTimerExpired, FxIdleTimingOut DEBUGGED_EVENT }, 72 }; 73 74 const FxPowerIdleTargetState FxPowerIdleMachine::m_TimedOutStates[] = 75 { 76 { PowerIdleEventPowerDown, FxIdleTimedOutPowerDown DEBUGGED_EVENT }, 77 { PowerIdleEventPowerDownFailed, FxIdleTimedOutPowerDownFailed DEBUGGED_EVENT }, 78 { PowerIdleEventDisabled, FxIdleTimedOutDisabled DEBUGGED_EVENT }, 79 { PowerIdleEventEnabled, FxIdleTimedOutEnabled DEBUGGED_EVENT }, 80 { PowerIdleEventIoIncrement, FxIdleTimedOutIoIncrement DEBUGGED_EVENT }, 81 }; 82 83 const FxPowerIdleTargetState FxPowerIdleMachine::m_InDxStates[] = 84 { 85 { PowerIdleEventPowerUpComplete, FxIdlePowerUp DEBUGGED_EVENT }, 86 { PowerIdleEventPowerUpFailed, FxIdleInDxPowerUpFailure DEBUGGED_EVENT }, 87 { PowerIdleEventPowerDownFailed, FxIdleInDxPowerUpFailure TRAP_ON_EVENT }, 88 { PowerIdleEventStop, FxIdleInDxStopped DEBUGGED_EVENT }, 89 { PowerIdleEventDisabled, FxIdleInDxDisabled DEBUGGED_EVENT }, 90 { PowerIdleEventIoIncrement, FxIdleInDxIoIncrement DEBUGGED_EVENT }, 91 { PowerIdleEventIoDecrement, FxIdleInDx DEBUGGED_EVENT }, 92 { PowerIdleEventPowerDown, FxIdleInDx DEBUGGED_EVENT }, 93 { PowerIdleEventEnabled, FxIdleInDxEnabled DEBUGGED_EVENT }, 94 }; 95 96 const FxPowerIdleTargetState FxPowerIdleMachine::m_WaitForTimeoutStates[] = 97 { 98 { PowerIdleEventTimerExpired, FxIdleTimerExpired DEBUGGED_EVENT }, 99 { PowerIdleEventPowerDownFailed, FxIdlePowerFailedWaitForTimeout TRAP_ON_EVENT }, 100 { PowerIdleEventDisabled, FxIdleDisablingWaitForTimeout DEBUGGED_EVENT }, 101 }; 102 103 const FxPowerIdleTargetState FxPowerIdleMachine::m_DisablingWaitForTimeoutStates[] = 104 { 105 { PowerIdleEventTimerExpired, FxIdleDisablingTimerExpired DEBUGGED_EVENT }, 106 }; 107 108 const FxPowerIdleTargetState FxPowerIdleMachine::m_PowerFailedWaitForTimeoutStates[] = 109 { 110 { PowerIdleEventTimerExpired, FxIdlePowerFailed TRAP_ON_EVENT }, 111 }; 112 113 const FxIdleStateTable FxPowerIdleMachine::m_StateTable[] = 114 { 115 // FxIdleStopped 116 { FxPowerIdleMachine::Stopped, 117 FxPowerIdleMachine::m_StoppedStates, 118 ARRAY_SIZE(FxPowerIdleMachine::m_StoppedStates), 119 }, 120 121 // FxIdleStarted 122 { FxPowerIdleMachine::Started, 123 FxPowerIdleMachine::m_StartedStates, 124 ARRAY_SIZE(FxPowerIdleMachine::m_StartedStates), 125 }, 126 127 // FxIdleStartedPowerUp 128 { FxPowerIdleMachine::StartedPowerUp, 129 NULL, 130 0, 131 }, 132 133 // FxIdleStartedPowerFailed 134 { FxPowerIdleMachine::StartedPowerFailed, 135 NULL, 136 0, 137 }, 138 139 // FxIdleDisabled 140 { FxPowerIdleMachine::Disabled, 141 FxPowerIdleMachine::m_DisabledStates, 142 ARRAY_SIZE(FxPowerIdleMachine::m_DisabledStates), 143 }, 144 145 // FxIdleCheckIoCount 146 { FxPowerIdleMachine::CheckIoCount, 147 NULL, 148 0, 149 }, 150 151 // FxIdleBusy 152 { NULL, 153 FxPowerIdleMachine::m_BusyStates, 154 ARRAY_SIZE(FxPowerIdleMachine::m_BusyStates), 155 }, 156 157 // FxIdleDecrementIo 158 { FxPowerIdleMachine::DecrementIo, 159 NULL, 160 0, 161 }, 162 163 // FxIdleStartTimer 164 { FxPowerIdleMachine::StartTimer, 165 NULL, 166 0, 167 }, 168 169 // FxIdleTimerRunning 170 { NULL, 171 FxPowerIdleMachine::m_TimerRunningStates, 172 ARRAY_SIZE(FxPowerIdleMachine::m_TimerRunningStates) 173 }, 174 175 // FxIdleTimingOut 176 { FxPowerIdleMachine::TimingOut, 177 NULL, 178 0, 179 }, 180 181 // FxIdleTimedOut 182 { NULL, 183 FxPowerIdleMachine::m_TimedOutStates, 184 ARRAY_SIZE(FxPowerIdleMachine::m_TimedOutStates), 185 }, 186 187 // FxIdleTimedOutIoIncrement 188 { FxPowerIdleMachine::TimedOutIoIncrement, 189 NULL, 190 0, 191 }, 192 193 // FxIdleTimedOutPowerDown 194 { FxPowerIdleMachine::TimedOutPowerDown, 195 NULL, 196 0, 197 }, 198 199 // FxIdleTimedOutPowerDownFailed 200 { FxPowerIdleMachine::TimedOutPowerDownFailed, 201 NULL, 202 0, 203 }, 204 205 // FxIdleGoingToDx, 206 { FxPowerIdleMachine::GoingToDx, 207 NULL, 208 0, 209 }, 210 211 // FxIdleInDx, 212 { FxPowerIdleMachine::InDx, 213 FxPowerIdleMachine::m_InDxStates, 214 ARRAY_SIZE(FxPowerIdleMachine::m_InDxStates), 215 }, 216 217 // FxIdleInDxIoIncrement 218 { FxPowerIdleMachine::InDxIoIncrement, 219 NULL, 220 0, 221 }, 222 223 // FxIdleInDxPowerUpFailure 224 { FxPowerIdleMachine::InDxPowerUpFailure, 225 NULL, 226 0, 227 }, 228 229 // FxIdleInDxStopped 230 { FxPowerIdleMachine::InDxStopped, 231 NULL, 232 0, 233 }, 234 235 // FxIdleInDxDisabled 236 { FxPowerIdleMachine::InDxDisabled, 237 NULL, 238 0, 239 }, 240 241 // FxIdleInDxEnabled 242 { FxPowerIdleMachine::InDxEnabled, 243 NULL, 244 0, 245 }, 246 247 // FxIdlePowerUp 248 { FxPowerIdleMachine::PowerUp, 249 NULL, 250 0, 251 }, 252 253 // FxIdlePowerUpComplete 254 { FxPowerIdleMachine::PowerUpComplete, 255 NULL, 256 0, 257 }, 258 259 // FxIdleTimedOutDisabled 260 { FxPowerIdleMachine::TimedOutDisabled, 261 NULL, 262 0, 263 }, 264 265 // FxIdleTimedOutEnabled 266 { FxPowerIdleMachine::TimedOutEnabled, 267 NULL, 268 0, 269 }, 270 271 // FxIdleCancelTimer 272 { FxPowerIdleMachine::CancelTimer, 273 NULL, 274 0, 275 }, 276 277 // FxIdleWaitForTimeout 278 { NULL, 279 FxPowerIdleMachine::m_WaitForTimeoutStates, 280 ARRAY_SIZE(FxPowerIdleMachine::m_WaitForTimeoutStates), 281 }, 282 283 // FxIdleTimerExpired 284 { FxPowerIdleMachine::TimerExpired, 285 NULL, 286 0, 287 }, 288 289 // FxIdleDisabling 290 { FxPowerIdleMachine::Disabling, 291 NULL, 292 0, 293 }, 294 295 // FxIdleDisablingWaitForTimeout 296 { NULL, 297 FxPowerIdleMachine::m_DisablingWaitForTimeoutStates, 298 ARRAY_SIZE(FxPowerIdleMachine::m_DisablingWaitForTimeoutStates), 299 }, 300 301 // FxIdleDisablingTimerExpired 302 { FxPowerIdleMachine::DisablingTimerExpired, 303 NULL, 304 0, 305 }, 306 307 // FxIdlePowerFailedWaitForTimeout 308 { NULL, 309 FxPowerIdleMachine::m_PowerFailedWaitForTimeoutStates, 310 ARRAY_SIZE(FxPowerIdleMachine::m_PowerFailedWaitForTimeoutStates), 311 }, 312 313 // FxIdlePowerFailed 314 { FxPowerIdleMachine::PowerFailed, 315 NULL, 316 0, 317 }, 318 }; 319 320 __inline 321 FxPkgPnp* 322 GetPnpPkg( 323 __inout FxPowerIdleMachine* This 324 ) 325 { 326 return CONTAINING_RECORD(This, 327 FxPowerPolicyOwnerSettings, 328 m_PowerIdleMachine)->m_PkgPnp; 329 } 330 331 332 FxPowerIdleMachine::FxPowerIdleMachine( 333 VOID 334 ) 335 /*++ 336 337 Routine Description: 338 Constructs the power idle state machine 339 340 Arguments: 341 None 342 343 Return Value: 344 None 345 346 --*/ 347 { 348 // 349 // m_Lock and m_PowerTimeoutTimer are now being initialized in Init method 350 // since they may fail for UM. 351 // 352 353 m_PowerTimeout.QuadPart = 0; 354 m_CurrentIdleState = FxIdleStopped; 355 356 m_EventHistoryIndex = 0; 357 m_StateHistoryIndex = 0; 358 359 RtlZeroMemory(&m_EventHistory[0], sizeof(m_EventHistory)); 360 RtlZeroMemory(&m_StateHistory[0], sizeof(m_StateHistory)); 361 362 m_TagTracker = NULL; 363 } 364 365 FxPowerIdleMachine::~FxPowerIdleMachine( 366 VOID 367 ) 368 { 369 if (m_TagTracker != NULL) { 370 delete m_TagTracker; 371 m_TagTracker = NULL; 372 } 373 } 374 375 _Must_inspect_result_ 376 NTSTATUS 377 FxPowerIdleMachine::Init( 378 VOID 379 ) 380 { 381 NTSTATUS status; 382 383 // 384 // For KM, event initialize always succeeds. For UM, it might fail. 385 // 386 status = m_D0NotificationEvent.Initialize(NotificationEvent, TRUE); 387 if (!NT_SUCCESS(status)) { 388 return status; 389 } 390 391 // 392 // For KM, timer initialize always succeeds. For UM, it might fail. 393 // 394 status = m_PowerTimeoutTimer.Initialize(this, _PowerTimeoutDpcRoutine, 0); 395 if (!NT_SUCCESS(status)) { 396 return status; 397 } 398 399 Reset(); 400 401 return STATUS_SUCCESS; 402 } 403 404 VOID 405 FxPowerIdleMachine::CheckAssumptions( 406 VOID 407 ) 408 /*++ 409 410 Routine Description: 411 This routine is never actually called by running code, it just has 412 WDFCASSERTs who upon failure, would not allow this file to be compiled. 413 414 DO NOT REMOVE THIS FUNCTION just because it is not called by any running 415 code. 416 417 Arguments: 418 None 419 420 Return Value: 421 None 422 423 --*/ 424 { 425 WDFCASSERT((sizeof(m_StateTable)/sizeof(m_StateTable[0])) 426 == 427 (FxIdleMax - FxIdleStopped)); 428 } 429 430 FxPowerIdleStates 431 FxPowerIdleMachine::Stopped( 432 __inout FxPowerIdleMachine* This 433 ) 434 /*++ 435 436 Routine Description: 437 State machine has entered the stopped state, clear the started flag 438 439 Arguments: 440 This - instance of the state machine 441 442 Return Value: 443 FxIdleMax 444 445 --*/ 446 { 447 This->m_Flags &= ~FxPowerIdleIsStarted; 448 449 return FxIdleMax; 450 } 451 452 FxPowerIdleStates 453 FxPowerIdleMachine::Started( 454 __inout FxPowerIdleMachine* This 455 ) 456 /*++ 457 458 Routine Description: 459 State machine has entered the started state, set the started flag 460 461 Arguments: 462 This - instance of the state machine 463 464 Return Value: 465 FxIdleMax 466 467 --*/ 468 { 469 This->m_Flags |= FxPowerIdleIsStarted; 470 471 // 472 // We are in the started state, but we are not powered up. 473 // 474 This->m_D0NotificationEvent.Clear(); 475 476 return FxIdleMax; 477 } 478 479 FxPowerIdleStates 480 FxPowerIdleMachine::StartedPowerUp( 481 __inout FxPowerIdleMachine* This 482 ) 483 /*++ 484 485 Routine Description: 486 We were in the started and powered off state. We are powered up, 487 so set the event now so that we can wake up any waiters. 488 489 Arguments: 490 This - instance of the state machine 491 492 Return Value: 493 FxIdleDisabled 494 495 --*/ 496 { 497 // 498 // Moving from the started state to the powered on state 499 // 500 This->SendD0Notification(); 501 502 return FxIdleDisabled; 503 } 504 505 FxPowerIdleStates 506 FxPowerIdleMachine::StartedPowerFailed( 507 __inout FxPowerIdleMachine* This 508 ) 509 /*++ 510 511 Routine Description: 512 The state machine was started, but the initial power up failed. Mark the 513 failure. 514 515 Arguments: 516 This - instance of the state machine 517 518 Return Value: 519 FxIdleStarted 520 521 --*/ 522 { 523 // 524 // Failed to initially power up 525 // 526 This->m_Flags |= FxPowerIdlePowerFailed; 527 528 // 529 // We assume in the started state that the event is set 530 // 531 ASSERT(This->m_D0NotificationEvent.ReadState() == 0); 532 533 return FxIdleStarted; 534 } 535 536 FxPowerIdleStates 537 FxPowerIdleMachine::Disabled( 538 __inout FxPowerIdleMachine* This 539 ) 540 /*++ 541 542 Routine Description: 543 State machine has entered the disabled state, unblock all waiters 544 545 Arguments: 546 This - instance of the state machine 547 548 Return Value: 549 FxIdleMax 550 551 --*/ 552 553 { 554 This->m_Flags &= ~FxPowerIdleTimerEnabled; 555 556 return FxIdleMax; 557 } 558 559 FxPowerIdleStates 560 FxPowerIdleMachine::CheckIoCount( 561 __inout FxPowerIdleMachine* This 562 ) 563 /*++ 564 565 Routine Description: 566 Checks the IO count and transitions the appropriate state. This is the 567 first state we are in after being disabled or after transitioning from Dx to 568 D0. 569 570 Arguments: 571 This - instance of the state machine 572 573 Return Value: 574 new state machine state 575 576 --*/ 577 { 578 This->m_Flags |= FxPowerIdleTimerEnabled; 579 580 if (This->m_IoCount == 0) { 581 return FxIdleStartTimer; 582 } 583 else { 584 return FxIdleBusy; 585 } 586 } 587 588 FxPowerIdleStates 589 FxPowerIdleMachine::DecrementIo( 590 __inout FxPowerIdleMachine* This 591 ) 592 /*++ 593 594 Routine Description: 595 Checks the IO count and returns a new state 596 597 Arguments: 598 This - instance of the state machine 599 600 Return Value: 601 new state machine state 602 603 --*/ 604 { 605 if (This->m_IoCount == 0) { 606 return FxIdleStartTimer; 607 } 608 else { 609 return FxIdleBusy; 610 } 611 } 612 613 FxPowerIdleStates 614 FxPowerIdleMachine::StartTimer( 615 __inout FxPowerIdleMachine* This 616 ) 617 /*++ 618 619 Routine Description: 620 The io count is now at zero. Start the idle timer so that when it expires, 621 the device will move into Dx. 622 623 Arguments: 624 This - instance of the state machine 625 626 Return Value: 627 FxIdleMax 628 629 --*/ 630 { 631 ASSERT((This->m_Flags & FxPowerIdleTimerEnabled) && This->m_IoCount == 0); 632 633 This->m_Flags |= FxPowerIdleTimerStarted; 634 This->m_PowerTimeoutTimer.Start(This->m_PowerTimeout, 635 m_IdleTimerTolerableDelayMS); 636 637 return FxIdleTimerRunning; 638 } 639 640 641 FxPowerIdleStates 642 FxPowerIdleMachine::TimingOut( 643 __inout FxPowerIdleMachine* This 644 ) 645 /*++ 646 647 Routine Description: 648 The idle timer has expired. Indicate to the power policy state machine 649 that it should power down. 650 651 Arguments: 652 This - instance of the state machine 653 654 Return Value: 655 FxIdleTimedOut 656 657 --*/ 658 { 659 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 660 GetPnpPkg(This)->PowerPolicyProcessEvent(PwrPolPowerTimeoutExpired); 661 #else 662 GetPnpPkg(This)->PowerPolicyProcessEvent( 663 PwrPolPowerTimeoutExpired, 664 TRUE // ProcessEventOnDifferentThread 665 ); 666 #endif 667 668 // 669 // Timer is no longer running. Used when we disable the state machine and 670 // need to know the timer's running state. 671 // 672 // 673 This->m_Flags &= ~FxPowerIdleTimerStarted; 674 675 // 676 // While the device is still powered up, we are no longer in D0 in terms of 677 // PowerReference returning immmediately if TRUE is specified to that call. 678 // 679 This->m_D0NotificationEvent.Clear(); 680 681 return FxIdleTimedOut; 682 } 683 684 FxPowerIdleStates 685 FxPowerIdleMachine::TimedOutIoIncrement( 686 __inout FxPowerIdleMachine* This 687 ) 688 /*++ 689 690 Routine Description: 691 A power reference occurred after we notified the power policy machine of 692 a power timeout, but before we timed out. Send an io present event to the 693 power policy machine so that it can move into the D0 state/not timed out 694 state again. 695 696 Arguments: 697 This - instance of the state machine 698 699 Return Value: 700 FxIdleTimedOut 701 702 --*/ 703 { 704 FxPkgPnp* pPkgPnp; 705 706 pPkgPnp = GetPnpPkg(This); 707 708 if (This->m_Flags & FxPowerIdleIoPresentSent) { 709 DoTraceLevelMessage( 710 pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 711 "WDFDEVICE %p idle (in D0) not sending io present event (already sent)", 712 pPkgPnp->GetDevice()->GetHandle()); 713 } 714 else { 715 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 716 pPkgPnp->PowerPolicyProcessEvent(PwrPolIoPresent); 717 #else 718 pPkgPnp->PowerPolicyProcessEvent( 719 PwrPolIoPresent, 720 TRUE // ProcessEventOnDifferentThread 721 ); 722 #endif 723 724 This->m_Flags |= FxPowerIdleIoPresentSent; 725 } 726 727 return FxIdleTimedOut; 728 } 729 730 FxPowerIdleStates 731 FxPowerIdleMachine::TimedOutPowerDown( 732 __inout FxPowerIdleMachine* This 733 ) 734 /*++ 735 736 Routine Description: 737 The idle timer fired and we are now powering down. Clear the flag that 738 limits our sending of the io present event to one time while in the timed 739 out state. 740 741 Arguments: 742 This - instance of the state machine 743 744 Return Value: 745 FxIdleGoingToDx 746 747 --*/ 748 { 749 // 750 // We can send the io present event again 751 // 752 This->m_Flags &= ~FxPowerIdleIoPresentSent; 753 754 return FxIdleGoingToDx; 755 } 756 757 FxPowerIdleStates 758 FxPowerIdleMachine::TimedOutPowerDownFailed( 759 __inout FxPowerIdleMachine* This 760 ) 761 /*++ 762 763 Routine Description: 764 The idle timer fired and we could no power down. Clear the flag that 765 limits our sending of the io present event to one time while in the timed 766 out state. 767 768 Arguments: 769 This - instance of the state machine 770 771 Return Value: 772 FxIdlePowerFailed 773 774 --*/ 775 { 776 // 777 // We can send the io present event again 778 // 779 This->m_Flags &= ~FxPowerIdleIoPresentSent; 780 781 return FxIdlePowerFailed; 782 } 783 784 FxPowerIdleStates 785 FxPowerIdleMachine::GoingToDx( 786 __inout FxPowerIdleMachine* This 787 ) 788 /*++ 789 790 Routine Description: 791 The device is going into Dx. It could be going into Dx because the idle 792 timer expired or because the machine is moving into Sx, the reason doesn't 793 matter though. Clear the in D0 event. 794 795 Arguments: 796 This - instance of the state machine 797 798 Return Value: 799 FxIdleInDx 800 801 --*/ 802 { 803 This->m_D0NotificationEvent.Clear(); 804 return FxIdleInDx; 805 } 806 807 FxPowerIdleStates 808 FxPowerIdleMachine::InDx( 809 __inout FxPowerIdleMachine* This 810 ) 811 /*++ 812 813 Routine Description: 814 The device has moved into Dx. If there is no pending io, mark the device 815 as idle. We can be in Dx with pending io if IoIncrement was called after 816 the device moved into Dx. 817 818 Arguments: 819 This - instance of the state machine 820 821 Return Value: 822 FxIdleMax 823 824 --*/ 825 { 826 This->m_Flags |= FxPowerIdleInDx; 827 828 return FxIdleMax; 829 } 830 831 FxPowerIdleStates 832 FxPowerIdleMachine::InDxIoIncrement( 833 __inout FxPowerIdleMachine* This 834 ) 835 /*++ 836 837 Routine Description: 838 In Dx and the io count went up. Send the event to the power policy state 839 machine indicating new io is present. 840 841 Arguments: 842 This - instance of the state machine 843 844 Return Value: 845 FxIdleInDx 846 847 --*/ 848 { 849 FxPkgPnp* pPkgPnp; 850 851 pPkgPnp = GetPnpPkg(This); 852 853 if (This->m_Flags & FxPowerIdleIoPresentSent) { 854 DoTraceLevelMessage( 855 pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 856 "WDFDEVICE %p idle (in Dx) not sending io present event (already sent)", 857 pPkgPnp->GetDevice()->GetHandle()); 858 } 859 else { 860 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 861 pPkgPnp->PowerPolicyProcessEvent(PwrPolIoPresent); 862 #else 863 pPkgPnp->PowerPolicyProcessEvent( 864 PwrPolIoPresent, 865 TRUE // ProcessEventOnDifferentThread 866 ); 867 #endif 868 This->m_Flags |= FxPowerIdleIoPresentSent; 869 } 870 871 return FxIdleInDx; 872 } 873 874 FxPowerIdleStates 875 FxPowerIdleMachine::InDxPowerUpFailure( 876 __inout FxPowerIdleMachine* This 877 ) 878 /*++ 879 880 Routine Description: 881 Device is in Dx and there was a failure in the power up path. The device 882 is no longer idle, even though it is stil in Dx. 883 884 Arguments: 885 This - instance of the state machine 886 887 Return Value: 888 FxIdlePowerFailed 889 890 --*/ 891 { 892 // 893 // FxPowerIdleInDx - We are no longer in Dx 894 // FxPowerIdleIoPresentSent = We can send the io present event again 895 // 896 This->m_Flags &= ~(FxPowerIdleInDx | FxPowerIdleIoPresentSent); 897 898 return FxIdlePowerFailed; 899 } 900 901 FxPowerIdleStates 902 FxPowerIdleMachine::InDxStopped( 903 __inout FxPowerIdleMachine* This 904 ) 905 /*++ 906 907 Routine Description: 908 The state machine was stopped while in the Dx state. When the machine is in 909 the stopped state, the notification event is in the signaled state. 910 911 Arguments: 912 This - instance of the state machine 913 914 Return Value: 915 FxIdleStopped 916 917 --*/ 918 { 919 // 920 // When the machine is in the stopped state, the notification event is in 921 // the signaled state. 922 // 923 This->SendD0Notification(); 924 925 // 926 // We are not longer idle since we are not in the Dx state anymore 927 // 928 This->m_Flags &= ~FxPowerIdleInDx; 929 930 // 931 // We are no longer enabled since we are stopped from the Dx state 932 // 933 This->m_Flags &= ~FxPowerIdleTimerEnabled; 934 935 // 936 // We can send the io present event again 937 // 938 This->m_Flags &= ~FxPowerIdleIoPresentSent; 939 940 return FxIdleStopped; 941 } 942 943 FxPowerIdleStates 944 FxPowerIdleMachine::InDxDisabled( 945 __inout FxPowerIdleMachine* This 946 ) 947 /*++ 948 949 Routine Description: 950 The device is in Dx and the state machine is being disabled (most likely due 951 to a surprise remove). 952 953 Arguments: 954 This - instance of the state machine 955 956 Return Value: 957 FxIdleDisabled 958 959 --*/ 960 { 961 // 962 // Idle timer is being disabled while in Dx. Remain in Dx. 963 // 964 This->m_Flags &= ~FxPowerIdleTimerEnabled; 965 966 return FxIdleInDx; 967 } 968 969 FxPowerIdleStates 970 FxPowerIdleMachine::InDxEnabled( 971 __inout FxPowerIdleMachine* This 972 ) 973 /*++ 974 975 Routine Description: 976 The device is in Dx and the state machine is being enabled (most like due 977 to trying to remain in Dx after Sx->S0. 978 979 Arguments: 980 This - instance of the state machine 981 982 Return Value: 983 FxIdleInDx 984 985 --*/ 986 { 987 // 988 // Idle timer is being enabled while in Dx. Remain in Dx. 989 // 990 This->m_Flags |= FxPowerIdleTimerEnabled; 991 992 return FxIdleInDx; 993 } 994 995 FxPowerIdleStates 996 FxPowerIdleMachine::PowerUp( 997 __inout FxPowerIdleMachine* This 998 ) 999 /*++ 1000 1001 Routine Description: 1002 The device powered up enough to where we can let waiters go and start pounding 1003 on their hardware. 1004 1005 Arguments: 1006 This - instance of the state machine 1007 1008 Return Value: 1009 FxIdlePowerUpComplete 1010 1011 --*/ 1012 { 1013 // 1014 // FxPowerIdleInDx - we are not longer idle since we are not in the Dx state 1015 // anymore 1016 // FxPowerIdleIoPresentSent - We can send the io present event again 1017 // 1018 This->m_Flags &= ~(FxPowerIdleInDx | FxPowerIdleIoPresentSent); 1019 1020 This->SendD0Notification(); 1021 1022 return FxIdlePowerUpComplete; 1023 } 1024 1025 FxPowerIdleStates 1026 FxPowerIdleMachine::PowerUpComplete( 1027 __inout FxPowerIdleMachine* This 1028 ) 1029 /*++ 1030 1031 Routine Description: 1032 The device is moving into D0, determine which D0 state to move into 1033 based on the enabled state and io count. 1034 1035 Arguments: 1036 This - instance of the state machine 1037 1038 Return Value: 1039 new state 1040 1041 --*/ 1042 { 1043 if (This->m_Flags & FxPowerIdleTimerEnabled) { 1044 if (This->m_Flags & FxPowerIdleTimerStarted) { 1045 COVERAGE_TRAP(); 1046 return FxIdleTimerRunning; 1047 } 1048 else { 1049 return FxIdleCheckIoCount; 1050 } 1051 } 1052 else { 1053 // 1054 // Not enabled, better not have a timer running 1055 // 1056 ASSERT((This->m_Flags & FxPowerIdleTimerStarted) == 0); 1057 1058 return FxIdleDisabled; 1059 } 1060 } 1061 1062 FxPowerIdleStates 1063 FxPowerIdleMachine::TimedOutDisabled( 1064 __inout FxPowerIdleMachine* This 1065 ) 1066 /*++ 1067 1068 Routine Description: 1069 The power idle state machine is moving into the disabled state. Set the 1070 D0 event. 1071 1072 Arguments: 1073 This - instance of the state machine 1074 1075 Return Value: 1076 FxIdleDisabled 1077 1078 --*/ 1079 { 1080 // 1081 // Notify any waiters that we are now in D0 1082 // 1083 This->SendD0Notification(); 1084 1085 // 1086 // We can send the io present event again 1087 // 1088 This->m_Flags &= ~FxPowerIdleIoPresentSent; 1089 1090 return FxIdleDisabled; 1091 } 1092 1093 FxPowerIdleStates 1094 FxPowerIdleMachine::TimedOutEnabled( 1095 __inout FxPowerIdleMachine* This 1096 ) 1097 { 1098 // 1099 // Notify any waiters that we are now in D0 1100 // 1101 This->SendD0Notification(); 1102 1103 // 1104 // We can send the io present event again 1105 // 1106 This->m_Flags &= ~FxPowerIdleIoPresentSent; 1107 1108 return FxIdleCheckIoCount; 1109 } 1110 1111 FxPowerIdleStates 1112 FxPowerIdleMachine::CancelTimer( 1113 __inout FxPowerIdleMachine* This 1114 ) 1115 /*++ 1116 1117 Routine Description: 1118 The timer is running and we need to cancel it because of an io increment or 1119 the state machine being disabled. 1120 1121 Arguments: 1122 This - instance of the state machine 1123 1124 Return Value: 1125 new state 1126 1127 --*/ 1128 { 1129 if (This->CancelIdleTimer()) { 1130 return FxIdleCheckIoCount; 1131 } 1132 else { 1133 return FxIdleWaitForTimeout; 1134 } 1135 } 1136 1137 FxPowerIdleStates 1138 FxPowerIdleMachine::TimerExpired( 1139 __inout FxPowerIdleMachine* This 1140 ) 1141 /*++ 1142 1143 Routine Description: 1144 The timer was not canceled because it was running. The timer has now 1145 fired, so we can move forward. 1146 1147 Arguments: 1148 This - instance of the state machine 1149 1150 Return Value: 1151 FxIdleCheckIoCount 1152 1153 --*/ 1154 { 1155 This->m_Flags &= ~FxPowerIdleTimerStarted; 1156 1157 return FxIdleCheckIoCount; 1158 } 1159 1160 FxPowerIdleStates 1161 FxPowerIdleMachine::Disabling( 1162 __inout FxPowerIdleMachine* This 1163 ) 1164 /*++ 1165 1166 Routine Description: 1167 Timer is running and the state machine is being disabled. Cancel the idle 1168 timer. 1169 1170 Arguments: 1171 This - instance of the state machine 1172 1173 Return Value: 1174 new state 1175 1176 --*/ 1177 { 1178 if (This->CancelIdleTimer()) { 1179 return FxIdleDisabled; 1180 } 1181 else { 1182 return FxIdleDisablingWaitForTimeout; 1183 } 1184 } 1185 1186 FxPowerIdleStates 1187 FxPowerIdleMachine::DisablingTimerExpired( 1188 __inout FxPowerIdleMachine* This 1189 ) 1190 /*++ 1191 1192 Routine Description: 1193 When disabling the state machine, the timer could not be canceled. The 1194 timer has now expired and the state machine can move forward. 1195 1196 Arguments: 1197 This - instance of the state machine 1198 1199 Return Value: 1200 FxIdleDisabled 1201 1202 --*/ 1203 { 1204 This->m_Flags &= ~FxPowerIdleTimerStarted; 1205 1206 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 1207 GetPnpPkg(This)->PowerPolicyProcessEvent(PwrPolPowerTimeoutExpired); 1208 #else 1209 GetPnpPkg(This)->PowerPolicyProcessEvent( 1210 PwrPolPowerTimeoutExpired, 1211 TRUE // ProcessEventOnDifferentThread 1212 ); 1213 #endif 1214 1215 return FxIdleDisabled; 1216 } 1217 1218 FxPowerIdleStates 1219 FxPowerIdleMachine::PowerFailed( 1220 __inout FxPowerIdleMachine* This 1221 ) 1222 /*++ 1223 1224 Routine Description: 1225 A power operation (up or down) failed. Mark the machine as failed so that 1226 PowerReference will fail properly. 1227 1228 Arguments: 1229 This - instance of the state machine 1230 1231 Return Value: 1232 FxIdleDisabled 1233 1234 --*/ 1235 { 1236 // 1237 // By this time, the timer should be stopped 1238 // 1239 ASSERT((This->m_Flags & FxPowerIdleTimerStarted) == 0); 1240 1241 This->m_Flags |= FxPowerIdlePowerFailed; 1242 1243 // 1244 // We are no longer enabled to time out since we are in a failed state 1245 // 1246 This->m_Flags &= ~FxPowerIdleTimerEnabled; 1247 1248 // 1249 // Wake up any waiters and indicate failure to them. 1250 // 1251 This->SendD0Notification(); 1252 1253 return FxIdleDisabled; 1254 } 1255 1256 __drv_maxIRQL(DISPATCH_LEVEL) 1257 __drv_minIRQL(DISPATCH_LEVEL) 1258 __drv_requiresIRQL(DISPATCH_LEVEL) 1259 __drv_sameIRQL 1260 VOID 1261 FxPowerIdleMachine::_PowerTimeoutDpcRoutine( 1262 __in PKDPC Dpc, 1263 __in_opt PVOID Context, 1264 __in_opt PVOID SystemArgument1, 1265 __in_opt PVOID SystemArgument2 1266 ) 1267 /*++ 1268 1269 Routine Description: 1270 Timer DPC which posts the timeout expired event to the power policy state 1271 machine 1272 1273 Arguments: 1274 Dpc - DPC 1275 Context, SysArg1, SysArg2 - Unused 1276 1277 Return Value: 1278 None 1279 1280 --*/ 1281 { 1282 FxPowerIdleMachine* pThis; 1283 1284 UNREFERENCED_PARAMETER(Dpc); 1285 UNREFERENCED_PARAMETER(SystemArgument1); 1286 UNREFERENCED_PARAMETER(SystemArgument2); 1287 1288 pThis = (FxPowerIdleMachine*) Context; 1289 1290 pThis->m_Lock.AcquireAtDpcLevel(); 1291 pThis->ProcessEventLocked(PowerIdleEventTimerExpired); 1292 1293 #if FX_IS_KERNEL_MODE 1294 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1295 PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd; 1296 1297 pFxDriverGlobals = GetPnpPkg(pThis)->GetDriverGlobals(); 1298 1299 // 1300 // We need to provide XPerf with a symbol of the client to figure out 1301 // which component this idle timer is for. Since AddDevice is always there 1302 // we use that to pass the symbol along. 1303 // 1304 pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); 1305 1306 FxPerfTraceDpc(&pDriverDeviceAdd); 1307 #endif 1308 1309 pThis->m_Lock.ReleaseFromDpcLevel(); 1310 } 1311 1312 VOID 1313 FxPowerIdleMachine::Reset( 1314 VOID 1315 ) 1316 /*++ 1317 1318 Routine Description: 1319 Reset the state machine to a known state on a PDO restart. 1320 1321 Arguments: 1322 None 1323 1324 Return Value: 1325 None 1326 1327 --*/ 1328 { 1329 FxPkgPnp* pPkgPnp; 1330 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1331 1332 ASSERT(m_CurrentIdleState == FxIdleStopped); 1333 1334 m_IoCount = 0; 1335 m_Flags = 0x0; 1336 1337 pPkgPnp = GetPnpPkg(this); 1338 pFxDriverGlobals = pPkgPnp->GetDriverGlobals(); 1339 1340 if (pFxDriverGlobals->DebugExtension != NULL && 1341 pFxDriverGlobals->DebugExtension->TrackPower != FxTrackPowerNone) { 1342 // 1343 // Ignore potential failure, power ref tracking is not an essential feature. 1344 // 1345 (void)FxTagTracker::CreateAndInitialize(&m_TagTracker, 1346 pFxDriverGlobals, 1347 FxTagTrackerTypePower, 1348 pFxDriverGlobals->DebugExtension->TrackPower == FxTrackPowerRefsAndStack, 1349 pPkgPnp->GetDevice()); 1350 } 1351 1352 SendD0Notification(); 1353 } 1354 1355 VOID 1356 FxPowerIdleMachine::EnableTimer( 1357 VOID 1358 ) 1359 /*++ 1360 1361 Routine Description: 1362 Public function that the power policy state machine uses to put this state 1363 machine in to an enabled state and potentially start the idle timer. 1364 1365 Arguments: 1366 None 1367 1368 Return Value: 1369 None 1370 1371 --*/ 1372 { 1373 KIRQL irql; 1374 1375 m_Lock.Acquire(&irql); 1376 ProcessEventLocked(PowerIdleEventEnabled); 1377 m_Lock.Release(irql); 1378 } 1379 1380 BOOLEAN 1381 FxPowerIdleMachine::DisableTimer( 1382 VOID 1383 ) 1384 /*++ 1385 1386 Routine Description: 1387 Public function which the power policy state machine uses to put this state 1388 machine into a disabled state. If necessary, the state machine will attempt 1389 to cancel the idle timer. 1390 1391 Arguments: 1392 None 1393 1394 Return Value: 1395 TRUE if the idle timer was cancelled and the caller may proceed directly to 1396 its new state 1397 1398 FALSE if the idle timer was not cancelled and the caller must wait for the 1399 io timeout event to be posted before proceeding. 1400 1401 --*/ 1402 { 1403 KIRQL irql; 1404 BOOLEAN disabledImmediately; 1405 1406 m_Lock.Acquire(&irql); 1407 1408 ProcessEventLocked(PowerIdleEventDisabled); 1409 1410 // 1411 // If FxPowerIdleTimerStarted is still set after disabling the state machine, 1412 // then we could not cancel the timer and we must wait for the timer expired 1413 // event to be posted to this state machine. This state machine will then 1414 // post a PwrPolIoPresent event to power policy. 1415 // 1416 if (m_Flags & FxPowerIdleTimerStarted) { 1417 disabledImmediately = FALSE; 1418 } 1419 else { 1420 disabledImmediately = TRUE; 1421 } 1422 1423 m_Lock.Release(irql); 1424 1425 return disabledImmediately; 1426 } 1427 1428 VOID 1429 FxPowerIdleMachine::Start( 1430 VOID 1431 ) 1432 /*++ 1433 1434 Routine Description: 1435 Public function that the power policy state machine uses to put this state 1436 machine into a started state so that the caller can call PowerReference 1437 successfully. 1438 1439 Arguments: 1440 None 1441 1442 Return Value: 1443 None 1444 1445 --*/ 1446 { 1447 KIRQL irql; 1448 m_Lock.Acquire(&irql); 1449 ProcessEventLocked(PowerIdleEventStart); 1450 m_Lock.Release(irql); 1451 } 1452 1453 VOID 1454 FxPowerIdleMachine::Stop( 1455 VOID 1456 ) 1457 /*++ 1458 1459 Routine Description: 1460 Public function which the power policy state machine uses to put this state 1461 machine into a state where PowerReference will no longer work. 1462 1463 Arguments: 1464 None 1465 1466 Return Value: 1467 None 1468 1469 --*/ 1470 { 1471 KIRQL irql; 1472 1473 m_Lock.Acquire(&irql); 1474 ProcessEventLocked(PowerIdleEventStop); 1475 m_Lock.Release(irql); 1476 } 1477 1478 _Must_inspect_result_ 1479 NTSTATUS 1480 FxPowerIdleMachine::PowerReferenceWorker( 1481 __in BOOLEAN WaitForD0, 1482 __in FxPowerReferenceFlags Flags, 1483 __in_opt PVOID Tag, 1484 __in_opt LONG Line, 1485 __in_opt PSTR File 1486 ) 1487 /*++ 1488 1489 Routine Description: 1490 Caller wants to move the device into D0 manually. The caller may optionally 1491 wait synchronously for the transition to occur if the device is currently in 1492 Dx. 1493 1494 Arguments: 1495 WaitForD0 - TRUE if the caller wants to synchronously wait for the Dx to D0 1496 transition 1497 1498 QueryPnpPending - TRUE if we are being called to bring the device back to 1499 working state when a QueryRemove or a QueryStop 1500 1501 Return Value: 1502 NTSTATUS 1503 1504 STATUS_SUCCESS - success 1505 STATUS_PENDING - transition is occurring 1506 STATUS_POWER_STATE_INVALID - ower transition has failed 1507 1508 --*/ 1509 { 1510 NTSTATUS status; 1511 KIRQL irql; 1512 ULONG count = 0; 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 // 1533 // Poke the state machine 1534 // 1535 status = IoIncrementWithFlags(Flags, &count); 1536 1537 // 1538 // STATUS_PENDING indicates a Dx to D0 transition is occurring right now 1539 // 1540 if (status == STATUS_PENDING) { 1541 if (WaitForD0) { 1542 FxPkgPnp* pPkgPnp; 1543 1544 ASSERT(Mx::MxGetCurrentIrql() <= APC_LEVEL); 1545 1546 // 1547 // With the current usage, if WaitForD0 is TRUE, then the only 1548 // acceptable flag is FxPowerReferenceDefault. 1549 // 1550 // If the usage changes in the future such that it is acceptable to 1551 // have WaitForD0 set to TRUE and some flag(s) set, then the ASSERT 1552 // below should be updated accordingly (or removed altogether). 1553 // 1554 ASSERT(FxPowerReferenceDefault == Flags); 1555 1556 pPkgPnp = GetPnpPkg(this); 1557 1558 DoTraceLevelMessage( 1559 pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 1560 "WDFDEVICE %p in thread %p waiting synchronously for Dx to D0 " 1561 "transition", 1562 pPkgPnp->GetDevice()->GetHandle(), 1563 Mx::MxGetCurrentThread()); 1564 1565 // 1566 // Returns success always 1567 // 1568 (void) FxPowerIdleMachine::WaitForD0(); 1569 1570 m_Lock.Acquire(&irql); 1571 1572 // 1573 // If WaitForD0 is TRUE, then the FxPowerIdleSendPnpPowerUpEvent 1574 // flag can't be set. That flag is only used when the PnP state 1575 // machine waits asynchronously for the device to power up during 1576 // query-remove. 1577 // 1578 ASSERT(0 == (m_Flags & FxPowerIdleSendPnpPowerUpEvent)); 1579 1580 if ((m_Flags & FxPowerIdlePowerFailed) != 0x0 || 1581 (m_Flags & FxPowerIdleIsStarted) == 0x0) { 1582 1583 // 1584 // Event was set because a power up or down failure occurred 1585 // 1586 status = STATUS_POWER_STATE_INVALID; 1587 1588 if (m_Flags & FxPowerIdlePowerFailed) { 1589 DoTraceLevelMessage( 1590 pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 1591 "WDFDEVICE %p waiting for D0 in thread %p failed because of " 1592 "power failure, %!STATUS!", 1593 pPkgPnp->GetDevice()->GetHandle(), 1594 Mx::MxGetCurrentThread(), 1595 status); 1596 } 1597 else { 1598 COVERAGE_TRAP(); 1599 DoTraceLevelMessage( 1600 pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 1601 "WDFDEVICE %p waiting for D0 in thread %p failed because of " 1602 "invalid state , %!STATUS!", 1603 pPkgPnp->GetDevice()->GetHandle(), 1604 Mx::MxGetCurrentThread(), status); 1605 } 1606 1607 // 1608 // Decrement the io count that was taken above 1609 // 1610 ASSERT(m_IoCount > 0); 1611 m_IoCount--; 1612 ProcessEventLocked(PowerIdleEventIoDecrement); 1613 } 1614 else { 1615 // 1616 // Successfully returned to D0 1617 // 1618 status = STATUS_SUCCESS; 1619 } 1620 m_Lock.Release(irql); 1621 } 1622 } 1623 1624 if (m_TagTracker != NULL) { 1625 // 1626 // Only track the reference if the call was successful 1627 // and the counter was actually incremented. 1628 // 1629 if (status == STATUS_SUCCESS || status == STATUS_PENDING) { 1630 m_TagTracker->UpdateTagHistory(Tag, Line, File, TagAddRef, count); 1631 } 1632 } 1633 1634 return status; 1635 } 1636 1637 _Must_inspect_result_ 1638 NTSTATUS 1639 FxPowerIdleMachine::IoIncrement( 1640 VOID 1641 ) 1642 /*++ 1643 1644 Routine Description: 1645 Public function for any component to increment the io count. The increment 1646 may cause the state machine to move out of the enabled state depending on 1647 the current state. 1648 1649 Arguments: 1650 None 1651 1652 Return Value: 1653 STATUS_PENDING if the state machine is transition from idle to non idle 1654 1655 STATUS_SUCCESS otherwise 1656 1657 --*/ 1658 { 1659 return IoIncrementWithFlags(FxPowerReferenceDefault); 1660 } 1661 1662 _Must_inspect_result_ 1663 NTSTATUS 1664 FxPowerIdleMachine::IoIncrementWithFlags( 1665 __in FxPowerReferenceFlags Flags, 1666 __out_opt PULONG Count 1667 ) 1668 /*++ 1669 1670 Routine Description: 1671 An enchanced version of FxPowerIdleMachine::IoIncrement that has special 1672 behavior based on flags passed in by the caller. Please read the routine 1673 description of FxPowerIdleMachine::IoIncrement as well. 1674 1675 Arguments: 1676 Flags - The following flags are defined - 1677 FxPowerReferenceDefault - No special behavior 1678 FxPowerReferenceSendPnpPowerUpEvent - Set the 1679 FxPowerIdleSendPnpPowerUpEvent flag in the idle state machine flags. 1680 This will indicate to the idle state machine that when the device 1681 powers up, it needs to send the PnpEventDeviceInD0 event to the PnP 1682 state machine. 1683 1684 Return Value: 1685 STATUS_PENDING if the state machine is transition from idle to non idle 1686 1687 STATUS_SUCCESS otherwise 1688 1689 --*/ 1690 { 1691 NTSTATUS status; 1692 KIRQL irql; 1693 1694 m_Lock.Acquire(&irql); 1695 1696 if (m_Flags & FxPowerIdlePowerFailed) { 1697 // 1698 // fail without incrementing the count because we are in an 1699 // invalid power state 1700 // 1701 status = STATUS_POWER_STATE_INVALID; 1702 COVERAGE_TRAP(); 1703 } 1704 else if ((m_Flags & FxPowerIdleIsStarted) == 0x0) { 1705 // 1706 // The state machine is not yet in a started state 1707 // 1708 status = STATUS_POWER_STATE_INVALID; 1709 } 1710 else { 1711 m_IoCount++; 1712 if (Count != NULL) { 1713 *Count = m_IoCount; 1714 } 1715 1716 ProcessEventLocked(PowerIdleEventIoIncrement); 1717 1718 if (InD0Locked()) { 1719 status = STATUS_SUCCESS; 1720 } 1721 else { 1722 status = STATUS_PENDING; 1723 if (Flags & FxPowerReferenceSendPnpPowerUpEvent) { 1724 m_Flags |= FxPowerIdleSendPnpPowerUpEvent; 1725 } 1726 } 1727 } 1728 m_Lock.Release(irql); 1729 1730 return status; 1731 } 1732 1733 1734 VOID 1735 FxPowerIdleMachine::IoDecrement( 1736 __in_opt PVOID Tag, 1737 __in_opt LONG Line, 1738 __in_opt PSTR File 1739 ) 1740 /*++ 1741 1742 Routine Description: 1743 Public function which allows the caller decrement the pending io count on 1744 this state machine. If the count goes to zero and idle is enabled, then 1745 the timer is started. 1746 1747 Arguments: 1748 None 1749 1750 Return Value: 1751 None 1752 1753 --*/ 1754 { 1755 KIRQL irql; 1756 FxPkgPnp* pPkgPnp; 1757 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1758 ULONG count; 1759 1760 pPkgPnp = GetPnpPkg(this); 1761 pFxDriverGlobals = pPkgPnp->GetDriverGlobals(); 1762 1763 m_Lock.Acquire(&irql); 1764 1765 if (m_IoCount == 0) { 1766 // 1767 // We can get here for the following reasons: 1768 // 1. Driver called WdfDevicveStopIdle/WdfDeviceResumeIdle in a mismatched 1769 // manner. This is a driver bug. 1770 // 2. Framework did power deref without a corresponding power ref. 1771 // This would be a framework bug. 1772 // 1773 // We will break into debugger if verifier is turned on. This will allow 1774 // developers to catch this problem during develeopment. 1775 // We limit this break to version 1.11+ because otherwise older drivers 1776 // may hit this, and if they cannot be fixed for some reason, then 1777 // verifier would need to be turned off to avoid the break which is not 1778 // desirable. 1779 // 1780 DoTraceLevelMessage( 1781 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1782 "WDFDEVICE 0x%p !devobj 0x%p The device is being power-dereferenced" 1783 " without a matching power-reference. This could occur if driver" 1784 " incorrectly calls WdfDeviceResumeIdle without a matching call to" 1785 " WdfDeviceStopIdle.", 1786 pPkgPnp->GetDevice()->GetHandle(), 1787 pPkgPnp->GetDevice()->GetDeviceObject()); 1788 1789 if (pFxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) { 1790 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1791 } 1792 } 1793 1794 ASSERT(m_IoCount > 0); 1795 count = --m_IoCount; 1796 ProcessEventLocked(PowerIdleEventIoDecrement); 1797 m_Lock.Release(irql); 1798 1799 if (m_TagTracker != NULL) { 1800 m_TagTracker->UpdateTagHistory(Tag, Line, File, TagRelease, count); 1801 } 1802 } 1803 1804 BOOLEAN 1805 FxPowerIdleMachine::QueryReturnToIdle( 1806 VOID 1807 ) 1808 /*++ 1809 1810 Routine Description: 1811 Public function which allows the caller to query the current io count on 1812 this state machine. If the count non zero, the device will be brought back 1813 to D0. If zero, the device will remain in Dx. 1814 1815 Arguments: 1816 None 1817 1818 Return Value: 1819 if TRUE is returned, there is an outstanding IO. 1820 if FALSE is returned, the device is idle. 1821 1822 --*/ 1823 { 1824 KIRQL irql; 1825 BOOLEAN result; 1826 1827 // 1828 // To return to idle, the following must be true 1829 // 1) the device must be in Dx (FxPowerIdleInDx) 1830 // 2) the timer must *NOT* be running 1831 // 3) an IO count of zero 1832 // 1833 m_Lock.Acquire(&irql); 1834 1835 // 1 1836 if ((m_Flags & FxPowerIdleInDx) == FxPowerIdleInDx && 1837 // 2 3 1838 (m_Flags & FxPowerIdleTimerStarted) == 0 && m_IoCount == 0x0) { 1839 result = TRUE; 1840 } 1841 else { 1842 result = FALSE; 1843 } 1844 1845 // 1846 // If the caller is querying about returning to idle, then they have 1847 // processed the io present event that we previously sent. We must clear 1848 // the flag, otherwise the following can occur 1849 // 1) new io arrives, send the io present message 1850 // 2) return to idle (io count goes to zero) 1851 // 3) get queried to return to idle, return TRUE 1852 // 4) new io arrives, we do not send the new io present message because the 1853 // FxPowerIdleIoPresentSent flag is set. 1854 // 1855 m_Flags &= ~FxPowerIdleIoPresentSent; 1856 1857 m_Lock.Release(irql); 1858 1859 return result; 1860 } 1861 1862 VOID 1863 FxPowerIdleMachine::SendD0Notification( 1864 VOID 1865 ) 1866 { 1867 m_D0NotificationEvent.Set(); 1868 1869 if (m_Flags & FxPowerIdleSendPnpPowerUpEvent) { 1870 1871 m_Flags &= ~FxPowerIdleSendPnpPowerUpEvent; 1872 1873 // 1874 // Send an event to the Pnp state machine indicating that the device is 1875 // now in D0. 1876 // 1877 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) 1878 GetPnpPkg(this)->PnpProcessEvent(PnpEventDeviceInD0); 1879 #else 1880 GetPnpPkg(this)->PnpProcessEvent( 1881 PnpEventDeviceInD0, 1882 TRUE // ProcessEventOnDifferentThread 1883 ); 1884 #endif 1885 1886 } 1887 return; 1888 } 1889 1890 VOID 1891 FxPowerIdleMachine::ProcessPowerEvent( 1892 __in FxPowerIdleEvents Event 1893 ) 1894 /*++ 1895 1896 Routine Description: 1897 Post a power related event to the state machine. 1898 1899 Arguments: 1900 Event - the event to post 1901 1902 Return Value: 1903 None 1904 1905 --*/ 1906 { 1907 KIRQL irql; 1908 1909 // 1910 // All other event types have specialized public functions 1911 // 1912 ASSERT(Event == PowerIdleEventPowerUpComplete || 1913 Event == PowerIdleEventPowerUpFailed || 1914 Event == PowerIdleEventPowerDown || 1915 Event == PowerIdleEventPowerDownFailed); 1916 1917 m_Lock.Acquire(&irql); 1918 ProcessEventLocked(Event); 1919 m_Lock.Release(irql); 1920 } 1921 1922 VOID 1923 FxPowerIdleMachine::ProcessEventLocked( 1924 __in FxPowerIdleEvents Event 1925 ) 1926 /*++ 1927 1928 Routine Description: 1929 Processes an event and runs it through the state machine 1930 1931 Arguments: 1932 1933 1934 Return Value: 1935 1936 1937 --*/ 1938 1939 { 1940 const FxIdleStateTable* entry; 1941 FxPowerIdleStates newState; 1942 FxPkgPnp* pPkgPnp; 1943 1944 pPkgPnp = GetPnpPkg(this); 1945 1946 m_EventHistory[m_EventHistoryIndex] = Event; 1947 m_EventHistoryIndex = (m_EventHistoryIndex + 1) % 1948 (sizeof(m_EventHistory)/sizeof(m_EventHistory[0])); 1949 1950 entry = &m_StateTable[m_CurrentIdleState-FxIdleStopped]; 1951 newState = FxIdleMax; 1952 1953 for (ULONG i = 0; i < entry->TargetStatesCount; i++) { 1954 if (entry->TargetStates[i].PowerIdleEvent == Event) { 1955 DO_EVENT_TRAP(&entry->TargetStates[i]); 1956 newState = entry->TargetStates[i].PowerIdleState; 1957 break; 1958 } 1959 } 1960 1961 if (newState == FxIdleMax) { 1962 switch (Event) { 1963 case PowerIdleEventIoIncrement: 1964 case PowerIdleEventIoDecrement: 1965 // 1966 // We always can handle io increment, io decrement, and query return 1967 // to idle from any state... 1968 // 1969 break; 1970 1971 case PowerIdleEventEnabled: 1972 if (m_Flags & FxPowerIdleTimerEnabled) { 1973 // 1974 // Getting an enable event while enabled is OK 1975 // 1976 break; 1977 } 1978 // || || Fall || || 1979 // \/ \/ through \/ \/ 1980 1981 default: 1982 // 1983 // ...but we should not be dropping any other events from this state. 1984 // 1985 1986 // 1987 DoTraceLevelMessage( 1988 pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 1989 "WDFDEVICE 0x%p !devobj 0x%p power idle state %!FxPowerIdleStates!" 1990 " dropping event %!FxPowerIdleEvents!", 1991 pPkgPnp->GetDevice()->GetHandle(), 1992 pPkgPnp->GetDevice()->GetDeviceObject(), 1993 m_CurrentIdleState, Event); 1994 1995 COVERAGE_TRAP(); 1996 } 1997 } 1998 1999 while (newState != FxIdleMax) { 2000 2001 DoTraceLevelMessage( 2002 pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES, 2003 "WDFDEVICE 0x%p !devobj 0x%p entering power idle state " 2004 "%!FxPowerIdleStates! from %!FxPowerIdleStates!", 2005 pPkgPnp->GetDevice()->GetHandle(), 2006 pPkgPnp->GetDevice()->GetDeviceObject(), 2007 newState, m_CurrentIdleState); 2008 2009 m_StateHistory[m_StateHistoryIndex] = newState; 2010 m_StateHistoryIndex = (m_StateHistoryIndex + 1) % 2011 (sizeof(m_StateHistory)/sizeof(m_StateHistory[0])); 2012 2013 m_CurrentIdleState = newState; 2014 entry = &m_StateTable[m_CurrentIdleState-FxIdleStopped]; 2015 2016 if (entry->StateFunc != NULL) { 2017 newState = entry->StateFunc(this); 2018 } 2019 else { 2020 newState = FxIdleMax; 2021 } 2022 } 2023 } 2024