ReactOS 0.4.17-dev-1190-g4c812f4
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
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));
60
61 /* Save the current IRQL */
63
64 /* Pick the expected timeout for this transition */
66 (PdoExtension->PowerState.CurrentDeviceState -
68
69 /* PCI power states are one less than NT power states */
70 PciState = PowerState - 1;
71
72 /* The state status is stored in the PMCSR offset */
73 PmcsrOffset = CapOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR);
74
75 /* Try changing the power state up to 100 times */
76 TryCount = 100;
77 while (--TryCount)
78 {
79 /* Check if this state transition will take time */
80 if (TimeoutEntry > 0)
81 {
82 /* Check if this is happening at high IRQL */
83 if (Irql >= DISPATCH_LEVEL)
84 {
85 /* Can't wait at high IRQL, stall the processor */
86 KeStallExecutionProcessor(TimeoutEntry);
87 }
88 else
89 {
90 /* Do a wait for the timeout specified instead */
91 Interval.QuadPart = -10 * TimeoutEntry;
92 Interval.QuadPart -= KeQueryTimeIncrement() - 1;
94 }
95 }
96
97 /* Read the PMCSR and see if the state has changed */
98 PciReadDeviceConfig(PdoExtension, &Pmcsr, PmcsrOffset, sizeof(PCI_PMCSR));
99 if (Pmcsr.PowerState == PciState) return STATUS_SUCCESS;
100
101 /* Try again, forcing a timeout of 1ms */
102 TimeoutEntry = 1000;
103 }
104
105 /* Call verifier with this error */
106 VerifierData = PciVerifierRetrieveFailureData(2);
107 ASSERT(VerifierData);
108 VfFailDeviceNode(PdoExtension->PhysicalDeviceObject,
109 PCI_VERIFIER_DETECTED_VIOLATION,
110 2, // The PMCSR register was not updated within the spec-mandated time.
111 VerifierData->FailureClass,
112 &VerifierData->AssertionControl,
113 VerifierData->DebuggerMessageText,
114 "%DevObj%Ulong",
115 PdoExtension->PhysicalDeviceObject,
116 PciState);
117
119}
120
122NTAPI
125 IN BOOLEAN IrpSet)
126{
128 PCI_PM_CAPABILITY PmCaps;
129 ULONG CapsOffset;
130
131 /* Assume success */
133
134 /* Check if this device can support low power states */
135 if (!(PciCanDisableDecodes(DeviceExtension, NULL, 0, TRUE)) &&
137 {
138 /* Simply return success, ignoring this request */
139 DPRINT1("PCIX - Cannot disable decodes on this device, ignoring PM request...\n");
140 return Status;
141 }
142
143 /* Does the device support power management at all? */
144 if (!(DeviceExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
145 {
146 /* Get the PM capabilities register */
147 CapsOffset = PciReadDeviceCapability(DeviceExtension,
148 DeviceExtension->CapabilitiesPtr,
150 &PmCaps.Header,
151 sizeof(PCI_PM_CAPABILITY));
152 ASSERT(CapsOffset);
154
155 /* Check if the device is being powered up */
157 {
158 /* Set full power state */
159 PmCaps.PMCSR.ControlStatus.PowerState = 0;
160
161 /* Check if the device supports Cold-D3 poweroff */
162 if (PmCaps.PMC.Capabilities.Support.PMED3Cold)
163 {
164 /* If there was a pending PME, clear it */
165 PmCaps.PMCSR.ControlStatus.PMEStatus = 1;
166 }
167 }
168 else
169 {
170 /* Otherwise, just set the new power state, converting from NT */
172 }
173
174 /* Write the new power state in the PMCSR */
175 PciWriteDeviceConfig(DeviceExtension,
176 &PmCaps.PMCSR,
177 CapsOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR),
178 sizeof(PCI_PMCSR));
179
180 /* Now wait for the change to "stick" based on the spec-mandated time */
181 Status = PciStallForPowerChange(DeviceExtension, DeviceState, CapsOffset);
182 if (!NT_SUCCESS(Status)) return Status;
183 }
184 else
185 {
186 /* Nothing to do! */
187 DPRINT1("PCIX - No PM on this device, ignoring request\n");
188 }
189
190 /* Check if new resources have to be assigned */
191 if (IrpSet)
192 {
193 /* Check if the new device state is lower (higher power) than now */
194 if (DeviceState < DeviceExtension->PowerState.CurrentDeviceState)
195 {
196 /* Leaving D3 may reset the function, so write its configuration again */
197 Status = PciSetResources(DeviceExtension, FALSE, FALSE);
198 }
199 }
200
201 /* Return the power state change status */
202 return Status;
203}
204
205static REQUEST_POWER_COMPLETE PciFdoDevicePowerCompletion;
206
215static
216VOID
217NTAPI
224{
225 PIRP SystemIrp = Context;
226
229 ASSERT(SystemIrp != NULL);
230
231 /* The system transition goes ahead even if the bus could not follow it */
232 if (!NT_SUCCESS(IoStatus->Status))
233 {
234 DPRINT1("PCIX - Bus failed to enter device state %lu (0x%08lx)\n",
235 PowerState.DeviceState,
236 IoStatus->Status);
237 }
238
239 PoStartNextPowerIrp(SystemIrp);
241}
242
243static IO_COMPLETION_ROUTINE PciFdoSystemPowerCompletion;
244
256static
258NTAPI
261 _In_ PIRP Irp,
262 _In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
263{
264 PPCI_FDO_EXTENSION DeviceExtension = Context;
268
270 ASSERT(DeviceExtension != NULL);
271
273 if (IoStackLocation->Parameters.Power.State.SystemState == PowerSystemWorking)
274 {
275 Target.DeviceState = PowerDeviceD0;
276 }
277 else
278 {
279 Target.DeviceState = PowerDeviceD3;
280 }
281
282 if ((NT_SUCCESS(Irp->IoStatus.Status)) &&
283 (DeviceExtension->PowerState.CurrentDeviceState != Target.DeviceState))
284 {
287 Target,
289 Irp,
290 NULL);
291 if (NT_SUCCESS(Status))
293
294 DPRINT1("PCIX - Could not request device state %lu (0x%08lx)\n",
295 Target.DeviceState,
296 Status);
297 }
298
301}
302
304NTAPI
307 IN PPCI_FDO_EXTENSION DeviceExtension)
308{
310
311 /* Arming the bus for its children's wake requests is not implemented yet */
312 DPRINT1("PCIX - Bus wake arming is not implemented, passing wait-wake down\n");
313 return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
314}
315
317NTAPI
320 IN PPCI_FDO_EXTENSION DeviceExtension)
321{
323
324 /* Bridge hardware is handled by the PDO below, so only the state is kept */
326 {
327 DeviceExtension->PowerState.CurrentDeviceState = State.DeviceState;
328 return STATUS_SUCCESS;
329 }
330
331 DeviceExtension->PowerState.CurrentSystemState = State.SystemState;
332 if (DeviceExtension->DeviceState != PciStarted)
333 return STATUS_SUCCESS;
334
335 /* The bus owns its power policy and follows up with a device state request */
336 Irp->IoStatus.Status = STATUS_SUCCESS;
341 DeviceExtension,
342 TRUE,
343 TRUE,
344 TRUE);
345 PoCallDriver(DeviceExtension->AttachedDeviceObject, Irp);
346 return STATUS_PENDING;
347}
348
350NTAPI
353 IN PPCI_FDO_EXTENSION DeviceExtension)
354{
357 UNREFERENCED_PARAMETER(DeviceExtension);
358
359 /* Refusing states that would break an armed wake is not implemented yet */
360 DPRINT1("PCIX - Wake-aware power queries are not implemented, accepting the state\n");
361 return STATUS_SUCCESS;
362}
363
364/* EOF */
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
_Out_ PKIRQL Irql
Definition: csq.h:179
_Check_return_ _In_ ULONG _In_ DEVICE_POWER_STATE DevicePowerState
Definition: dispmprt.h:1274
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
NTSTATUS NTAPI PciPassIrpFromFdoToPdo(IN PPCI_FDO_EXTENSION DeviceExtension, IN PIRP Irp)
Definition: dispatch.c:70
NTSTATUS NTAPI PciSetResources(IN PPCI_PDO_EXTENSION PdoExtension, IN BOOLEAN DoReset, IN BOOLEAN SomethingSomethingDarkSide)
Definition: enum.c:2490
VOID NTAPI PciWriteDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length)
Definition: config.c:133
@ PciStarted
Definition: pci.h:169
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:958
PPCI_VERIFIER_DATA NTAPI PciVerifierRetrieveFailureData(IN ULONG FailureCode)
Definition: pcivrify.c:60
BOOLEAN NTAPI PciCanDisableDecodes(IN PPCI_PDO_EXTENSION DeviceExtension, IN PPCI_COMMON_HEADER Config, IN ULONGLONG HackFlags, IN BOOLEAN ForPowerDown)
Definition: utils.c:1027
VOID NTAPI PciReadDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length)
Definition: config.c:149
static REQUEST_POWER_COMPLETE PciFdoDevicePowerCompletion
Definition: power.c:205
NTSTATUS NTAPI PciFdoWaitWake(IN PIRP Irp, IN PIO_STACK_LOCATION IoStackLocation, IN PPCI_FDO_EXTENSION DeviceExtension)
Definition: power.c:305
NTSTATUS NTAPI PciFdoSetPowerState(IN PIRP Irp, IN PIO_STACK_LOCATION IoStackLocation, IN PPCI_FDO_EXTENSION DeviceExtension)
Definition: power.c:318
ULONG PciPowerDelayTable[PowerDeviceD3 *PowerDeviceD3]
Definition: power.c:18
NTSTATUS NTAPI PciStallForPowerChange(IN PPCI_PDO_EXTENSION PdoExtension, IN DEVICE_POWER_STATE PowerState, IN ULONG_PTR CapOffset)
Definition: power.c:45
NTSTATUS NTAPI PciSetPowerManagedDevicePowerState(IN PPCI_PDO_EXTENSION DeviceExtension, IN DEVICE_POWER_STATE DeviceState, IN BOOLEAN IrpSet)
Definition: power.c:123
NTSTATUS NTAPI PciFdoIrpQueryPower(IN PIRP Irp, IN PIO_STACK_LOCATION IoStackLocation, IN PPCI_FDO_EXTENSION DeviceExtension)
Definition: power.c:351
static IO_COMPLETION_ROUTINE PciFdoSystemPowerCompletion
Definition: power.c:243
@ PdoExtension
Definition: precomp.h:61
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define KeDelayExecutionThread(mode, foo, t)
Definition: env_spec_w32.h:484
Status
Definition: gdiplustypes.h:24
IoMarkIrpPending(Irp)
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:490
_In_ PIRP Irp
Definition: kse.h:79
_In_ PIRP _In_ PIO_COMPLETION_ROUTINE _In_ PVOID Context
Definition: kse.h:81
#define ASSERT(a)
Definition: mode.c:44
#define KeStallExecutionProcessor(MicroSeconds)
Definition: precomp.h:27
__in UCHAR __in POWER_STATE __in_opt PVOID __in PIO_STATUS_BLOCK IoStatus
Definition: mxum.h:159
#define KernelMode
Definition: asm.h:38
DWORD Interval
Definition: netstat.c:28
#define _In_reads_opt_(s)
Definition: no_sal2.h:222
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
#define IoCopyCurrentIrpStackLocationToNext(Irp)
Definition: ntifs_ex.h:413
#define IoCompleteRequest
Definition: irp.c:1272
ULONG NTAPI KeQueryTimeIncrement(VOID)
Definition: clock.c:151
VOID NTAPI PoStartNextPowerIrp(IN PIRP Irp)
Definition: power.c:758
NTSTATUS NTAPI PoRequestPowerIrp(_In_ PDEVICE_OBJECT DeviceObject, _In_ UCHAR MinorFunction, _In_ POWER_STATE PowerState, _In_opt_ PREQUEST_POWER_COMPLETE CompletionFunction, _In_opt_ __drv_aliasesMem PVOID Context, _Outptr_opt_ PIRP *pIrp)
Definition: power.c:659
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
@ PowerSystemWorking
Definition: ntpoapi.h:36
@ PowerDeviceUnspecified
Definition: ntpoapi.h:48
@ PowerDeviceD0
Definition: ntpoapi.h:49
@ PowerDeviceD3
Definition: ntpoapi.h:52
enum _DEVICE_POWER_STATE DEVICE_POWER_STATE
#define STATUS_DEVICE_PROTOCOL_ERROR
Definition: ntstatus.h:717
#define PCI_HACK_NO_PM_CAPS
Definition: pci.h:40
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
#define STATUS_SUCCESS
Definition: shellext.h:65
union _IO_STACK_LOCATION::@1814 Parameters
struct _IO_STACK_LOCATION::@5020::@5056 Power
PDEVICE_OBJECT FunctionalDeviceObject
Definition: pci.h:250
PCI_POWER_STATE PowerState
Definition: pci.h:267
USHORT PowerState
Definition: iotypes.h:3704
USHORT PMEStatus
Definition: iotypes.h:3709
struct _PCI_PMC::_PM_SUPPORT Support
PCI_CAPABILITIES_HEADER Header
Definition: iotypes.h:3719
PCI_PMCSR ControlStatus
Definition: iotypes.h:3725
union _PCI_PM_CAPABILITY::@5067 PMCSR
PCI_PMC Capabilities
Definition: iotypes.h:3721
union _PCI_PM_CAPABILITY::@5066 PMC
DEVICE_POWER_STATE CurrentDeviceState
Definition: pci.h:218
VF_FAILURE_CLASS FailureClass
Definition: pci.h:481
PCHAR DebuggerMessageText
Definition: pci.h:483
ULONG AssertionControl
Definition: pci.h:482
#define STATUS_PENDING
Definition: telnetd.h:14
unsigned char UCHAR
Definition: typedefs.h:53
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
_In_ PIO_STACK_LOCATION IoStackLocation
Definition: usbdlib.h:292
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2061
_In_ WDFDEVICE _Out_ PWDF_DEVICE_STATE DeviceState
Definition: wdfdevice.h:2005
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_ WDF_DEVICE_POWER_STATE PowerState
Definition: wdfdevice.h:3040
_In_ UCHAR _In_ UCHAR MinorFunction
Definition: wdfdevice.h:1705
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
#define STATUS_CONTINUE_COMPLETION
#define IO_NO_INCREMENT
Definition: iotypes.h:598
#define IRP_MN_SET_POWER
#define PCI_CAPABILITY_ID_POWER_MANAGEMENT
Definition: iotypes.h:3662