1 /*++
2 Copyright (c) Microsoft. All rights reserved.
3
4 Module Name:
5
6 DevicePwrReq.cpp
7
8 Abstract:
9
10 This module implements the device power requirement logic in the framework.
11
12 --*/
13
14 #include "pnppriv.hpp"
15
16 extern "C" {
17 #if defined(EVENT_TRACING)
18 #include "DevicePwrReqStateMachine.tmh"
19 #endif
20 }
21
22 const FxDevicePwrRequirementTargetState
23 FxDevicePwrRequirementMachine::m_UnregisteredStates[] =
24 {
25 {DprEventRegisteredWithPox, DprDevicePowerRequiredD0 DEBUGGED_EVENT}
26 };
27
28 const FxDevicePwrRequirementTargetState
29 FxDevicePwrRequirementMachine::m_DevicePowerRequiredD0States[] =
30 {
31 {DprEventPoxDoesNotRequirePower, DprDevicePowerNotRequiredD0 DEBUGGED_EVENT},
32 {DprEventUnregisteredWithPox, DprUnregistered DEBUGGED_EVENT},
33 {DprEventDeviceReturnedToD0, DprDevicePowerRequiredD0 DEBUGGED_EVENT}
34 };
35
36 const FxDevicePwrRequirementTargetState
37 FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredD0States[] =
38 {
39 {DprEventDeviceGoingToDx, DprDevicePowerNotRequiredDx DEBUGGED_EVENT},
40 {DprEventPoxRequiresPower, DprReportingDevicePowerAvailable DEBUGGED_EVENT},
41 {DprEventUnregisteredWithPox, DprUnregistered TRAP_ON_EVENT}
42 };
43
44 const FxDevicePwrRequirementTargetState
45 FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredDxStates[] =
46 {
47 {DprEventDeviceReturnedToD0, DprWaitingForDevicePowerRequiredD0 DEBUGGED_EVENT},
48 {DprEventPoxRequiresPower, DprDevicePowerRequiredDx DEBUGGED_EVENT}
49 };
50
51 const FxDevicePwrRequirementTargetState
52 FxDevicePwrRequirementMachine::m_DevicePowerRequiredDxStates[] =
53 {
54 {DprEventDeviceReturnedToD0, DprReportingDevicePowerAvailable DEBUGGED_EVENT}
55 };
56
57 const FxDevicePwrRequirementTargetState
58 FxDevicePwrRequirementMachine::m_WaitingForDevicePowerRequiredD0States[] =
59 {
60 {DprEventPoxRequiresPower, DprReportingDevicePowerAvailable DEBUGGED_EVENT},
61 {DprEventDeviceReturnedToD0, DprWaitingForDevicePowerRequiredD0 TRAP_ON_EVENT},
62 {DprEventUnregisteredWithPox, DprUnregistered DEBUGGED_EVENT},
63 };
64
65 const FxDevicePwrRequirementStateTable
66 FxDevicePwrRequirementMachine::m_StateTable[] =
67 {
68 // DprUnregistered
69 { NULL,
70 FxDevicePwrRequirementMachine::m_UnregisteredStates,
71 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_UnregisteredStates),
72 },
73
74 // DprDevicePowerRequiredD0
75 { NULL,
76 FxDevicePwrRequirementMachine::m_DevicePowerRequiredD0States,
77 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerRequiredD0States),
78 },
79
80 // DprDevicePowerNotRequiredD0
81 { FxDevicePwrRequirementMachine::PowerNotRequiredD0,
82 FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredD0States,
83 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredD0States),
84 },
85
86 // DprDevicePowerNotRequiredDx
87 { NULL,
88 FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredDxStates,
89 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredDxStates),
90 },
91
92 // DprDevicePowerRequiredDx
93 { FxDevicePwrRequirementMachine::PowerRequiredDx,
94 FxDevicePwrRequirementMachine::m_DevicePowerRequiredDxStates,
95 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerRequiredDxStates),
96 },
97
98 // DprReportingDevicePowerAvailable
99 { FxDevicePwrRequirementMachine::ReportingDevicePowerAvailable,
100 NULL,
101 0,
102 },
103
104 // DprWaitingForDevicePowerRequiredD0
105 { NULL,
106 FxDevicePwrRequirementMachine::m_WaitingForDevicePowerRequiredD0States,
107 ARRAY_SIZE(FxDevicePwrRequirementMachine::m_WaitingForDevicePowerRequiredD0States),
108 },
109 };
110
FxDevicePwrRequirementMachine(__in FxPoxInterface * PoxInterface)111 FxDevicePwrRequirementMachine::FxDevicePwrRequirementMachine(
112 __in FxPoxInterface * PoxInterface
113 ) : FxThreadedEventQueue(FxDevicePwrRequirementEventQueueDepth)
114 {
115 //
116 // Make sure we can fit the state into a byte
117 //
118 C_ASSERT(DprMax <= 0xFF);
119
120 m_CurrentState = DprUnregistered;
121
122 RtlZeroMemory(&m_Queue, sizeof(m_Queue));
123 RtlZeroMemory(&m_States, sizeof(m_States));
124
125 //
126 // Store the initial state in the state history array
127 //
128 m_States.History[IncrementHistoryIndex()] = m_CurrentState;
129 m_PoxInterface = PoxInterface;
130 }
131
132 VOID
ProcessEvent(__in FxDevicePwrRequirementEvents Event)133 FxDevicePwrRequirementMachine::ProcessEvent(
134 __in FxDevicePwrRequirementEvents Event
135 )
136 {
137 NTSTATUS status;
138 KIRQL irql;
139 LONGLONG timeout = 0;
140
141 //
142 // Acquire state machine *queue* lock, raising to DISPATCH_LEVEL
143 //
144 Lock(&irql);
145
146 if (IsFull()) {
147 //
148 // The queue is full. This should never happen.
149 //
150 Unlock(irql);
151
152 ASSERTMSG("The device power requirement state machine queue is full\n",
153 FALSE);
154 return;
155 }
156
157 if (IsClosedLocked()) {
158 //
159 // The queue is closed. This should never happen.
160 //
161 DoTraceLevelMessage(
162 m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
163 "WDFDEVICE 0x%p !devobj 0x%p current device power requirement state"
164 " %!FxDevicePwrRequirementStates! dropping event "
165 "%!FxDevicePwrRequirementEvents! because of a closed queue",
166 m_PoxInterface->m_PkgPnp->GetDevice()->GetHandle(),
167 m_PoxInterface->m_PkgPnp->GetDevice()->GetDeviceObject(),
168 m_CurrentState,
169 Event);
170
171 Unlock(irql);
172
173 ASSERTMSG(
174 "The device power requirement state machine queue is closed\n",
175 FALSE
176 );
177 return;
178 }
179
180 //
181 // Enqueue the event
182 //
183 m_Queue[InsertAtTail()] = Event;
184
185 //
186 // Drop the state machine *queue* lock
187 //
188 Unlock(irql);
189
190 //
191 // Now, if we are running at PASSIVE_LEVEL, attempt to run the state machine
192 // on this thread. If we can't do that, then queue a work item.
193 //
194 if (irql == PASSIVE_LEVEL) {
195 //
196 // Try to acquire the state machine lock
197 //
198 status = m_StateMachineLock.AcquireLock(
199 m_PoxInterface->m_PkgPnp->GetDriverGlobals(),
200 &timeout
201 );
202 if (FxWaitLockInternal::IsLockAcquired(status)) {
203 FxPostProcessInfo info;
204
205 //
206 // We now hold the state machine lock. So call the function that
207 // dispatches the next state.
208 //
209 ProcessEventInner(&info);
210
211 //
212 // The pnp state machine should be the only one deleting the object
213 //
214 ASSERT(info.m_DeleteObject == FALSE);
215
216 //
217 // Release the state machine lock
218 //
219 m_StateMachineLock.ReleaseLock(
220 m_PoxInterface->m_PkgPnp->GetDriverGlobals()
221 );
222
223 info.Evaluate(m_PkgPnp);
224
225 return;
226 }
227 }
228
229 //
230 // For one reason or another, we couldn't run the state machine on this
231 // thread. So queue a work item to do it.
232 //
233 QueueToThread();
234 return;
235 }
236
237 VOID
_ProcessEventInner(__inout FxPkgPnp * PkgPnp,__inout FxPostProcessInfo * Info,__in PVOID WorkerContext)238 FxDevicePwrRequirementMachine::_ProcessEventInner(
239 __inout FxPkgPnp* PkgPnp,
240 __inout FxPostProcessInfo* Info,
241 __in PVOID WorkerContext
242 )
243 {
244 FxDevicePwrRequirementMachine * pThis = NULL;
245
246 UNREFERENCED_PARAMETER(WorkerContext);
247
248 pThis = PkgPnp->m_PowerPolicyMachine.m_Owner->
249 m_PoxInterface.m_DevicePowerRequirementMachine;
250
251 //
252 // Take the state machine lock.
253 //
254 pThis->m_StateMachineLock.AcquireLock(
255 pThis->m_PoxInterface->m_PkgPnp->GetDriverGlobals()
256 );
257
258 //
259 // Call the function that will actually run the state machine.
260 //
261 pThis->ProcessEventInner(Info);
262
263 //
264 // We are being called from the work item and m_WorkItemRunning is > 0, so
265 // we cannot be deleted yet.
266 //
267 ASSERT(Info->SomethingToDo() == FALSE);
268
269 //
270 // Now release the state machine lock
271 //
272 pThis->m_StateMachineLock.ReleaseLock(
273 pThis->m_PoxInterface->m_PkgPnp->GetDriverGlobals()
274 );
275
276 return;
277 }
278
279 VOID
ProcessEventInner(__inout FxPostProcessInfo * Info)280 FxDevicePwrRequirementMachine::ProcessEventInner(
281 __inout FxPostProcessInfo* Info
282 )
283 {
284 KIRQL irql;
285 FxDevicePwrRequirementEvents event;
286 const FxDevicePwrRequirementStateTable* entry;
287 FxDevicePwrRequirementStates newState;
288
289 //
290 // Process as many events as we can
291 //
292 for ( ; ; ) {
293 //
294 // Acquire state machine *queue* lock
295 //
296 Lock(&irql);
297
298 if (IsEmpty()) {
299 //
300 // The queue is empty.
301 //
302 GetFinishedState(Info);
303 Unlock(irql);
304 return;
305 }
306
307 //
308 // Get the event from the queue
309 //
310 event = m_Queue[GetHead()];
311 IncrementHead();
312
313 //
314 // Drop the state machine *queue* lock
315 //
316 Unlock(irql);
317
318 //
319 // Get the state table entry for the current state
320 //
321 // NOTE: Prefast complains about buffer overflow if (m_CurrentState ==
322 // DprMax), but that should never happen because DprMax is not a real
323 // state. We just use it to represent the maximum value in the enum that
324 // defines the states.
325 //
326 __analysis_assume(m_CurrentState < DprMax);
327 entry = &m_StateTable[m_CurrentState - DprUnregistered];
328
329 //
330 // Based on the event received, figure out the next state
331 //
332 newState = DprMax;
333 for (ULONG i = 0; i < entry->TargetStatesCount; i++) {
334 if (entry->TargetStates[i].DprEvent == event) {
335 DO_EVENT_TRAP(&entry->TargetStates[i]);
336 newState = entry->TargetStates[i].DprState;
337 break;
338 }
339 }
340
341 if (newState == DprMax) {
342 //
343 // Unexpected event for this state
344 //
345 DoTraceLevelMessage(
346 m_PoxInterface->PkgPnp()->GetDriverGlobals(),
347 TRACE_LEVEL_INFORMATION,
348 TRACINGPNP,
349 "WDFDEVICE 0x%p !devobj 0x%p device power requirement state "
350 "%!FxDevicePwrRequirementStates! dropping event "
351 "%!FxDevicePwrRequirementEvents!",
352 m_PoxInterface->PkgPnp()->GetDevice()->GetHandle(),
353 m_PoxInterface->PkgPnp()->GetDevice()->GetDeviceObject(),
354 m_CurrentState,
355 event
356 );
357
358 COVERAGE_TRAP();
359 }
360
361 while (newState != DprMax) {
362 DoTraceLevelMessage(
363 m_PoxInterface->PkgPnp()->GetDriverGlobals(),
364 TRACE_LEVEL_INFORMATION,
365 TRACINGPNPPOWERSTATES,
366 "WDFDEVICE 0x%p !devobj 0x%p entering device power requirement "
367 "state %!FxDevicePwrRequirementStates! from "
368 "%!FxDevicePwrRequirementStates!",
369 m_PoxInterface->PkgPnp()->GetDevice()->GetHandle(),
370 m_PoxInterface->PkgPnp()->GetDevice()->GetDeviceObject(),
371 newState,
372 m_CurrentState
373 );
374
375 //
376 // Update the state history array
377 //
378 m_States.History[IncrementHistoryIndex()] = (UCHAR) newState;
379
380 //
381 // Move to the new state
382 //
383 m_CurrentState = (BYTE) newState;
384 entry = &m_StateTable[m_CurrentState-DprUnregistered];
385
386 //
387 // Invoke the state entry function (if present) for the new state
388 //
389 if (entry->StateFunc != NULL) {
390 newState = entry->StateFunc(this);
391 }
392 else {
393 newState = DprMax;
394 }
395 }
396 }
397
398 return;
399 }
400
401 FxDevicePwrRequirementStates
PowerNotRequiredD0(__in FxDevicePwrRequirementMachine * This)402 FxDevicePwrRequirementMachine::PowerNotRequiredD0(
403 __in FxDevicePwrRequirementMachine* This
404 )
405 {
406 This->m_PoxInterface->PkgPnp()->PowerPolicyProcessEvent(
407 PwrPolDevicePowerNotRequired
408 );
409 return DprMax;
410 }
411
412 FxDevicePwrRequirementStates
PowerRequiredDx(__in FxDevicePwrRequirementMachine * This)413 FxDevicePwrRequirementMachine::PowerRequiredDx(
414 __in FxDevicePwrRequirementMachine* This
415 )
416 {
417 This->m_PoxInterface->PkgPnp()->PowerPolicyProcessEvent(
418 PwrPolDevicePowerRequired
419 );
420 return DprMax;
421 }
422
423 FxDevicePwrRequirementStates
ReportingDevicePowerAvailable(__in FxDevicePwrRequirementMachine * This)424 FxDevicePwrRequirementMachine::ReportingDevicePowerAvailable(
425 __in FxDevicePwrRequirementMachine* This
426 )
427 {
428 This->m_PoxInterface->PoxReportDevicePoweredOn();
429 return DprDevicePowerRequiredD0;
430 }
431