Beispiel #1
0
/**
 * \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);
}
Beispiel #2
0
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;
}
Beispiel #3
0
/**
 * \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     txnQ_Transact
 * \brief  Issue a new transaction 
 * 
 * Called by the functional driver to initiate a new transaction.
 * In critical section save transaction and call scheduler.
 * 
 * \note   
 * \param  hTxnQ - The module's object
 * \param  pTxn  - The transaction object 
 * \return COMPLETE if input pTxn completed in this context, PENDING if not, ERROR if failed
 * \sa     
 */ 
ETxnStatus txnQ_Transact (handle_t hTxnQ, TTxnStruct *pTxn)
{
    TTxnQObj    *pTxnQ   = (TTxnQObj*)hTxnQ;
    McpU32    uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn);
    ETxnStatus   rc;

    MCPF_ENTER_CRIT_SEC (pTxnQ->hMcpf);

    if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) 
    {
        pTxnQ->aFuncInfo[uFuncId].pSingleStep = pTxn;
    }
    else 
    {
        handle_t hQueue = pTxnQ->aTxnQueues[uFuncId][TXN_PARAM_GET_PRIORITY(pTxn)];
        que_Enqueue (hQueue, (handle_t)pTxn);
    }

    /* Send queued transactions as possible */
    rc = txnQ_RunScheduler (pTxnQ, pTxn, MCP_FALSE); 

    MCPF_EXIT_CRIT_SEC (pTxnQ->hMcpf);

    return rc;
}
/** 
 * \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;
}
Beispiel #6
0
/** 
 * \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);
}
Beispiel #7
0
/** 
 * \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);
}
/** 
 * \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 (handle_t hTxnQ, void *hTxn)
{
    TTxnQObj   *pTxnQ   = (TTxnQObj*)hTxnQ;
    TTxnStruct *pTxn    = (TTxnStruct *)hTxn;
    McpU32   uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn);

#ifdef TRAN_DBG
    if (pTxn != pTxnQ->pCurrTxn) 
    {
        MCPF_REPORT_ERROR(pTxnQ->hMcpf, QUEUE_MODULE_LOG,
            ("%s: CB returned pTxn 0x%p  while pCurrTxn is 0x%p !!\n", __FUNCTION__, pTxn, pTxnQ->pCurrTxn));
    }
#endif

    /* Enter critical section if configured to do so */
    if (pTxnQ->bProtectTxnDone)
    {
        MCPF_ENTER_CRIT_SEC (pTxnQ->hMcpf);
    }

    /* If the function of the completed Txn is waiting for restart */
    if (pTxnQ->aFuncInfo[uFuncId].eState == FUNC_STATE_RESTART) 
    {
        /* Call function CB for current Txn with recovery indication */
        TXN_PARAM_SET_STATUS(pTxn, TXN_STATUS_RECOVERY);
        pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb (pTxnQ->aFuncInfo[uFuncId].hCbHandle, pTxn, MCP_TRUE);

        /* Clear the restarted function queues (call function CB with status=RECOVERY) */
        txnQ_ClearQueues (pTxnQ, uFuncId, MCP_TRUE);
    }

    /* In the normal case (no restart), enqueue completed transaction in TxnDone queue */
    else 
    {
        que_Enqueue (pTxnQ->hTxnDoneQueue, (handle_t)pTxn);
    }

    /* 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, MCP_TRUE); 

    /* Leave critical section if configured to do so */
    if (pTxnQ->bProtectTxnDone)
    {
        MCPF_EXIT_CRIT_SEC (pTxnQ->hMcpf);
    }
}
Beispiel #9
0
/** 
 * \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     mcpf_EnqueueMsg
 * \brief  Enqueue MCPF message
 *
 */
