Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1772 lines
45 KiB

  1. /*++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. power.c
  5. Abstract:
  6. This module contains power management code for PCI.SYS.
  7. Author:
  8. Joe Dai (joedai) 11-Sept-1997
  9. Peter Johnston (peterj) 24-Oct-1997
  10. Revision History:
  11. --*/
  12. #include "pcip.h"
  13. NTSTATUS
  14. PciFdoWaitWakeCompletion(
  15. IN PDEVICE_OBJECT DeviceObject,
  16. IN PIRP Irp,
  17. IN PPCI_FDO_EXTENSION FdoExtension
  18. );
  19. NTSTATUS
  20. PciFdoWaitWakeCallBack(
  21. IN PDEVICE_OBJECT DeviceObject,
  22. IN UCHAR MinorFunction,
  23. IN POWER_STATE PowerState,
  24. IN PVOID Context,
  25. IN PIO_STATUS_BLOCK IoStatus
  26. );
  27. VOID
  28. PciFdoWaitWakeCancel(
  29. IN PDEVICE_OBJECT DeviceObject,
  30. IN OUT PIRP Irp
  31. );
  32. VOID
  33. PciFdoSetPowerStateCompletion(
  34. IN PDEVICE_OBJECT DeviceObject,
  35. IN UCHAR MinorFunction,
  36. IN POWER_STATE PowerState,
  37. IN PVOID Context,
  38. IN PIO_STATUS_BLOCK IoStatus
  39. );
  40. NTSTATUS
  41. PciPdoWaitWakeCallBack(
  42. IN PDEVICE_OBJECT DeviceObject,
  43. IN UCHAR MinorFunction,
  44. IN POWER_STATE PowerState,
  45. IN PVOID Context,
  46. IN PIO_STATUS_BLOCK IoStatus
  47. );
  48. VOID
  49. PciPdoAdjustPmeEnable(
  50. IN PPCI_PDO_EXTENSION PdoExtension,
  51. IN BOOLEAN Enable
  52. );
  53. VOID
  54. PciPmeClearPmeStatus(
  55. IN PDEVICE_OBJECT Pdo
  56. );
  57. //
  58. // This table is taken from the PCI spec. The units are microseconds.
  59. LONG PciPowerDelayTable[4][4] = {
  60. // D0 D1 D2 D3(Hot)
  61. 0, 0, 200, 10000, // D0
  62. 0, 0, 200, 10000, // D1
  63. 200, 200, 0, 10000, // D2
  64. 10000, 10000, 10000, 0 // D3(Hot)
  65. };
  66. VOID
  67. PciPdoAdjustPmeEnable(
  68. IN PPCI_PDO_EXTENSION PdoExtension,
  69. IN BOOLEAN Enable
  70. )
  71. /*++
  72. Routine Description:
  73. Enable or Disable the PME Enable bit for a device(function).
  74. Note: The PDO Extension lock is held on entry and is not released
  75. by this routine.
  76. Arguments:
  77. PdoExtension - Pointer to the PDO Extension for the device whose
  78. PME Enable bit is to be altered.
  79. Enable - TRUE if PME Enable is to be set, FALSE if to be cleared.
  80. Return Value:
  81. None.
  82. --*/
  83. {
  84. //
  85. // Is the device's PME management owned by someone else?
  86. //
  87. if (PdoExtension->NoTouchPmeEnable) {
  88. PciDebugPrint(
  89. PciDbgWaitWake,
  90. "AdjustPmeEnable on pdox %08x but PME not owned.\n",
  91. PdoExtension
  92. );
  93. return;
  94. }
  95. //
  96. // Really update the PME signal. Note that we always need to supply
  97. // the 3rd argument as FALSE --- we don't want to just clear the PME
  98. // Status bit
  99. //
  100. PciPmeAdjustPmeEnable( PdoExtension, Enable, FALSE );
  101. }
  102. NTSTATUS
  103. PciPdoIrpQueryPower(
  104. IN PIRP Irp,
  105. IN PIO_STACK_LOCATION IrpSp,
  106. IN PPCI_COMMON_EXTENSION DeviceExtension
  107. )
  108. {
  109. //
  110. // pass 1, claim we can do it.
  111. //
  112. //
  113. // ADRIAO N.B. 08/29/1999 -
  114. // For D-IRPs, we do *not* want to verify the requested D-state is
  115. // actually supported. See PciQueryPowerCapabilities for details.
  116. //
  117. return STATUS_SUCCESS;
  118. }
  119. NTSTATUS
  120. PciPdoSetPowerState (
  121. IN PIRP Irp,
  122. IN PIO_STACK_LOCATION IrpStack,
  123. IN PPCI_COMMON_EXTENSION DeviceExtension
  124. )
  125. /*++
  126. Routine Description:
  127. Handles SetPower Irps send to a PCI PDO
  128. If the irp is an S-Irp, then do nothing
  129. If the irp is an D-Irp, then put the device in the appropriate state.
  130. Exceptions: If the device is in the hibernate path, then don't
  131. actually power down if we are hibernating
  132. Arguments:
  133. Irp - The request
  134. IrpStack - The current stack location
  135. DeviceExtension - The device that is getting powered down
  136. Return Value:
  137. NTSTATUS
  138. --*/
  139. {
  140. DEVICE_POWER_STATE desiredDeviceState;
  141. NTSTATUS status;
  142. PPCI_PDO_EXTENSION pdoExtension;
  143. POWER_ACTION powerAction;
  144. POWER_STATE powerState;
  145. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  146. ASSERT_PCI_PDO_EXTENSION(pdoExtension);
  147. status = STATUS_SUCCESS;
  148. switch (IrpStack->Parameters.Power.Type) {
  149. case DevicePowerState:
  150. desiredDeviceState = IrpStack->Parameters.Power.State.DeviceState;
  151. powerAction = IrpStack->Parameters.Power.ShutdownType;
  152. break;
  153. case SystemPowerState:
  154. return STATUS_SUCCESS;
  155. default:
  156. return STATUS_NOT_SUPPORTED;
  157. }
  158. if ((desiredDeviceState == PowerDeviceD0)
  159. && (pdoExtension->PowerState.CurrentDeviceState == PowerDeviceD0)) {
  160. return STATUS_SUCCESS;
  161. }
  162. #if DBG
  163. if ((desiredDeviceState < PowerDeviceD0) ||
  164. (desiredDeviceState > PowerDeviceD3)) {
  165. //
  166. // Invalid power level.
  167. //
  168. return STATUS_INVALID_PARAMETER;
  169. }
  170. #endif
  171. //
  172. // If the device is trying to power down perform some sanity checks
  173. //
  174. if (desiredDeviceState > PowerDeviceD0) {
  175. if (pdoExtension->OnDebugPath) {
  176. KdPowerTransition(desiredDeviceState);
  177. }
  178. //
  179. // If device is currently in D0 state, capture it's command
  180. // register settings in case the FDO changed them since we
  181. // looked at them.
  182. //
  183. if (pdoExtension->PowerState.CurrentDeviceState == PowerDeviceD0) {
  184. PciGetCommandRegister(pdoExtension,
  185. &pdoExtension->CommandEnables);
  186. }
  187. //
  188. // Prevent race conditions and remember that the device is off before
  189. // we actually turn it off
  190. //
  191. pdoExtension->PowerState.CurrentDeviceState = desiredDeviceState;
  192. if (pdoExtension->DisablePowerDown) {
  193. //
  194. // Powerdown of this device disabled (based on device type).
  195. //
  196. PciDebugPrint(
  197. PciDbgObnoxious,
  198. "PCI power down of PDOx %08x, disabled, ignored.\n",
  199. pdoExtension
  200. );
  201. return STATUS_SUCCESS;
  202. }
  203. //
  204. // Device driver should likely not be powering down any device
  205. // that's on the hibernate path or the crashdump path
  206. //
  207. if ( powerAction == PowerActionHibernate &&
  208. (pdoExtension->PowerState.Hibernate || pdoExtension->PowerState.CrashDump ) ) {
  209. //
  210. // Don't actually change the device, but new device state was
  211. // recorded above (as if we HAD done it) so we know to reset
  212. // resources as the system comes up again.
  213. //
  214. return STATUS_SUCCESS;
  215. }
  216. //
  217. // If we are a device on the VGA path then don't turn off for shutdown so we can
  218. // display the "Safe to turn off your machine" screen. For hibernate we also
  219. // don't want to turn off so we can display the "Dumping stuff to your disk progress
  220. // bar" but this is accomplished by video putting device on the video path on the hibernate
  221. // path.
  222. //
  223. if (IrpStack->Parameters.Power.State.DeviceState == PowerDeviceD3
  224. && (IrpStack->Parameters.Power.ShutdownType == PowerActionShutdownReset ||
  225. IrpStack->Parameters.Power.ShutdownType == PowerActionShutdownOff ||
  226. IrpStack->Parameters.Power.ShutdownType == PowerActionShutdown)
  227. && PciIsOnVGAPath(pdoExtension)) {
  228. return STATUS_SUCCESS;
  229. }
  230. //
  231. // If this device is on the debug path then don't power it down so we
  232. // can report if this crashes the machine...
  233. //
  234. if (pdoExtension->OnDebugPath) {
  235. return STATUS_SUCCESS;
  236. }
  237. } else {
  238. //
  239. // Device is powering UP.
  240. //
  241. // Verify the device is still the same as before (and that someone
  242. // hasn't removed/replaced it with something else)
  243. //
  244. if (!PciIsSameDevice(pdoExtension)) {
  245. return STATUS_NO_SUCH_DEVICE;
  246. }
  247. }
  248. //
  249. // Place the device in the proper power state
  250. //
  251. status = PciSetPowerManagedDevicePowerState(
  252. pdoExtension,
  253. desiredDeviceState,
  254. TRUE
  255. );
  256. //
  257. // If the device is transitioning to the D0 state, reset the common
  258. // config information on the device and inform the system of the device
  259. // state change.
  260. //
  261. if (desiredDeviceState == PowerDeviceD0) {
  262. if (NT_SUCCESS(status)) {
  263. pdoExtension->PowerState.CurrentDeviceState = desiredDeviceState;
  264. PoSetPowerState (
  265. pdoExtension->PhysicalDeviceObject,
  266. DevicePowerState,
  267. IrpStack->Parameters.Power.State
  268. );
  269. if (pdoExtension->OnDebugPath) {
  270. KdPowerTransition(PowerDeviceD0);
  271. }
  272. }
  273. } else {
  274. //
  275. // The new device state is something other then D0.
  276. // notify the system before continuing
  277. //
  278. PoSetPowerState (
  279. pdoExtension->PhysicalDeviceObject,
  280. DevicePowerState,
  281. IrpStack->Parameters.Power.State
  282. );
  283. //
  284. // Turn off the device's IO and MEMory access.
  285. //
  286. PciDecodeEnable(pdoExtension, FALSE, NULL);
  287. status = STATUS_SUCCESS;
  288. }
  289. return status;
  290. }
  291. NTSTATUS
  292. PciPdoWaitWake(
  293. IN PIRP Irp,
  294. IN PIO_STACK_LOCATION IrpSp,
  295. IN PPCI_COMMON_EXTENSION DeviceExtension
  296. )
  297. /*++
  298. Routine Description:
  299. Handle IRP_MN_WAIT_WAKE for PCI PDOs.
  300. This operation is used to wait for the device to signal a wake event.
  301. By waiting for a wake signal from a device, its wake event is enabled
  302. so long as the System Power State is above the requested SystemWake
  303. state. By not waiting for a wake signal from a device, its wake
  304. signal is not enabled.
  305. Arguments:
  306. DeviceObject - Pointer to the device object for which this IRP applies.
  307. Irp - Pointer to the IRP.
  308. Return Value:
  309. NT status.
  310. STATUS_INVALID_DEVICE_STATE, if the device is in the PowerD0 state or
  311. a state below which can support waking or if the SystemWake state
  312. is below a state which can be supported.
  313. A pending IRP_MN_WAIT_WAKE will complete with this error if the
  314. device's state is changed to be incompatible with the wake request.
  315. STATUS_DEVICE_BUSY, if the device already has a WAIT_WAKE request
  316. outstanding. To change the SystemWake level the outstanding
  317. IRP must be canceled.
  318. STATUS_INVALID_DEVICE_REQUEST, if the device is not capable of
  319. signaling a wakeup. In theory we should have gotten out
  320. before getting this far because DeviceWake woud be unspecified.
  321. STATUS_SUCCESS. The device has signaled a WAKE event.
  322. STATUS_PENDING. This is the expected return, the IRP will not
  323. complete until the wait is complete or cancelled.
  324. --*/
  325. {
  326. BOOLEAN pmeCapable;
  327. DEVICE_POWER_STATE devPower;
  328. NTSTATUS status;
  329. PPCI_FDO_EXTENSION fdoExtension;
  330. PIO_STACK_LOCATION irpStack;
  331. PIRP irpToParent;
  332. POWER_STATE powerState;
  333. PPCI_PDO_EXTENSION pdoExtension;
  334. ULONG waitCount;
  335. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  336. ASSERT_PCI_PDO_EXTENSION(pdoExtension);
  337. PoStartNextPowerIrp(Irp);
  338. devPower = pdoExtension->PowerState.CurrentDeviceState;
  339. //
  340. // The docs say WAIT_WAKE is allowed only from a state < D0, and
  341. // only if current power state supports wakeup.
  342. //
  343. ASSERT(devPower < PowerDeviceMaximum);
  344. if ((devPower > pdoExtension->PowerState.DeviceWakeLevel) ||
  345. (pdoExtension->PowerState.DeviceWakeLevel == PowerDeviceUnspecified)) {
  346. //
  347. // NTRAID #62653 - 4/28/2000 - andrewth
  348. // Need to add system state to conditions here.
  349. //
  350. PciDebugPrint(
  351. PciDbgWaitWake,
  352. "WaitWake: pdox %08x current state (%d) not valid for waiting\n",
  353. pdoExtension,
  354. devPower
  355. );
  356. status = STATUS_INVALID_DEVICE_STATE;
  357. goto PciPdoWaitWakeFailIrp;
  358. }
  359. PCI_LOCK_OBJECT(pdoExtension);
  360. //
  361. // Only one WAIT_WAKE IRP allowed. Set THIS IRP as the wait wake
  362. // irp in the pdo extension, if and only if, there is no other irp
  363. // there.
  364. //
  365. if (pdoExtension->PowerState.WaitWakeIrp != NULL) {
  366. //
  367. // A WAIT_WAKE IRP is already pending for this device.
  368. //
  369. PCI_UNLOCK_OBJECT(pdoExtension);
  370. PciDebugPrint(
  371. PciDbgWaitWake,
  372. "WaitWake: pdox %08x is already waiting\n",
  373. devPower
  374. );
  375. status = STATUS_DEVICE_BUSY;
  376. goto PciPdoWaitWakeFailIrp;
  377. }
  378. //
  379. // Does this device support Power Management? That is, do we
  380. // know how to enable PME?
  381. //
  382. PciPmeGetInformation(
  383. pdoExtension->PhysicalDeviceObject,
  384. &pmeCapable,
  385. NULL,
  386. NULL
  387. );
  388. if (pmeCapable == FALSE) {
  389. //
  390. // This device does not support Power Management.
  391. // Don't allow a wait wake. In theory we couldn't
  392. // have gotten here because our capabilities should
  393. // have stopped the caller from even trying this.
  394. //
  395. PCI_UNLOCK_OBJECT(pdoExtension);
  396. PciDebugPrint(
  397. PciDbgWaitWake,
  398. "WaitWake: pdox %08x does not support PM\n",
  399. devPower
  400. );
  401. status = STATUS_INVALID_DEVICE_REQUEST;
  402. goto PciPdoWaitWakeFailIrp;
  403. }
  404. fdoExtension = PCI_PARENT_FDOX(pdoExtension);
  405. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  406. if (fdoExtension->Fake) {
  407. //
  408. // Parent is really PCMCIA.sys, his filter will take care
  409. // of sending the wait wake to the parent,... bail out.
  410. //
  411. PCI_UNLOCK_OBJECT(pdoExtension);
  412. return STATUS_PENDING;
  413. }
  414. //
  415. // We're going to do this. Set the wait wake irp field in the
  416. // pdo extension and set cancel routine for this IRP.
  417. //
  418. PciDebugPrint(
  419. PciDbgWaitWake,
  420. "WaitWake: pdox %08x setting PMEEnable.\n",
  421. pdoExtension
  422. );
  423. pdoExtension->PowerState.WaitWakeIrp = Irp;
  424. IoMarkIrpPending(Irp);
  425. pdoExtension->PowerState.SavedCancelRoutine =
  426. IoSetCancelRoutine(Irp, PciPdoWaitWakeCancelRoutine);
  427. //
  428. // NTRAID #62653 - 4/28/2000 - andrewth
  429. // What is the correct behaviour if there are stacked
  430. // cancel routines?
  431. //
  432. ASSERT(!pdoExtension->PowerState.SavedCancelRoutine);
  433. //
  434. // Set the PME Enable bit.
  435. //
  436. PciPdoAdjustPmeEnable( pdoExtension, TRUE );
  437. //
  438. // Remember that the parent now has one more child that is armed
  439. // for wakeup
  440. //
  441. waitCount = InterlockedIncrement(&fdoExtension->ChildWaitWakeCount);
  442. //
  443. // Once we have a wait count reference, we can unlock the object
  444. //
  445. PCI_UNLOCK_OBJECT(pdoExtension);
  446. //
  447. // This PDO is now waiting. If this is the first child of this
  448. // PDO's parent bus to enter this state, the parent bus should
  449. // also enter this state.
  450. //
  451. if (waitCount == 1) {
  452. //
  453. // Note that there are two values that can use here, the
  454. // SystemWakeLevel of the FDO itself or the SystemWakeLevel of
  455. // the PDO. Both are equally valid, but since we want to catch people
  456. // who fail to prevent the system from going into a deeper sleep state
  457. // than their device can support, we use the SystemWakeLevel from the
  458. // PDO, which conviniently enough, is stored in the irp..
  459. //
  460. powerState.SystemState = IrpSp->Parameters.WaitWake.PowerState;
  461. //
  462. // Request a power irp to go to our parent stack
  463. //
  464. PoRequestPowerIrp(
  465. fdoExtension->FunctionalDeviceObject,
  466. IRP_MN_WAIT_WAKE,
  467. powerState,
  468. PciPdoWaitWakeCallBack,
  469. fdoExtension,
  470. NULL
  471. );
  472. }
  473. //
  474. // If we get to this point, then we will return pending because we
  475. // have queue up the request
  476. //
  477. status = STATUS_PENDING;
  478. PciPdoWaitWakeFailIrp:
  479. if (!NT_SUCCESS(status)) {
  480. Irp->IoStatus.Status = status;
  481. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  482. } else {
  483. ASSERT( status == STATUS_PENDING );
  484. }
  485. return status;
  486. }
  487. NTSTATUS
  488. PciPdoWaitWakeCallBack(
  489. IN PDEVICE_OBJECT DeviceObject,
  490. IN UCHAR MinorFunction,
  491. IN POWER_STATE PowerState,
  492. IN PVOID Context,
  493. IN PIO_STATUS_BLOCK IoStatus
  494. )
  495. /*++
  496. Routine Description:
  497. This is the callback routine that gets invoked when the W/W irp that was
  498. sent to the FDO by a PDO is finished. The purpose of this routine is to
  499. see if we need to re-arm the W/W on the FDO because we have more devices
  500. with W/W outstanding on them
  501. Arguments:
  502. DeviceObject - The FDO's device object
  503. MinorFunction - IRP_MN_WAIT_WAKE
  504. PowerState - The sleep state that was used to wake up the system
  505. Context - The FDO Extension
  506. IoStatus - The Status of the request
  507. Return Value:
  508. NTSTATUS
  509. --*/
  510. {
  511. BOOLEAN pmeStatus;
  512. PPCI_FDO_EXTENSION fdoExtension = (PPCI_FDO_EXTENSION) Context;
  513. PIRP finishedIrp;
  514. PPCI_PDO_EXTENSION pdoExtension;
  515. //
  516. // Normally, the IRP (to the PDO) will have completed with
  517. // STATUS_SUCCESS. In that case, just wake up the one device
  518. // which is signalling for wakeup. If the IRP to the PDO
  519. // failed, wake up ALL devices that are dependent on this wake.
  520. //
  521. //
  522. // For each child
  523. //
  524. for (pdoExtension = fdoExtension->ChildPdoList;
  525. pdoExtension && fdoExtension->ChildWaitWakeCount;
  526. pdoExtension = pdoExtension->Next) {
  527. //
  528. // Does this device do power management and if so, does
  529. // it have an outstanding WaitWake IRP?
  530. //
  531. PCI_LOCK_OBJECT(pdoExtension);
  532. if (pdoExtension->PowerState.WaitWakeIrp != NULL) {
  533. PciPmeGetInformation(
  534. pdoExtension->PhysicalDeviceObject,
  535. NULL,
  536. &pmeStatus,
  537. NULL
  538. );
  539. //
  540. // Is this device signalling for a wakeup? (Or, if we
  541. // are completing wake irps because our own wait_wake
  542. // failed).
  543. //
  544. if (pmeStatus || !NT_SUCCESS(IoStatus->Status)) {
  545. //
  546. // Yes. Complete its outstanding wait wake IRP.
  547. //
  548. #if DBG
  549. if (pmeStatus) {
  550. PciDebugPrint(
  551. PciDbgWaitWake,
  552. "PCI - pdox %08x is signalling a PME\n",
  553. pdoExtension
  554. );
  555. } else {
  556. PciDebugPrint(
  557. PciDbgWaitWake,
  558. "PCI - waking pdox %08x because fdo wait failed %0x.\n",
  559. pdoExtension,
  560. IoStatus->Status
  561. );
  562. }
  563. #endif
  564. //
  565. // Wait_wake irp being dequeued, disable the PME enable,
  566. // clear PMEStatus (if set) and EOI this device.
  567. //
  568. PciPdoAdjustPmeEnable( pdoExtension, FALSE );
  569. //
  570. // Make sure this IRP will not be completed again,
  571. // or, canceled.
  572. //
  573. finishedIrp = pdoExtension->PowerState.WaitWakeIrp;
  574. pdoExtension->PowerState.WaitWakeIrp = NULL;
  575. IoSetCancelRoutine(finishedIrp, NULL);
  576. PoStartNextPowerIrp( finishedIrp );
  577. PciCompleteRequest(
  578. finishedIrp, // send down parent status
  579. IoStatus->Status
  580. );
  581. //
  582. // Decrement the waiter count.
  583. //
  584. ASSERT(fdoExtension->ChildWaitWakeCount > 0);
  585. InterlockedDecrement( &(fdoExtension->ChildWaitWakeCount) );
  586. }
  587. }
  588. PCI_UNLOCK_OBJECT(pdoExtension);
  589. }
  590. //
  591. // Did we succeed this irp?
  592. //
  593. if (!NT_SUCCESS(IoStatus->Status)) {
  594. PciDebugPrint(
  595. PciDbgWaitWake,
  596. "WaitWake (fdox %08x) - WaitWake Irp Failed %08x\n",
  597. fdoExtension,
  598. IoStatus->Status
  599. );
  600. return IoStatus->Status;
  601. }
  602. //
  603. // Are there any children with outstanding WaitWakes on thems?
  604. //
  605. if (fdoExtension->ChildWaitWakeCount) {
  606. PciDebugPrint(
  607. PciDbgWaitWake,
  608. "WaitWake (fdox %08x) - WaitWake Irp restarted - count = %x\n",
  609. fdoExtension,
  610. fdoExtension->ChildWaitWakeCount
  611. );
  612. //
  613. // Loop
  614. //
  615. PoRequestPowerIrp(
  616. DeviceObject,
  617. MinorFunction,
  618. PowerState,
  619. PciPdoWaitWakeCallBack,
  620. Context,
  621. NULL
  622. );
  623. #if DBG
  624. } else {
  625. PciDebugPrint(
  626. PciDbgWaitWake,
  627. "WaitWake (fdox %08x) - WaitWake Irp Finished\n",
  628. fdoExtension
  629. );
  630. #endif
  631. }
  632. //
  633. // Done
  634. //
  635. return STATUS_SUCCESS;
  636. }
  637. VOID
  638. PciPdoWaitWakeCancelRoutine(
  639. IN PDEVICE_OBJECT DeviceObject,
  640. IN OUT PIRP Irp
  641. )
  642. /*++
  643. Routine Description:
  644. Cancel an outstanding WAIT_WAKE IRP.
  645. Note: The Cancel Spin Lock is held on entry.
  646. Arguments:
  647. DeviceObject - Pointer to the device object for which this IRP applies.
  648. Irp - Pointer to the IRP.
  649. Return Value:
  650. None.
  651. --*/
  652. {
  653. PPCI_PDO_EXTENSION pdoExtension;
  654. PPCI_FDO_EXTENSION fdoExtension;
  655. KIRQL oldIrql;
  656. ULONG waitCount;
  657. pdoExtension = (PPCI_PDO_EXTENSION) DeviceObject->DeviceExtension;
  658. PciDebugPrint(
  659. PciDbgWaitWake,
  660. "WaitWake (pdox %08x) Cancel routine, Irp %08x.\n",
  661. pdoExtension,
  662. Irp
  663. );
  664. ASSERT_PCI_PDO_EXTENSION(pdoExtension);
  665. oldIrql = Irp->CancelIrql;
  666. IoReleaseCancelSpinLock(oldIrql);
  667. PCI_LOCK_OBJECT(pdoExtension);
  668. if (pdoExtension->PowerState.WaitWakeIrp == NULL) {
  669. //
  670. // The WaitWake IRP has already been dealt with.
  671. //
  672. PCI_UNLOCK_OBJECT(pdoExtension);
  673. return;
  674. }
  675. //
  676. // Clear WaitWake Irp in the PDO.
  677. //
  678. pdoExtension->PowerState.WaitWakeIrp = NULL;
  679. PciPdoAdjustPmeEnable(pdoExtension, FALSE);
  680. //
  681. // As this is a cancel, the wait wake count in the parent has not
  682. // been decremented. Decrement it here and if decrementing to
  683. // zero waiters, cancel the IRP at the parent.
  684. //
  685. fdoExtension = PCI_PARENT_FDOX(pdoExtension);
  686. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  687. waitCount = InterlockedDecrement(&fdoExtension->ChildWaitWakeCount);
  688. PCI_UNLOCK_OBJECT(pdoExtension);
  689. if (waitCount == 0) {
  690. //
  691. // Cancel the parent's wait wake also.
  692. //
  693. PciDebugPrint(
  694. PciDbgWaitWake,
  695. "WaitWake (pdox %08x) zero waiters remain on parent, cancelling parent wait.\n",
  696. pdoExtension
  697. );
  698. IoCancelIrp(fdoExtension->PowerState.WaitWakeIrp);
  699. }
  700. //
  701. // Complete the IRP.
  702. //
  703. Irp->IoStatus.Information = 0;
  704. PoStartNextPowerIrp(Irp);
  705. PciCompleteRequest(Irp, STATUS_CANCELLED);
  706. //
  707. // NTRAID #62653 - 4/28/2000 - andrewth
  708. // Need to cause the bus parent to decrement its outstanding
  709. // IRP counter,... how to make this happen?
  710. //
  711. return;
  712. }
  713. NTSTATUS
  714. PciFdoIrpQueryPower(
  715. IN PIRP Irp,
  716. IN PIO_STACK_LOCATION IrpSp,
  717. IN PPCI_COMMON_EXTENSION DeviceExtension
  718. )
  719. {
  720. //
  721. // pass 1, claim we can do it.
  722. //
  723. return STATUS_SUCCESS;
  724. }
  725. NTSTATUS
  726. PciFdoSetPowerState (
  727. IN PIRP Irp,
  728. IN PIO_STACK_LOCATION IrpSp,
  729. IN PPCI_COMMON_EXTENSION DeviceExtension
  730. )
  731. /*++
  732. Routine Description:
  733. Handle SET_POWER irps set to an FDO
  734. Basic Rules for handling this:
  735. - If this is a DEVICE power irp, we don't need to do anything since
  736. for root buses and bridges, all necessary programming is done by the
  737. PDO
  738. - If this is a SYSTEM power irp, then
  739. a) block all incoming IRP_MN_POWER requests (using a spinlock)
  740. b) use the capabilities table in the device extension to determine
  741. what the "highest" allowed DEVICE state that we should transition
  742. the device into
  743. c) look at all the children of this device and see if we can pick a
  744. "lower" DEVICE state.
  745. d) Consideration should be granted if a child is armed for wake
  746. or if this device is armed for wake (in general, both should be
  747. true, or both should be false)
  748. e) Remember the answer as the "Desired State"
  749. f) Release the spinlock and allow other IRP_MN_POWER requests in
  750. g) Use PoRequestPowerIrp() to request a power irp to put the device
  751. in the appropriate state
  752. h) return STATUS_PENDING
  753. - In another thread context (ie: in the context of the completion
  754. passed to PoRequestPowerIrp), complete the irp that was handed to
  755. us
  756. Arguments:
  757. Irp - The Power Irp
  758. IrpSp - The current stack location in the irp
  759. DeviceExtension - The device whose power we want to set
  760. --*/
  761. {
  762. POWER_STATE desiredState;
  763. PPCI_FDO_EXTENSION fdoExtension;
  764. NTSTATUS status;
  765. SYSTEM_POWER_STATE systemState;
  766. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  767. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  768. //
  769. // If this is a device power irp, remember that we say it go by, and
  770. // remember what D-state the bus/bridge is now in. If we needed to do more
  771. // here, then we should have to distinguish between power up and power down
  772. // requests. PowerDown requests we can add the code in-line. PowerUp
  773. // requests would force us to set a completion routine on the IRP and do
  774. // the work in the completion routine
  775. //
  776. if (IrpSp->Parameters.Power.Type == DevicePowerState) {
  777. fdoExtension->PowerState.CurrentDeviceState =
  778. IrpSp->Parameters.Power.State.DeviceState;
  779. return STATUS_SUCCESS;
  780. }
  781. //
  782. // If we aren't started, don't touch the power IRP.
  783. //
  784. if (fdoExtension->DeviceState != PciStarted) {
  785. return STATUS_NOT_SUPPORTED;
  786. }
  787. //
  788. // If this isn't a SystemPowerState irp, then we don't know what it is, and
  789. // so we will not support it
  790. //
  791. ASSERT( IrpSp->Parameters.Power.Type == SystemPowerState );
  792. if (IrpSp->Parameters.Power.Type != SystemPowerState) {
  793. return STATUS_NOT_SUPPORTED;
  794. }
  795. //
  796. // If this is a Shutdown so we can warm reboot don't take the bridges to D3 as
  797. // if the video or boot device is behind the bridge and the BIOS doesn't power
  798. // things up (most don't) then we don't reboot...
  799. //
  800. if (IrpSp->Parameters.Power.State.SystemState == PowerSystemShutdown
  801. && IrpSp->Parameters.Power.ShutdownType == PowerActionShutdownReset) {
  802. return STATUS_SUCCESS;
  803. }
  804. //
  805. // Grab the system state that we want to go to
  806. //
  807. systemState = IrpSp->Parameters.Power.State.SystemState;
  808. ASSERT( systemState > PowerSystemUnspecified && systemState < PowerSystemMaximum );
  809. //
  810. // At this point, we can assume that we will transition the Device into a
  811. // least the following D-state
  812. //
  813. desiredState.DeviceState = fdoExtension->PowerState.SystemStateMapping[ systemState ];
  814. //
  815. // Mark the irp as pending
  816. //
  817. IoMarkIrpPending( Irp );
  818. //
  819. // Send a request
  820. //
  821. PoRequestPowerIrp(
  822. fdoExtension->FunctionalDeviceObject,
  823. IRP_MN_SET_POWER,
  824. desiredState,
  825. PciFdoSetPowerStateCompletion,
  826. Irp,
  827. NULL
  828. );
  829. return STATUS_PENDING;
  830. }
  831. VOID
  832. PciFdoSetPowerStateCompletion(
  833. IN PDEVICE_OBJECT DeviceObject,
  834. IN UCHAR MinorFunction,
  835. IN POWER_STATE PowerState,
  836. IN PVOID Context,
  837. IN PIO_STATUS_BLOCK IoStatus
  838. )
  839. /*++
  840. Routine Description:
  841. This routine is called when the D-Irp that was requested by the FDO
  842. has been completed.
  843. This routine needs to pass the S-Irp that initiated the D-Irp all the
  844. way down the stack
  845. Arguments:
  846. DeviceObject - The FDO device object
  847. MinorFunction - IRP_MN_SET_POWER
  848. PowerState - Whatever the requested power state was
  849. Context - This is really the S-Irp that requested the D-Irp
  850. IoStatus - The result of the D-Irp
  851. Return Value:
  852. None
  853. --*/
  854. {
  855. PPCI_FDO_EXTENSION fdoExtension;
  856. PIRP irp = (PIRP) Context;
  857. PIO_STACK_LOCATION irpSp;
  858. UNREFERENCED_PARAMETER( MinorFunction );
  859. UNREFERENCED_PARAMETER( PowerState );
  860. ASSERT( IoStatus->Status == STATUS_SUCCESS );
  861. //
  862. // Grab a pointer to the FDO extension and make sure that it is valid
  863. fdoExtension = (PPCI_FDO_EXTENSION) DeviceObject->DeviceExtension;
  864. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  865. irpSp = IoGetCurrentIrpStackLocation(irp);
  866. //
  867. // Check if we are returning from a hibernate and powering on the bus
  868. //
  869. if (irpSp->Parameters.Power.State.SystemState == PowerSystemWorking
  870. && fdoExtension->Hibernated) {
  871. fdoExtension->Hibernated = FALSE;
  872. //
  873. // Scan the bus and turn off any new hardware
  874. //
  875. PciScanHibernatedBus(fdoExtension);
  876. }
  877. if (irpSp->Parameters.Power.ShutdownType == PowerActionHibernate
  878. && irpSp->Parameters.Power.State.SystemState > PowerSystemWorking) {
  879. //
  880. // We're powering down for a hibernate so remember
  881. //
  882. fdoExtension->Hibernated = TRUE;
  883. }
  884. //
  885. // Mark the current irp as having succeeded
  886. //
  887. irp->IoStatus.Status = STATUS_SUCCESS;
  888. //
  889. // Start the next power irp for this device
  890. //
  891. PoStartNextPowerIrp( irp );
  892. //
  893. // Get ready to pass the power irp down the stack
  894. //
  895. IoCopyCurrentIrpStackLocationToNext( irp );
  896. //
  897. // Pass the irp down the stack
  898. //
  899. PoCallDriver( fdoExtension->AttachedDeviceObject, irp );
  900. }
  901. NTSTATUS
  902. PciFdoWaitWake(
  903. IN PIRP Irp,
  904. IN PIO_STACK_LOCATION IrpSp,
  905. IN PPCI_COMMON_EXTENSION DeviceExtension
  906. )
  907. /*++
  908. Routine Description:
  909. Handle IRP_MN_WAIT_WAKE for PCI FDOs.
  910. PCI FDOs receive a WAIT_WAKE IRP when the number of child PDOs
  911. with a pending WAIT_WAKE IRP transitions from 0 to 1.
  912. Arguments:
  913. DeviceObject - Pointer to the device object for which this IRP applies.
  914. Irp - Pointer to the IRP.
  915. Return Value:
  916. NT status.
  917. --*/
  918. {
  919. PIO_STACK_LOCATION irpStack;
  920. PPCI_FDO_EXTENSION fdoExtension;
  921. NTSTATUS status;
  922. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  923. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  924. irpStack = IrpSp;
  925. PCI_LOCK_OBJECT(fdoExtension);
  926. //
  927. // Only one WAIT_WAKE IRP allowed. Set THIS IRP as the wait wake
  928. // irp in the fdo extension, if and only if, there is no other irp
  929. // there.
  930. //
  931. // Note: The ChildWaitWakeCount field is incremented by the PCI
  932. // driver before sending this IRP down. Only accept this IRP if
  933. // the ChildWaitWakeCount field is one (ie don't listen to ACPI).
  934. //
  935. if (!fdoExtension->ChildWaitWakeCount) {
  936. //
  937. // Didn't come from a PCI PDO, ignore it.
  938. //
  939. PciDebugPrint(
  940. PciDbgWaitWake,
  941. "WaitWake (fdox %08x) Unexpected WaitWake IRP IGNORED.\n",
  942. fdoExtension
  943. );
  944. status = STATUS_DEVICE_BUSY;
  945. goto Cleanup;
  946. }
  947. if (fdoExtension->PowerState.WaitWakeIrp != NULL) {
  948. //
  949. // A WAIT_WAKE IRP is already pending for this device.
  950. //
  951. PciDebugPrint(
  952. PciDbgWaitWake,
  953. "WaitWake: fdox %08x already waiting (%d waiters)\n",
  954. fdoExtension,
  955. fdoExtension->ChildWaitWakeCount
  956. );
  957. status = STATUS_DEVICE_BUSY;
  958. goto Cleanup;
  959. }
  960. fdoExtension->PowerState.WaitWakeIrp = Irp;
  961. //
  962. // This IRP will be passed down to the underlying PDO who
  963. // will pend it. The completion routine does needs to check
  964. // that the bus is capable of checking its children and then
  965. // examining each child (that has a wait wake outstanding).
  966. //
  967. PciDebugPrint(
  968. PciDbgWaitWake,
  969. "WaitWake: fdox %08x is a now waiting for a wake event\n",
  970. fdoExtension
  971. );
  972. IoCopyCurrentIrpStackLocationToNext(Irp);
  973. IoSetCompletionRoutine(
  974. Irp,
  975. PciFdoWaitWakeCompletion,
  976. fdoExtension,
  977. TRUE,
  978. TRUE,
  979. TRUE
  980. );
  981. Irp->IoStatus.Status = status = STATUS_SUCCESS;
  982. Cleanup:
  983. PCI_UNLOCK_OBJECT(fdoExtension);
  984. //
  985. // Start the next power irp
  986. //
  987. PoStartNextPowerIrp(Irp);
  988. if (!NT_SUCCESS(status) ) {
  989. PciCompleteRequest(Irp, status);
  990. return status;
  991. }
  992. //
  993. // Pass the IRP down the stack.
  994. //
  995. return PoCallDriver(fdoExtension->AttachedDeviceObject ,Irp);
  996. }
  997. NTSTATUS
  998. PciFdoWaitWakeCallBack(
  999. IN PDEVICE_OBJECT DeviceObject,
  1000. IN UCHAR MinorFunction,
  1001. IN POWER_STATE PowerState,
  1002. IN PVOID Context,
  1003. IN PIO_STATUS_BLOCK IoStatus
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This routine is called when a device has transitioned back into the
  1008. into the D-zero state
  1009. Arguments:
  1010. DeviceObject - Pointer to the FDO
  1011. MinorFunction - IRP_MN_SET_POWER
  1012. PowerState - D0
  1013. Context - The WaitWake irp that caused us to make this transition
  1014. IoStatus - The status of the request
  1015. Return Value:
  1016. NTSTATUS
  1017. --*/
  1018. {
  1019. PIRP waitWakeIrp = (PIRP) Context;
  1020. UNREFERENCED_PARAMETER( MinorFunction );
  1021. UNREFERENCED_PARAMETER( PowerState );
  1022. //
  1023. // Complete the wait wake irp
  1024. //
  1025. PoStartNextPowerIrp( waitWakeIrp );
  1026. PciCompleteRequest( waitWakeIrp, IoStatus->Status );
  1027. //
  1028. // Done
  1029. //
  1030. return IoStatus->Status;
  1031. }
  1032. VOID
  1033. PciFdoWaitWakeCancel(
  1034. IN PDEVICE_OBJECT DeviceObject,
  1035. IN OUT PIRP Irp
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. Cancel an outstanding WAIT_WAKE IRP.
  1040. Note: The Cancel Spin Lock is held on entry.
  1041. Arguments:
  1042. DeviceObject - Pointer to the device object for which this IRP applies.
  1043. Irp - Pointer to the IRP.
  1044. Return Value:
  1045. None.
  1046. --*/
  1047. {
  1048. PPCI_FDO_EXTENSION fdoExtension;
  1049. NTSTATUS status;
  1050. KIRQL oldIrql;
  1051. fdoExtension = (PPCI_FDO_EXTENSION)DeviceObject->DeviceExtension;
  1052. PciDebugPrint(
  1053. PciDbgWaitWake,
  1054. "WaitWake (fdox %08x) Cancel routine, Irp %08x.\n",
  1055. fdoExtension,
  1056. Irp
  1057. );
  1058. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  1059. oldIrql = Irp->CancelIrql;
  1060. IoReleaseCancelSpinLock(oldIrql);
  1061. PCI_LOCK_OBJECT(fdoExtension);
  1062. if (fdoExtension->PowerState.WaitWakeIrp == NULL) {
  1063. //
  1064. // The WaitWake IRP has already been dealt with.
  1065. //
  1066. PCI_UNLOCK_OBJECT(fdoExtension);
  1067. return;
  1068. }
  1069. fdoExtension->PowerState.WaitWakeIrp = NULL;
  1070. PCI_UNLOCK_OBJECT(fdoExtension);
  1071. Irp->IoStatus.Information = 0;
  1072. PoStartNextPowerIrp(Irp);
  1073. PciCompleteRequest(Irp, STATUS_CANCELLED);
  1074. return;
  1075. }
  1076. NTSTATUS
  1077. PciFdoWaitWakeCompletion(
  1078. IN PDEVICE_OBJECT DeviceObject,
  1079. IN PIRP Irp,
  1080. IN PPCI_FDO_EXTENSION FdoExtension
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. Handle IRP_MN_WAIT_WAKE completion for PCI FDOs.
  1085. WAIT_WAKE completion at the FDO means some device (not necesarily
  1086. a child of this FDO) is signalling wake. This routine scans each
  1087. child to see if that device is the one. This is a recursive
  1088. operation.
  1089. Arguments:
  1090. DeviceObject - Pointer to the device object for which this IRP applies.
  1091. Irp - Pointer to the IRP.
  1092. Return Value:
  1093. NT status.
  1094. --*/
  1095. {
  1096. POWER_STATE powerState;
  1097. PciDebugPrint(
  1098. PciDbgWaitWake,
  1099. "WaitWake (fdox %08x) Completion routine, Irp %08x, IrpStatus = %08x.\n",
  1100. FdoExtension,
  1101. Irp,
  1102. Irp->IoStatus.Status
  1103. );
  1104. ASSERT_PCI_FDO_EXTENSION(FdoExtension);
  1105. //
  1106. // We will need the device's lock for some of the following...
  1107. //
  1108. PCI_LOCK_OBJECT(FdoExtension);
  1109. ASSERT (FdoExtension->PowerState.WaitWakeIrp);
  1110. //
  1111. // We no longer have a WaitWake irp in the the FDO...
  1112. //
  1113. FdoExtension->PowerState.WaitWakeIrp = NULL;
  1114. //
  1115. // Check the bus is at a power level at which the config space
  1116. // of its children can be examined.
  1117. //
  1118. // NTRAID #62653 - 4/28/2000 - andrewth
  1119. //
  1120. // Question: Should we depend on PO to take care of this requirement?
  1121. // can we use PO to do the needed power state changes?
  1122. //
  1123. // Assumption: The parent of this bus is powered at this moment.
  1124. //
  1125. if (FdoExtension->PowerState.CurrentDeviceState != PowerDeviceD0) {
  1126. powerState.SystemState = PowerDeviceD0;
  1127. //
  1128. // Power up the bus.
  1129. //
  1130. PoRequestPowerIrp(
  1131. DeviceObject,
  1132. IRP_MN_SET_POWER,
  1133. powerState,
  1134. PciFdoWaitWakeCallBack,
  1135. Irp,
  1136. NULL
  1137. );
  1138. PCI_UNLOCK_OBJECT(FdoExtension);
  1139. return STATUS_MORE_PROCESSING_REQUIRED;
  1140. }
  1141. //
  1142. // Done with lock
  1143. //
  1144. PCI_UNLOCK_OBJECT(FdoExtension);
  1145. return STATUS_SUCCESS;
  1146. }
  1147. NTSTATUS
  1148. PciStallForPowerChange(
  1149. IN PPCI_PDO_EXTENSION PdoExtension,
  1150. IN DEVICE_POWER_STATE PowerState,
  1151. IN UCHAR PowerCapabilityPointer
  1152. )
  1153. {
  1154. NTSTATUS status = STATUS_DEVICE_PROTOCOL_ERROR;
  1155. PVERIFIER_DATA verifierData;
  1156. LONG delay;
  1157. ULONG retries = 100;
  1158. KIRQL irql;
  1159. PCI_PMCSR pmcsr;
  1160. ASSERT(PdoExtension->PowerState.CurrentDeviceState >= PowerDeviceD0
  1161. && PdoExtension->PowerState.CurrentDeviceState <= PowerDeviceD3);
  1162. ASSERT(PowerState >= PowerDeviceD0 && PowerState <= PowerDeviceD3);
  1163. ASSERT(!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS));
  1164. //
  1165. // Lookup the delay we are meant to do as in the PCI spec
  1166. //
  1167. delay = PciPowerDelayTable[PdoExtension->PowerState.CurrentDeviceState-1][PowerState-1];
  1168. //
  1169. // Stall in a polite fashion if IRQL allows
  1170. //
  1171. irql = KeGetCurrentIrql();
  1172. while (retries--) {
  1173. if (delay > 0) {
  1174. if (irql < DISPATCH_LEVEL) {
  1175. //
  1176. // Get off the processor.
  1177. //
  1178. // timeoutPeriod is in units of 100ns, negative means
  1179. // relative.
  1180. //
  1181. LARGE_INTEGER timeoutPeriod;
  1182. timeoutPeriod.QuadPart = -10 * delay;
  1183. timeoutPeriod.QuadPart -= (KeQueryTimeIncrement() - 1);
  1184. KeDelayExecutionThread(KernelMode,
  1185. FALSE,
  1186. &timeoutPeriod
  1187. );
  1188. } else {
  1189. //
  1190. // Spin, units are microseconds
  1191. //
  1192. KeStallExecutionProcessor((ULONG)delay);
  1193. }
  1194. }
  1195. //
  1196. // Reread the status and control register. The assumption here is that
  1197. // some cards don't get their act together fast enough and the fact that
  1198. // they arn't ready yet is reflected by them not updating the power control
  1199. // register with what we just wrote to it. This is not in the PCI spec
  1200. // but is how some of these broken cards work and it can't hurt...
  1201. //
  1202. PciReadDeviceConfig(
  1203. PdoExtension,
  1204. &pmcsr,
  1205. PowerCapabilityPointer + FIELD_OFFSET(PCI_PM_CAPABILITY,PMCSR),
  1206. sizeof(PCI_PMCSR)
  1207. );
  1208. //
  1209. // Pci power states are 0-3 where as NT power states are 1-4
  1210. //
  1211. if (pmcsr.PowerState == PowerState-1) {
  1212. //
  1213. // Device is ready, we're done.
  1214. //
  1215. return STATUS_SUCCESS;
  1216. }
  1217. //
  1218. // Subsequent iterations, delay 1ms.
  1219. //
  1220. delay = 1000;
  1221. }
  1222. //
  1223. // So how nasty can this sort of problem be?
  1224. //
  1225. // If this is an ATI M1 (mobile video) and on some machines under some
  1226. // circumstances (and no ATI doesn't know which ones) they disable the
  1227. // operation of the PMCSR. It would have been nice if they had just
  1228. // removed the PM capability from the list so we would have never
  1229. // attempted to power manage this chip but they would have failed
  1230. // WHQL. Unfortunately it is not possible to just add these to the
  1231. // list of devices that have bad PM because some BIOSes (read HP and
  1232. // Dell) monitor this register to save extra state from the chip and
  1233. // thus if we don't change it we spin in AML forever.
  1234. //
  1235. // Yes this is a gross hack.
  1236. //
  1237. verifierData = PciVerifierRetrieveFailureData(
  1238. PCI_VERIFIER_PMCSR_TIMEOUT
  1239. );
  1240. ASSERT(verifierData);
  1241. VfFailDeviceNode(
  1242. PdoExtension->PhysicalDeviceObject,
  1243. PCI_VERIFIER_DETECTED_VIOLATION,
  1244. PCI_VERIFIER_PMCSR_TIMEOUT,
  1245. verifierData->FailureClass,
  1246. &verifierData->Flags,
  1247. verifierData->FailureText,
  1248. "%DevObj%Ulong",
  1249. PdoExtension->PhysicalDeviceObject,
  1250. PowerState-1
  1251. );
  1252. return status;
  1253. }
  1254. NTSTATUS
  1255. PciSetPowerManagedDevicePowerState(
  1256. IN PPCI_PDO_EXTENSION PdoExtension,
  1257. IN DEVICE_POWER_STATE DeviceState,
  1258. IN BOOLEAN RefreshConfigSpace
  1259. )
  1260. /*++
  1261. Routine Description:
  1262. If the PCI device supports the PCI Power Management extensions,
  1263. set the device to the desired state. Otherwise, this routine
  1264. does (can do) nothing.
  1265. Arguments:
  1266. PdoExtension Pointer to the PDO device extension for the device
  1267. being programmed. The current power state stored
  1268. in the extension is *not* updated by this function.
  1269. DeviceState Power state the device is to be set to.
  1270. Return Value:
  1271. None.
  1272. --*/
  1273. {
  1274. PCI_PM_CAPABILITY pmCap;
  1275. UCHAR pmCapPtr = 0;
  1276. NTSTATUS status = STATUS_SUCCESS;
  1277. //
  1278. // If we are standing by then we want to power down the video to preseve the batteries,
  1279. // we have already (in PdoPdoSetPoweState) decided to leave the video on for the hibernate
  1280. // and shutdown cases.
  1281. //
  1282. if ((!PciCanDisableDecodes(PdoExtension, NULL, 0, PCI_CAN_DISABLE_VIDEO_DECODES)) &&
  1283. (DeviceState != PowerDeviceD0)) {
  1284. //
  1285. // Here is a device we unfortunately can't turn off. We do not however
  1286. // convert this to D0 - the virtual state of the device will represent
  1287. // a powered down device, and only when a real D0 is requested will we
  1288. // restore all the various state.
  1289. //
  1290. return STATUS_SUCCESS;
  1291. }
  1292. if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS) ) {
  1293. pmCapPtr = PciReadDeviceCapability(
  1294. PdoExtension,
  1295. PdoExtension->CapabilitiesPtr,
  1296. PCI_CAPABILITY_ID_POWER_MANAGEMENT,
  1297. &pmCap,
  1298. sizeof(pmCap)
  1299. );
  1300. if (pmCapPtr == 0) {
  1301. //
  1302. // We don't have a power management capability - how did we get here?
  1303. //
  1304. ASSERT(pmCapPtr);
  1305. return STATUS_INVALID_DEVICE_REQUEST;
  1306. }
  1307. //
  1308. // Set the device into its new D state
  1309. //
  1310. switch (DeviceState) {
  1311. case PowerDeviceD0:
  1312. pmCap.PMCSR.ControlStatus.PowerState = 0;
  1313. //
  1314. // PCI Power Management Specification. Table-7. Page 25
  1315. //
  1316. if (pmCap.PMC.Capabilities.Support.PMED3Cold) {
  1317. pmCap.PMCSR.ControlStatus.PMEStatus = 1;
  1318. }
  1319. break;
  1320. case PowerDeviceUnspecified:
  1321. ASSERT( DeviceState != PowerDeviceUnspecified);
  1322. pmCapPtr = 0;
  1323. break;
  1324. default:
  1325. pmCap.PMCSR.ControlStatus.PowerState = (DeviceState - 1);
  1326. break;
  1327. }
  1328. if (pmCapPtr) {
  1329. PciWriteDeviceConfig(
  1330. PdoExtension,
  1331. &pmCap.PMCSR.ControlStatus,
  1332. pmCapPtr + FIELD_OFFSET(PCI_PM_CAPABILITY,PMCSR.ControlStatus),
  1333. sizeof(pmCap.PMCSR.ControlStatus)
  1334. );
  1335. } else {
  1336. //
  1337. // Debug only. ControlFlags should have been set so this
  1338. // can't happen.
  1339. //
  1340. ASSERT(pmCapPtr);
  1341. }
  1342. //
  1343. // Stall for the appropriate time
  1344. //
  1345. status = PciStallForPowerChange(PdoExtension, DeviceState, pmCapPtr);
  1346. }
  1347. //
  1348. // Only update the config space if:
  1349. // - The device is happy and in the correct power state
  1350. // - We have been asked to refresh the config space
  1351. // - We have powered up the device
  1352. //
  1353. if (NT_SUCCESS(status)
  1354. && RefreshConfigSpace
  1355. && DeviceState < PdoExtension->PowerState.CurrentDeviceState) {
  1356. status = PciSetResources(PdoExtension, TRUE, FALSE);
  1357. }
  1358. return status;
  1359. }