Leaked source code of windows server 2003
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.

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