EMcpfRes mcpf_EnqueueMsg (handle_t		hMcpf,
                          EmcpTaskId	eDestTaskId,
                          McpU8			uDestQId,
                          TmcpfMsg  	*pMsg)
{
    Tmcpf		*pMcpf = (Tmcpf	*) hMcpf;
    TMcpfTask   *pTask = pMcpf->tTask[ eDestTaskId ];
    EMcpfRes   res;

    if (uDestQId >= pMcpf->tTask[eDestTaskId]->uNumOfQueues)
    {
        /* Destination queue is not valid */
        mcpf_mem_free_from_pool (hMcpf, pMsg);
        return RES_ERROR;
    }

    mcpf_critSec_Enter (hMcpf, pTask->hCritSecObj, MCPF_INFINIT);

    res = que_Enqueue ( pTask->hQueue[ uDestQId ], (handle_t) pMsg);

    mcpf_critSec_Exit (hMcpf, pTask->hCritSecObj);

    if (res == RES_OK)
    {
#ifdef DEBUG
        MCPF_REPORT_INFORMATION(hMcpf, MCPF_MODULE_LOG,
                                ("ENQUEUED MSG FOR TASK #%d, TO QUEUE #%d", eDestTaskId, uDestQId));
#endif

        res = os_sigobj_set (pMcpf->hPla, pTask->hSignalObj);
    }
    else
    {
        return RES_ERROR;
    }
    return res;
}
Beispiel #11
0
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;
	} 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) {
			return TXN_STATUS_ERROR;
		}
	}

	/* Send queued transactions as possible */
	rc = txnQ_RunScheduler (pTxnQ, pTxn);

	return rc;
}
Beispiel #12
0
/** 
 * \fn     cmdHndlr_InsertCommand 
 * \brief  Insert a new command to the driver
 * 
 * Insert a new command to the commands queue from user context.
 * If commands are not beeing processed set a request to start processing in the driver context.
 * Wait on the current command's signal until its processing is completed.
 * Note that this prevents the user application from sending further commands before completion.
 * 
 * \note   
 * \param  hCmdHndlr    - The module object
 * \param  cmd          - User request
 * \param  others       - The command flags, data and params
 * \return TI_OK if command processed successfully, TI_NOK if failed in processing or memory allocation.  
 * \sa     cmdHndlr_HandleCommands, cmdHndlr_Complete
 */ 
