/*----------------------------------------------------------------------------- Routine Name: os_RequestSchedule Routine Description: Arguments: Return Value: TI_OK -----------------------------------------------------------------------------*/ int os_RequestSchedule (TI_HANDLE OsContext) { TWlanDrvIfObj *drv = (TWlanDrvIfObj *)OsContext; /* Note: The performance trace below doesn't inclose the schedule itself because the rescheduling * can occur immediately and call os_RequestSchedule again which will confuse the trace tools */ CL_TRACE_START_L3(); CL_TRACE_END_L3("tiwlan_drv.ko", "OS", "TASK", ""); if (!queue_work (drv->pWorkQueue, &drv->tWork)) { return TI_NOK; } return TI_OK; }
/* * \brief FW-Event state machine * * \param hFwEvent - FwEvent Driver handle * \return void * * \par Description * * Process the current FW events in a sequence that may progress in the same context, * or exit if pending an Async transaction, which will call back the SM when finished. * * \sa */ static void fwEvent_StateMachine (TfwEvent *pFwEvent) { ETxnStatus eStatus = TXN_STATUS_ERROR; /* Set to error to detect if used uninitialized */ CL_TRACE_START_L3(); /* * Loop through the states sequence as long as the process is synchronous. * Exit when finished or if an Asynchronous process is required. * In this case the SM will be called back upon Async operation completion. */ while (1) { switch (pFwEvent->eSmState) { /* IDLE: Update TwIf and read interrupt info from FW */ case FWEVENT_STATE_IDLE: { CL_TRACE_START_L5(); twIf_Awake(pFwEvent->hTwIf); eStatus = fwEvent_SmReadIntrInfo (pFwEvent); pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".ReadInfo"); break; } /* WAIT_INTR_INFO: We have the interrupt info so call the handlers accordingly */ case FWEVENT_STATE_WAIT_INTR_INFO: { CL_TRACE_START_L5(); eStatus = fwEvent_SmHandleEvents (pFwEvent); /* If state was changed to IDLE by recovery or stop process, exit (process terminated) */ if (pFwEvent->eSmState == FWEVENT_STATE_IDLE) { CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlEvents"); CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); return; } pFwEvent->eSmState = FWEVENT_STATE_WAIT_HANDLE_COMPLT; CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlEvents"); break; } /* WAIT_HANDLE_COMPLT: Current handling is completed. */ case FWEVENT_STATE_WAIT_HANDLE_COMPLT: { /* If pending interrupt, read interrupt info (back to WAIT_INTR_INFO state) */ if (pFwEvent->bIntrPending) { CL_TRACE_START_L5(); pFwEvent->bIntrPending = TI_FALSE; eStatus = fwEvent_SmReadIntrInfo (pFwEvent); pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlCmplt"); } /* Else - all done so release TwIf to sleep and exit */ else { twIf_Sleep(pFwEvent->hTwIf); pFwEvent->eSmState = FWEVENT_STATE_IDLE; TRACE3(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_StateMachine: Completed, NewState=%d, Status=%d, IntrPending=%d\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending); CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); /**** Finished all current events handling so exit ****/ return; } break; } } /* switch */ TRACE3(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_StateMachine: NewState=%d, Status=%d, IntrPending=%d\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending); /* If last status is Pending, exit the SM (to be called back upon Async operation completion) */ if (eStatus == TXN_STATUS_PENDING) { CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); return; } /* If error occured, stop the process and exit (should be cleaned by recovery process) */ else if (eStatus == TXN_STATUS_ERROR) { TRACE5(pFwEvent->hReport, REPORT_SEVERITY_ERROR, "fwEvent_StateMachine: NewState=%d, Status=%d, IntrPending=%d, EventVector=0x%x, EventMask=0x%x\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending, pFwEvent->uEventVector, pFwEvent->uEventMask); CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); fwEvent_Stop ((TI_HANDLE)pFwEvent); return; } /* If we got here the status is COMPLETE so continue in the while loop to the next state */ } /* while */ }
TI_STATUS txDataQ_InsertPacket (TI_HANDLE hTxDataQ, TTxCtrlBlk *pPktCtrlBlk, TI_UINT8 uPacketDtag) { TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; TEthernetHeader *pEthHead = (TEthernetHeader *)(pPktCtrlBlk->tTxnStruct.aBuf[0]); TI_STATUS eStatus; TI_UINT32 uQueId; TI_UINT32 uQueSize; txCtrl_t *pTxCtrl = (txCtrl_t *)(pTxDataQ->hTxCtrl); TI_BOOL bRequestSchedule = TI_FALSE; TI_BOOL bStopNetStack = TI_FALSE; CL_TRACE_START_L3(); /* If packet is EAPOL or from the generic Ethertype, forward it to the Mgmt-Queue and exit */ if ((HTOWLANS(pEthHead->type) == ETHERTYPE_EAPOL) || (HTOWLANS(pEthHead->type) == pTxCtrl->genericEthertype)) { pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_EAPOL; return txMgmtQ_Xmit (pTxDataQ->hTxMgmtQ, pPktCtrlBlk, TI_TRUE); /* Note: The last parameter indicates that we are running in external context */ } pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_ETHER; /* Enter critical section to protect classifier data and queue access */ context_EnterCriticalSection (pTxDataQ->hContext); /* Call the Classify function to set the TID field */ if (txDataClsfr_ClassifyTxPacket (hTxDataQ, pPktCtrlBlk, uPacketDtag) != TI_OK) { #ifdef TI_DBG pTxDataQ->uClsfrMismatchCount++; TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_WARNING, "txDataQueue_xmit: No matching classifier found \n"); #endif /* TI_DBG */ } /* Enqueue the packet in the appropriate Queue */ uQueId = aTidToQueueTable[pPktCtrlBlk->tTxDescriptor.tid]; eStatus = que_Enqueue (pTxDataQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); /* Get number of packets in current queue */ uQueSize = que_Size (pTxDataQ->aQueues[uQueId]); /* If the current queue is not stopped */ if (pTxDataQ->aQueueBusy[uQueId] == TI_FALSE) { /* If the queue has the desired number of packets, request switch to driver context for handling them */ if (uQueSize == pTxDataQ->aTxSendPaceThresh[uQueId]) { tmr_StopTimer (pTxDataQ->hTxSendPaceTimer); bRequestSchedule = TI_TRUE; } /* If below Tx-Send pacing threshold, start timer to trigger packets handling if expired */ else if (uQueSize < pTxDataQ->aTxSendPaceThresh[uQueId]) { tmr_StartTimer (pTxDataQ->hTxSendPaceTimer, txDataQ_TxSendPaceTimeout, hTxDataQ, TX_SEND_PACE_TIMEOUT_MSEC, TI_FALSE); } } /* If allowed to stop network stack and the queue is full, indicate to stop network and to schedule Tx handling (both are executed below, outside the critical section!) */ if ((pTxDataQ->bStopNetStackTx) && (uQueSize == pTxDataQ->aQueueMaxSize[uQueId])) { pTxDataQ->aNetStackQueueStopped[uQueId] = TI_TRUE; bRequestSchedule = TI_TRUE; bStopNetStack = TI_TRUE; } /* Leave critical section */ context_LeaveCriticalSection (pTxDataQ->hContext); /* If needed, schedule Tx handling */ if (bRequestSchedule) { context_RequestSchedule (pTxDataQ->hContext, pTxDataQ->uContextId); } /* If needed, stop the network stack Tx */ if (bStopNetStack) { /* Stop the network stack from sending Tx packets as we have at least one date queue full. Note that in some of the OS's (e.g Win Mobile) it is implemented by blocking the thread*/ wlanDrvIf_StopTx (pTxDataQ->hOs); } if (eStatus != TI_OK) { /* If the packet can't be queued drop it */ txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK); #ifdef TI_DBG pTxDataQ->aQueueCounters[uQueId].uDroppedPacket++; #endif /* TI_DBG */ } else { #ifdef TI_DBG pTxDataQ->aQueueCounters[uQueId].uEnqueuePacket++; #endif /* TI_DBG */ } CL_TRACE_END_L3 ("tiwlan_drv.ko", "INHERIT", "TX", ""); return eStatus; }