/********************************************************** NDIS5.X handler of power management ***********************************************************/ NDIS_STATUS ParaNdis_OnSetPower(PARANDIS_ADAPTER *pContext, tOidDesc *pOid) { NDIS_STATUS status; NDIS_DEVICE_POWER_STATE newState; DEBUG_ENTRY(0); status = ParaNdis_OidSetCopy(pOid, &newState, sizeof(newState)); if (status == NDIS_STATUS_SUCCESS) { tPowerWorkItem *pwi = ParaNdis_AllocateMemory(pContext, sizeof(tPowerWorkItem)); status = NDIS_STATUS_FAILURE; if (pwi) { pwi->pContext = pContext; pwi->state = newState; NdisInitializeWorkItem(&pwi->wi, OnSetPowerWorkItem, pwi); if (NdisScheduleWorkItem(&pwi->wi) == NDIS_STATUS_SUCCESS) { status = NDIS_STATUS_PENDING; } else NdisFreeMemory(pwi, 0, 0); } } return status; }
/************************************************************* Required NDIS procedure Called when some procedure (like OID handler) returns PENDING and does not complete or when CheckForHang return TRUE *************************************************************/ static NDIS_STATUS ParaNdis5_Reset( OUT PBOOLEAN AddressingReset, IN NDIS_HANDLE MiniportAdapterContext) { NDIS_STATUS status; tGeneralWorkItem *pwi; PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; DEBUG_ENTRY(0); ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 1, 0, 0); status = NDIS_STATUS_FAILURE; pwi = ParaNdis_AllocateMemory(pContext, sizeof(tGeneralWorkItem)); if (pwi) { pwi->pContext = pContext; NdisInitializeWorkItem(&pwi->wi, OnResetWorkItem, pwi); if (NdisScheduleWorkItem(&pwi->wi) == NDIS_STATUS_SUCCESS) { status = NDIS_STATUS_PENDING; } else { NdisFreeMemory(pwi, 0, 0); } } if (status != NDIS_STATUS_PENDING) { ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 0, status, 0); } return status; }
VOID NICFreeNotify( IN PNOTICB pNotiCB) /*++ Routine Description: pRCB - pointer to RCB block Arguments: This routine reinitializes the RCB block and puts it back into the RecvFreeList for reuse. Return Value: VOID --*/ { PMP_ADAPTER Adapter = pNotiCB->Adapter; DEBUGP(MP_TRACE, ("--> NICFreeNotify %p\n", pNotiCB)); ASSERT(pNotiCB->Irp); // shouldn't be NULL ASSERT(!pNotiCB->Ref); // should be 0 ASSERT(pNotiCB->Adapter); // shouldn't be NULL IoReuseIrp(pNotiCB->Irp, STATUS_SUCCESS); pNotiCB->ulSize=0; // // Set the MDL field to NULL so that we don't end up double freeing the // MDL in our call to IoFreeIrp. // pNotiCB->Irp->MdlAddress = NULL; // // Insert the RCB back in the Recv free list // NdisAcquireSpinLock(&Adapter->InterruptNotifyLock); RemoveEntryList(&pNotiCB->List); InsertTailList(&Adapter->InterruptFreeList, &pNotiCB->List); NdisInterlockedDecrement(&Adapter->nBusyNotify); ASSERT(Adapter->nBusyNotify >= 0); NdisReleaseSpinLock(&Adapter->InterruptNotifyLock); // // For performance, instead of scheduling a workitem at the end of // every read completion, we will do it only when the number of // outstanding IRPs goes below NIC_SEND_LOW_WATERMARK. // We shouldn't queue a workitem if it's already scheduled and waiting in // the system workitem queue to be fired. // if((Adapter->nBusyNotify ==0) && MP_TEST_FLAG(Adapter, fMP_POST_INTERRUPT)) { MP_INC_REF(Adapter); NdisScheduleWorkItem(&Adapter->InterruptNotifyItem); } DEBUGP(MP_TRACE, ("<-- NICFreeNotify %d\n", Adapter->nBusyNotify)); }
VOID NICFreeRCB( IN PRCB pRCB) /*++ Routine Description: pRCB - pointer to RCB block Arguments: This routine reinitializes the RCB block and puts it back into the RecvFreeList for reuse. Return Value: VOID --*/ { PMP_ADAPTER Adapter = pRCB->Adapter; ULONG ulSendLowW= NIC_SEND_LOW_WATERMARK; DEBUGP(MP_TRACE, ("--> NICFreeRCB %p\n", pRCB)); ASSERT(pRCB->Irp); // shouldn't be NULL ASSERT(!pRCB->Ref); // should be 0 ASSERT(pRCB->Adapter); // shouldn't be NULL IoReuseIrp(pRCB->Irp, STATUS_SUCCESS); pRCB->nextndeoffset=0; pRCB->nextndpoffset=0; pRCB->bIsOver=FALSE; pRCB->ulSize=0; // // Set the MDL field to NULL so that we don't end up double freeing the // MDL in our call to IoFreeIrp. // pRCB->Irp->MdlAddress = NULL; // // Re adjust the length to the originl size // //NdisAdjustBufferLength(pRCB->BufferArray[0], pRCB->ulBufferSize); // // Insert the RCB back in the Recv free list // NdisAcquireSpinLock(&Adapter->RecvLock); RemoveEntryList(&pRCB->List); InsertTailList(&Adapter->RecvFreeList, &pRCB->List); NdisInterlockedDecrement(&Adapter->nBusyRecv); ASSERT(Adapter->nBusyRecv >= 0); NdisReleaseSpinLock(&Adapter->RecvLock); // // For performance, instead of scheduling a workitem at the end of // every read completion, we will do it only when the number of // outstanding IRPs goes below NIC_SEND_LOW_WATERMARK. // We shouldn't queue a workitem if it's already scheduled and waiting in // the system workitem queue to be fired. // if((!ulSendLowW || Adapter->nBusyRecv <= NIC_SEND_LOW_WATERMARK) && MP_TEST_FLAG(Adapter, fMP_POST_READS) && (InterlockedExchange(&Adapter->IsReadWorkItemQueued, TRUE) == FALSE)) { Adapter->nReadWorkItemScheduled++; MP_INC_REF(Adapter); NdisScheduleWorkItem(&Adapter->ReadWorkItem); } DEBUGP(MP_TRACE, ("<-- NICFreeRCB %d\n", Adapter->nBusyRecv)); }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtWorkItemSchedule -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtWorkItemSchedule(DtWorkItem* pWorkItem, DtWorkItemArgs* pArgs) { DtStatus Result = DT_STATUS_OK; Int OldState; Bool DoRun = FALSE; Bool DoQueue = FALSE; DtWorkItemStruct WorkItemStruct; DT_ASSERT(pWorkItem->m_SchedulingEnabled); // Allocate workitem Result = DtWorkItemStructCreate(&WorkItemStruct, pWorkItem->m_pDevice); if (!DT_SUCCESS(Result)) return Result; // Try to set running from idle state OldState = DtAtomicCompareExchange((Int*)&pWorkItem->m_State, 0, WI_STATE_BIT_RUNNING); if (OldState == 0) // Successfully running DoRun = TRUE; else if (pWorkItem->m_QueueIfRunning) { // Try to set Queuing OldState = DtAtomicCompareExchange((Int*)&pWorkItem->m_State, WI_STATE_BIT_RUNNING, WI_STATE_BIT_RUNNING|WI_STATE_BIT_QUEUING); if (OldState == WI_STATE_BIT_RUNNING) // Successfully set to queuing DoQueue = TRUE; // Not running anymore? // Try to set running again to be sure a full execution of the worker is pending // after the call the DtDpcSchedule... else if ((OldState&WI_STATE_BIT_RUNNING) == 0) { // Retry to set running from idle state OldState = DtAtomicCompareExchange((Int*)&pWorkItem->m_State, 0, WI_STATE_BIT_RUNNING); if (OldState == 0) // Successfully set to running DoRun = TRUE; else Result = DT_STATUS_IN_USE; } else Result = DT_STATUS_IN_USE; } if (!DT_SUCCESS(Result)) { // Delete workitem DtWorkItemStructDelete(&WorkItemStruct); return Result; } // Queue WorkItem? if (DoQueue) { // Copy arguments pWorkItem->m_QueuedArgs = *pArgs; // Set to queued (running|queuing|queued) OldState = DtAtomicCompareExchange((Int*)&pWorkItem->m_State, WI_STATE_BIT_RUNNING|WI_STATE_BIT_QUEUING, WI_STATE_BIT_RUNNING|WI_STATE_BIT_QUEUING|WI_STATE_BIT_QUEUED); // Check if we failed because we were not running anymore if (OldState == WI_STATE_BIT_QUEUING) { // Choose running slot --> try to set from queuing to running instead of // queued OldState = DtAtomicCompareExchange((Int*)&pWorkItem->m_State, WI_STATE_BIT_QUEUING, WI_STATE_BIT_RUNNING); if (OldState == WI_STATE_BIT_QUEUING) DoRun = TRUE; else { Result = DT_STATUS_IN_USE; // Can not happen? DT_ASSERT(FALSE); } } } // Start initial WorkItem? if (DoRun) { pWorkItem->m_Args = *pArgs; DtWorkItemStructCopy(&pWorkItem->m_WorkStruct, &WorkItemStruct); #ifdef WINBUILD #ifdef USES_NDIS NdisInitializeWorkItem(&pWorkItem->m_WorkStruct.m_NdisWorkItem, DtWorkItemWorker, pWorkItem); NdisScheduleWorkItem(&pWorkItem->m_WorkStruct.m_NdisWorkItem); #else IoQueueWorkItem(pWorkItem->m_WorkStruct.m_pIoWorkItem, DtWorkItemWorker, DelayedWorkQueue, pWorkItem); #endif // USES_NDIS #else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) // INIT_WORK has been redefined in kernel version 2.6.20 (no 3rd context parameter) INIT_WORK(&pWorkItem->m_WorkStruct.m_Work, DtWorkItemWorker); #else INIT_WORK(&pWorkItem->m_WorkStruct.m_Work, DtWorkItemWorker, pWorkItem); #endif schedule_work(&pWorkItem->m_WorkStruct.m_Work); #endif // Running flag is already set... } else // We do not need the WorkItemStruct. DtWorkItemStructDelete(&WorkItemStruct); return Result; }