TI_STATUS cmdHndlr_InsertCommand (TI_HANDLE     hCmdHndlr,
                                  TI_UINT32     cmd,
                                  TI_UINT32     flags,
                                  void         *buffer1,
                                  TI_UINT32     buffer1_len,
                                  void         *buffer2,
                                  TI_UINT32     buffer2_len,
                                  TI_UINT32    *param3,
                                  TI_UINT32    *param4)
{
    TCmdHndlrObj     *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
	TConfigCommand   *pNewCmd;
	TI_STATUS         eStatus;

	/* Allocated command structure */
	pNewCmd = os_memoryAlloc (pCmdHndlr->hOs, sizeof (TConfigCommand));
	if (pNewCmd == NULL)
	{
		return TI_NOK;
	}
    os_memoryZero (pCmdHndlr->hOs, (void *)pNewCmd, sizeof(TConfigCommand));

	/* Copy user request into local structure */
	pNewCmd->cmd = cmd;
	pNewCmd->flags = flags;
	pNewCmd->buffer1 = buffer1;
	pNewCmd->buffer1_len = buffer1_len;
	pNewCmd->buffer2 = buffer2;
	pNewCmd->buffer2_len = buffer2_len;
	pNewCmd->param3 = param3;
	pNewCmd->param4 = param4;
	pNewCmd->pSignalObject = os_SignalObjectCreate (pCmdHndlr->hOs); /* initialize "complete-flag" */

	/* If creating the signal object failed */
	if (pNewCmd->pSignalObject == NULL)
	{
		os_printf("cmdPerform: Failed to create signalling object\n");
		/* free allocated memory and return error */
		os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand));
		return TI_NOK;
	}

    /* Indicate the start of command process, from adding it to the queue until get return status form it */  
    pNewCmd->bWaitFlag = TI_TRUE;

    /* Enter critical section to protect queue access */
    context_EnterCriticalSection (pCmdHndlr->hContext);

    /* Enqueue the command (if failed, release memory and return NOK) */
    eStatus = que_Enqueue (pCmdHndlr->hCmdQueue, (TI_HANDLE)pNewCmd);
    if (eStatus != TI_OK) 
    {
        os_printf("cmdPerform: Failed to enqueue new command\n");
        os_SignalObjectFree (pCmdHndlr->hOs, pNewCmd->pSignalObject);
        pNewCmd->pSignalObject = NULL;
        os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand));
        context_LeaveCriticalSection (pCmdHndlr->hContext);  /* Leave critical section */
        return TI_NOK;
    }

    /* 
     * Note: The bProcessingCmds flag is used for indicating if we are already processing
     *           the queued commands, so the context-engine shouldn't invoke cmdHndlr_HandleCommands.
     *       This is important because if we make this decision according to the queue being empty,
     *           there may be a command under processing (already dequeued) while the queue is empty.
     *       Note that although we are blocking the current command's originator, there may be another
     *           application that will issue a command.
     */

    if (pCmdHndlr->bProcessingCmds)
    {
        /* No need to schedule the driver (already handling commands) so just leave critical section */
        context_LeaveCriticalSection (pCmdHndlr->hContext);
    }
    else
    {
        /* Indicate that we are handling queued commands (before leaving critical section!) */
        pCmdHndlr->bProcessingCmds = TI_TRUE;

        /* Leave critical section */
        context_LeaveCriticalSection (pCmdHndlr->hContext);

        /* Request driver task schedule for command handling (after we left critical section!) */
        context_RequestSchedule (pCmdHndlr->hContext, pCmdHndlr->uContextId);
    }

	/* Wait until the command is executed */
	os_SignalObjectWait (pCmdHndlr->hOs, pNewCmd->pSignalObject);

	/* After "wait" - the command has already been processed by the drivers' context */
	/* Indicate the end of command process, from adding it to the queue until get return status form it */  
	pNewCmd->bWaitFlag = TI_FALSE;

	/* Copy the return code */
	eStatus = pNewCmd->return_code;

	/* Free signalling object and command structure */
	os_SignalObjectFree (pCmdHndlr->hOs, pNewCmd->pSignalObject);
	pNewCmd->pSignalObject = NULL;

	/* If command not completed in this context (Async) don't free the command memory */
	if(COMMAND_PENDING != pNewCmd->eCmdStatus)
	{
		os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand));
	}

	/* Return to calling process with command return code */
	return eStatus;
}
Beispiel #13
0
/** 
 * \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;
    TI_UINT32 uHlid;
    TMgmtLinkQ *pLinkQ;

    /* Find link id by destination MAC address, if not found use global link id */
    if (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_MGMT)
    {
        /* MGMT packet, use destination MAC address from WLAN header, aBuf[0] is the WLAN header */
        if ((txDataQ_LinkMacFind( pTxMgmtQ->hTxDataQ, &uHlid ,((dot11_header_t *)(pPktCtrlBlk->tTxnStruct.aBuf[0]))->address1 )) != TI_OK)
        {
            uHlid = pTxMgmtQ->uGlobalHlid;
        }
    }
    else
    {
        /* EAPOL packet, use destination MAC address from ETHERNET header, aBuf[0] is the ETHERNET header */
        if ((txDataQ_LinkMacFind( pTxMgmtQ->hTxDataQ, &uHlid, ((TEthernetHeader *)(pPktCtrlBlk->tTxnStruct.aBuf[0]))->dst)) != TI_OK)
        {
            uHlid = pTxMgmtQ->uGlobalHlid;
        }
    }
    pPktCtrlBlk->tTxDescriptor.hlid = uHlid;

    pLinkQ = &pTxMgmtQ->aMgmtLinkQ[uHlid]; /* Link queues */

    /* Always set highest TID for mgmt-queues packets. */
    pPktCtrlBlk->tTxDescriptor.tid = MGMT_QUEUES_TID; 

    if ((pLinkQ->bEncrypt)&& (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_EAPOL)) 
    {
        SET_PKT_TYPE_ENCRYPT(pPktCtrlBlk);
    }

    /* 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);

    /* Check resources per LINK and per MGMT AC (VOICE)*/
    if (txDataQ_AllocCheckResources( pTxMgmtQ->hTxDataQ, pPktCtrlBlk) != TI_OK)
    {
        pLinkQ->tDbgCounters.aDroppedPackets[uQueId]++;
        pLinkQ->tDbgCounters.uNoResourcesCount++;
        /* Leave critical section */
        context_LeaveCriticalSection (pTxMgmtQ->hContext);

        /* If the packet can't be queued drop it */
        /* !!! This call should be out of the critical section */
        txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
        return TI_NOK;
    }

    /* Enqueue the packet in the appropriate Queue */
    eStatus = que_Enqueue (pLinkQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk);

    /* Get number of packets in current queue */
    uQueSize = que_Size (pLinkQ->aQueues[uQueId]);

    /* Leave critical section */
    context_LeaveCriticalSection (pTxMgmtQ->hContext);

    /* If packet enqueued successfully */
    if (eStatus == TI_OK)
    {
        pLinkQ->tDbgCounters.aEnqueuePackets[uQueId]++;

        /* If selected queue was empty before packet insertion */
        if (uQueSize == 1 ) 
        if (uQueSize ) 
        {
            /* If called from external context (EAPOL from network), request switch to the driver's context. */
            if (bExternalContext) 
            {
                /* Set bSendEvent_NotEmpty flag to use in driver context */
                pLinkQ->bSendEvent_NotEmpty = TI_TRUE;
                context_RequestSchedule (pTxMgmtQ->hContext, pTxMgmtQ->uContextId);
            }

            /* If already in the driver's context, call the SM with QUEUES_NOT_EMPTY event. */
            else 
            {
                mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_QUEUES_NOT_EMPTY);
            }
        }
    }

    else
    {
        /* If the packet can't be queued so drop it */
        txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
        pLinkQ->tDbgCounters.aDroppedPackets[uQueId]++;
    }

    return eStatus;
}
Beispiel #14
0
TI_STATUS txDataQ_InsertPacket (TI_HANDLE hTxDataQ, TTxCtrlBlk *pPktCtrlBlk, TI_UINT8 uPacketDtag, TIntraBssBridge *pIntraBssBridgeParam)
{
	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;
	TDataLinkQ       *pLinkQ;
	TI_UINT32        uHlid;

	/* 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 */
	}

	/* Find link id by destination MAC address, if not found drop the packet */
	/* use Intra Bss bridge params*/
	if(!pIntraBssBridgeParam) {
		if (TI_UNLIKELY(MAC_MULTICAST(pEthHead->dst))) {
			uHlid = pTxDataQ->uBcastHlid;
		} else {
			if (txDataQ_LinkMacFind( hTxDataQ, &uHlid, pEthHead->dst) != TI_OK) {
				/* If the packet can't be queued drop it */
				txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
				pTxDataQ->uLinkNotFoundCount++;
				return TI_NOK;
			}
		}
	} else {
		uHlid = pIntraBssBridgeParam->uParam;
	}
	pPktCtrlBlk->tTxDescriptor.hlid = uHlid;

	pLinkQ = &pTxDataQ->aDataLinkQ[uHlid]; /* Link queues */

	pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_ETHER;
	/*  set encryption bit */
	if (pLinkQ->bEncrypt) {
		SET_PKT_TYPE_ENCRYPT(pPktCtrlBlk);
	}

	/* 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++;
#endif /* TI_DBG */
	}

	uQueId = aTidToQueueTable[pPktCtrlBlk->tTxDescriptor.tid];

	/* Check resources per LINK and per AC */
	if (txDataQ_AllocCheckResources( hTxDataQ, pPktCtrlBlk) != TI_OK) {
#ifdef TI_DBG
		pLinkQ->aQueueCounters[uQueId].uDroppedPacket++;
		pTxDataQ->uNoResourcesCount++;
#endif /* TI_DBG */

		/* Leave critical section */
		context_LeaveCriticalSection (pTxDataQ->hContext);
		/* If the packet can't be queued drop it - Should be out of the critical section */
		/* !!! This call should be out of the critical section */
		txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
		return TI_NOK;
	}

	/* Enqueue the packet in the appropriate Queue */
	eStatus = que_Enqueue (pLinkQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk);

	/* Get number of packets in current queue */
	uQueSize = que_Size (pLinkQ->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])) {
		pLinkQ->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
		pLinkQ->aQueueCounters[uQueId].uDroppedPacket++;
#endif /* TI_DBG */
	} else {
#ifdef TI_DBG
		pLinkQ->aQueueCounters[uQueId].uEnqueuePacket++;
#endif /* TI_DBG */
	}


	return eStatus;
}
/** 
 * \fn     txnQ_RunScheduler
 * \brief  Send queued transactions
 * 
 * Issue transactions as long as they are available and the bus is not occupied.
 * Call CBs of completed transactions, except conpletion of pCurrTxn (covered by the return value).
 * Note that this function can't be preempted, since it is always called in critical section 
 * See txnQ_Transact(), txnQ_SendCtrlByte(), txnQ_Run() and txnQ_TxnDoneCb().
 * 
 * \note   
 * \param  pTxnQ            - The module's object
 * \param  pCurrTxn         - The transaction inserted in the current context (NULL if none)
 * \param  bExternalContext - TRUE if called in external context (TxnDone)
 * \return COMPLETE if pCurrTxn completed in this context, PENDING if not, ERROR if failed
 * \sa     
 */ 
