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 
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
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
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
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
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
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
424 FxDevicePwrRequirementMachine::ReportingDevicePowerAvailable(
425     __in FxDevicePwrRequirementMachine* This
426     )
427 {
428     This->m_PoxInterface->PoxReportDevicePoweredOn();
429     return DprDevicePowerRequiredD0;
430 }
431