diff options
| author | Leo Chang <schang@qca.qualcomm.com> | 2015-02-17 19:10:32 -0800 |
|---|---|---|
| committer | AnjaneeDevi Kapparapu <c_akappa@qti.qualcomm.com> | 2015-02-24 16:23:40 +0530 |
| commit | e4b43adc142e3a3e1978713f46f14070eaddb139 (patch) | |
| tree | 5a1ae449b3cf1c8d316ac4d0ce0ab0f7478e7e11 | |
| parent | 819880fa52b429edf3a826255829f6a0d3057f51 (diff) | |
qca-cld: ipa: IPA UC sync init
WLAN IPA UC data path initialize should be sync up with UC load
status. If UC driver is not loaded when WLAN driver loading,
WLAN UC data path initialize should be delayed till UC driver
will be ready
Change-Id: I297a53d1913ec4d88a5c51794959dcfebf85b45b
CRs-fixed: 786656
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_ipa.c | 240 |
1 files changed, 203 insertions, 37 deletions
diff --git a/CORE/HDD/src/wlan_hdd_ipa.c b/CORE/HDD/src/wlan_hdd_ipa.c index 641858b5d073..8c85e62871b8 100644 --- a/CORE/HDD/src/wlan_hdd_ipa.c +++ b/CORE/HDD/src/wlan_hdd_ipa.c @@ -78,6 +78,7 @@ typedef enum { HDD_IPA_UC_OPCODE_RX_SUSPEND = 2, HDD_IPA_UC_OPCODE_RX_RESUME = 3, HDD_IPA_UC_OPCODE_STATS = 4, + HDD_IPA_UC_OPCODE_UC_READY = 5, /* keep this last */ HDD_IPA_UC_OPCODE_MAX } hdd_ipa_uc_op_code; @@ -438,6 +439,9 @@ struct hdd_ipa_priv { uint32_t ipa_p_tx_packets; uint32_t ipa_p_rx_packets; hdd_ipa_uc_stat_reason stat_req_reason; + struct ipa_wdi_in_params cons_pipe_in; + struct ipa_wdi_in_params prod_pipe_in; + v_BOOL_t uc_loaded; #endif /* IPA_UC_OFFLOAD */ }; @@ -457,6 +461,7 @@ static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data); static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data); +static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type); #ifdef IPA_UC_OFFLOAD extern int process_wma_set_command(int sessid, int paramid, @@ -954,6 +959,66 @@ static int hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa) return 0; } +static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt) +{ + hdd_context_t *hdd_ctx = ipa_ctxt->hdd_ctx; + struct ipa_wdi_out_params pipe_out; + + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, + "%s : UC READY", __func__); + if (VOS_TRUE == ipa_ctxt->uc_loaded) { + HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO_HIGH, + "%s : UC already loaded", __func__); + return; + } + + ipa_ctxt->uc_loaded = VOS_TRUE; + /* Connect pipe */ + ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out); + ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl; + hdd_ctx->tx_comp_doorbell_paddr = (v_U32_t)pipe_out.uc_door_bell_pa; + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, + "%s : TX PIPE Handle %d, DBPA 0x%x", + __func__, ipa_ctxt->tx_pipe_handle, (v_U32_t)pipe_out.uc_door_bell_pa); + + + ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out); + ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl; + hdd_ctx->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa; + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, + "%s : RX PIPE Handle %d, DBPA 0x%x", + __func__, ipa_ctxt->rx_pipe_handle, (v_U32_t)pipe_out.uc_door_bell_pa); + + /* If already any STA connected, enable IPA/FW PIPEs */ + if (ipa_ctxt->sap_num_connected_sta) { + hdd_ipa_uc_handle_first_con(ipa_ctxt); + } +} +void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt) +{ + struct hdd_ipa_priv *hdd_ipa; + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work; + + if (NULL == priv_ctxt) { + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "Invalid IPA context"); + return; + } + + hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt; + msg = (struct op_msg_type *)vos_mem_malloc(sizeof(struct op_msg_type)); + msg->op_code = HDD_IPA_UC_OPCODE_UC_READY; + + uc_op_work = &hdd_ipa->uc_op_work[msg->op_code]; + if (uc_op_work->msg) + /* When the same uC OPCODE is already pended, just return */ + return; + + uc_op_work->msg = msg; + schedule_work(&uc_op_work->work); + return; +} + static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) { struct op_msg_type *msg = op_msg; @@ -962,6 +1027,9 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) struct hdd_ipa_priv *hdd_ipa; hdd_context_t *hdd_ctx; VOS_STATUS status = VOS_STATUS_SUCCESS; + struct ipa_msg_meta meta; + struct ipa_wlan_msg *ipa_msg; + int ret = 0; if (!op_msg || !usr_ctxt) { HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, @@ -998,17 +1066,59 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) hdd_ipa->activated_fw_pipe++; if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) { hdd_ipa->resource_loading = VOS_FALSE; + + /* WDI enable message to IPA */ + meta.msg_len = sizeof(*ipa_msg); + ipa_msg = adf_os_mem_alloc(NULL, meta.msg_len); + if (ipa_msg == NULL) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "msg allocation failed"); + adf_os_mem_free(op_msg); + vos_lock_release(&hdd_ipa->event_lock); + return; + } + + meta.msg_type = WLAN_WDI_ENABLE; + hddLog(VOS_TRACE_LEVEL_INFO, + "ipa_send_msg(Evt:%d)", meta.msg_type); + ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn); + if (ret) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "ipa_send_msg(Evt:%d) - fail=%d", + meta.msg_type, ret); + adf_os_mem_free(ipa_msg); + } hdd_ipa_uc_proc_pending_event(hdd_ipa); } vos_lock_release(&hdd_ipa->event_lock); - } - - if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) || + } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) || (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) { vos_lock_acquire(&hdd_ipa->event_lock); hdd_ipa->activated_fw_pipe--; if (!hdd_ipa->activated_fw_pipe) { hdd_ipa_uc_disable_pipes(hdd_ipa); + + /* WDI disable message to IPA */ + meta.msg_len = sizeof(*ipa_msg); + ipa_msg = adf_os_mem_alloc(NULL, meta.msg_len); + if (ipa_msg == NULL) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "msg allocation failed"); + vos_lock_release(&hdd_ipa->event_lock); + adf_os_mem_free(op_msg); + return; + } + meta.msg_type = WLAN_WDI_DISABLE; + hddLog(VOS_TRACE_LEVEL_INFO, + "ipa_send_msg(Evt:%d)", meta.msg_type); + ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn); + if (ret) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "ipa_send_msg(Evt:%d) - fail=%d", + meta.msg_type, ret); + adf_os_mem_free(ipa_msg); + } + if ((hdd_ipa_is_rm_enabled(hdd_ipa)) && (!ipa_rm_release_resource(IPA_RM_RESOURCE_WLAN_PROD))) { /* Sync return success from IPA @@ -1223,7 +1333,12 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) uc_fw_stat->rx_num_ind_drop_no_buf + uc_fw_stat->rx_num_pkts_indicated); vos_lock_release(&hdd_ipa->event_lock); + } else if (HDD_IPA_UC_OPCODE_UC_READY == msg->op_code) { + vos_lock_acquire(&hdd_ipa->event_lock); + hdd_ipa_uc_loaded_handler(hdd_ipa); + vos_lock_release(&hdd_ipa->event_lock); } + adf_os_mem_free(op_msg); } @@ -1290,6 +1405,10 @@ static VOS_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) struct ipa_wdi_out_params pipe_out; struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; uint8_t i; + struct ipa_wdi_db_params dbpa; + + vos_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params)); + vos_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params)); vos_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params)); vos_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params)); @@ -1323,22 +1442,37 @@ static VOS_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) pipe_in.u.dl.ce_ring_size = hdd_ctx->ce_sr_ring_size * 8; pipe_in.u.dl.num_tx_buffers = hdd_ctx->tx_num_alloc_buffer; - /* Connect WDI IPA PIPE */ - ipa_connect_wdi_pipe(&pipe_in, &pipe_out); - /* Micro Controller Doorbell register */ - hdd_ctx->tx_comp_doorbell_paddr = (v_U32_t)pipe_out.uc_door_bell_pa; - /* WLAN TX PIPE Handle */ - ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl; - HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO_HIGH, - "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x," - " CERZ %d, NB %d, CDBPAD 0x%x", - (unsigned int)pipe_in.u.dl.comp_ring_base_pa, - pipe_in.u.dl.comp_ring_size, - (unsigned int)pipe_in.u.dl.ce_ring_base_pa, - (unsigned int)pipe_in.u.dl.ce_door_bell_pa, - pipe_in.u.dl.ce_ring_size, - pipe_in.u.dl.num_tx_buffers, - (unsigned int)hdd_ctx->tx_comp_doorbell_paddr); + vos_mem_copy(&ipa_ctxt->cons_pipe_in, + &pipe_in, + sizeof(struct ipa_wdi_in_params)); + dbpa.client = IPA_CLIENT_WLAN1_CONS; + ipa_uc_wdi_get_dbpa(&dbpa); + HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO, + "%s CONS DB get dbpa 0x%x", + __func__, (unsigned int)dbpa.uc_door_bell_pa); + hdd_ctx->tx_comp_doorbell_paddr = dbpa.uc_door_bell_pa; + if (VOS_TRUE == ipa_ctxt->uc_loaded) { + /* Connect WDI IPA PIPE */ + ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out); + /* Micro Controller Doorbell register */ + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, + "%s CONS DB pipe out 0x%x", + __func__, (unsigned int)pipe_out.uc_door_bell_pa); + + hdd_ctx->tx_comp_doorbell_paddr = (v_U32_t)pipe_out.uc_door_bell_pa; + /* WLAN TX PIPE Handle */ + ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl; + HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO_HIGH, + "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x," + " CERZ %d, NB %d, CDBPAD 0x%x", + (unsigned int)pipe_in.u.dl.comp_ring_base_pa, + pipe_in.u.dl.comp_ring_size, + (unsigned int)pipe_in.u.dl.ce_ring_base_pa, + (unsigned int)pipe_in.u.dl.ce_door_bell_pa, + pipe_in.u.dl.ce_ring_size, + pipe_in.u.dl.num_tx_buffers, + (unsigned int)hdd_ctx->tx_comp_doorbell_paddr); + } /* RX PIPE */ pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; @@ -1360,17 +1494,29 @@ static VOS_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) pipe_in.u.ul.rdy_ring_size = hdd_ctx->rx_rdy_ring_size; pipe_in.u.ul.rdy_ring_rp_pa = hdd_ctx->rx_proc_done_idx_paddr; - - ipa_connect_wdi_pipe(&pipe_in, &pipe_out); - hdd_ctx->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa; - ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl; - HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO_HIGH, - "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x", - (unsigned int)pipe_in.u.ul.rdy_ring_base_pa, - pipe_in.u.ul.rdy_ring_size, - (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa, - (unsigned int)hdd_ctx->rx_ready_doorbell_paddr); - + vos_mem_copy(&ipa_ctxt->prod_pipe_in, + &pipe_in, + sizeof(struct ipa_wdi_in_params)); + dbpa.client = IPA_CLIENT_WLAN1_PROD; + ipa_uc_wdi_get_dbpa(&dbpa); + hdd_ctx->rx_ready_doorbell_paddr = dbpa.uc_door_bell_pa; + HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO, + "%s PROD DB get dbpa 0x%x", + __func__, (unsigned int)dbpa.uc_door_bell_pa); + if (VOS_TRUE == ipa_ctxt->uc_loaded) { + ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out); + hdd_ctx->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa; + ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl; + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, + "%s PROD DB pipe out 0x%x", + __func__, (unsigned int)pipe_out.uc_door_bell_pa); + HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO_HIGH, + "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x", + (unsigned int)pipe_in.u.ul.rdy_ring_base_pa, + pipe_in.u.ul.rdy_ring_size, + (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa, + (unsigned int)hdd_ctx->rx_ready_doorbell_paddr); + } WLANTL_SetUcDoorbellPaddr((pVosContextType)(hdd_ctx->pvosContext), (v_U32_t)hdd_ctx->tx_comp_doorbell_paddr, (v_U32_t)hdd_ctx->rx_ready_doorbell_paddr); @@ -3361,6 +3507,7 @@ int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, && (!hdd_ipa_uc_sta_is_enabled(hdd_ipa) || !hdd_ipa->sta_connected) #endif + && (VOS_TRUE == hdd_ipa->uc_loaded) ) { ret = hdd_ipa_uc_handle_first_con(hdd_ipa); if (!ret) { @@ -3370,7 +3517,7 @@ int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, } else { vos_lock_release(&hdd_ipa->event_lock); return ret; - } + } } vos_lock_release(&hdd_ipa->event_lock); } @@ -3403,6 +3550,7 @@ int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, && (!hdd_ipa_uc_sta_is_enabled(hdd_ipa) || !hdd_ipa->sta_connected) #endif + && (VOS_TRUE == hdd_ipa->uc_loaded) ) { hdd_ipa_uc_handle_last_discon(hdd_ipa); } @@ -3754,6 +3902,9 @@ VOS_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx) struct hdd_ipa_priv *hdd_ipa = NULL; int ret, i; struct hdd_ipa_iface_context *iface_context = NULL; +#ifdef IPA_UC_OFFLOAD + struct ipa_wdi_uc_ready_params uc_ready_param; +#endif /* IPA_UC_OFFLOAD */ if (!hdd_ipa_is_enabled(hdd_ctx)) return VOS_STATUS_SUCCESS; @@ -3809,6 +3960,19 @@ VOS_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx) goto fail_create_sys_pipe; } #endif + hdd_ipa->uc_loaded = VOS_FALSE; + uc_ready_param.priv = (void *)hdd_ipa; + uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb; + if (ipa_uc_reg_rdyCB(&uc_ready_param)) { + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, + "UC Ready CB register fail"); + goto fail_setup_rm; + } + if (TRUE == uc_ready_param.is_uC_ready) { + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, + "UC Ready"); + hdd_ipa->uc_loaded = VOS_TRUE; + } hdd_ipa_uc_ol_init(hdd_ctx); } else #endif /* IPA_UC_OFFLOAD */ @@ -3918,12 +4082,14 @@ VOS_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx) #ifdef IPA_UC_OFFLOAD if (hdd_ipa_uc_is_enabled(hdd_ipa)) { - HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO, - "%s: Disconnect TX PIPE", __func__); - ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle); - HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO, - "%s: Disconnect RX PIPE", __func__); - ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (VOS_TRUE == hdd_ipa->uc_loaded) { + HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO, + "%s: Disconnect TX PIPE", __func__); + ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle); + HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO, + "%s: Disconnect RX PIPE", __func__); + ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle); + } vos_lock_destroy(&hdd_ipa->event_lock); vos_list_destroy(&hdd_ipa->pending_event); #ifdef WLAN_OPEN_SOURCE |
