VOID FxPkgIo::ResetStateForRestart( VOID ) /*++ Routine Description: This is called on a device which has been restarted from the removed state. It will reset purged queues so that they can accept new requests when ResumeProcessingForPower is called afterwards. Arguments: None Return Value: None --*/ { KIRQL irql; FxIoQueue* queue; SINGLE_LIST_ENTRY queueList, *ple; DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, "Restart queues from purged state for WDFDEVICE 0x%p due to " "device restart", m_Device->GetHandle()); queueList.Next = NULL; Lock(&irql); GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOn); Unlock(irql); for (ple = PopEntryList(&queueList); ple != NULL; ple = PopEntryList(&queueList)) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->ResetStateForRestart(); ple->Next = NULL; queue->RELEASE(IO_ITERATOR_POWER_TAG); } Lock(&irql); m_PowerStateOn = TRUE; m_QueuesAreShuttingDown = FALSE; Unlock(irql); return; }
_Must_inspect_result_ NTSTATUS FxPkgIo::FlushAllQueuesByFileObject( __in MdFileObject FileObject ) /*++ Routine Description: Enumerate all the queues and cancel the requests that have the same fileobject as the Cleanup IRP. We are making an assumption that cleanup irps are sent only at passive-level. Return Value: NTSTATUS --*/ { FxIoQueue* queue = NULL; PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); FxIoQueueNode flushBookmark(FxIoQueueNodeTypeBookmark); KIRQL irql; if(Mx::MxGetCurrentIrql() != PASSIVE_LEVEL) { DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "Currently framework allow flushing of queues " "by fileobject on cleanup only at PASSIVE_LEVEL"); FxVerifierDbgBreakPoint(pFxDriverGlobals); return STATUS_SUCCESS; } // // Iterate through the queue list and flush each one. // Lock(&irql); queue = GetFirstIoQueueLocked(&flushBookmark, IO_ITERATOR_FLUSH_TAG); Unlock(irql); while(queue != NULL) { queue->FlushByFileObject(FileObject); queue->RELEASE(IO_ITERATOR_FLUSH_TAG); Lock(&irql); queue = GetNextIoQueueLocked(&flushBookmark, IO_ITERATOR_FLUSH_TAG); Unlock(irql); } return STATUS_SUCCESS; }
_Must_inspect_result_ NTSTATUS FxPkgIo::ResumeProcessingForPower() /*++ Routine Description: Resumes all PowerManaged queues for automatic I/O processing due to a power event that allows I/O to resume. Non-PowerManaged queues are left alone. Arguments: Return Value: NTSTATUS --*/ { KIRQL irql; FxIoQueue* queue; SINGLE_LIST_ENTRY queueList, *ple; DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, "Power resume all queues of WDFDEVICE 0x%p", m_Device->GetHandle()); queueList.Next = NULL; Lock(&irql); GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOn); // // Change the state so that new queues created while we // are resuming the existing queues can be in a powered-on state. // m_PowerStateOn = TRUE; // // Change the accepting state so that new queues created while we // are resuming the existing queues can be accept request. // m_QueuesAreShuttingDown = FALSE; Unlock(irql); // // We will power-up the queues in two steps. First we will resume // the power of all the queues and then we will start dispatching I/Os. // This is to avoid a queue being powered up at the begining of the list // trying to forward a request to another queue lower in the list that's // not powered up yet. // for(ple = queueList.Next; ple != NULL; ple = ple->Next) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->ResumeProcessingForPower(); } for (ple = PopEntryList(&queueList); ple != NULL; ple = PopEntryList(&queueList)) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->StartPowerTransitionOn(); ple->Next = NULL; queue->RELEASE(IO_ITERATOR_POWER_TAG); } return STATUS_SUCCESS; }
_Must_inspect_result_ NTSTATUS FxPkgIo::StopProcessingForPower( __in FxIoStopProcessingForPowerAction Action ) /*++ Routine Description: Stops all PowerManaged queues automatic I/O processing due to a power event that requires I/O to stop. This is called on a PASSIVE_LEVEL thread that can block until I/O has been stopped, or completed/cancelled. Arguments: Action - FxIoStopProcessingForPowerHold: the function returns when the driver has acknowledged that it has stopped all I/O processing, but may have outstanding "in-flight" requests that have not been completed. FxIoStopProcessingForPowerPurgeManaged: the function returns when all requests from a power managed queue have been completed and/or cancelled., and there are no more in-flight requests. FxIoStopProcessingForPowerPurgeNonManaged: the function returns when all requests from a non-power managed queue have been completed and/or cancelled., and there are no more in-flight requests. Only called during device-remove. Return Value: NTSTATUS --*/ { KIRQL irql; FxIoQueue* queue; SINGLE_LIST_ENTRY queueList, *ple; DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, "Perform %!FxIoStopProcessingForPowerAction! for all queues of " "WDFDEVICE 0x%p", Action, m_Device->GetHandle()); queueList.Next = NULL; Lock(&irql); // // Device is moving into low power state. So any new queues // created after this point would start off as powered off. // m_PowerStateOn = FALSE; // // If queues are shutting down, any new queue created after // this point would not accept any requests. // switch(Action) { case FxIoStopProcessingForPowerPurgeManaged: case FxIoStopProcessingForPowerPurgeNonManaged: m_QueuesAreShuttingDown = TRUE; break; } GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOff); Unlock(irql); // // If the power action is hold then first change the state of all the queues // to PowerStartTransition. This will prevent the queues from dispatching // new requests before we start asking each queue to stop processing // inflight requests. // if(Action == FxIoStopProcessingForPowerHold) { // // Walk the list without popping entries because we need to scan // the list again. // for(ple = queueList.Next; ple != NULL; ple = ple->Next) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->StartPowerTransitionOff(); } } // // Ask the queues to stop processing inflight requests. // for (ple = PopEntryList(&queueList); ple != NULL; ple = PopEntryList(&queueList)) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->StopProcessingForPower(Action); ple->Next = NULL; queue->RELEASE(IO_ITERATOR_POWER_TAG); } return STATUS_SUCCESS; }