static ETxnStatus txnQ_RunScheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn, McpBool bExternalContext)
{
    /* Use as return value the status of the input transaction (PENDING unless sent and completed here) */
    ETxnStatus eInputTxnStatus = TXN_STATUS_PENDING; 
	McpBool loopCond = MCP_TRUE;

    /* if a previous transaction is in progress, return PENDING */
    if (pTxnQ->pCurrTxn)
    {
        return TXN_STATUS_PENDING;
    }

    /* Loop while transactions are available and can be sent to bus driver */
    while (loopCond)
    {
        TTxnStruct   *pSelectedTxn;
        ETxnStatus    eStatus;

#ifdef TRAN_DBG
#define TXN_MAX_LOOP_ITERATES 	100
		int			  loopIterates = 0;

		if (loopIterates++ >= TXN_MAX_LOOP_ITERATES)
		{
			MCPF_REPORT_WARNING (pTxnQ->hMcpf, QUEUE_MODULE_LOG, 
								 ("txnQ_RunScheduler loop reached max iterates=%d\n", loopIterates));
		}
#endif

        /* Get next enabled transaction by priority. If none, exit loop. */
        pSelectedTxn = txnQ_SelectTxn (pTxnQ);
        if (pSelectedTxn == NULL)
        {
            break;
        }

        /* Send selected transaction to bus driver */
        eStatus = busDrv_Transact (pTxnQ->hBusDrv, pSelectedTxn);

        /* If we've just sent the input transaction, use the status as the return value */
        if (pSelectedTxn == pInputTxn)
        {
            eInputTxnStatus = eStatus;
        }

        /* If transaction completed */
        if (eStatus == TXN_STATUS_COMPLETE)
        {
            /* If it's not the input transaction, enqueue it in TxnDone queue */
            if (pSelectedTxn != pInputTxn)
            {
                que_Enqueue (pTxnQ->hTxnDoneQueue, (handle_t)pSelectedTxn);
            }
        }

        /* If pending or error */
        else 
        {
            /* If transaction pending, save it to indicate that the bus driver is busy */
            if (eStatus == TXN_STATUS_PENDING)
            {
                pTxnQ->pCurrTxn = pSelectedTxn;
            }

            /* Exit loop! */
            break;
        }
    }

    /* Dequeue completed transactions and call their functional driver CB */
    /* Note that it's the functional driver CB and not the specific CB in the Txn! */
    while (loopCond)
    {
        TTxnStruct      *pCompletedTxn;
        McpU32        uFuncId;
        TTxnQueueDoneCb  fTxnQueueDoneCb;
        handle_t        hCbHandle;

        pCompletedTxn   = (TTxnStruct *) que_Dequeue (pTxnQ->hTxnDoneQueue);
        if (pCompletedTxn == NULL)
        {
            /* Return the status of the input transaction (PENDING unless sent and completed here) */
            return eInputTxnStatus;
        }

        uFuncId         = TXN_PARAM_GET_FUNC_ID(pCompletedTxn);
        fTxnQueueDoneCb = pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb;
        hCbHandle       = pTxnQ->aFuncInfo[uFuncId].hCbHandle;

        fTxnQueueDoneCb (hCbHandle, pCompletedTxn, bExternalContext);
    }

	return TXN_STATUS_PENDING;
}
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;
}
Beispiel #17
0
/** 
 * \fn     txnQ_Scheduler
 * \brief  Send queued transactions
 * 
 * Issue transactions as long as they are available and the bus is not occupied.
 * Call CBs of completed transactions, except completion of pInputTxn (covered by the return value).
 * Note that this function is called from either internal or external (TxnDone) context.
 * However, the txnQ_RunScheduler which calls it, prevents scheduler reentry.
 * 
 * \note   
 * \param  pTxnQ     - The module's object
 * \param  pInputTxn - The transaction inserted in the current context (NULL if none)
 * \return COMPLETE if pInputTxn completed in this context, PENDING if not, ERROR if failed
 * \sa     txnQ_RunScheduler
 */ 
