/** * \fn txnQ_RunScheduler * \brief Send queued transactions * * Run the scheduler, which issues transactions as long as possible. * Since this function is called from either internal or external (TxnDone) context, * it handles reentry by setting a bSchedulerPend flag, and running the scheduler again * when its current iteration is finished. * * \note * \param pTxnQ - The module's object * \param pInputTxn - The transaction inserted in the current context (NULL if none) * \return COMPLETE if pCurrTxn completed in this context, PENDING if not, ERROR if failed * \sa */ static ETxnStatus txnQ_RunScheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn) { TI_BOOL bFirstIteration; ETxnStatus eStatus = TXN_STATUS_NONE; TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_RunScheduler()\n"); context_EnterCriticalSection (pTxnQ->hContext); /* If the scheduler is currently busy, set bSchedulerPend flag and exit */ if (pTxnQ->bSchedulerBusy) { TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_RunScheduler(): Scheduler is busy\n"); pTxnQ->bSchedulerPend = TI_TRUE; context_LeaveCriticalSection (pTxnQ->hContext); return TXN_STATUS_PENDING; } /* Indicate that the scheduler is currently busy */ pTxnQ->bSchedulerBusy = TI_TRUE; context_LeaveCriticalSection (pTxnQ->hContext); bFirstIteration = TI_TRUE; /* * Run the scheduler while it has work to do */ while (1) { /* If first scheduler iteration, save its return code to return the original Txn result */ if (bFirstIteration) { eStatus = txnQ_Scheduler (pTxnQ, pInputTxn); bFirstIteration = TI_FALSE; } /* This is for handling pending calls when the scheduler was busy (see above) */ else { TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_RunScheduler(): Handle pending scheduler call\n"); txnQ_Scheduler (pTxnQ, NULL); } context_EnterCriticalSection (pTxnQ->hContext); /* If no pending calls, clear the busy flag and return the original caller Txn status */ if (!pTxnQ->bSchedulerPend) { pTxnQ->bSchedulerBusy = TI_FALSE; context_LeaveCriticalSection (pTxnQ->hContext); return eStatus; } pTxnQ->bSchedulerPend = TI_FALSE; context_LeaveCriticalSection (pTxnQ->hContext); } }
/** * \fn twIf_TxnDoneCb * \brief Transaction completion CB * * This callback is called by the TxnQ upon transaction completion, unless is was completed in * the original context where it was issued. * It may be called from bus driver external context (TxnDone ISR) or from WLAN driver context. * * \note * \param hTwIf - The module's object * \param pTxn - The completed transaction object * \return void * \sa twIf_HandleTxnDone */ static void twIf_TxnDoneCb(TI_HANDLE hTwIf, TTxnStruct * pTxn) { TTwIfObj *pTwIf = (TTwIfObj *) hTwIf; #ifdef TI_DBG pTwIf->uDbgCountTxnDoneCb++; TRACE6(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_TxnDoneCb: Params=0x%x, HwAddr=0x%x, Len0=%d, Len1=%d, Len2=%d, Len3=%d\n", pTxn->uTxnParams, pTxn->uHwAddr, pTxn->aLen[0], pTxn->aLen[1], pTxn->aLen[2], pTxn->aLen[3]); #endif /* In case of recovery flag, Call directly restart callback */ if (TXN_PARAM_GET_STATUS(pTxn) == TXN_PARAM_STATUS_RECOVERY) { if (pTwIf->fRecoveryCb) { TRACE0(pTwIf->hReport, REPORT_SEVERITY_INFORMATION, "twIf_TxnDoneCb: During Recovery\n"); pTwIf->bTxnDoneInRecovery = TI_TRUE; /* Request schedule to continue handling in driver context (will call twIf_HandleTxnDone()) */ context_RequestSchedule(pTwIf->hContext, pTwIf->uContextId); return; } } /* If the completed Txn is ELP, nothing to do (not counted) so exit */ if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) { return; } if (pTxn->fTxnDoneCb) { TI_STATUS eStatus; /* In critical section, enqueue the completed transaction in the TxnDoneQ. */ context_EnterCriticalSection(pTwIf->hContext); eStatus = que_Enqueue(pTwIf->hTxnDoneQueue, (TI_HANDLE) pTxn); if (eStatus != TI_OK) { TRACE3(pTwIf->hReport, REPORT_SEVERITY_ERROR, "twIf_TxnDoneCb(): Enqueue failed, pTxn=0x%x, HwAddr=0x%x, Len0=%d\n", pTxn, pTxn->uHwAddr, pTxn->aLen[0]); } context_LeaveCriticalSection(pTwIf->hContext); } else { context_EnterCriticalSection(pTwIf->hContext); /* Decrement pending Txn counter, It's value will be checked in twIf_HandleTxnDone() */ if (pTwIf->uPendingTxnCount > 0) { /* in case of callback on recovery after restart */ pTwIf->uPendingTxnCount--; } context_LeaveCriticalSection(pTwIf->hContext); } /* Request schedule to continue handling in driver context (will call twIf_HandleTxnDone()) */ context_RequestSchedule(pTwIf->hContext, pTwIf->uContextId); }
/** * \fn twIf_TxnDoneCb * \brief Transaction completion CB * * This callback is called by the TxnQ upon transaction completion, unless is was completed in * the original context where it was issued. * It may be called from bus driver external context (TxnDone ISR) or from WLAN driver context. * * \note * \param hTwIf - The module's object * \param pTxn - The completed transaction object * \return void * \sa twIf_HandleTxnDone */ static void twIf_TxnDoneCb (TI_HANDLE hTwIf, TTxnStruct *pTxn) { TTwIfObj *pTwIf = (TTwIfObj*)hTwIf; #ifdef TI_DBG pTwIf->uDbgCountTxnDoneCb++; #endif /* In case of recovery flag, Call directly restart callback */ if (TXN_PARAM_GET_STATUS(pTxn) == TXN_PARAM_STATUS_RECOVERY) { if (pTwIf->fRecoveryCb) { pTwIf->bTxnDoneInRecovery = TI_TRUE; /* Request schedule to continue handling in driver context (will call twIf_HandleTxnDone()) */ context_RequestSchedule (pTwIf->hContext, pTwIf->uContextId); return; } } /* If the completed Txn is ELP, nothing to do (not counted) so exit */ if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) { return; } if (pTxn->fTxnDoneCb) { TI_STATUS eStatus; /* In critical section, enqueue the completed transaction in the TxnDoneQ. */ context_EnterCriticalSection (pTwIf->hContext); eStatus = que_Enqueue (pTwIf->hTxnDoneQueue, (TI_HANDLE)pTxn); context_LeaveCriticalSection (pTwIf->hContext); } else { context_EnterCriticalSection (pTwIf->hContext); /* Decrement pending Txn counter, It's value will be checked in twIf_HandleTxnDone() */ if (pTwIf->uPendingTxnCount > 0) /* in case of callback on recovery after restart */ { pTwIf->uPendingTxnCount--; } context_LeaveCriticalSection (pTwIf->hContext); } /* Request schedule to continue handling in driver context (will call twIf_HandleTxnDone()) */ context_RequestSchedule (pTwIf->hContext, pTwIf->uContextId); }
ETxnStatus txnQ_Transact (TI_HANDLE hTxnQ, TTxnStruct *pTxn) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; TI_UINT32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); ETxnStatus rc; if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) { pTxnQ->aFuncInfo[uFuncId].pSingleStep = pTxn; TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Transact(): Single step Txn\n"); } else { TI_STATUS eStatus; TI_HANDLE hQueue = pTxnQ->aTxnQueues[uFuncId][TXN_PARAM_GET_PRIORITY(pTxn)]; context_EnterCriticalSection (pTxnQ->hContext); eStatus = que_Enqueue (hQueue, (TI_HANDLE)pTxn); context_LeaveCriticalSection (pTxnQ->hContext); if (eStatus != TI_OK) { TRACE3(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_Transact(): Enqueue failed, pTxn=0x%x, HwAddr=0x%x, Len0=%d\n", pTxn, pTxn->uHwAddr, pTxn->aLen[0]); return TXN_STATUS_ERROR; } TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Transact(): Regular Txn\n"); } /* Send queued transactions as possible */ rc = txnQ_RunScheduler (pTxnQ, pTxn); return rc; }
ETxnStatus txnQ_Restart (TI_HANDLE hTxnQ, TI_UINT32 uFuncId) { TTxnQObj *pTxnQ = (TTxnQObj*) hTxnQ; TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Restart()\n"); context_EnterCriticalSection (pTxnQ->hContext); /* If a Txn from the calling function is in progress, set state to RESTART return PENDING */ if (pTxnQ->pCurrTxn) { if (TXN_PARAM_GET_FUNC_ID(pTxnQ->pCurrTxn) == uFuncId) { pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_RESTART; context_LeaveCriticalSection (pTxnQ->hContext); TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Restart(): pCurrTxn pending\n"); /* Return PENDING to indicate that the restart will be completed later (in TxnDone) */ return TXN_STATUS_PENDING; } } context_LeaveCriticalSection (pTxnQ->hContext); /* Clear the calling function's queues (call function CB with status=RECOVERY) */ txnQ_ClearQueues (hTxnQ, uFuncId); /* Return COMPLETE to indicate that the restart was completed */ return TXN_STATUS_COMPLETE; }
/** * \fn tmr_GetExpiry * \brief Called by OS-API upon any timer expiry * * This is the common callback function called upon expiartion of any timer. * It is called by the OS-API in timer expiry context and handles the transition * to the driver's context for handling the expiry event. * * \note * \param hTimerInfo - The specific timer handle * \return void * \sa tmr_HandleExpiry */ void tmr_GetExpiry (TI_HANDLE hTimerInfo) { TTimerInfo *pTimerInfo = (TTimerInfo *)hTimerInfo; /* The timer handle */ TTimerModule *pTimerModule = (TTimerModule *)pTimerInfo->hTimerModule; /* The timer module handle */ if (!pTimerModule) { WLAN_OS_REPORT (("tmr_GetExpiry(): ERROR - NULL timer!\n")); return; } /* Enter critical section */ context_EnterCriticalSection (pTimerModule->hContext); /* * If the expired timer was started when the driver's state was Operational, * insert it to the Operational-queue */ if (pTimerInfo->bOperStateWhenStarted) { que_Enqueue (pTimerModule->hOperQueue, hTimerInfo); } /* * Else (started when driver's state was NOT-Operational), if now the state is still * NOT Operational insert it to the Init-queue. * (If state changed from non-operational to operational the event is ignored) */ else if (!pTimerModule->bOperState) { que_Enqueue (pTimerModule->hInitQueue, hTimerInfo); } /* Leave critical section */ context_LeaveCriticalSection (pTimerModule->hContext); /* Request switch to driver context for handling timer events */ context_RequestSchedule (pTimerModule->hContext, pTimerModule->uContextId); }
/** * \fn tmr_UpdateDriverState * \brief Update driver state * * Under critical section, update driver state (operational or not), * and if opertional, clear init queue. * Leave critical section and if operational state, request schedule for handling * timer events in driver context (if any). * * \note * \param hTimerModule - The timer module object * \param bOperState - TRUE if driver state is now operational, FALSE if not. * \return void * \sa */ void tmr_UpdateDriverState (TI_HANDLE hTimerModule, TI_BOOL bOperState) { TTimerModule *pTimerModule = (TTimerModule *)hTimerModule; if (bOperState == pTimerModule->bOperState) { return; } /* Enter critical section */ context_EnterCriticalSection (pTimerModule->hContext); /* Save new state (TRUE means operational). */ pTimerModule->bOperState = bOperState; /* If new state is operational */ if (bOperState) { /* Increment the TWD initializations counter (for detecting recovery events). */ pTimerModule->uTwdInitCount++; /* Empty the init queue (obsolete). */ while (que_Dequeue (pTimerModule->hInitQueue) != NULL) {} } /* Leave critical section */ context_LeaveCriticalSection (pTimerModule->hContext); /* If new state is operational, request switch to driver context for handling timer events */ if (bOperState) { context_RequestSchedule (pTimerModule->hContext, pTimerModule->uContextId); } }
/** * \fn tmr_Destroy * \brief Destroy the module. * * Free the module's queues and object. * * \note This is NOT a specific timer destruction! (see tmr_DestroyTimer) * \param hTimerModule - The module object * \return TI_OK on success or TI_NOK on failure * \sa tmr_Create */ TI_STATUS tmr_Destroy (TI_HANDLE hTimerModule) { TTimerModule *pTimerModule = (TTimerModule *)hTimerModule; if (!pTimerModule) { WLAN_OS_REPORT (("tmr_Destroy(): ERROR - NULL timer!\n")); return TI_NOK; } /* Alert if there are still timers that were not destroyed */ if (pTimerModule->uTimersCount) { WLAN_OS_REPORT (("tmr_Destroy(): ERROR - Destroying Timer module but not all timers were destroyed!!\n")); } /* Destroy the module's queues (protect in critical section)) */ context_EnterCriticalSection (pTimerModule->hContext); que_Destroy (pTimerModule->hInitQueue); que_Destroy (pTimerModule->hOperQueue); context_LeaveCriticalSection (pTimerModule->hContext); /* free module object */ os_memoryFree (pTimerModule->hOs, pTimerModule, sizeof(TTimerModule)); return TI_OK; }
/** * \fn txnQ_ClearQueues * \brief Clear the function queues * * Clear the specified function queues and call its CB for each Txn with status=RECOVERY. * * \note Called in critical section. * \param hTxnQ - The module's object * \param uFuncId - The calling functional driver * \return void * \sa */ void txnQ_ClearQueues (TI_HANDLE hTxnQ, TI_UINT32 uFuncId) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; TTxnStruct *pTxn; TI_UINT32 uPrio; context_EnterCriticalSection (pTxnQ->hContext); pTxnQ->aFuncInfo[uFuncId].pSingleStep = NULL; /* For all function priorities */ for (uPrio = 0; uPrio < pTxnQ->aFuncInfo[uFuncId].uNumPrios; uPrio++) { do { /* Dequeue Txn from current priority queue */ pTxn = (TTxnStruct *) que_Dequeue (pTxnQ->aTxnQueues[uFuncId][uPrio]); /* * Drop on Restart * do not call fTxnQueueDoneCb (hCbHandle, pTxn) callback */ } while (pTxn != NULL); } /* Clear state - for restart (doesn't call txnQ_Open) */ pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_RUNNING; context_LeaveCriticalSection (pTxnQ->hContext); }
/** * \fn twIf_ClearTxnDoneQueue * \brief Clean the DoneQueue * * Clear the specified done queue - don't call the callbacks. * * \note * \param hTwIf - The module's object * \return void * \sa */ static void twIf_ClearTxnDoneQueue(TI_HANDLE hTwIf) { TTwIfObj *pTwIf = (TTwIfObj *) hTwIf; TTxnStruct *pTxn; /* Loop while there are completed transactions to handle */ while (1) { /* In critical section, dequeue completed transaction from the TxnDoneQ. */ context_EnterCriticalSection(pTwIf->hContext); pTxn = (TTxnStruct *) que_Dequeue(pTwIf->hTxnDoneQueue); context_LeaveCriticalSection(pTwIf->hContext); /* If no more transactions to handle, exit */ if (pTxn != NULL) { /* Decrement pending Txn counter */ if (pTwIf->uPendingTxnCount > 0) { /* in case of callback on recovery after restart */ pTwIf->uPendingTxnCount--; } /* * Drop on Recovery * do not call pTxn->fTxnDoneCb (pTxn->hCbHandle, pTxn) callback */ } if (pTxn == NULL) { return; } } }
void txnQ_Close (TI_HANDLE hTxnQ, TI_UINT32 uFuncId) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; TI_UINT32 i; context_EnterCriticalSection (pTxnQ->hContext); /* Destroy the functional driver's queues */ for (i = 0; i < pTxnQ->aFuncInfo[uFuncId].uNumPrios; i++) { que_Destroy (pTxnQ->aTxnQueues[uFuncId][i]); } /* Clear functional driver info */ pTxnQ->aFuncInfo[uFuncId].uNumPrios = 0; pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb = NULL; pTxnQ->aFuncInfo[uFuncId].hCbHandle = NULL; pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_NONE; /* Update functions actual range (to optimize Txn selection loops - see txnQ_SelectTxn) */ pTxnQ->uMinFuncId = MAX_FUNCTIONS; pTxnQ->uMaxFuncId = 0; for (i = 0; i < MAX_FUNCTIONS; i++) { if (pTxnQ->aFuncInfo[i].eState != FUNC_STATE_NONE) { if (i < pTxnQ->uMinFuncId) { pTxnQ->uMinFuncId = i; } if (i > pTxnQ->uMaxFuncId) { pTxnQ->uMaxFuncId = i; } } } context_LeaveCriticalSection (pTxnQ->hContext); }
/** * \fn TxMgmtQ_FlushLinkQueues * \brief Flush management queues the specific link * * * \note * \param hTxMgmtQ - The module's object * \param uHlid - link id * \return void * \sa */ void TxMgmtQ_FlushLinkQueues(TI_HANDLE hTxMgmtQ, TI_UINT32 uHlid) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; TTxCtrlBlk *pPktCtrlBlk; TI_UINT32 uQueId; TMgmtLinkQ *pLinkQ; pLinkQ = &pTxMgmtQ->aMgmtLinkQ[uHlid]; /* Link queues */ /* Dequeue and free all queued packets */ for (uQueId = 0 ; uQueId < NUM_OF_MGMT_QUEUES ; uQueId++) { while (1) { context_EnterCriticalSection (pTxMgmtQ->hContext); pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pLinkQ->aQueues[uQueId]); context_LeaveCriticalSection (pTxMgmtQ->hContext); if (pPktCtrlBlk == NULL) { break; } txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK); } } }
/** * \fn txnQ_TxnDoneCb * \brief Pending Transaction completion CB * * Called back by bus-driver upon pending transaction completion in TxnDone context (external!). * Enqueue completed transaction in TxnDone queue and call scheduler to send queued transactions. * * \note * \param hTxnQ - The module's object * \param pTxn - The completed transaction object * \return void * \sa */ static void txnQ_TxnDoneCb (TI_HANDLE hTxnQ, void *hTxn) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; TTxnStruct *pTxn = (TTxnStruct *)hTxn; TI_UINT32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); /* If the function of the completed Txn is waiting for restart */ if (pTxnQ->aFuncInfo[uFuncId].eState == FUNC_STATE_RESTART) { /* First, Clear the restarted function queues */ txnQ_ClearQueues (hTxnQ, uFuncId); /* Call function CB for current Txn with restart indication */ TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_RECOVERY); pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb (pTxnQ->aFuncInfo[uFuncId].hCbHandle, pTxn); } /* In the normal case (no restart), enqueue completed transaction in TxnDone queue */ else { TI_STATUS eStatus; context_EnterCriticalSection (pTxnQ->hContext); eStatus = que_Enqueue (pTxnQ->hTxnDoneQueue, (TI_HANDLE)pTxn); context_LeaveCriticalSection (pTxnQ->hContext); } /* Indicate that no transaction is currently processed in the bus-driver */ pTxnQ->pCurrTxn = NULL; /* Send queued transactions as possible (TRUE indicates we are in external context) */ txnQ_RunScheduler (pTxnQ, NULL); }
/** * \fn txDataQ_LinkMacFind * \brief Find entry with MAC address * * \return status * \sa txDataQ_LinkMacFind */ TI_STATUS txDataQ_LinkMacFind (TI_HANDLE hTxDataQ, TI_UINT32 *uHlid, TMacAddr tMacAddr) { TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; int i; int j; /* Enter critical section to protect links data */ context_EnterCriticalSection (pTxDataQ->hContext); for (i=0; i<LINK_MAC_TABLE_SIZE; i++) { if (!pTxDataQ->aLinkMac[i].uValid) { /* entry not valid, skip to next entry */ continue; } for (j=MAC_ADDR_LEN-1; j>=0; j--) { if (pTxDataQ->aLinkMac[i].tMacAddr[j] != tMacAddr[j]) { /* different MAC, skip to next entry */ break; } } if (j < 0) { /* Found, return index */ *uHlid = i; context_LeaveCriticalSection (pTxDataQ->hContext); return TI_OK; } } context_LeaveCriticalSection (pTxDataQ->hContext); /* Not found */ *uHlid = 0xff; /* for debug */ return TI_NOK; }
/** * \fn txDataQ_FlushLinkQueues * \brief Flush all queues of the specific link * * Free all pending packets in link queue * * \note * \param hTxDataQ - The object * \param uHlid - Link ID * \return void * \sa */ void txDataQ_FlushLinkQueues (TI_HANDLE hTxDataQ, TI_UINT32 uHlid) { TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; TTxCtrlBlk *pPktCtrlBlk; TI_UINT32 uQueId; TDataLinkQ *pLinkQ; pLinkQ = &pTxDataQ->aDataLinkQ[uHlid]; /* Link queues */ /* Dequeue and free all queued packets */ for (uQueId = 0 ; uQueId < pTxDataQ->uNumQueues ; uQueId++) { while (1) { context_EnterCriticalSection (pTxDataQ->hContext); pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pLinkQ->aQueues[uQueId]); context_LeaveCriticalSection (pTxDataQ->hContext); if (pPktCtrlBlk == NULL) { break; } txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK); } } }
void tmr_ClearOperQueue (TI_HANDLE hTimerModule) { TTimerModule *pTimerModule = (TTimerModule *)hTimerModule; context_EnterCriticalSection (pTimerModule->hContext); while (que_Dequeue (pTimerModule->hOperQueue) != NULL) {} context_LeaveCriticalSection (pTimerModule->hContext); }
/** * \fn txMgmtQ_Xmit * \brief Insert non-data packet for transmission * * This function is used by the driver applications to send Tx packets other than the * regular data traffic, including the following packet types: * - Management * - EAPOL * - NULL * - IAPP * The managment packets are enqueued to the Mgmt-queue and the others to the Eapol-queue. * EAPOL packets may be inserted from the network stack context, so it requires switching * to the driver's context (after the packet is enqueued). * If the selected queue was empty before the packet insertion, the SM is called * with QUEUES_NOT_EMPTY event (in case of external context, only after the context switch). * * \note * \param hTxMgmtQ - The module's object * \param pPktCtrlBlk - Pointer to the packet CtrlBlk * \param bExternalContext - Indicates if called from non-driver context * \return TI_OK - if the packet was queued, TI_NOK - if the packet was dropped. * \sa txMgmtQ_QueuesNotEmpty */ TI_STATUS txMgmtQ_Xmit (TI_HANDLE hTxMgmtQ, TTxCtrlBlk *pPktCtrlBlk, TI_BOOL bExternalContext) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; TI_STATUS eStatus; TI_UINT32 uQueId; TI_UINT32 uQueSize; /* Always set highest TID for mgmt-queues packets. */ pPktCtrlBlk->tTxDescriptor.tid = MGMT_QUEUES_TID; /* Select queue asccording to the packet type */ uQueId = (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_MGMT) ? QUEUE_TYPE_MGMT : QUEUE_TYPE_EAPOL ; /* Enter critical section to protect queue access */ context_EnterCriticalSection (pTxMgmtQ->hContext); /* Enqueue the packet in the appropriate Queue */ eStatus = que_Enqueue (pTxMgmtQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); /* Get number of packets in current queue */ uQueSize = que_Size (pTxMgmtQ->aQueues[uQueId]); /* Leave critical section */ context_LeaveCriticalSection (pTxMgmtQ->hContext); /* If packet enqueued successfully */ if (eStatus == TI_OK) { pTxMgmtQ->tDbgCounters.aEnqueuePackets[uQueId]++; /* If selected queue was empty before packet insertion */ if (uQueSize == 1) { /* If called from external context (EAPOL from network), request switch to the driver's context. */ if (bExternalContext) { context_RequestSchedule (pTxMgmtQ->hContext, pTxMgmtQ->uContextId); } /* If already in the driver's context, call the SM with QUEUES_NOT_EMPTY event. */ else { mgmtQueuesSM(pTxMgmtQ, SM_EVENT_QUEUES_NOT_EMPTY); } } } else { /* If the packet can't be queued so drop it */ txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK); pTxMgmtQ->tDbgCounters.aDroppedPackets[uQueId]++; } return eStatus; }
/** * \fn tmr_HandleExpiry * \brief Handles queued expiry events in driver context * * This is the Timer module's callback that is registered to the ContextEngine module to be invoked * from the driver task (after requested by tmr_GetExpiry through context_RequestSchedule ()). * It dequeues all expiry events from the queue that correlates to the current driver state, * and calls their users callbacks. * * \note * \param hTimerModule - The module object * \return void * \sa tmr_GetExpiry */ void tmr_HandleExpiry (TI_HANDLE hTimerModule) { TTimerModule *pTimerModule = (TTimerModule *)hTimerModule; /* The timer module handle */ TTimerInfo *pTimerInfo; /* The timer handle */ TI_BOOL bTwdInitOccured; /* Indicates if TWD init occured since timer start */ if (!pTimerModule) { WLAN_OS_REPORT (("tmr_HandleExpiry(): ERROR - NULL timer!\n")); return; } while (1) { /* Enter critical section */ context_EnterCriticalSection (pTimerModule->hContext); /* If current driver state is Operational, dequeue timer object from Operational-queue */ if (pTimerModule->bOperState) { pTimerInfo = (TTimerInfo *) que_Dequeue (pTimerModule->hOperQueue); } /* Else (driver state is NOT-Operational), dequeue timer object from Init-queue */ else { pTimerInfo = (TTimerInfo *) que_Dequeue (pTimerModule->hInitQueue); } /* Leave critical section */ context_LeaveCriticalSection (pTimerModule->hContext); /* If no more objects in queue, exit */ if (!pTimerInfo) { return; /** EXIT Point **/ } /* If current TWD-Init-Count is different than when the timer was started, Init occured. */ bTwdInitOccured = (pTimerModule->uTwdInitCount != pTimerInfo->uTwdInitCountWhenStarted); /* Call specific timer callback function */ pTimerInfo->fExpiryCbFunc (pTimerInfo->hExpiryCbHndl, bTwdInitOccured); /* If the expired timer is periodic, start it again. */ if (pTimerInfo->bPeriodic) { tmr_StartTimer ((TI_HANDLE)pTimerInfo, pTimerInfo->fExpiryCbFunc, pTimerInfo->hExpiryCbHndl, pTimerInfo->uIntervalMsec, pTimerInfo->bPeriodic); } } }
/** * \fn cmdHndlr_HandleCommands * \brief Handle queued commands * * While there are queued commands, dequeue a command and call the * commands interpreter (OID or WEXT selected at compile time). * If the command processing is not completed in this context (pending), we exit and * this function is called again upon commnad completion, so it can continue processing * further queued commands (if any). * * \note * \param hCmdHndlr - The module object * \return void * \sa cmdHndlr_InsertCommand, cmdHndlr_Complete */ void cmdHndlr_HandleCommands(TI_HANDLE hCmdHndlr) { TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *) hCmdHndlr; while (1) { /* Enter critical section to protect queue access */ context_EnterCriticalSection(pCmdHndlr->hContext); /* Dequeue a command */ pCmdHndlr->pCurrCmd = (TConfigCommand *) que_Dequeue(pCmdHndlr->hCmdQueue); /* If we have got a command */ if (pCmdHndlr->pCurrCmd) { /* Leave critical section */ context_LeaveCriticalSection(pCmdHndlr->hContext); /* Convert to driver structure and execute command */ pCmdHndlr->pCurrCmd->eCmdStatus = cmdInterpret_convertAndExecute(pCmdHndlr-> hCmdInterpret, pCmdHndlr->pCurrCmd); /* * If command not completed in this context (Async), return. * (we'll be called back upon command completion) */ if (COMMAND_PENDING == pCmdHndlr->pCurrCmd->eCmdStatus) { return; } /* Command was completed so free the wait signal and continue to next command */ wlanDrvIf_CommandDone(pCmdHndlr->hOs, pCmdHndlr->pCurrCmd-> pSignalObject, pCmdHndlr->pCurrCmd-> CmdRespBuffer); pCmdHndlr->pCurrCmd = NULL; } /* Else, we don't have commands to handle */ else { /* Indicate that we are not handling commands (before leaving critical section!) */ pCmdHndlr->bProcessingCmds = TI_FALSE; /* Leave critical section */ context_LeaveCriticalSection(pCmdHndlr->hContext); /* Exit (no more work) */ return; } } }
/** * \fn txDataQ_FreeResources * \brief Free resources per Link and per Ac * */ void txDataQ_FreeResources (TI_HANDLE hTxDataQ, TTxCtrlBlk *pPktCtrlBlk) { TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; TDataResources *pDataRsrc = &pTxDataQ->tDataRsrc; TI_UINT32 uHlid = pPktCtrlBlk->tTxDescriptor.hlid; TI_UINT32 uAc; /* Free TxData resources only if previous allocated by txDataQ_AllocCheckResources */ if (!IS_TX_CTRL_FLAG_RSRC_ALLOCATED(pPktCtrlBlk)) { return; } /* Enter critical section to protect classifier data and queue access */ context_EnterCriticalSection (pTxDataQ->hContext); /* Extract original AC (saved by txDataQ_AllocCheckResources) from tx ctrl block */ uAc = GET_TX_CTRL_FLAG_RSRC_AC(pPktCtrlBlk); /* new packet, Increment packet in use counters */ pDataRsrc->uPktInUse_PerAc[uAc]--; pDataRsrc->uPktInUse_PerLink[uHlid]--; /* Update Effective totals = Sum of Max ( PktInUse_PerAc [uAc], Min_PerAc[uAc] ), uAc=0..MAX_AC */ /* no need to calculate Sum of Max on every packet, just small check for this ac only */ if (pDataRsrc->uPktInUse_PerAc[uAc] >= pDataRsrc->uMinGuarantee_PerAc[uAc]) { pDataRsrc->uEffectiveTotal_Ac--; #ifdef TI_DBG /* sanity check */ if (pDataRsrc->uEffectiveTotal_Ac < pDataRsrc->uEffectiveTotal_Ac_Min ) { WLAN_OS_REPORT(("%s: uEffectiveTotal_Ac=%d is below MIN=%d\n", __FUNCTION__, pDataRsrc->uEffectiveTotal_Ac, pDataRsrc->uEffectiveTotal_Ac_Min)); } #endif } /* Update Effective totals = Sum of Max ( PktInUse_PerLik [uHlid], Min_PerLink[uHlid] ), uHlid=0..MAX_LINK */ /* no need to calculate Sum of Max on every packet, just small check for this link only*/ if (pDataRsrc->uPktInUse_PerLink[uHlid] >= pDataRsrc->uMinGuarantee_PerLink) { pDataRsrc->uEffectiveTotal_Link--; #ifdef TI_DBG /* sanity check */ if (pDataRsrc->uEffectiveTotal_Link < pDataRsrc->uEffectiveTotal_Link_Min ) { WLAN_OS_REPORT(("%s: uEffectiveTotal_Ac=%d is below MIN=%d\n", __FUNCTION__, pDataRsrc->uEffectiveTotal_Link, pDataRsrc->uEffectiveTotal_Link_Min)); } #endif } /* Leave critical section */ context_LeaveCriticalSection (pTxDataQ->hContext); }
TI_STATUS txnQ_Open (TI_HANDLE hTxnQ, TI_UINT32 uFuncId, TI_UINT32 uNumPrios, TTxnQueueDoneCb fTxnQueueDoneCb, TI_HANDLE hCbHandle) { TTxnQObj *pTxnQ = (TTxnQObj*) hTxnQ; TI_UINT32 uNodeHeaderOffset; TI_UINT32 i; if (uFuncId >= MAX_FUNCTIONS || uNumPrios > MAX_PRIORITY) { TRACE2(pTxnQ->hReport, REPORT_SEVERITY_ERROR, ": Invalid Params! uFuncId = %d, uNumPrios = %d\n", uFuncId, uNumPrios); return TI_NOK; } context_EnterCriticalSection (pTxnQ->hContext); /* Save functional driver info */ pTxnQ->aFuncInfo[uFuncId].uNumPrios = uNumPrios; pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb = fTxnQueueDoneCb; pTxnQ->aFuncInfo[uFuncId].hCbHandle = hCbHandle; pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_STOPPED; /* Create the functional driver's queues. */ uNodeHeaderOffset = TI_FIELD_OFFSET(TTxnStruct, tTxnQNode); for (i = 0; i < uNumPrios; i++) { pTxnQ->aTxnQueues[uFuncId][i] = que_Create (pTxnQ->hOs, pTxnQ->hReport, TXN_QUE_SIZE, uNodeHeaderOffset); if (pTxnQ->aTxnQueues[uFuncId][i] == NULL) { TRACE0(pTxnQ->hReport, REPORT_SEVERITY_ERROR, ": Queues creation failed!\n"); context_LeaveCriticalSection (pTxnQ->hContext); return TI_NOK; } } /* Update functions actual range (to optimize Txn selection loops - see txnQ_SelectTxn) */ if (uFuncId < pTxnQ->uMinFuncId) { pTxnQ->uMinFuncId = uFuncId; } if (uFuncId > pTxnQ->uMaxFuncId) { pTxnQ->uMaxFuncId = uFuncId; } context_LeaveCriticalSection (pTxnQ->hContext); TRACE2(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, ": Function %d registered successfully, uNumPrios = %d\n", uFuncId, uNumPrios); return TI_OK; }
/** * \fn txDataQ_LinkMacRemove * \brief Set LinkMac table entry as invalid * * \return void * \sa txDataQ_LinkMacRemove */ void txDataQ_LinkMacRemove (TI_HANDLE hTxDataQ, TI_UINT32 uHlid) { TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; if (uHlid >= LINK_MAC_TABLE_SIZE) { WLAN_OS_REPORT(("%s: illegal uHlid = %d\n", __FUNCTION__, uHlid)); return; } /* Enter critical section to protect links data */ context_EnterCriticalSection (pTxDataQ->hContext); pTxDataQ->aLinkMac[uHlid].uValid = TI_FALSE; context_LeaveCriticalSection (pTxDataQ->hContext); }
/** * \fn cmdHndlr_ClearQueue * \brief Clear commands queue * * Dequeue and free all queued commands. * * \note * \param hCmdHndlr - The object * \return void * \sa */ void cmdHndlr_ClearQueue (TI_HANDLE hCmdHndlr) { TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; TConfigCommand *pCurrCmd; /* Dequeue and free all queued commands */ do { context_EnterCriticalSection (pCmdHndlr->hContext); pCurrCmd = (TConfigCommand *)que_Dequeue(pCmdHndlr->hCmdQueue); context_LeaveCriticalSection (pCmdHndlr->hContext); if (pCurrCmd != NULL) { /* Just release the semaphore. The command is freed subsequently. */ os_SignalObjectSet (pCmdHndlr->hOs, pCurrCmd->pSignalObject); } } while (pCurrCmd != NULL); }
/** * \fn txnQ_TxnDoneCb * \brief Pending Transaction completion CB * * Called back by bus-driver upon pending transaction completion in TxnDone context (external!). * Enqueue completed transaction in TxnDone queue and call scheduler to send queued transactions. * * \note * \param hTxnQ - The module's object * \param pTxn - The completed transaction object * \return void * \sa */ static void txnQ_TxnDoneCb (TI_HANDLE hTxnQ, void *hTxn) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; TTxnStruct *pTxn = (TTxnStruct *)hTxn; TI_UINT32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); #ifdef TI_DBG TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_TxnDoneCb()\n"); if (pTxn != pTxnQ->pCurrTxn) { TRACE2(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_TxnDoneCb(): CB returned pTxn 0x%x while pCurrTxn is 0x%x !!\n", pTxn, pTxnQ->pCurrTxn); } #endif /* If the function of the completed Txn is waiting for restart */ if (pTxnQ->aFuncInfo[uFuncId].eState == FUNC_STATE_RESTART) { TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_TxnDoneCb(): Handling restart\n"); /* First, Clear the restarted function queues */ txnQ_ClearQueues (hTxnQ, uFuncId); /* Call function CB for current Txn with restart indication */ TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_RECOVERY); pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb (pTxnQ->aFuncInfo[uFuncId].hCbHandle, pTxn); } /* In the normal case (no restart), enqueue completed transaction in TxnDone queue */ else { TI_STATUS eStatus; context_EnterCriticalSection (pTxnQ->hContext); eStatus = que_Enqueue (pTxnQ->hTxnDoneQueue, (TI_HANDLE)pTxn); if (eStatus != TI_OK) { TRACE3(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_TxnDoneCb(): Enqueue failed, pTxn=0x%x, HwAddr=0x%x, Len0=%d\n", pTxn, pTxn->uHwAddr, pTxn->aLen[0]); } context_LeaveCriticalSection (pTxnQ->hContext); } /* Indicate that no transaction is currently processed in the bus-driver */ pTxnQ->pCurrTxn = NULL; /* Send queued transactions as possible (TRUE indicates we are in external context) */ txnQ_RunScheduler (pTxnQ, NULL); }
/** * \fn txDataQ_LinkMacAdd * \brief Set MAC address for the link id. * * \return void * \sa txDataQ_LinkMacAdd */ TI_STATUS txDataQ_LinkMacAdd (TI_HANDLE hTxDataQ, TI_UINT32 uHlid, TMacAddr tMacAddr) { TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; if (uHlid >= LINK_MAC_TABLE_SIZE) { WLAN_OS_REPORT(("%s: illegal uHlid = %d\n", __FUNCTION__, uHlid)); return TI_NOK; } /* Enter critical section to protect links data */ context_EnterCriticalSection (pTxDataQ->hContext); pTxDataQ->aLinkMac[uHlid].uValid = TI_TRUE; MAC_COPY (pTxDataQ->aLinkMac[uHlid].tMacAddr, tMacAddr); context_LeaveCriticalSection (pTxDataQ->hContext); return TI_OK; }
/** * \fn txDataQ_ClearQueues * \brief Clear all queues * * Dequeue and free all queued packets. * * \note * \param hTxDataQ - The object * \return void * \sa */ void txDataQ_ClearQueues (TI_HANDLE hTxDataQ) { TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; TTxCtrlBlk *pPktCtrlBlk; TI_UINT32 uQueId; /* Dequeue and free all queued packets */ for (uQueId = 0 ; uQueId < pTxDataQ->uNumQueues ; uQueId++) { do { context_EnterCriticalSection (pTxDataQ->hContext); pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue(pTxDataQ->aQueues[uQueId]); context_LeaveCriticalSection (pTxDataQ->hContext); if (pPktCtrlBlk != NULL) { txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK); } } while (pPktCtrlBlk != NULL); } }
/** * \fn tmr_UpdateDriverState * \brief Update driver state * * Under critical section, update driver state (operational or not), * and if opertional, clear init queue. * Leave critical section and if operational state, request schedule for handling * timer events in driver context (if any). * * \note * \param hTimerModule - The timer module object * \param bOperState - TRUE if driver state is now operational, FALSE if not. * \return void * \sa */ void tmr_UpdateDriverState (TI_HANDLE hTimerModule, TI_BOOL bOperState) { TTimerModule *pTimerModule = (TTimerModule *)hTimerModule; if (!pTimerModule) { WLAN_OS_REPORT (("tmr_UpdateDriverState(): ERROR - NULL timer!\n")); return; } /* Enter critical section */ context_EnterCriticalSection (pTimerModule->hContext); if (bOperState == pTimerModule->bOperState) { context_LeaveCriticalSection (pTimerModule->hContext); TRACE1(pTimerModule->hReport, REPORT_SEVERITY_ERROR, "tmr_UpdateDriverState(): New bOperState (%d) is as current!\n", bOperState); return; } /* Save new state (TRUE means operational). */ pTimerModule->bOperState = bOperState; /* If new state is operational */ if (bOperState) { /* Increment the TWD initializations counter (for detecting recovery events). */ pTimerModule->uTwdInitCount++; /* Empty the init queue (obsolete). */ while (que_Dequeue (pTimerModule->hInitQueue) != NULL) {} } /* Leave critical section */ context_LeaveCriticalSection (pTimerModule->hContext); /* If new state is operational, request switch to driver context for handling timer events */ if (bOperState) { context_RequestSchedule (pTimerModule->hContext, pTimerModule->uContextId); } }
/**************************************************************************** * txCtrlBlk_Free() **************************************************************************** * DESCRIPTION: Link the freed entry after entry 0, so now it is the first free entry to be allocated. ****************************************************************************/ void txCtrlBlk_Free (TI_HANDLE hTxCtrlBlk, TTxCtrlBlk *pCurrentEntry) { TTxCtrlBlkObj *pTxCtrlBlk = (TTxCtrlBlkObj *)hTxCtrlBlk; TTxCtrlBlk *pFirstFreeEntry = &(pTxCtrlBlk->aTxCtrlBlkTbl[0]); #ifdef TI_DBG /* If the pointed entry is already free, print error and exit (not expected to happen). */ if (pCurrentEntry->pNextFreeEntry != 0) { return; } pTxCtrlBlk->uNumUsedEntries--; #endif /* Protect block freeing from preemption (may be called from external context) */ context_EnterCriticalSection (pTxCtrlBlk->hContext); /* Link the freed entry between entry 0 and the next free entry. */ pCurrentEntry->pNextFreeEntry = pFirstFreeEntry->pNextFreeEntry; pFirstFreeEntry->pNextFreeEntry = pCurrentEntry; context_LeaveCriticalSection (pTxCtrlBlk->hContext); }
/**************************************************************************** * txCtrlBlk_Alloc() **************************************************************************** * DESCRIPTION: Allocate a free control-block entry for the current Tx packet's parameters (including the descriptor structure). Note that entry 0 in the list is never allocated and points to the first free entry. ****************************************************************************/ TTxCtrlBlk *txCtrlBlk_Alloc (TI_HANDLE hTxCtrlBlk) { TTxCtrlBlkObj *pTxCtrlBlk = (TTxCtrlBlkObj *)hTxCtrlBlk; TTxCtrlBlk *pCurrentEntry; /* The pointer of the new entry allocated for the packet. */ TTxCtrlBlk *pFirstFreeEntry; /* The first entry just points to the first free entry. */ pFirstFreeEntry = &(pTxCtrlBlk->aTxCtrlBlkTbl[0]); /* Protect block allocation from preemption (may be called from external context) */ context_EnterCriticalSection (pTxCtrlBlk->hContext); pCurrentEntry = pFirstFreeEntry->pNextFreeEntry; /* Get free entry. */ #ifdef TI_DBG /* If no free entries, print error (not expected to happen) and return NULL. */ if (pCurrentEntry->pNextFreeEntry == NULL) { TRACE1(pTxCtrlBlk->hReport, REPORT_SEVERITY_ERROR, "txCtrlBlk_alloc(): No free entry, UsedEntries=%d\n", pTxCtrlBlk->uNumUsedEntries); context_LeaveCriticalSection (pTxCtrlBlk->hContext); return NULL; } pTxCtrlBlk->uNumUsedEntries++; #endif /* Link the first entry to the next free entry. */ pFirstFreeEntry->pNextFreeEntry = pCurrentEntry->pNextFreeEntry; context_LeaveCriticalSection (pTxCtrlBlk->hContext); /* Clear the next-free-entry index just as an indication that our entry is not free. */ pCurrentEntry->pNextFreeEntry = 0; pCurrentEntry->tTxPktParams.uFlags = 0; pCurrentEntry->tTxPktParams.uHeadroomSize = 0; return pCurrentEntry; }
/** * \fn tmr_Destroy * \brief Destroy the module. * * Free the module's queues and object. * * \note This is NOT a specific timer destruction! (see tmr_DestroyTimer) * \param hTimerModule - The module object * \return TI_OK on success or TI_NOK on failure * \sa tmr_Create */ TI_STATUS tmr_Destroy (TI_HANDLE hTimerModule) { TTimerModule *pTimerModule = (TTimerModule *)hTimerModule; /* Alert if there are still timers that were not destroyed */ if (pTimerModule->uTimersCount) { } /* Clear queues (critical section is used inside these functions) */ // tmr_ClearInitQueue (hTimerModule); // tmr_ClearOperQueue (hTimerModule); /* Destroy the module's queues (protect in critical section)) */ context_EnterCriticalSection (pTimerModule->hContext); que_Destroy (pTimerModule->hInitQueue); que_Destroy (pTimerModule->hOperQueue); context_LeaveCriticalSection (pTimerModule->hContext); /* free module object */ os_memoryFree (pTimerModule->hOs, pTimerModule, sizeof(TTimerModule)); return TI_OK; }