static INT32 _stp_btm_put_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) { INT32 ret; if (!pOpQ || !pOp) { STP_BTM_WARN_FUNC("invalid input param: 0x%p, 0x%p\n", pOpQ, pOp); return 0; /* ;MTK_WCN_BOOL_FALSE; */ } ret = 0; osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); /* acquire lock success */ if (!RB_FULL(pOpQ)) RB_PUT(pOpQ, pOp); else ret = -1; osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); if (ret) { STP_BTM_WARN_FUNC("RB_FULL(0x%p) %d ,rFreeOpQ = %p, rActiveOpQ = %p\n", pOpQ, RB_COUNT(pOpQ), &stp_btm->rFreeOpQ, &stp_btm->rActiveOpQ); return 0; } else { /* STP_BTM_WARN_FUNC("RB_COUNT = %d\n",RB_COUNT(pOpQ)); */ return 1; } }
static P_OSAL_OP _stp_btm_get_op ( MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ ) { P_OSAL_OP pOp; INT32 ret = 0; if (!pOpQ) { STP_BTM_WARN_FUNC("!pOpQ \n"); return NULL; } osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); if (ret) { STP_BTM_WARN_FUNC("mutex_lock_interruptible (%d) \n", ret); return NULL; } /* acquire lock success */ RB_GET(pOpQ, pOp); osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); if (!pOp) { //STP_BTM_WARN_FUNC("RB_GET fail\n"); } return pOp; }
static inline INT32 _stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm){ P_OSAL_OP pOp; INT32 bRet; INT32 retval; if(stp_btm == NULL) { return STP_BTM_OPERATION_FAIL; } else { pOp = _stp_btm_get_free_op(stp_btm); if (!pOp) { STP_BTM_WARN_FUNC("get_free_lxop fail \n"); return -1;//break; } pOp->op.opId = STP_OPID_BTM_RETRY; pOp->signal.timeoutValue= 0; bRet = _stp_btm_put_act_op(stp_btm, pOp); STP_BTM_DBG_FUNC("OPID(%d) type(%d) bRet(%d) \n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; } return retval; }
static inline INT32 _stp_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm) { #if 0 P_OSAL_OP pOp; INT32 bRet; INT32 retval; if (stp_btm == NULL) { return STP_BTM_OPERATION_FAIL; } else { pOp = _stp_btm_get_free_op(stp_btm); if (!pOp) { STP_BTM_WARN_FUNC("get_free_lxop fail\n"); return -1; /* break; */ } pOp->op.opId = STP_OPID_BTM_FORCE_FW_ASSERT; pOp->signal.timeoutValue = 0; bRet = _stp_btm_put_act_op(stp_btm, pOp); STP_BTM_DBG_FUNC("OPID(%d) type(%d) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; } return retval; #endif INT32 ret = -1; ret = _stp_trigger_firmware_assert_via_emi(); return ret; }
static P_OSAL_OP _stp_btm_get_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ) { P_OSAL_OP pOp; /* INT32 ret = 0; */ if (!pOpQ) { STP_BTM_WARN_FUNC("!pOpQ\n"); return NULL; } osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); /* acquire lock success */ RB_GET(pOpQ, pOp); osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); if (!pOp) STP_BTM_WARN_FUNC("RB_GET fail\n"); return pOp; }
static inline INT32 _stp_btm_do_fw_assert_via_emi(MTKSTP_BTM_T *stp_btm){ #if 0 P_OSAL_OP pOp; INT32 bRet; INT32 retval; if(stp_btm == NULL) { return STP_BTM_OPERATION_FAIL; } else { pOp = _stp_btm_get_free_op(stp_btm); if (!pOp) { STP_BTM_WARN_FUNC("get_free_lxop fail \n"); return -1;//break; } pOp->op.opId = STP_OPID_BTM_FORCE_FW_ASSERT; pOp->signal.timeoutValue= 0; bRet = _stp_btm_put_act_op(stp_btm, pOp); STP_BTM_DBG_FUNC("OPID(%d) type(%d) bRet(%d) \n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; } return retval; #endif INT32 ret = -1; ret = _stp_trigger_firmware_assert_via_emi(); #if 0 if(0 != _stp_get_dump_info(EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1)) { STP_BTM_INFO_FUNC("EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1 has not clear,reset it\n"); _stp_set_dump_info(EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, 0x0); } else { STP_BTM_INFO_FUNC("EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1 reset by fw side\n"); } #endif return ret; }
static inline INT32 _stp_btm_dump_type(MTKSTP_BTM_T *stp_btm, ENUM_STP_BTM_OPID_T opid) { P_OSAL_OP pOp; INT32 bRet; INT32 retval; pOp = _stp_btm_get_free_op(stp_btm); if (!pOp) { STP_BTM_WARN_FUNC("get_free_lxop fail\n"); return -1; /* break; */ } pOp->op.opId = opid; pOp->signal.timeoutValue = 0; bRet = _stp_btm_put_act_op(stp_btm, pOp); STP_BTM_DBG_FUNC("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); retval = (0 == bRet) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; return retval; }
static INT32 stp_btm_dump_send_retry_handler(PINT8 tmp, INT32 len) { if (NULL == tmp) return -1; INT32 rc = 0, nl_retry = 0; rc = stp_dbg_nl_send(tmp, 2, len+5); while (rc) { nl_retry++; if (rc == 32) { STP_BTM_ERR_FUNC("**dump send timeout : %d**\n", rc); return 1; } if (nl_retry > 1000) { STP_BTM_ERR_FUNC("**dump send fails, and retry more than 1000: %d.**\n", rc); return 2; } STP_BTM_WARN_FUNC("**dump send fails, and retry again.**\n"); osal_sleep_ms(3); rc = stp_dbg_nl_send(tmp, 2, len+5); if (!rc) STP_BTM_DBG_FUNC("****retry again ok!**\n"); } return rc; }
static INT32 _stp_btm_put_dump_to_nl(void) { #define NUM_FETCH_ENTRY 8 static UINT8 buf[2048]; static UINT8 tmp[2048]; UINT32 buf_len; STP_PACKET_T *pkt; STP_DBG_HDR_T *hdr; INT32 remain=0, index =0; INT32 retry = 0, rc = 0, nl_retry = 0; STP_BTM_INFO_FUNC("Enter..\n"); index = 0; tmp[index++]='['; tmp[index++]='M'; tmp[index++]=']'; do { index = 3; remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len); if (buf_len > 0) { pkt = (STP_PACKET_T *)buf; hdr = &pkt->hdr; if (hdr->dbg_type == STP_DBG_FW_DMP){ memcpy(&tmp[index], pkt->raw, pkt->hdr.len); if(pkt->hdr.len <= 1500) { tmp[index + pkt->hdr.len] = '\n'; tmp[index + pkt->hdr.len + 1] = '\0'; //printk("\n%s\n+++\n", tmp); rc = stp_dbg_nl_send((char *)&tmp, 2); while(rc){ nl_retry++; if(nl_retry > 1000){ break; } STP_BTM_WARN_FUNC("**dump send fails, and retry again.**\n"); msleep(3); rc = stp_dbg_nl_send((char *)&tmp, 2); if(!rc){ STP_BTM_WARN_FUNC("****retry again ok!**\n"); } } //schedule(); } else { STP_BTM_INFO_FUNC("dump entry length is over long\n"); BUG_ON(0); } retry = 0; } }else { retry ++; msleep(100); } }while((remain > 0) || (retry < 2)); STP_BTM_INFO_FUNC("Exit..\n"); return 0; }
static INT32 _stp_btm_proc (void *pvData) { MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *)pvData; P_OSAL_OP pOp; INT32 id; INT32 result; if (!stp_btm) { STP_BTM_WARN_FUNC("!stp_btm \n"); return -1; } for (;;) { pOp = NULL; osal_wait_for_event(&stp_btm->STPd_event, _stp_btm_wait_for_msg, (void *)stp_btm ); if (osal_thread_should_stop(&stp_btm->BTMd)) { STP_BTM_INFO_FUNC("should stop now... \n"); // TODO: clean up active opQ break; } /* get Op from activeQ */ pOp = _stp_btm_get_op(stp_btm, &stp_btm->rActiveOpQ); if (!pOp) { STP_BTM_WARN_FUNC("get_lxop activeQ fail\n"); continue; } id = osal_op_get_id(pOp); STP_BTM_DBG_FUNC("======> lxop_get_opid = %d, %s, remaining count = *%d*\n", id, (id >= 4)?("???"):(g_btm_op_name[id]), RB_COUNT(&stp_btm->rActiveOpQ)); if (id >= STP_OPID_BTM_NUM) { STP_BTM_WARN_FUNC("abnormal opid id: 0x%x \n", id); result = -1; goto handler_done; } result = _stp_btm_handler(stp_btm, &pOp->op); handler_done: if (result) { STP_BTM_WARN_FUNC("opid id(0x%x)(%s) error(%d)\n", id, (id >= 4)?("???"):(g_btm_op_name[id]), result); } if (osal_op_is_wait_for_signal(pOp)) { osal_op_raise_signal(pOp, result); } else { /* put Op back to freeQ */ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); } if (STP_OPID_BTM_EXIT == id) { break; } } STP_BTM_INFO_FUNC("exits \n"); return 0; };
INT32 _stp_btm_put_act_op ( MTKSTP_BTM_T *stp_btm, P_OSAL_OP pOp ) { INT32 bRet = 0; INT32 bCleanup = 0; long wait_ret = -1; P_OSAL_SIGNAL pSignal = NULL; do { if (!stp_btm || !pOp) { break; } pSignal = &pOp->signal; if (pSignal->timeoutValue) { pOp->result = -9; osal_signal_init(&pOp->signal); } /* put to active Q */ bRet = _stp_btm_put_op(stp_btm, &stp_btm->rActiveOpQ, pOp); if(0 == bRet) { STP_BTM_WARN_FUNC("put active queue fail\n"); bCleanup = 1;//MTK_WCN_BOOL_TRUE; break; } /* wake up wmtd */ osal_trigger_event(&stp_btm->STPd_event); if (pSignal->timeoutValue == 0) { bRet = 1;//MTK_WCN_BOOL_TRUE; /* clean it in wmtd */ break; } /* wait result, clean it here */ bCleanup = 1;//MTK_WCN_BOOL_TRUE; /* check result */ wait_ret = osal_wait_for_signal_timeout(&pOp->signal); STP_BTM_DBG_FUNC("wait completion:%ld\n", wait_ret); if (!wait_ret) { STP_BTM_ERR_FUNC("wait completion timeout \n"); // TODO: how to handle it? retry? } else { if (pOp->result) { STP_BTM_WARN_FUNC("op(%d) result:%d\n", pOp->op.opId, pOp->result); } bRet = (pOp->result) ? 0 : 1; } } while(0); if (bCleanup) { /* put Op back to freeQ */ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); } return bRet; }
static INT32 _stp_btm_proc(PVOID pvData) { MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData; P_OSAL_OP pOp; INT32 id; INT32 result; if (!stp_btm) { STP_BTM_WARN_FUNC("!stp_btm\n"); return -1; } for (;;) { pOp = NULL; osal_wait_for_event(&stp_btm->STPd_event, _stp_btm_wait_for_msg, (PVOID)stp_btm); if (osal_thread_should_stop(&stp_btm->BTMd)) { STP_BTM_INFO_FUNC("should stop now...\n"); /* TODO: clean up active opQ */ break; } #if 1 if (gDumplogflag) { /* pr_warn("enter place1\n"); */ if (mtk_wcn_stp_is_uart_mand_mode() || mtk_wcn_stp_is_uart_fullset_mode()) dump_uart_history(); gDumplogflag = 0; continue; } #endif /* get Op from activeQ */ pOp = _stp_btm_get_op(stp_btm, &stp_btm->rActiveOpQ); if (!pOp) { STP_BTM_WARN_FUNC("get_lxop activeQ fail\n"); continue; } id = osal_op_get_id(pOp); STP_BTM_DBG_FUNC("======> lxop_get_opid = %d, %s, remaining count = *%d*\n", id, (id >= 4) ? ("???") : (g_btm_op_name[id]), RB_COUNT(&stp_btm->rActiveOpQ)); if (id >= STP_OPID_BTM_NUM) { STP_BTM_WARN_FUNC("abnormal opid id: 0x%x\n", id); result = -1; goto handler_done; } osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); stp_btm_set_current_op(stp_btm, pOp); osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); result = _stp_btm_handler(stp_btm, &pOp->op); osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); stp_btm_set_current_op(stp_btm, NULL); osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); handler_done: if (result) { STP_BTM_WARN_FUNC("opid id(0x%x)(%s) error(%d)\n", id, (id >= 4) ? ("???") : (g_btm_op_name[id]), result); } if (osal_op_is_wait_for_signal(pOp)) { osal_op_raise_signal(pOp, result); } else { /* put Op back to freeQ */ _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); } if (STP_OPID_BTM_EXIT == id) { break; } else if (STP_OPID_BTM_RST == id) { /* prevent multi reset case */ stp_btm_reset_btm_wq(stp_btm); } } STP_BTM_INFO_FUNC("exits\n"); return 0; };
static INT32 _stp_btm_put_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) { INT32 ret; P_OSAL_OP pOp_latest; P_OSAL_OP pOp_current; INT32 flag_latest = 1; INT32 flag_current = 1; if (!pOpQ || !pOp) { STP_BTM_WARN_FUNC("invalid input param: 0x%p, 0x%p\n", pOpQ, pOp); return 0; /* ;MTK_WCN_BOOL_FALSE; */ } ret = 0; osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); /* acquire lock success */ if (&stp_btm->rFreeOpQ == pOpQ) { if (!RB_FULL(pOpQ)) RB_PUT(pOpQ, pOp); else ret = -1; } else if (pOp->op.opId == STP_OPID_BTM_RST || pOp->op.opId == STP_OPID_BTM_DUMP_TIMEOUT) { if (!RB_FULL(pOpQ)) { RB_PUT(pOpQ, pOp); STP_BTM_ERR_FUNC("RB_PUT: 0x%d\n", pOp->op.opId); } else ret = -1; } else { pOp_current = stp_btm_get_current_op(stp_btm); if (pOp_current) { if (pOp_current->op.opId == STP_OPID_BTM_RST || pOp_current->op.opId == STP_OPID_BTM_DUMP_TIMEOUT) { STP_BTM_ERR_FUNC("current: 0x%d\n", pOp_current->op.opId); flag_current = 0; } } RB_GET_LATEST(pOpQ, pOp_latest); if (pOp_latest) { if (pOp_latest->op.opId == STP_OPID_BTM_RST || pOp_latest->op.opId == STP_OPID_BTM_DUMP_TIMEOUT) { STP_BTM_ERR_FUNC("latest: 0x%d\n", pOp_latest->op.opId); flag_latest = 0; } if (pOp_latest->op.opId == pOp->op.opId) { flag_latest = 0; STP_BTM_DBG_FUNC("With the latest a command repeat: latest 0x%d,current 0x%d\n", pOp_latest->op.opId, pOp->op.opId); } } if (flag_current && flag_latest) { if (!RB_FULL(pOpQ)) { RB_PUT(pOpQ, pOp); STP_BTM_ERR_FUNC("RB_PUT: 0x%d\n", pOp->op.opId); } else ret = -1; } else ret = -1; } osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); if (ret) { STP_BTM_DBG_FUNC("RB_FULL(0x%p) %d ,rFreeOpQ = %p, rActiveOpQ = %p\n", pOpQ, RB_COUNT(pOpQ), &stp_btm->rFreeOpQ, &stp_btm->rActiveOpQ); return 0; } else { /* STP_BTM_WARN_FUNC("RB_COUNT = %d\n",RB_COUNT(pOpQ)); */ return 1; } }