ReactOS  0.4.13-dev-100-gc8611ae
power.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS PCI Bus Driver
3  * LICENSE: BSD - See COPYING.ARM in the top level directory
4  * FILE: drivers/bus/pci/power.c
5  * PURPOSE: Bus/Device Power Management
6  * PROGRAMMERS: ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <pci.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
19 {
20  0, // D0 -> D0
21  0, // D1 -> D0
22  200, // D2 -> D0
23  10000, // D3 -> D0
24 
25  0, // D0 -> D1
26  0, // D1 -> D1
27  200, // D2 -> D1
28  10000, // D3 -> D1
29 
30  200, // D0 -> D2
31  200, // D1 -> D2
32  0, // D2 -> D2
33  10000, // D3 -> D2
34 
35  10000, // D0 -> D3
36  10000, // D1 -> D3
37  10000, // D2 -> D3
38  0 // D3 -> D3
39 };
40 
41 /* FUNCTIONS ******************************************************************/
42 
44 NTAPI
47  IN ULONG_PTR CapOffset)
48 {
49  ULONG PciState, TimeoutEntry, PmcsrOffset, TryCount;
50  PPCI_VERIFIER_DATA VerifierData;
52  PCI_PMCSR Pmcsr;
53  KIRQL Irql;
54 
55  /* Make sure the power state is valid, and the device can support it */
56  ASSERT((PdoExtension->PowerState.CurrentDeviceState >= PowerDeviceD0) &&
57  (PdoExtension->PowerState.CurrentDeviceState <= PowerDeviceD3));
59  ASSERT(!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS));
60 
61  /* Save the current IRQL */
63 
64  /* Pick the expected timeout for this transition */
65  TimeoutEntry = PciPowerDelayTable[PowerState * PdoExtension->PowerState.CurrentDeviceState];
66 
67  /* PCI power states are one less than NT power states */
68  PciState = PowerState - 1;
69 
70  /* The state status is stored in the PMCSR offset */
71  PmcsrOffset = CapOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR);
72 
73  /* Try changing the power state up to 100 times */
74  TryCount = 100;
75  while (--TryCount)
76  {
77  /* Check if this state transition will take time */
78  if (TimeoutEntry > 0)
79  {
80  /* Check if this is happening at high IRQL */
81  if (Irql >= DISPATCH_LEVEL)
82  {
83  /* Can't wait at high IRQL, stall the processor */
84  KeStallExecutionProcessor(TimeoutEntry);
85  }
86  else
87  {
88  /* Do a wait for the timeout specified instead */
89  Interval.QuadPart = -10 * TimeoutEntry;
90  Interval.QuadPart -= KeQueryTimeIncrement() - 1;
92  }
93  }
94 
95  /* Read the PMCSR and see if the state has changed */
96  PciReadDeviceConfig(PdoExtension, &Pmcsr, PmcsrOffset, sizeof(PCI_PMCSR));
97  if (Pmcsr.PowerState == PciState) return STATUS_SUCCESS;
98 
99  /* Try again, forcing a timeout of 1ms */
100  TimeoutEntry = 1000;
101  }
102 
103  /* Call verifier with this error */
104  VerifierData = PciVerifierRetrieveFailureData(2);
105  ASSERT(VerifierData);
106  VfFailDeviceNode(PdoExtension->PhysicalDeviceObject,
107  PCI_VERIFIER_DETECTED_VIOLATION,
108  2, // The PMCSR register was not updated within the spec-mandated time.
109  VerifierData->FailureClass,
110  &VerifierData->AssertionControl,
111  VerifierData->DebuggerMessageText,
112  "%DevObj%Ulong",
113  PdoExtension->PhysicalDeviceObject,
114  PciState);
115 
117 }
118 
119 NTSTATUS
120 NTAPI
122  IN DEVICE_POWER_STATE DeviceState,
123  IN BOOLEAN IrpSet)
124 {
126  PCI_PM_CAPABILITY PmCaps;
127  ULONG CapsOffset;
128 
129  /* Assume success */
131 
132  /* Check if this device can support low power states */
133  if (!(PciCanDisableDecodes(DeviceExtension, NULL, 0, TRUE)) &&
134  (DeviceState != PowerDeviceD0))
135  {
136  /* Simply return success, ignoring this request */
137  DPRINT1("Cannot disable decodes on this device, ignoring PM request...\n");
138  return Status;
139  }
140 
141  /* Does the device support power management at all? */
142  if (!(DeviceExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
143  {
144  /* Get the PM capabilities register */
145  CapsOffset = PciReadDeviceCapability(DeviceExtension,
146  DeviceExtension->CapabilitiesPtr,
148  &PmCaps.Header,
149  sizeof(PCI_PM_CAPABILITY));
150  ASSERT(CapsOffset);
151  ASSERT(DeviceState != PowerDeviceUnspecified);
152 
153  /* Check if the device is being powered up */
154  if (DeviceState == PowerDeviceD0)
155  {
156  /* Set full power state */
157  PmCaps.PMCSR.ControlStatus.PowerState = 0;
158 
159  /* Check if the device supports Cold-D3 poweroff */
160  if (PmCaps.PMC.Capabilities.Support.PMED3Cold)
161  {
162  /* If there was a pending PME, clear it */
163  PmCaps.PMCSR.ControlStatus.PMEStatus = 1;
164  }
165  }
166  else
167  {
168  /* Otherwise, just set the new power state, converting from NT */
169  PmCaps.PMCSR.ControlStatus.PowerState = DeviceState - 1;
170  }
171 
172  /* Write the new power state in the PMCSR */
173  PciWriteDeviceConfig(DeviceExtension,
174  &PmCaps.PMCSR,
175  CapsOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR),
176  sizeof(PCI_PMCSR));
177 
178  /* Now wait for the change to "stick" based on the spec-mandated time */
179  Status = PciStallForPowerChange(DeviceExtension, DeviceState, CapsOffset);
180  if (!NT_SUCCESS(Status)) return Status;
181  }
182  else
183  {
184  /* Nothing to do! */
185  DPRINT1("No PM on this device, ignoring request\n");
186  }
187 
188  /* Check if new resources have to be assigned */
189  if (IrpSet)
190  {
191  /* Check if the new device state is lower (higher power) than now */
192  if (DeviceState < DeviceExtension->PowerState.CurrentDeviceState)
193  {
194  /* We would normally re-assign resources after powerup */
197  }
198  }
199 
200  /* Return the power state change status */
201  return Status;
202 }
203 
204 NTSTATUS
205 NTAPI
207  IN PIO_STACK_LOCATION IoStackLocation,
208  IN PPCI_FDO_EXTENSION DeviceExtension)
209 {
211  UNREFERENCED_PARAMETER(IoStackLocation);
212  UNREFERENCED_PARAMETER(DeviceExtension);
213 
215  while (TRUE);
216  return STATUS_NOT_SUPPORTED;
217 }
218 
219 NTSTATUS
220 NTAPI
222  IN PIO_STACK_LOCATION IoStackLocation,
223  IN PPCI_FDO_EXTENSION DeviceExtension)
224 {
226  UNREFERENCED_PARAMETER(IoStackLocation);
227  UNREFERENCED_PARAMETER(DeviceExtension);
228 
230  while (TRUE);
231  return STATUS_NOT_SUPPORTED;
232 }
233 
234 NTSTATUS
235 NTAPI
237  IN PIO_STACK_LOCATION IoStackLocation,
238  IN PPCI_FDO_EXTENSION DeviceExtension)
239 {
241  UNREFERENCED_PARAMETER(IoStackLocation);
242  UNREFERENCED_PARAMETER(DeviceExtension);
243 
245  while (TRUE);
246  return STATUS_NOT_SUPPORTED;
247 }
248 
249 /* EOF */
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
PPCI_VERIFIER_DATA NTAPI PciVerifierRetrieveFailureData(IN ULONG FailureCode)
Definition: pcivrify.c:60
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
_In_ UCHAR _In_ POWER_STATE PowerState
Definition: pofuncs.h:42
UCHAR NTAPI PciReadDeviceCapability(IN PPCI_PDO_EXTENSION DeviceExtension, IN UCHAR Offset, IN ULONG CapabilityId, OUT PPCI_CAPABILITIES_HEADER Buffer, IN ULONG Length)
Definition: utils.c:886
union _PCI_PM_CAPABILITY::@3630 PMCSR
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:225
VOID __cdecl VfFailDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject, IN ULONG BugCheckMajorCode, IN ULONG BugCheckMinorCode, IN VF_FAILURE_CLASS FailureClass, IN OUT PULONG AssertionControl, IN PSTR DebuggerMessageText, IN PSTR ParameterFormatString,...)
Definition: driver.c:34
_In_ PIRP Irp
Definition: csq.h:116
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
struct _PCI_PMC::_PM_SUPPORT Support
USHORT PMEStatus
Definition: iotypes.h:3337
PCI_PMC Capabilities
Definition: iotypes.h:3349
LONG NTSTATUS
Definition: precomp.h:26
ULONG NTAPI KeQueryTimeIncrement(VOID)
Definition: clock.c:153
_Out_ PKIRQL Irql
Definition: csq.h:179
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define STATUS_DEVICE_PROTOCOL_ERROR
Definition: ntstatus.h:609
UCHAR KIRQL
Definition: env_spec_w32.h:591
VOID NTAPI PciWriteDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length)
Definition: config.c:91
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
NTSTATUS NTAPI KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Interval OPTIONAL)
Definition: wait.c:283
NTSTATUS NTAPI PciFdoIrpQueryPower(IN PIRP Irp, IN PIO_STACK_LOCATION IoStackLocation, IN PPCI_FDO_EXTENSION DeviceExtension)
Definition: power.c:236
#define PCI_CAPABILITY_ID_POWER_MANAGEMENT
Definition: iotypes.h:3290
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
NTSTATUS NTAPI PciFdoWaitWake(IN PIRP Irp, IN PIO_STACK_LOCATION IoStackLocation, IN PPCI_FDO_EXTENSION DeviceExtension)
Definition: power.c:206
BOOLEAN NTAPI PciCanDisableDecodes(IN PPCI_PDO_EXTENSION DeviceExtension, IN PPCI_COMMON_HEADER Config, IN ULONGLONG HackFlags, IN BOOLEAN ForPowerDown)
Definition: utils.c:955
DWORD Interval
Definition: netstat.c:30
enum _DEVICE_POWER_STATE DEVICE_POWER_STATE
NTSTATUS NTAPI PciFdoSetPowerState(IN PIRP Irp, IN PIO_STACK_LOCATION IoStackLocation, IN PPCI_FDO_EXTENSION DeviceExtension)
Definition: power.c:221
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
NTSTATUS NTAPI PciSetPowerManagedDevicePowerState(IN PPCI_PDO_EXTENSION DeviceExtension, IN DEVICE_POWER_STATE DeviceState, IN BOOLEAN IrpSet)
Definition: power.c:121
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
VF_FAILURE_CLASS FailureClass
Definition: pci.h:414
PCHAR DebuggerMessageText
Definition: pci.h:416
Status
Definition: gdiplustypes.h:24
union _PCI_PM_CAPABILITY::@3629 PMC
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
PCI_PMCSR ControlStatus
Definition: iotypes.h:3353
ULONG PciPowerDelayTable[PowerDeviceD3 *PowerDeviceD3]
Definition: power.c:18
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
USHORT PowerState
Definition: iotypes.h:3332
#define PCI_HACK_NO_PM_CAPS
Definition: pci.h:39
#define UNIMPLEMENTED_DBGBREAK(...)
Definition: debug.h:57
#define DPRINT1
Definition: precomp.h:8
VOID NTAPI PciReadDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length)
Definition: config.c:107
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:409
unsigned int ULONG
Definition: retypes.h:1
#define UNIMPLEMENTED
Definition: debug.h:114
NTSTATUS NTAPI PciStallForPowerChange(IN PPCI_PDO_EXTENSION PdoExtension, IN DEVICE_POWER_STATE PowerState, IN ULONG_PTR CapOffset)
Definition: power.c:45
ULONG AssertionControl
Definition: pci.h:415
return STATUS_SUCCESS
Definition: btrfs.c:2725
VOID NTAPI KeStallExecutionProcessor(IN ULONG MicroSeconds)
Definition: ntoskrnl.c:99
PCI_CAPABILITIES_HEADER Header
Definition: iotypes.h:3347