diff options
| author | Yun Park <yunp@qca.qualcomm.com> | 2014-12-16 17:21:48 -0800 |
|---|---|---|
| committer | AnjaneeDevi Kapparapu <c_akappa@qti.qualcomm.com> | 2015-01-23 16:44:05 +0530 |
| commit | 225439d9f894f44542f6d6f38bd00aa344d7da16 (patch) | |
| tree | 2ab4165da368301b9934d9570ce24c2127d0af27 | |
| parent | a1f9c67fe5dc9ebf580133f92d18da45c9a88fce (diff) | |
qcacld:IPA UC: Use work queue to defer RM notification and uC OP
This change is to remove a dependency of UC_OFFLOAD with CONFIG_SMP.
Change-Id: Iaaeec1c14606dacea8ff6a2aa3c44e7a2f7b90e8
CRs-Fixed: 772119
| -rw-r--r-- | CORE/CLD_TXRX/TLSHIM/tl_shim.c | 94 | ||||
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_ipa.c | 188 | ||||
| -rwxr-xr-x[-rw-r--r--] | Kbuild | 3 |
3 files changed, 151 insertions, 134 deletions
diff --git a/CORE/CLD_TXRX/TLSHIM/tl_shim.c b/CORE/CLD_TXRX/TLSHIM/tl_shim.c index 03d9ec03d6bc..08987524e9aa 100644 --- a/CORE/CLD_TXRX/TLSHIM/tl_shim.c +++ b/CORE/CLD_TXRX/TLSHIM/tl_shim.c @@ -2408,83 +2408,6 @@ void WLANTL_SetUcActive(void *vos_ctx, } /*============================================================================= - FUNCTION WLANTL_IpaUcFwOpEventHandler - - DESCRIPTION - This function will be called by TL client. - Firmware data path activation response handler. - Firmware response will be routed to upper layer - - PARAMETERS - IN - context : pre-registered shim context - rxpkt : message pointer from firmware - staid : STA ID, not used - - RETURN VALUE - NONE - - SIDE EFFECTS - -==============================================================================*/ -void WLANTL_IpaUcFwOpEventHandler(void *context, - void *rxpkt, - u_int16_t staid) -{ - struct txrx_tl_shim_ctx *tl_shim = (struct txrx_tl_shim_ctx *)context; - - if (!tl_shim) { - TLSHIM_LOGE("%s: Invalid context", __func__); - return; - } - - if (tl_shim->fw_op_cb) { - tl_shim->fw_op_cb(rxpkt, tl_shim->usr_ctxt); - } -} - -/*============================================================================= - FUNCTION WLANTL_IpaUcOpEventHandler - - DESCRIPTION - This function will be called by TL client. - This API will be registered into OL layer and if firmware send any - Activity related notification, OL layer will call this function. - firmware indication will be serialized within TLSHIM RX Thread - - PARAMETERS - IN - op_code : OP Code from firmware - shim_ctxt : shim context pointer - - RETURN VALUE - NONE - - SIDE EFFECTS - -==============================================================================*/ -void WLANTL_IpaUcOpEventHandler(v_U8_t *op_msg, void *shim_ctxt) -{ - pVosSchedContext sched_ctx = get_vos_sched_ctxt(); - struct VosTlshimPkt *pkt; - - if (unlikely(!sched_ctx)) - return; - - pkt = vos_alloc_tlshim_pkt(sched_ctx); - if (!pkt) { - TLSHIM_LOGW("No available Rx message buffer"); - return; - } - - pkt->callback = (vos_tlshim_cb) WLANTL_IpaUcFwOpEventHandler; - pkt->context = shim_ctxt; - pkt->Rxpkt = (void *)op_msg; - pkt->staId = 0; - vos_indicate_rxpkt(sched_ctx, pkt); -} - -/*============================================================================= FUNCTION WLANTL_RegisterOPCbFnc DESCRIPTION @@ -2504,23 +2427,8 @@ void WLANTL_IpaUcOpEventHandler(v_U8_t *op_msg, void *shim_ctxt) void WLANTL_RegisterOPCbFnc(void *vos_ctx, void (*func)(v_U8_t *op_msg, void *usr_ctxt), void *usr_ctxt) { - struct txrx_tl_shim_ctx *tl_shim; - - if (!vos_ctx) { - TLSHIM_LOGE("%s: Invalid context", __func__); - return; - } - - tl_shim = vos_get_context(VOS_MODULE_ID_TL, vos_ctx); - if (NULL == tl_shim) { - TLSHIM_LOGW("Invalid TL Shim context"); - return; - } - - tl_shim->fw_op_cb = func; - tl_shim->usr_ctxt = usr_ctxt; wdi_in_ipa_uc_register_op_cb(((pVosContextType)vos_ctx)->pdev_txrx_ctx, - WLANTL_IpaUcOpEventHandler, (void *)tl_shim); + func, usr_ctxt); } #endif /* IPA_UC_OFFLOAD */ diff --git a/CORE/HDD/src/wlan_hdd_ipa.c b/CORE/HDD/src/wlan_hdd_ipa.c index 63f8f4a6cf1a..aa0a77976cf1 100644 --- a/CORE/HDD/src/wlan_hdd_ipa.c +++ b/CORE/HDD/src/wlan_hdd_ipa.c @@ -359,6 +359,16 @@ static const char *op_string[] = { "RX_RESUME", "STATS", }; + +struct uc_rm_work_struct { + struct work_struct work; + enum ipa_rm_event event; +}; + +struct uc_op_work_struct { + struct work_struct work; + struct op_msg_type *msg; +}; #endif /* IPA_UC_OFFLOAD */ struct hdd_ipa_priv { @@ -372,6 +382,10 @@ struct hdd_ipa_priv { */ adf_os_spinlock_t rm_lock; struct work_struct rm_work; +#ifdef IPA_UC_OFFLOAD + struct uc_rm_work_struct uc_rm_work; + struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX]; +#endif vos_wake_lock_t wake_lock; struct delayed_work wake_lock_work; bool wake_lock_released; @@ -840,20 +854,27 @@ static int hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa) return 0; } -static void -hdd_ipa_uc_rm_notify_handler(void *context, void *rxpkt, u_int16_t staid) +static void hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event) { - enum ipa_rm_event event_code; - struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + struct hdd_ipa_priv *hdd_ipa = context; + VOS_STATUS status = VOS_STATUS_SUCCESS; + + /* + * When SSR is going on or driver is unloading, just return. + */ + status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx); + if (0 != status) { + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "HDD context is not valid"); + return; + } if (!hdd_ipa_is_rm_enabled(hdd_ipa)) return; - vos_mem_copy(&event_code, rxpkt, sizeof(event_code)); HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO, "%s, event code %d", - __func__, event_code); + __func__, event); - switch(event_code) { + switch (event) { case IPA_RM_RESOURCE_GRANTED: /* Differed RM Granted */ hdd_ipa_uc_enable_pipes(hdd_ipa); @@ -877,37 +898,28 @@ hdd_ipa_uc_rm_notify_handler(void *context, void *rxpkt, u_int16_t staid) default: HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "%s, invalid event code %d", - __func__, event_code); + __func__, event); break; } } -static void -hdd_ipa_uc_rm_notify_defer(void *hdd_ipa, enum ipa_rm_event event) +static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work) { - pVosSchedContext sched_ctx = get_vos_sched_ctxt(); - struct VosTlshimPkt *pkt; - v_U8_t *event_code_pkt; - - if (unlikely(!sched_ctx)) - return; + enum ipa_rm_event event; + struct uc_rm_work_struct *uc_rm_work = container_of(work, + struct uc_rm_work_struct, work); + struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work, + struct hdd_ipa_priv, uc_rm_work); - pkt = vos_alloc_tlshim_pkt(sched_ctx); - if (!pkt) { - HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, - "%s, alloc fail", __func__); - return; - } - - event_code_pkt = vos_mem_malloc(sizeof(unsigned int)); - vos_mem_copy(event_code_pkt, &event, 1); + vos_ssr_protect(__func__); + event = uc_rm_work->event; HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO_HIGH, "%s, posted event %d", __func__, event); - pkt->callback = (vos_tlshim_cb)hdd_ipa_uc_rm_notify_handler; - pkt->context = hdd_ipa; - pkt->Rxpkt = (void *) event_code_pkt; - pkt->staId = 0; - vos_indicate_rxpkt(sched_ctx, pkt); + + hdd_ipa_uc_rm_notify_handler(hdd_ipa, event); + vos_ssr_unprotect(__func__); + + return; } static int hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa) @@ -939,13 +951,14 @@ static int hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa) return 0; } -static void hdd_ipa_uc_op_cb(v_U8_t *op_msg, void *usr_ctxt) +static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) { - struct op_msg_type *msg; + struct op_msg_type *msg = op_msg; struct ipa_uc_fw_stats *uc_fw_stat; struct IpaHwStatsWDIInfoData_t ipa_stat; struct hdd_ipa_priv *hdd_ipa; hdd_context_t *hdd_ctx; + VOS_STATUS status = VOS_STATUS_SUCCESS; if (!op_msg || !usr_ctxt) { HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, @@ -953,15 +966,26 @@ static void hdd_ipa_uc_op_cb(v_U8_t *op_msg, void *usr_ctxt) return; } - msg = (struct op_msg_type *)op_msg; if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) { HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "%s, INVALID OPCODE %d", __func__, msg->op_code); + adf_os_mem_free(op_msg); return; } hdd_ctx = (hdd_context_t *)usr_ctxt; hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + /* + * When SSR is going on or driver is unloading, just return. + */ + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "HDD context is not valid"); + adf_os_mem_free(op_msg); + return; + } + HDD_IPA_LOG(VOS_TRACE_LEVEL_DEBUG, "%s, OPCODE %s", __func__, op_string[msg->op_code]); @@ -1196,6 +1220,63 @@ static void hdd_ipa_uc_op_cb(v_U8_t *op_msg, void *usr_ctxt) adf_os_mem_free(op_msg); } +static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work) +{ + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work = container_of(work, + struct uc_op_work_struct, work); + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + + vos_ssr_protect(__func__); + + msg = uc_op_work->msg; + uc_op_work->msg = NULL; + HDD_IPA_LOG(VOS_TRACE_LEVEL_INFO_HIGH, + "%s, posted msg %d", __func__, msg->op_code); + + hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx); + + vos_ssr_unprotect(__func__); + + return; +} + +static void hdd_ipa_uc_op_event_handler(v_U8_t *op_msg, void *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa; + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work; + + if (NULL == hdd_ctx) { + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "Invalid HDD context"); + goto end; + } + + msg = (struct op_msg_type *)op_msg; + hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa; + + if (unlikely(!hdd_ipa)) + goto end; + + if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) { + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)", + __func__, msg->op_code); + goto end; + } + + 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 */ + goto end; + + uc_op_work->msg = msg; + schedule_work(&uc_op_work->work); + return; + +end: + adf_os_mem_free(op_msg); +} + static uint8_t hdd_ipa_uc_get_iface_id(struct hdd_ipa_priv *hdd_ipa, uint8_t session_id) { @@ -1216,6 +1297,7 @@ static VOS_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) struct ipa_wdi_in_params pipe_in; struct ipa_wdi_out_params pipe_out; struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + uint8_t i; vos_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params)); vos_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params)); @@ -1302,7 +1384,13 @@ static VOS_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) (v_U32_t)hdd_ctx->rx_ready_doorbell_paddr); WLANTL_RegisterOPCbFnc((pVosContextType)(hdd_ctx->pvosContext), - hdd_ipa_uc_op_cb, (void *)hdd_ctx); + hdd_ipa_uc_op_event_handler, (void *)hdd_ctx); + + for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) { + cnss_init_work(&ipa_ctxt->uc_op_work[i].work, + hdd_ipa_uc_fw_op_event_handler); + ipa_ctxt->uc_op_work[i].msg = NULL; + } return VOS_STATUS_SUCCESS; } @@ -1625,10 +1713,11 @@ static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event, #ifdef IPA_UC_OFFLOAD if (hdd_ipa_uc_is_enabled(hdd_ipa)) { /* RM Notification comes with ISR context - * it should be serialized into differed thread to avoid + * it should be serialized into work queue to avoid * ISR sleep problem */ if (hdd_ipa->resource_loading) { - hdd_ipa_uc_rm_notify_defer(hdd_ipa, event); + hdd_ipa->uc_rm_work.event = event; + schedule_work(&hdd_ipa->uc_rm_work.work); } else { HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "UCResource Grntd with invalid status"); @@ -1765,6 +1854,9 @@ static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa) #else INIT_WORK(&hdd_ipa->rm_work, hdd_ipa_rm_send_pkt_to_ipa); #endif +#ifdef IPA_UC_OFFLOAD + cnss_init_work(&hdd_ipa->uc_rm_work.work, hdd_ipa_uc_rm_notify_defer); +#endif memset(&create_params, 0, sizeof(create_params)); create_params.name = IPA_RM_RESOURCE_WLAN_PROD; create_params.reg_params.user_data = hdd_ipa; @@ -1852,6 +1944,9 @@ static void hdd_ipa_destory_rm_resource(struct hdd_ipa_priv *hdd_ipa) #ifdef WLAN_OPEN_SOURCE cancel_work_sync(&hdd_ipa->rm_work); +#ifdef IPA_UC_OFFLOAD + cancel_work_sync(&hdd_ipa->uc_rm_work.work); +#endif #endif adf_os_spinlock_destroy(&hdd_ipa->rm_lock); @@ -2277,6 +2372,7 @@ static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, struct hdd_ipa_iface_context *iface_context; adf_nbuf_t skb; struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL; + VOS_STATUS status = VOS_STATUS_SUCCESS; if (evt != IPA_RECEIVE) { skb = (adf_nbuf_t) data; @@ -2295,8 +2391,9 @@ static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, * During SSR, there is no use in queueing the packets as STA has to * connect back any way */ - if (hdd_ipa->hdd_ctx->isLogpInProgress || - hdd_ipa->hdd_ctx->isUnloadInProgress) { + status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx); + if (0 != status) { + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "HDD context is not valid"); ipa_free_skb(ipa_tx_desc); iface_context->stats.num_tx_drop++; return; @@ -3090,8 +3187,10 @@ int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "%s: handle 1st con ret %d", msg_ex->name, ret); + } else { + goto end; } - } + } #endif ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id); if (ret) @@ -3214,7 +3313,10 @@ int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "%s: handle 1st con ret %d", msg_ex->name, ret); - } + } else { + vos_lock_release(&hdd_ipa->event_lock); + return ret; + } } vos_lock_release(&hdd_ipa->event_lock); } @@ -3770,6 +3872,12 @@ VOS_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx) 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 + for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) { + cancel_work_sync(&hdd_ipa->uc_op_work[i].work); + hdd_ipa->uc_op_work[i].msg = NULL; + } +#endif } else #endif /* IPA_UC_OFFLOAD */ { @@ -1197,10 +1197,11 @@ ifeq ($(CONFIG_IPA_UC_OFFLOAD), 1) CDEFINES += -DIPA_UC_OFFLOAD ifeq ($(CONFIG_ARCH_MDM9640), y) CDEFINES += -DIPA_UC_STA_OFFLOAD -endif +else CDEFINES += -DQCA_CONFIG_SMP endif endif +endif #Enable GTK Offload ifeq ($(CONFIG_GTK_OFFLOAD), 1) |
