power.c 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. power.c
  5. Abstract:
  6. This module implements generic support for device runtime power managment
  7. within the kernel.
  8. Author:
  9. Evan Green 2-Sep-2015
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/kernel.h>
  17. #include "pmp.h"
  18. #include "iop.h"
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. //
  23. // Define the default delay in seconds before a device that has no power
  24. // references is sent an idle request.
  25. //
  26. #define PM_INITIAL_IDLE_DELAY_SECONDS 1
  27. //
  28. // Define the number of data points of device idle history to keep, expressed
  29. // as a bit shift.
  30. //
  31. #define PM_DEVICE_HISTORY_SIZE_SHIFT 5
  32. //
  33. // ------------------------------------------------------ Data Type Definitions
  34. //
  35. //
  36. // ----------------------------------------------- Internal Function Prototypes
  37. //
  38. KSTATUS
  39. PmpInitializeDevice (
  40. PDEVICE Device
  41. );
  42. VOID
  43. PmpDeviceIdleTimerDpc (
  44. PDPC Dpc
  45. );
  46. VOID
  47. PmpDeviceIdleWorker (
  48. PVOID Parameter
  49. );
  50. VOID
  51. PmpDeviceIncrementActiveChildren (
  52. PDEVICE Device
  53. );
  54. VOID
  55. PmpDeviceDecrementActiveChildren (
  56. PDEVICE Device
  57. );
  58. KSTATUS
  59. PmpDeviceAddReference (
  60. PDEVICE Device,
  61. DEVICE_POWER_REQUEST Request
  62. );
  63. KSTATUS
  64. PmpDeviceQueuePowerTransition (
  65. PDEVICE Device,
  66. DEVICE_POWER_REQUEST Request
  67. );
  68. KSTATUS
  69. PmpDeviceResume (
  70. PDEVICE Device,
  71. DEVICE_POWER_REQUEST Request
  72. );
  73. VOID
  74. PmpDeviceIdle (
  75. PDEVICE Device
  76. );
  77. VOID
  78. PmpDeviceSuspend (
  79. PDEVICE Device
  80. );
  81. //
  82. // -------------------------------------------------------------------- Globals
  83. //
  84. //
  85. // Set this boolean to TRUE to print power transitions.
  86. //
  87. BOOL PmDebugPowerTransitions;
  88. //
  89. // ------------------------------------------------------------------ Functions
  90. //
  91. KERNEL_API
  92. KSTATUS
  93. PmInitialize (
  94. PDEVICE Device
  95. )
  96. /*++
  97. Routine Description:
  98. This routine initializes power management infrastructure for a given
  99. device.
  100. Arguments:
  101. Device - Supplies a pointer to the device to prepare to do power management
  102. calls on.
  103. Return Value:
  104. Status code.
  105. --*/
  106. {
  107. if (Device->Power != NULL) {
  108. return STATUS_SUCCESS;
  109. }
  110. return PmpInitializeDevice(Device);
  111. }
  112. KERNEL_API
  113. KSTATUS
  114. PmDeviceAddReference (
  115. PDEVICE Device
  116. )
  117. /*++
  118. Routine Description:
  119. This routine adds a power management reference on the given device,
  120. and waits for the device to transition to the active state.
  121. Arguments:
  122. Device - Supplies a pointer to the device to add a power reference to.
  123. Return Value:
  124. Status code. On failure, the caller will not have a reference on the
  125. device, and should not assume that the device or its parent lineage is
  126. active.
  127. --*/
  128. {
  129. return PmpDeviceAddReference(Device, DevicePowerRequestResume);
  130. }
  131. KERNEL_API
  132. KSTATUS
  133. PmDeviceAddReferenceAsynchronous (
  134. PDEVICE Device
  135. )
  136. /*++
  137. Routine Description:
  138. This routine adds a power management reference on the given device,
  139. preventing the device from idling until the reference is released.
  140. Arguments:
  141. Device - Supplies a pointer to the device to add a power reference to.
  142. Return Value:
  143. Status code indicating if the request was successfully queued. On failure,
  144. the caller will not have the reference on the device.
  145. --*/
  146. {
  147. UINTN PreviousCount;
  148. PDEVICE_POWER State;
  149. KSTATUS Status;
  150. State = Device->Power;
  151. PreviousCount = RtlAtomicAdd(&(State->ReferenceCount), 1);
  152. ASSERT(PreviousCount < 0x10000000);
  153. if (PreviousCount != 0) {
  154. return STATUS_SUCCESS;
  155. }
  156. Status = PmpDeviceQueuePowerTransition(Device, DevicePowerRequestResume);
  157. if (!KSUCCESS(Status)) {
  158. RtlAtomicAdd(&(State->ReferenceCount), -1);
  159. }
  160. return Status;
  161. }
  162. KERNEL_API
  163. KSTATUS
  164. PmDeviceReleaseReference (
  165. PDEVICE Device
  166. )
  167. /*++
  168. Routine Description:
  169. This routine releases a power management reference on a device.
  170. Arguments:
  171. Device - Supplies a pointer to the device to subtract a power reference
  172. from.
  173. Return Value:
  174. Status code indicating if the idle timer was successfully queued. The
  175. reference itself is always dropped, even on failure.
  176. --*/
  177. {
  178. UINTN PreviousCount;
  179. PDEVICE_POWER State;
  180. KSTATUS Status;
  181. ULONG TimerQueued;
  182. State = Device->Power;
  183. Status = STATUS_SUCCESS;
  184. PreviousCount = RtlAtomicAdd(&(State->ReferenceCount), -1);
  185. ASSERT((PreviousCount != 0) && (PreviousCount < 0x10000000));
  186. if (PreviousCount > 1) {
  187. return Status;
  188. }
  189. //
  190. // Bump up the idle deadline even if the timer is already queued. The
  191. // timer will see this and requeue itself.
  192. //
  193. State->IdleTimeout = HlQueryTimeCounter() + State->IdleDelay;
  194. //
  195. // Try to win the race to queue the timer.
  196. //
  197. TimerQueued = RtlAtomicCompareExchange32(&(State->TimerQueued), 1, 0);
  198. if (TimerQueued == 0) {
  199. Status = KeQueueTimer(State->IdleTimer,
  200. TimerQueueSoftWake,
  201. State->IdleTimeout,
  202. 0,
  203. 0,
  204. State->IdleTimerDpc);
  205. if (!KSUCCESS(Status)) {
  206. RtlDebugPrint("PM: Cannot queue idle timer: device %x: %x\n",
  207. Device,
  208. Status);
  209. }
  210. }
  211. return Status;
  212. }
  213. KERNEL_API
  214. KSTATUS
  215. PmDeviceSetState (
  216. PDEVICE Device,
  217. DEVICE_POWER_STATE PowerState
  218. )
  219. /*++
  220. Routine Description:
  221. This routine sets a new power state for the device. This can be used to
  222. clear an error. It should not be called from a power IRP.
  223. Arguments:
  224. Device - Supplies a pointer to the device to set the power state for.
  225. PowerState - Supplies the new power management state to set. The only
  226. valid states to set are active and suspended.
  227. Return Value:
  228. Status code.
  229. --*/
  230. {
  231. PDEVICE_POWER State;
  232. KSTATUS Status;
  233. State = Device->Power;
  234. Status = STATUS_SUCCESS;
  235. switch (PowerState) {
  236. case DevicePowerStateActive:
  237. if (State->State == DevicePowerStateActive) {
  238. Status = STATUS_SUCCESS;
  239. } else {
  240. //
  241. // Add a reference on the device to bring it up, then release that
  242. // reference to send it down towards sleepytown.
  243. //
  244. Status = PmpDeviceAddReference(Device,
  245. DevicePowerRequestMarkActive);
  246. if (KSUCCESS(Status)) {
  247. Status = PmDeviceReleaseReference(Device);
  248. }
  249. }
  250. break;
  251. case DevicePowerStateSuspended:
  252. KeAcquireQueuedLock(State->Lock);
  253. if (State->State == DevicePowerStateRemoved) {
  254. Status = STATUS_DEVICE_NOT_CONNECTED;
  255. } else {
  256. if ((State->State == DevicePowerStateActive) ||
  257. ((State->State == DevicePowerStateTransitioning) &&
  258. (State->PreviousState == DevicePowerStateActive))) {
  259. PmpDeviceDecrementActiveChildren(Device->ParentDevice);
  260. }
  261. State->State = DevicePowerStateSuspended;
  262. State->Request = DevicePowerRequestNone;
  263. }
  264. KeReleaseQueuedLock(State->Lock);
  265. break;
  266. case DevicePowerStateIdle:
  267. default:
  268. ASSERT(FALSE);
  269. Status = STATUS_INVALID_PARAMETER;
  270. break;
  271. }
  272. return Status;
  273. }
  274. KSTATUS
  275. PmInitializeLibrary (
  276. VOID
  277. )
  278. /*++
  279. Routine Description:
  280. This routine performs global initialization for the power management
  281. library. It is called towards the end of I/O initialization.
  282. Arguments:
  283. None.
  284. Return Value:
  285. None.
  286. --*/
  287. {
  288. KSTATUS Status;
  289. Status = PmpArchInitialize();
  290. if (!KSUCCESS(Status)) {
  291. goto InitializeLibraryEnd;
  292. }
  293. InitializeLibraryEnd:
  294. return Status;
  295. }
  296. VOID
  297. PmpRemoveDevice (
  298. PDEVICE Device
  299. )
  300. /*++
  301. Routine Description:
  302. This routine is called when a device is removed from the system. It cleans
  303. up the power management state. It is assumed that the device lock is
  304. already held exclusive.
  305. Arguments:
  306. Device - Supplies a pointer to the device to remove.
  307. Return Value:
  308. None.
  309. --*/
  310. {
  311. DEVICE_POWER_STATE OldPreviousState;
  312. DEVICE_POWER_STATE OldState;
  313. PDEVICE_POWER State;
  314. State = Device->Power;
  315. if (State == NULL) {
  316. return;
  317. }
  318. //
  319. // A transition to the removed state is effective immediately, but must be
  320. // synchronized with all other transitions.
  321. //
  322. KeAcquireQueuedLock(State->Lock);
  323. OldState = State->State;
  324. OldPreviousState = State->PreviousState;
  325. State->State = DevicePowerStateRemoved;
  326. State->Request = DevicePowerRequestNone;
  327. RtlAtomicExchange32(&(State->TimerQueued), 1);
  328. KeCancelTimer(State->IdleTimer);
  329. KeCancelDpc(State->IdleTimerDpc);
  330. KeCancelWorkItem(State->IdleTimerWorkItem);
  331. if (OldState != DevicePowerStateTransitioning) {
  332. State->PreviousState = OldState;
  333. }
  334. KeReleaseQueuedLock(State->Lock);
  335. //
  336. // If an active child was just removed, decrement the parent's count.
  337. //
  338. if ((OldState == DevicePowerStateActive) ||
  339. ((OldState == DevicePowerStateTransitioning) &&
  340. (OldPreviousState == DevicePowerStateActive))) {
  341. PmpDeviceDecrementActiveChildren(Device->ParentDevice);
  342. }
  343. return;
  344. }
  345. VOID
  346. PmpDestroyDevice (
  347. PDEVICE Device
  348. )
  349. /*++
  350. Routine Description:
  351. This routine tears down the power management structures associated with a
  352. device.
  353. Arguments:
  354. Device - Supplies a pointer to the device to tear down.
  355. Return Value:
  356. None.
  357. --*/
  358. {
  359. PDEVICE_POWER State;
  360. if (Device->Power != NULL) {
  361. State = Device->Power;
  362. //
  363. // Work through the timer, DPC, work item flow, starting at the source
  364. // and squeezing the tube along the way.
  365. //
  366. if (State->IdleTimer != NULL) {
  367. KeDestroyTimer(State->IdleTimer);
  368. }
  369. if (State->IdleTimerDpc != NULL) {
  370. KeDestroyDpc(State->IdleTimerDpc);
  371. }
  372. if (State->IdleTimerWorkItem != NULL) {
  373. KeCancelWorkItem(State->IdleTimerWorkItem);
  374. KeFlushWorkItem(State->IdleTimerWorkItem);
  375. KeDestroyWorkItem(State->IdleTimerWorkItem);
  376. }
  377. if (State->ActiveEvent != NULL) {
  378. KeDestroyEvent(State->ActiveEvent);
  379. }
  380. if (State->Lock != NULL) {
  381. KeDestroyQueuedLock(State->Lock);
  382. }
  383. if (State->Irp != NULL) {
  384. IoDestroyIrp(State->Irp);
  385. }
  386. if (State->History != NULL) {
  387. PmpDestroyIdleHistory(State->History);
  388. }
  389. Device->Power = NULL;
  390. MmFreeNonPagedPool(State);
  391. }
  392. return;
  393. }
  394. VOID
  395. PmpDevicePowerTransition (
  396. PDEVICE Device
  397. )
  398. /*++
  399. Routine Description:
  400. This routine is called by the worker thread to perform a device power
  401. transition.
  402. Arguments:
  403. Device - Supplies a pointer to the device to work on.
  404. Return Value:
  405. None.
  406. --*/
  407. {
  408. PDEVICE_POWER State;
  409. State = Device->Power;
  410. if (State->State == DevicePowerStateTransitioning) {
  411. switch (State->Request) {
  412. case DevicePowerRequestIdle:
  413. PmpDeviceIdle(Device);
  414. break;
  415. case DevicePowerRequestSuspend:
  416. PmpDeviceSuspend(Device);
  417. break;
  418. //
  419. // It is OK to do a second unprotected read of the state's request.
  420. // When a resume or activate request is set, no other request can trump
  421. // it, not even another resume or active (as only one thread grabs the
  422. // first reference on the device and starts the resume process).
  423. //
  424. case DevicePowerRequestResume:
  425. case DevicePowerRequestMarkActive:
  426. PmpDeviceResume(Device, State->Request);
  427. break;
  428. default:
  429. break;
  430. }
  431. }
  432. return;
  433. }
  434. //
  435. // --------------------------------------------------------- Internal Functions
  436. //
  437. KSTATUS
  438. PmpInitializeDevice (
  439. PDEVICE Device
  440. )
  441. /*++
  442. Routine Description:
  443. This routine initializes the power management portion of a device structure.
  444. Arguments:
  445. Device - Supplies a pointer to the device to initialize.
  446. Return Value:
  447. Status code.
  448. --*/
  449. {
  450. PDEVICE_POWER Power;
  451. KSTATUS Status;
  452. Power = MmAllocateNonPagedPool(sizeof(DEVICE_POWER),
  453. PM_DEVICE_ALLOCATION_TAG);
  454. if (Power == NULL) {
  455. Status = STATUS_INSUFFICIENT_RESOURCES;
  456. }
  457. RtlZeroMemory(Power, sizeof(DEVICE_POWER));
  458. Device->Power = Power;
  459. Power->State = DevicePowerStateSuspended;
  460. Power->IdleDelay = HlQueryTimeCounterFrequency() *
  461. PM_INITIAL_IDLE_DELAY_SECONDS;
  462. Power->Lock = KeCreateQueuedLock();
  463. Power->ActiveEvent = KeCreateEvent(NULL);
  464. Power->IdleTimer = KeCreateTimer(PM_DEVICE_ALLOCATION_TAG);
  465. //
  466. // This work item should go on the same work queue as the device worker
  467. // thread to avoid an extra context switch.
  468. //
  469. Power->IdleTimerWorkItem = KeCreateWorkItem(IoDeviceWorkQueue,
  470. WorkPriorityNormal,
  471. PmpDeviceIdleWorker,
  472. Device,
  473. PM_DEVICE_ALLOCATION_TAG);
  474. Power->IdleTimerDpc = KeCreateDpc(PmpDeviceIdleTimerDpc,
  475. Power->IdleTimerWorkItem);
  476. Power->Irp = IoCreateIrp(Device, IrpMajorStateChange, 0);
  477. Power->History = PmpCreateIdleHistory(IDLE_HISTORY_NON_PAGED,
  478. PM_DEVICE_HISTORY_SIZE_SHIFT);
  479. if ((Power->Lock == NULL) ||
  480. (Power->ActiveEvent == NULL) ||
  481. (Power->IdleTimer == NULL) ||
  482. (Power->IdleTimerDpc == NULL) ||
  483. (Power->IdleTimerWorkItem == NULL) ||
  484. (Power->Irp == NULL) ||
  485. (Power->History == NULL)) {
  486. Status = STATUS_INSUFFICIENT_RESOURCES;
  487. goto InitializeDeviceEnd;
  488. }
  489. //
  490. // Start the active event as unsignaled since the device is in the
  491. // suspended state.
  492. //
  493. KeSignalEvent(Power->ActiveEvent, SignalOptionUnsignal);
  494. Status = STATUS_SUCCESS;
  495. InitializeDeviceEnd:
  496. if (!KSUCCESS(Status)) {
  497. PmpDestroyDevice(Device);
  498. }
  499. return Status;
  500. }
  501. VOID
  502. PmpDeviceIdleTimerDpc (
  503. PDPC Dpc
  504. )
  505. /*++
  506. Routine Description:
  507. This routine is called at dispatch level when the device's idle timer
  508. expires.
  509. Arguments:
  510. Dpc - Supplies a pointer to the DPC that is running.
  511. Return Value:
  512. None.
  513. --*/
  514. {
  515. KSTATUS Status;
  516. //
  517. // The user data for the DPC is the work item itself, which is important
  518. // since the power state structure is paged and cannot be touched here.
  519. //
  520. Status = KeQueueWorkItem(Dpc->UserData);
  521. ASSERT(KSUCCESS(Status));
  522. return;
  523. }
  524. VOID
  525. PmpDeviceIdleWorker (
  526. PVOID Parameter
  527. )
  528. /*++
  529. Routine Description:
  530. This routine implements the work item queued when a device's idle timer
  531. expires.
  532. Arguments:
  533. Parameter - Supplies a context parameter, which in this case is a pointer
  534. to the device.
  535. Return Value:
  536. None.
  537. --*/
  538. {
  539. ULONGLONG CurrentTime;
  540. PDEVICE Device;
  541. PDEVICE_POWER State;
  542. KSTATUS Status;
  543. ULONGLONG Timeout;
  544. ULONG TimerQueued;
  545. Device = Parameter;
  546. State = Device->Power;
  547. //
  548. // The timer gets left on a lot, even if it's no longer needed. If there
  549. // are references on the device now, just do nothing.
  550. //
  551. if (State->ReferenceCount != 0) {
  552. RtlAtomicExchange32(&(State->TimerQueued), 0);
  553. //
  554. // Assuming there are still references, then this is done.
  555. //
  556. if (State->ReferenceCount != 0) {
  557. return;
  558. //
  559. // The references went away, but may have lost the race to queue the
  560. // timer. Try to reclaim the right to queue the timer. If someone else
  561. // got there first, then the timer is requeued and doesn't need
  562. // the rest of this routine.
  563. //
  564. } else {
  565. TimerQueued = RtlAtomicCompareExchange32(&(State->TimerQueued),
  566. 1,
  567. 0);
  568. if (TimerQueued == 0) {
  569. return;
  570. }
  571. }
  572. }
  573. //
  574. // If the idle timeout has moved beyond the current time, then re-queue
  575. // the timer for that new time.
  576. //
  577. CurrentTime = HlQueryTimeCounter();
  578. Timeout = State->IdleTimeout;
  579. if (CurrentTime < Timeout) {
  580. Status = KeQueueTimer(State->IdleTimer,
  581. TimerQueueSoftWake,
  582. Timeout,
  583. 0,
  584. 0,
  585. State->IdleTimerDpc);
  586. if (!KSUCCESS(Status)) {
  587. RtlAtomicExchange32(&(State->TimerQueued), 0);
  588. }
  589. //
  590. // The idle timer really did expire. Reset the timer queued variable, and
  591. // queue the idle transition.
  592. //
  593. } else {
  594. RtlAtomicExchange32(&(State->TimerQueued), 0);
  595. Status = PmpDeviceQueuePowerTransition(Device, DevicePowerRequestIdle);
  596. if (!KSUCCESS(Status)) {
  597. RtlDebugPrint("PM: Failed to queue idle work: %x %x\n",
  598. Device,
  599. Status);
  600. }
  601. }
  602. return;
  603. }
  604. VOID
  605. PmpDeviceDecrementActiveChildren (
  606. PDEVICE Device
  607. )
  608. /*++
  609. Routine Description:
  610. This routine decrements the active child count on a given device.
  611. Arguments:
  612. Device - Supplies a pointer to the device to subtract an active child count
  613. from.
  614. Return Value:
  615. None.
  616. --*/
  617. {
  618. UINTN PreviousCount;
  619. PDEVICE_POWER State;
  620. State = Device->Power;
  621. if (State == NULL) {
  622. return;
  623. }
  624. PreviousCount = RtlAtomicAdd(&(State->ActiveChildren), -1);
  625. ASSERT((PreviousCount != 0) && (PreviousCount < 0x10000000));
  626. //
  627. // If this is the first active child, release a power reference on this
  628. // device.
  629. //
  630. if (PreviousCount == 1) {
  631. PmDeviceReleaseReference(Device);
  632. }
  633. return;
  634. }
  635. KSTATUS
  636. PmpDeviceAddReference (
  637. PDEVICE Device,
  638. DEVICE_POWER_REQUEST Request
  639. )
  640. /*++
  641. Routine Description:
  642. This routine asynchronously adds a power management reference on the given
  643. device.
  644. Arguments:
  645. Device - Supplies a pointer to the device to add a power reference to.
  646. Request - Supplies the request type, which can either be actually becoming
  647. active or just marking it as such.
  648. Return Value:
  649. Status code.
  650. --*/
  651. {
  652. UINTN PreviousCount;
  653. PDEVICE_POWER State;
  654. KSTATUS Status;
  655. Status = STATUS_SUCCESS;
  656. State = Device->Power;
  657. PreviousCount = RtlAtomicAdd(&(State->ReferenceCount), 1);
  658. ASSERT(PreviousCount < 0x10000000);
  659. //
  660. // Attempt to the resume the device if this is the first reference.
  661. //
  662. if (PreviousCount == 0) {
  663. Status = PmpDeviceResume(Device, Request);
  664. if (!KSUCCESS(Status)) {
  665. RtlAtomicAdd(&(State->ReferenceCount), -1);
  666. }
  667. //
  668. // All subsequent references need to wait for the active event and then
  669. // check the state to see if the resume succeeded.
  670. //
  671. } else {
  672. KeWaitForEvent(Device->Power->ActiveEvent, FALSE, WAIT_TIME_INDEFINITE);
  673. if (Device->Power->State != DevicePowerStateActive) {
  674. RtlAtomicAdd(&(State->ReferenceCount), -1);
  675. Status = STATUS_NOT_READY;
  676. }
  677. }
  678. return Status;
  679. }
  680. KSTATUS
  681. PmpDeviceQueuePowerTransition (
  682. PDEVICE Device,
  683. DEVICE_POWER_REQUEST Request
  684. )
  685. /*++
  686. Routine Description:
  687. This routine queues a power request on a device.
  688. Arguments:
  689. Device - Supplies a pointer to the device to affect.
  690. Request - Supplies the type of request to queue.
  691. Return Value:
  692. Status code.
  693. --*/
  694. {
  695. BOOL QueueRequest;
  696. PDEVICE_POWER State;
  697. KSTATUS Status;
  698. State = Device->Power;
  699. Status = STATUS_SUCCESS;
  700. //
  701. // Do a quick exit for resuming a device that's not idle.
  702. //
  703. if ((Request == DevicePowerRequestResume) &&
  704. (State->State == DevicePowerStateActive)) {
  705. return STATUS_SUCCESS;
  706. }
  707. //
  708. // If the state is already what it should be and there are no other
  709. // requests, also exit.
  710. //
  711. QueueRequest = FALSE;
  712. KeAcquireQueuedLock(State->Lock);
  713. //
  714. // Don't bother if the same request is already queued.
  715. //
  716. if ((State->State != DevicePowerStateRemoved) &&
  717. ((State->State != DevicePowerStateTransitioning) ||
  718. (State->Request != Request))) {
  719. switch (Request) {
  720. //
  721. // Resume trumps all other requests.
  722. //
  723. case DevicePowerRequestResume:
  724. case DevicePowerRequestMarkActive:
  725. if (State->State != DevicePowerStateActive) {
  726. State->Request = Request;
  727. QueueRequest = TRUE;
  728. }
  729. break;
  730. //
  731. // Suspend trumps idle.
  732. //
  733. case DevicePowerRequestSuspend:
  734. if (State->State != DevicePowerStateSuspended) {
  735. if ((State->Request != DevicePowerRequestResume) &&
  736. (State->Request != DevicePowerRequestMarkActive)) {
  737. State->Request = Request;
  738. QueueRequest = TRUE;
  739. }
  740. }
  741. break;
  742. //
  743. // Idle only happens if nothing else is going on.
  744. //
  745. case DevicePowerRequestIdle:
  746. if (State->State != DevicePowerStateIdle) {
  747. if (State->Request == DevicePowerRequestNone) {
  748. State->Request = Request;
  749. QueueRequest = TRUE;
  750. }
  751. }
  752. break;
  753. default:
  754. ASSERT(FALSE);
  755. break;
  756. }
  757. }
  758. //
  759. // If a request is needed, set the state correctly while the lock is held.
  760. //
  761. if (QueueRequest != FALSE) {
  762. if (State->State != DevicePowerStateTransitioning) {
  763. State->PreviousState = State->State;
  764. }
  765. State->State = DevicePowerStateTransitioning;
  766. }
  767. KeReleaseQueuedLock(State->Lock);
  768. //
  769. // If needed, actually queue the work request now that the lock is released.
  770. //
  771. if (QueueRequest != FALSE) {
  772. Status = IopQueueDeviceWork(Device,
  773. DeviceActionPowerTransition,
  774. NULL,
  775. 0);
  776. //
  777. // If queueing the work fails, then attempt to transition the state
  778. // back to what it was. There may already be an item on the queue and
  779. // the request may still run, but there is no guarantee of that. The
  780. // state must be rolled back.
  781. //
  782. if (!KSUCCESS(Status)) {
  783. KeAcquireQueuedLock(State->Lock);
  784. //
  785. // If the request is still set, then roll back the state. If it's
  786. // not, then there is a subsequent attempt at queueing action that
  787. // may well succeed.
  788. //
  789. if (Request == State->Request) {
  790. State->State = State->PreviousState;
  791. }
  792. KeReleaseQueuedLock(State->Lock);
  793. //
  794. // If this is a failed resume action, then signal the event. Other
  795. // threads may be waiting on the event for the resume to succeed.
  796. //
  797. if ((Request == DevicePowerRequestResume) ||
  798. (Request == DevicePowerRequestMarkActive)) {
  799. KeSignalEvent(State->ActiveEvent, SignalOptionSignalAll);
  800. }
  801. }
  802. }
  803. return Status;
  804. }
  805. KSTATUS
  806. PmpDeviceResume (
  807. PDEVICE Device,
  808. DEVICE_POWER_REQUEST Request
  809. )
  810. /*++
  811. Routine Description:
  812. This routine performs the actual resume action for a given device.
  813. Arguments:
  814. Device - Supplies a pointer to the device to resume.
  815. Request - Supplies the type of resume to request.
  816. Return Value:
  817. Status code.
  818. --*/
  819. {
  820. ULONGLONG CurrentTime;
  821. ULONGLONG Duration;
  822. PIRP Irp;
  823. BOOL LockHeld;
  824. PDEVICE Parent;
  825. PDEVICE_POWER ParentState;
  826. UINTN PreviousCount;
  827. PDEVICE_POWER State;
  828. KSTATUS Status;
  829. ASSERT((Request == DevicePowerRequestResume) ||
  830. (Request == DevicePowerRequestMarkActive));
  831. //
  832. // If the state isn't already active, then the caller won the race to
  833. // transition it out of an idle or suspended state by being the first to
  834. // increment the device's reference count. As such, other threads may be
  835. // waiting on the active event. Except for this case where the device is
  836. // already active, this routine always needs to release others waiting on
  837. // the resume transition.
  838. //
  839. State = Device->Power;
  840. if (State->State == DevicePowerStateActive) {
  841. return STATUS_SUCCESS;
  842. }
  843. LockHeld = FALSE;
  844. CurrentTime = HlQueryTimeCounter();
  845. //
  846. // First resume the parent recursively. Always resume the parent, even if
  847. // the initiali request was to mark the device active. The parent is not
  848. // necessarily resumed.
  849. //
  850. Parent = Device->ParentDevice;
  851. ParentState = Parent->Power;
  852. if (ParentState != NULL) {
  853. PreviousCount = RtlAtomicAdd(&(ParentState->ActiveChildren), 1);
  854. ASSERT(PreviousCount < 0x10000000);
  855. //
  856. // If this is the first active child, up the reference count on the
  857. // device.
  858. //
  859. if (PreviousCount == 0) {
  860. PreviousCount = RtlAtomicAdd(&(ParentState->ReferenceCount), 1);
  861. ASSERT(PreviousCount < 0x10000000);
  862. //
  863. // If this was the first power reference on this device, resume
  864. // that device, recursing up parents as needed.
  865. //
  866. if (PreviousCount == 0) {
  867. Status = PmpDeviceResume(Parent, DevicePowerRequestResume);
  868. if (!KSUCCESS(Status)) {
  869. goto DeviceResumeEnd;
  870. }
  871. }
  872. }
  873. //
  874. // Wait until the parent's state settles. If this thread does not set
  875. // the active child count to 1 or the reference count to 1, then
  876. // another thread is doing the work and the device is not resumed until
  877. // the active event is signaled. Fail the resume transition if the
  878. // parent doesn't make it into the resumed state.
  879. //
  880. KeWaitForEvent(ParentState->ActiveEvent, FALSE, WAIT_TIME_INDEFINITE);
  881. if (ParentState->State != DevicePowerStateActive) {
  882. Status = STATUS_NOT_READY;
  883. goto DeviceResumeEnd;
  884. }
  885. }
  886. //
  887. // Synchronize the transition to the active state with other requests and
  888. // work items that might be trying to send the device to idle or suspend.
  889. //
  890. KeAcquireQueuedLock(State->Lock);
  891. LockHeld = TRUE;
  892. ASSERT(State->State != DevicePowerStateActive);
  893. if (State->State == DevicePowerStateRemoved) {
  894. Status = STATUS_DEVICE_NOT_CONNECTED;
  895. goto DeviceResumeEnd;
  896. }
  897. //
  898. // If the device was transitioning but never made it, then an extra parent
  899. // reference count was taken (as idle/suspend will return early and not
  900. // release it).
  901. //
  902. if ((State->State == DevicePowerStateTransitioning) &&
  903. (State->PreviousState == DevicePowerStateActive)) {
  904. ASSERT((ParentState == NULL) || (ParentState->ActiveChildren > 1));
  905. PmpDeviceDecrementActiveChildren(Parent);
  906. }
  907. if (Request == DevicePowerRequestResume) {
  908. Irp = State->Irp;
  909. IoInitializeIrp(Irp);
  910. Irp->MinorCode = IrpMinorResume;
  911. Status = IoSendSynchronousIrp(Irp);
  912. if (KSUCCESS(Status)) {
  913. Status = IoGetIrpStatus(Irp);
  914. }
  915. } else {
  916. ASSERT(Request == DevicePowerRequestMarkActive);
  917. Status = STATUS_SUCCESS;
  918. }
  919. if (PmDebugPowerTransitions != FALSE) {
  920. RtlDebugPrint("PM: 0x%08x Active: 0x%08x\n", Device, Status);
  921. }
  922. if (KSUCCESS(Status)) {
  923. //
  924. // If the device just switched from idle to active, then compute the
  925. // idle duration.
  926. //
  927. if (State->State == DevicePowerStateIdle) {
  928. ASSERT(State->TransitionTime != 0);
  929. Duration = CurrentTime - State->TransitionTime;
  930. PmpIdleHistoryAddDataPoint(State->History, Duration);
  931. }
  932. if (State->State != DevicePowerStateTransitioning) {
  933. State->PreviousState = State->State;
  934. }
  935. State->State = DevicePowerStateActive;
  936. State->TransitionTime = CurrentTime;
  937. //
  938. // Smash any outstanding request state. Now that the device is active
  939. // again, any request associated with a transition is stale.
  940. //
  941. State->Request = DevicePowerRequestNone;
  942. //
  943. // On failure, the state is either transitioning (with a request), idle, or
  944. // suspended. Let the device stay idle or suspended and keep any pending
  945. // transition unless it is a resume transition.
  946. //
  947. } else {
  948. ASSERT((State->State == DevicePowerStateIdle) ||
  949. (State->State == DevicePowerStateSuspended) ||
  950. ((State->State == DevicePowerStateTransitioning) &&
  951. (State->Request != DevicePowerRequestNone)));
  952. if ((State->State == DevicePowerStateTransitioning) &&
  953. ((State->Request == DevicePowerRequestResume) ||
  954. (State->Request == DevicePowerRequestMarkActive))) {
  955. ASSERT(State->PreviousState != DevicePowerStateTransitioning);
  956. ASSERT(State->PreviousState != DevicePowerStateActive);
  957. State->State = State->PreviousState;
  958. State->Request = DevicePowerRequestNone;
  959. }
  960. }
  961. DeviceResumeEnd:
  962. if (LockHeld != FALSE) {
  963. KeReleaseQueuedLock(State->Lock);
  964. }
  965. //
  966. // Signal the event to release any threads waiting on the resume transition.
  967. // They need to check the state when they wake up in case the resume
  968. // failed.
  969. //
  970. KeSignalEvent(State->ActiveEvent, SignalOptionSignalAll);
  971. //
  972. // If it failed, release the references taken on the parent.
  973. //
  974. if (!KSUCCESS(Status)) {
  975. RtlDebugPrint("PM: Failed to resume 0x%08x: 0x%08x\n", Device, Status);
  976. PmpDeviceDecrementActiveChildren(Parent);
  977. }
  978. return Status;
  979. }
  980. VOID
  981. PmpDeviceIdle (
  982. PDEVICE Device
  983. )
  984. /*++
  985. Routine Description:
  986. This routine performs the actual idle action for a given device.
  987. Arguments:
  988. Device - Supplies a pointer to the device to resume.
  989. Return Value:
  990. None.
  991. --*/
  992. {
  993. ULONGLONG CurrentTime;
  994. BOOL DecrementParent;
  995. PIRP Irp;
  996. ULONG Milliseconds;
  997. PDEVICE_POWER State;
  998. KSTATUS Status;
  999. State = Device->Power;
  1000. //
  1001. // Exit quickly if there are references now, which there often will be. The
  1002. // state should be active or about to become active.
  1003. //
  1004. if (State->ReferenceCount != 0) {
  1005. return;
  1006. }
  1007. DecrementParent = FALSE;
  1008. Status = STATUS_UNSUCCESSFUL;
  1009. KeAcquireQueuedLock(State->Lock);
  1010. if (State->State == DevicePowerStateRemoved) {
  1011. goto DeviceIdleEnd;
  1012. }
  1013. //
  1014. // Unsignal the event now so that there isn't a window in between
  1015. // 1) Checking the references here, and
  1016. // 2) Unsignaling the event
  1017. // where an add reference call could zoom through, get past the event, and
  1018. // then get in trouble when this lumbering idle finally rolls through. It
  1019. // means add reference calls may get stuck briefly while this routine
  1020. // figures out it's not needed.
  1021. //
  1022. KeSignalEvent(State->ActiveEvent, SignalOptionUnsignal);
  1023. //
  1024. // Do nothing if it turns out this request was stale.
  1025. //
  1026. if ((State->State != DevicePowerStateTransitioning) ||
  1027. (State->Request != DevicePowerRequestIdle) ||
  1028. (State->ReferenceCount != 0)) {
  1029. goto DeviceIdleEnd;
  1030. }
  1031. Irp = State->Irp;
  1032. IoInitializeIrp(Irp);
  1033. Irp->MinorCode = IrpMinorIdle;
  1034. Irp->U.Idle.ExpectedDuration = PmpIdleHistoryGetAverage(State->History);
  1035. Status = IoSendSynchronousIrp(Irp);
  1036. if (KSUCCESS(Status)) {
  1037. Status = IoGetIrpStatus(Irp);
  1038. }
  1039. if (PmDebugPowerTransitions != FALSE) {
  1040. Milliseconds = (Irp->U.Idle.ExpectedDuration * 1000ULL) /
  1041. HlQueryTimeCounterFrequency();
  1042. RtlDebugPrint("PM: %x Idle (%d ms): %x\n",
  1043. Device,
  1044. Milliseconds,
  1045. Status);
  1046. }
  1047. ASSERT(State->PreviousState == DevicePowerStateActive);
  1048. if (KSUCCESS(Status)) {
  1049. CurrentTime = HlQueryTimeCounter();
  1050. State->State = DevicePowerStateIdle;
  1051. State->TransitionTime = CurrentTime;
  1052. DecrementParent = TRUE;
  1053. } else {
  1054. State->State = State->PreviousState;
  1055. }
  1056. //
  1057. // Success or failure, this request is old news. No additional idle
  1058. // requests could have been queued while this one was in flight. And this
  1059. // routine bails earlier if the request type is anything other than idle.
  1060. //
  1061. State->Request = DevicePowerRequestNone;
  1062. DeviceIdleEnd:
  1063. //
  1064. // If the device is active because a resume happened before the idle or the
  1065. // idle failed, wake up everything waiting on the active event.
  1066. //
  1067. if (State->State == DevicePowerStateActive) {
  1068. KeSignalEvent(State->ActiveEvent, SignalOptionSignalAll);
  1069. }
  1070. KeReleaseQueuedLock(State->Lock);
  1071. //
  1072. // If the device was put down, then decrement the active child count of
  1073. // the parent. It moved to the idle state from the active state, which held
  1074. // a reference on the parent.
  1075. //
  1076. if (DecrementParent != FALSE) {
  1077. PmpDeviceDecrementActiveChildren(Device->ParentDevice);
  1078. }
  1079. return;
  1080. }
  1081. VOID
  1082. PmpDeviceSuspend (
  1083. PDEVICE Device
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. This routine performs the actual device suspension.
  1088. Arguments:
  1089. Device - Supplies a pointer to the device to resume.
  1090. Return Value:
  1091. None.
  1092. --*/
  1093. {
  1094. BOOL DecrementParent;
  1095. PIRP Irp;
  1096. PDEVICE_POWER State;
  1097. KSTATUS Status;
  1098. DecrementParent = FALSE;
  1099. State = Device->Power;
  1100. KeAcquireQueuedLock(State->Lock);
  1101. if (State->State == DevicePowerStateRemoved) {
  1102. goto DeviceSuspendEnd;
  1103. }
  1104. KeSignalEvent(State->ActiveEvent, SignalOptionUnsignal);
  1105. //
  1106. // Do nothing if it turns out this request was stale.
  1107. //
  1108. if ((State->State != DevicePowerStateTransitioning) ||
  1109. (State->Request != DevicePowerRequestSuspend)) {
  1110. goto DeviceSuspendEnd;
  1111. }
  1112. Irp = State->Irp;
  1113. IoInitializeIrp(Irp);
  1114. Irp->MinorCode = IrpMinorSuspend;
  1115. Status = IoSendSynchronousIrp(Irp);
  1116. if (KSUCCESS(Status)) {
  1117. Status = IoGetIrpStatus(Irp);
  1118. }
  1119. if (PmDebugPowerTransitions != FALSE) {
  1120. RtlDebugPrint("PM: %x Suspend: %x\n", Device, Status);
  1121. }
  1122. ASSERT((State->PreviousState == DevicePowerStateActive) ||
  1123. (State->PreviousState == DevicePowerStateIdle));
  1124. if (KSUCCESS(Status)) {
  1125. State->State = DevicePowerStateSuspended;
  1126. if (State->PreviousState == DevicePowerStateActive) {
  1127. DecrementParent = TRUE;
  1128. }
  1129. } else {
  1130. State->State = State->PreviousState;
  1131. }
  1132. //
  1133. // Success or failure, this request is old news. No additional suspend
  1134. // requests could have been queued while this one was in flight. And this
  1135. // routine bails earlier if the request type is anything other than suspend.
  1136. //
  1137. State->Request = DevicePowerRequestNone;
  1138. DeviceSuspendEnd:
  1139. //
  1140. // If the device is active because a resume happened before the suspend or
  1141. // the suspend failed to transition from active to suspended, wake up
  1142. // everything waiting on the active event.
  1143. //
  1144. if (State->State == DevicePowerStateActive) {
  1145. KeSignalEvent(State->ActiveEvent, SignalOptionSignalAll);
  1146. }
  1147. KeReleaseQueuedLock(State->Lock);
  1148. //
  1149. // If the device was put down, then decrement the active child count of
  1150. // the parent. This only needs to happen if the previous state was the
  1151. // active state. The device may have already been idle, in which case it
  1152. // would not have held a reference on its parent.
  1153. //
  1154. if (DecrementParent != FALSE) {
  1155. PmpDeviceDecrementActiveChildren(Device->ParentDevice);
  1156. }
  1157. return;
  1158. }