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; }
/** * \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 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; } 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; }
/** * \fn busDrv_SendTxnParts * \brief Send prepared transaction parts * * Called first by busDrv_Transact(), and also from TxnDone CB after Async completion. * Sends the prepared transaction parts in a loop. * If a transaction part is Async, the loop continues later in the TxnDone ISR context. * When all parts are done, the upper layer TxnDone CB is called. * * \note * \param pBusDrv - The module's object * \return void * \sa busDrv_Transact, busDrv_PrepareTxnParts */ static void busDrv_SendTxnParts (TBusDrvObj *pBusDrv) { ETxnStatus eStatus; TTxnPart *pTxnPart; TTxnStruct *pTxn = pBusDrv->pCurrTxn; /* While there are transaction parts to send */ while (pBusDrv->uCurrTxnPartsCount < pBusDrv->uCurrTxnPartsNum) { pTxnPart = &(pBusDrv->aTxnParts[pBusDrv->uCurrTxnPartsCount]); pBusDrv->uCurrTxnPartsCount++; /* Assume pending to be ready in case we are preempted by the TxnDon CB !! */ pBusDrv->eCurrTxnStatus = TXN_STATUS_PENDING; /* If single step, send ELP byte */ if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) { /* Overwrite the function id with function 0 - for ELP register !!!! */ eStatus = sdioAdapt_TransactBytes (TXN_FUNC_ID_CTRL, pTxnPart->uHwAddr, pTxnPart->pHostAddr, pTxnPart->uLength, TXN_PARAM_GET_DIRECTION(pTxn), pTxnPart->bMore); /* If first write failed try once again (may happen once upon chip wakeup) */ if (eStatus == TXN_STATUS_ERROR) { /* Overwrite the function id with function 0 - for ELP register !!!! */ eStatus = sdioAdapt_TransactBytes (TXN_FUNC_ID_CTRL, pTxnPart->uHwAddr, pTxnPart->pHostAddr, pTxnPart->uLength, TXN_PARAM_GET_DIRECTION(pTxn), pTxnPart->bMore); TRACE0(pBusDrv->hReport, REPORT_SEVERITY_WARNING, "busDrv_SendTxnParts: SDIO Single-Step transaction failed once so try again"); } } else { eStatus = sdioAdapt_Transact (TXN_PARAM_GET_FUNC_ID(pTxn), pTxnPart->uHwAddr, pTxnPart->pHostAddr, pTxnPart->uLength, TXN_PARAM_GET_DIRECTION(pTxn), pTxnPart->bBlkMode, ((TXN_PARAM_GET_FIXED_ADDR(pTxn) == 1) ? 0 : 1), pTxnPart->bMore); } TRACE7(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_SendTxnParts: PartNum = %d, SingleStep = %d, Direction = %d, HwAddr = 0x%x, HostAddr = 0x%x, Length = %d, BlkMode = %d\n", pBusDrv->uCurrTxnPartsCount-1, TXN_PARAM_GET_SINGLE_STEP(pTxn), TXN_PARAM_GET_DIRECTION(pTxn), pTxnPart->uHwAddr, pTxnPart->pHostAddr, pTxnPart->uLength, pTxnPart->bBlkMode); /* If pending TxnDone (Async), continue this loop in the next TxnDone interrupt */ if (eStatus == TXN_STATUS_PENDING) { return; } /* Update current transaction status to deduce if it is all finished in the original context (Sync) or not. */ pBusDrv->eCurrTxnStatus = eStatus; pBusDrv->uCurrTxnPartsCountSync++; /* If error, set error in Txn struct, call TxnDone CB if not fully sync, and exit */ if (eStatus == TXN_STATUS_ERROR) { TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_ERROR); if (pBusDrv->uCurrTxnPartsCountSync != pBusDrv->uCurrTxnPartsCount) { pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pTxn); } return; } } /* If we got here we sent all buffers and we don't pend transaction end */ TRACE3(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_SendTxnParts: Txn finished successfully, Status = %d, PartsCount = %d, SyncCount = %d\n", pBusDrv->eCurrTxnStatus, pBusDrv->uCurrTxnPartsCount, pBusDrv->uCurrTxnPartsCountSync); /* For read transaction, copy the data from the DMA-able buffer to the host buffer(s) */ if (TXN_PARAM_GET_DIRECTION(pTxn) == TXN_DIRECTION_READ) { TI_UINT32 uBufNum; TI_UINT32 uBufLen; TI_UINT8 *pDmaBuf = pBusDrv->pRxDmaBuf; /* After the read transaction the data is in the Rx DMA buffer */ for (uBufNum = 0; uBufNum < MAX_XFER_BUFS; uBufNum++) { uBufLen = pTxn->aLen[uBufNum]; /* If no more buffers, exit the loop */ if (uBufLen == 0) { break; } os_memoryCopy (pBusDrv->hOs, pTxn->aBuf[uBufNum], pDmaBuf, uBufLen); pDmaBuf += uBufLen; } } /* If not fully sync, call TxnDone CB */ if (pBusDrv->uCurrTxnPartsCountSync != pBusDrv->uCurrTxnPartsCount) { pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pTxn); } }
/** * \fn ifSlpMng_HandleRxEvent * \brief Interface Sleep Manager state machine for Rx event * * Process Rx event of Interface Sleep Manager state machine * */ EIfSlpMngStatus ifSlpMng_HandleRxEvent (handle_t hIfSlpMng, TTxnStruct *pTxn) { TifSlpMngObj * pIfSlpMng = (TifSlpMngObj *) hIfSlpMng; EIfSlpMngStatus eRes = IfSlpMng_ERR; McpBool stateChanged = MCP_FALSE; if (TXN_PARAM_GET_SINGLE_STEP (pTxn)) { /* IfSlpMng transaction is always single step, * get IfSlpMng opcode from transaction structure */ eRes = IfSlpMng_SLP_PKT_TYPE; switch (TXN_PARAM_GET_IFSLPMNG_OP (pTxn)) { case TXN_PARAM_IFSLPMNG_OP_SLEEP: MCPF_REPORT_DEBUG_RX(pIfSlpMng->hMcpf, IFSLPMNG_MODULE_LOG, ("ifSlpMng_HandleRxEvent: SLEEP_IND, state=%d\n",pIfSlpMng->eState)); MCPF_ENTER_CRIT_SEC (pIfSlpMng->hMcpf); if (pIfSlpMng->eState == IFSLPMNG_STATE_AWAKE) { pIfSlpMng->eState = IFSLPMNG_STATE_WAIT_FOR_SLEEPACK_TX_COMPL; stateChanged = MCP_TRUE; } pIfSlpMng->stat.SleepInd_Rx++; MCPF_EXIT_CRIT_SEC (pIfSlpMng->hMcpf); if (stateChanged) { txnQ_Stop (pIfSlpMng->hTxnQ, pIfSlpMng->uFuncId); /* Prepare and send SleepAck request */ TXN_PARAM_SET_IFSLPMNG_OP (pIfSlpMng->pMngTxn, TXN_PARAM_IFSLPMNG_OP_SLEEP_ACK); txnQ_Transact (pIfSlpMng->hTxnQ, pIfSlpMng->pMngTxn); pIfSlpMng->stat.SleepAck_Tx++; } break; case TXN_PARAM_IFSLPMNG_OP_SLEEP_ACK: MCPF_REPORT_ERROR (pIfSlpMng->hMcpf, IFSLPMNG_MODULE_LOG, ("%s: Not expected SleepAck received\n", __FUNCTION__)); pIfSlpMng->stat.SleepAck_Rx++; break; case TXN_PARAM_IFSLPMNG_OP_AWAKE: { EIfSlpMngState oldState; MCPF_REPORT_DEBUG_RX(pIfSlpMng->hMcpf, IFSLPMNG_MODULE_LOG, ("ifSlpMng_HandleRxEvent: AWAKE_IND, state=%d\n",pIfSlpMng->eState)); MCPF_ENTER_CRIT_SEC (pIfSlpMng->hMcpf); oldState = pIfSlpMng->eState; if ((pIfSlpMng->eState == IFSLPMNG_STATE_ASLEEP) || (pIfSlpMng->eState == IFSLPMNG_STATE_WAIT_FOR_AWAKE_ACK)) { pIfSlpMng->eState = IFSLPMNG_STATE_AWAKE; stateChanged = MCP_TRUE; } pIfSlpMng->stat.AwakeInd_Rx++; MCPF_EXIT_CRIT_SEC (pIfSlpMng->hMcpf); if (stateChanged) { switch (oldState) { case IFSLPMNG_STATE_ASLEEP: /* Prepare and send SleepAck request */ TXN_PARAM_SET_IFSLPMNG_OP (pIfSlpMng->pMngTxn, TXN_PARAM_IFSLPMNG_OP_AWAKE_ACK); txnQ_Transact (pIfSlpMng->hTxnQ, pIfSlpMng->pMngTxn); txnQ_Run (pIfSlpMng->hTxnQ, pIfSlpMng->uFuncId); pIfSlpMng->stat.AwakeAck_Tx++; break; case IFSLPMNG_STATE_WAIT_FOR_AWAKE_ACK: txnQ_Run (pIfSlpMng->hTxnQ, pIfSlpMng->uFuncId); break; default: break; } } } break; case TXN_PARAM_IFSLPMNG_OP_AWAKE_ACK: MCPF_REPORT_DEBUG_RX(pIfSlpMng->hMcpf, IFSLPMNG_MODULE_LOG, ("ifSlpMng_HandleRxEvent: AWAKE_ACK, state=%d\n",pIfSlpMng->eState)); MCPF_ENTER_CRIT_SEC (pIfSlpMng->hMcpf); if (pIfSlpMng->eState == IFSLPMNG_STATE_WAIT_FOR_AWAKE_ACK) { pIfSlpMng->eState = IFSLPMNG_STATE_AWAKE; stateChanged = MCP_TRUE; } pIfSlpMng->stat.AwakeAck_Rx++; MCPF_EXIT_CRIT_SEC (pIfSlpMng->hMcpf); if (stateChanged) { txnQ_Run (pIfSlpMng->hTxnQ, pIfSlpMng->uFuncId); } break; default: MCPF_REPORT_ERROR (pIfSlpMng->hMcpf, IFSLPMNG_MODULE_LOG, ("%s: Invalid IfSlpMng opcode=%u\n", __FUNCTION__, TXN_PARAM_GET_IFSLPMNG_OP (pTxn))); eRes = IfSlpMng_ERR; break; } /* Rx IFSLPMNG_OP */ } else { /* Normal packet received */ MCPF_ENTER_CRIT_SEC (pIfSlpMng->hMcpf); if (pIfSlpMng->eState == IFSLPMNG_STATE_ASLEEP) { pIfSlpMng->eState = IFSLPMNG_STATE_AWAKE; stateChanged = MCP_TRUE; pIfSlpMng->stat.AwakeAck_Tx++; } MCPF_EXIT_CRIT_SEC (pIfSlpMng->hMcpf); if (stateChanged) { /* Prepare and send SleepAck request */ TXN_PARAM_SET_IFSLPMNG_OP (pIfSlpMng->pMngTxn, TXN_PARAM_IFSLPMNG_OP_AWAKE_ACK); txnQ_Transact (pIfSlpMng->hTxnQ, pIfSlpMng->pMngTxn); txnQ_Run (pIfSlpMng->hTxnQ, pIfSlpMng->uFuncId); MCPF_REPORT_DEBUG_RX(pIfSlpMng->hMcpf, IFSLPMNG_MODULE_LOG, ("ifSlpMng_HandleRxEvent: Normal RX, state=%d\n",pIfSlpMng->eState)); } eRes = IfSlpMng_OK; } return eRes; }