static ETxnStatus txnQ_Scheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn)
{
    ETxnStatus eInputTxnStatus;  

    /* Use as return value the status of the input transaction (PENDING unless sent and completed here) */
    eInputTxnStatus = TXN_STATUS_PENDING;  

    /* if a previous transaction is in progress, return PENDING */
    if (pTxnQ->pCurrTxn)
    {
        TRACE1(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): pCurrTxn isn't null (0x%x) so exit\n", pTxnQ->pCurrTxn);
        return TXN_STATUS_PENDING;
    }

    /* Loop while transactions are available and can be sent to bus driver */
    while (1)
    {
        TTxnStruct   *pSelectedTxn;
        ETxnStatus    eStatus;

        /* Get next enabled transaction by priority. If none, exit loop. */
        context_EnterCriticalSection (pTxnQ->hContext);
        pSelectedTxn = txnQ_SelectTxn (pTxnQ);
        context_LeaveCriticalSection (pTxnQ->hContext);
        if (pSelectedTxn == NULL)
        {
            break;
        }

        /* Save transaction in case it will be async (to indicate that the bus driver is busy) */
        pTxnQ->pCurrTxn = pSelectedTxn;

        /* Send selected transaction to bus driver */
        eStatus = busDrv_Transact (pTxnQ->hBusDrv, pSelectedTxn);

        /* If we've just sent the input transaction, use the status as the return value */
        if (pSelectedTxn == pInputTxn)
        {
            eInputTxnStatus = eStatus;
        }

        TRACE3(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): Txn 0x%x sent, status = %d, eInputTxnStatus = %d\n", pSelectedTxn, eStatus, eInputTxnStatus);

        /* If transaction completed */
        if (eStatus != TXN_STATUS_PENDING)
        {
            pTxnQ->pCurrTxn = NULL;

            /* If it's not the input transaction, enqueue it in TxnDone queue */
            if (pSelectedTxn != pInputTxn)
            {
                TI_STATUS eStatus;

                context_EnterCriticalSection (pTxnQ->hContext);
                eStatus = que_Enqueue (pTxnQ->hTxnDoneQueue, (TI_HANDLE)pSelectedTxn);
                if (eStatus != TI_OK)
                {
                    TRACE3(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_Scheduler(): Enqueue failed, pTxn=0x%x, HwAddr=0x%x, Len0=%d\n", pSelectedTxn, pSelectedTxn->uHwAddr, pSelectedTxn->aLen[0]);
                }
                context_LeaveCriticalSection (pTxnQ->hContext);
            }
        }

        /* If pending Exit loop! */
        else 
        {
            break;
        }
    }

    /* Dequeue completed transactions and call their functional driver CB */
    /* Note that it's the functional driver CB and not the specific CB in the Txn! */
    while (1)
    {
        TTxnStruct      *pCompletedTxn;
        TI_UINT32        uFuncId;
        TTxnQueueDoneCb  fTxnQueueDoneCb;
        TI_HANDLE        hCbHandle;

        context_EnterCriticalSection (pTxnQ->hContext);
        pCompletedTxn   = (TTxnStruct *) que_Dequeue (pTxnQ->hTxnDoneQueue);
        context_LeaveCriticalSection (pTxnQ->hContext);
        if (pCompletedTxn == NULL)
        {
            /* Return the status of the input transaction (PENDING unless sent and completed here) */
            return eInputTxnStatus;
        }

        TRACE1(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): Calling TxnDone for Txn 0x%x\n", pCompletedTxn);

        uFuncId         = TXN_PARAM_GET_FUNC_ID(pCompletedTxn);
        fTxnQueueDoneCb = pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb;
        hCbHandle       = pTxnQ->aFuncInfo[uFuncId].hCbHandle;

        fTxnQueueDoneCb (hCbHandle, pCompletedTxn);
    }
}