diff --git a/wmi/inc/wmi_unified_api.h b/wmi/inc/wmi_unified_api.h index 5d5318af81..7a524a5711 100644 --- a/wmi/inc/wmi_unified_api.h +++ b/wmi/inc/wmi_unified_api.h @@ -151,11 +151,14 @@ enum wmi_target_type { * enum wmi_rx_exec_ctx - wmi rx execution context * @WMI_RX_WORK_CTX: work queue context execution provided by WMI layer * @WMI_RX_UMAC_CTX: execution context provided by umac layer + * @WMI_RX_SERIALIZER_CTX: Execution context is serialized thread context * */ enum wmi_rx_exec_ctx { WMI_RX_WORK_CTX, - WMI_RX_UMAC_CTX + WMI_RX_UMAC_CTX, + WMI_RX_TASKLET_CTX = WMI_RX_UMAC_CTX, + WMI_RX_SERIALIZER_CTX = 2 }; /** @@ -3628,7 +3631,6 @@ wmi_unified_send_peer_cfr_capture_cmd(wmi_unified_t wmi_handle, QDF_STATUS wmi_extract_cfr_peer_tx_event_param(wmi_unified_t wmi_handle, void *evt_buf, wmi_cfr_peer_tx_event_param *peer_tx_event); - #endif /* WLAN_CFR_ENABLE */ #ifdef WIFI_POS_CONVERGED @@ -3644,4 +3646,13 @@ QDF_STATUS wmi_extract_oem_response_param(wmi_unified_t wmi_hdl, void *resp_buf, struct wmi_oem_response_param *oem_resp_param); #endif /* WIFI_POS_CONVERGED */ +/** + * wmi_critical_events_in_flight() - get the number of critical events in flight + * + * @wmi_hdl: WMI handle + * + * Return: the number of critical events in flight. + */ +uint32_t wmi_critical_events_in_flight(struct wmi_unified *wmi); + #endif /* _WMI_UNIFIED_API_H_ */ diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 88bbc906b0..e332da8c63 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -2127,6 +2127,7 @@ struct wmi_unified { struct wmi_soc *soc; uint16_t wmi_max_cmds; struct dentry *debugfs_de[NUM_DEBUG_INFOS]; + qdf_atomic_t critical_events_in_flight; #ifdef WMI_EXT_DBG int wmi_ext_dbg_msg_queue_size; qdf_list_t wmi_ext_dbg_msg_queue; @@ -2172,6 +2173,16 @@ struct wmi_soc { #endif /*WMI_INTERFACE_EVENT_LOGGING */ }; +/** + * struct wmi_process_fw_event_params - fw event parameters + * @wmi_handle: wmi handle + * @evt_buf: event buffer + */ +struct wmi_process_fw_event_params { + void *wmi_handle; + void *evt_buf; +}; + /** * wmi_mtrace() - Wrappper function for qdf_mtrace api * @message_id: 32-Bit Wmi message ID diff --git a/wmi/src/wmi_unified.c b/wmi/src/wmi_unified.c index 772e9d59c0..88b475e34b 100644 --- a/wmi/src/wmi_unified.c +++ b/wmi/src/wmi_unified.c @@ -34,7 +34,7 @@ #endif #include - +#include #ifdef WMI_EXT_DBG #include "qdf_atomic.h" @@ -2083,29 +2083,6 @@ int wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle, } qdf_export_symbol(wmi_unified_unregister_event_handler); -/** - * wmi_process_fw_event_default_ctx() - process in default caller context - * @wmi_handle: handle to wmi - * @htc_packet: pointer to htc packet - * @exec_ctx: execution context for wmi fw event - * - * Event process by below function will be in default caller context. - * wmi internally provides rx work thread processing context. - * - * Return: none - */ -static void wmi_process_fw_event_default_ctx(struct wmi_unified *wmi_handle, - HTC_PACKET *htc_packet, uint8_t exec_ctx) -{ - wmi_buf_t evt_buf; - evt_buf = (wmi_buf_t) htc_packet->pPktContext; - - wmi_handle->rx_ops.wma_process_fw_event_handler_cbk - (wmi_handle->scn_handle, evt_buf, exec_ctx); - - return; -} - void wmi_process_fw_event_worker_thread_ctx(struct wmi_unified *wmi_handle, void *evt_buf) { @@ -2121,6 +2098,129 @@ void wmi_process_fw_event_worker_thread_ctx(struct wmi_unified *wmi_handle, qdf_export_symbol(wmi_process_fw_event_worker_thread_ctx); +uint32_t wmi_critical_events_in_flight(struct wmi_unified *wmi) +{ + return qdf_atomic_read(&wmi->critical_events_in_flight); +} + +static bool +wmi_is_event_critical(struct wmi_unified *wmi_handle, uint32_t event_id) +{ + if (wmi_handle->wmi_events[wmi_roam_synch_event_id] == event_id) + return true; + + return false; +} + +static void wmi_discard_fw_event(struct scheduler_msg *msg) +{ + struct wmi_process_fw_event_params *event_param; + + if (!msg->bodyptr) + return; + + event_param = (struct wmi_process_fw_event_params *)msg->bodyptr; + qdf_nbuf_free(event_param->evt_buf); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + msg->bodyval = 0; + msg->type = 0; +} + +static int wmi_process_fw_event_handler(struct scheduler_msg *msg) +{ + struct wmi_process_fw_event_params *params = + (struct wmi_process_fw_event_params *)msg->bodyptr; + struct wmi_unified *wmi_handle; + uint32_t event_id; + + wmi_handle = (struct wmi_unified *)params->wmi_handle; + event_id = WMI_GET_FIELD(qdf_nbuf_data(params->evt_buf), + WMI_CMD_HDR, COMMANDID); + wmi_process_fw_event(wmi_handle, params->evt_buf); + + if (wmi_is_event_critical(wmi_handle, event_id)) + qdf_atomic_dec(&wmi_handle->critical_events_in_flight); + + qdf_mem_free(msg->bodyptr); + + return 0; +} + +/** + * wmi_process_fw_event_sched_thread_ctx() - common event handler to serialize + * event processing through scheduler thread + * @ctx: wmi context + * @ev: event buffer + * @rx_ctx: rx execution context + * + * Return: 0 on success, errno on failure + */ +static QDF_STATUS +wmi_process_fw_event_sched_thread_ctx(struct wmi_unified *wmi, + void *ev) +{ + struct wmi_process_fw_event_params *params_buf; + struct scheduler_msg msg = { 0 }; + uint32_t event_id; + struct target_psoc_info *tgt_hdl; + bool is_wmi_ready = false; + struct wlan_objmgr_psoc *psoc; + + psoc = target_if_get_psoc_from_scn_hdl(wmi->scn_handle); + if (!psoc) { + target_if_err("psoc is null"); + qdf_nbuf_free(ev); + return QDF_STATUS_E_INVAL; + } + + tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc); + if (!tgt_hdl) { + wmi_err("target_psoc_info is null"); + qdf_nbuf_free(ev); + return QDF_STATUS_E_INVAL; + } + + is_wmi_ready = target_psoc_get_wmi_ready(tgt_hdl); + if (!is_wmi_ready) { + wmi_debug("fw event recvd before ready event processed"); + wmi_debug("therefore use worker thread"); + wmi_process_fw_event_worker_thread_ctx(wmi, ev); + return QDF_STATUS_E_INVAL; + } + + params_buf = qdf_mem_malloc(sizeof(struct wmi_process_fw_event_params)); + if (!params_buf) { + wmi_err("malloc failed"); + qdf_nbuf_free(ev); + return QDF_STATUS_E_NOMEM; + } + + params_buf->wmi_handle = wmi; + params_buf->evt_buf = ev; + + event_id = WMI_GET_FIELD(qdf_nbuf_data(params_buf->evt_buf), + WMI_CMD_HDR, COMMANDID); + if (wmi_is_event_critical(wmi, event_id)) + qdf_atomic_inc(&wmi->critical_events_in_flight); + + msg.bodyptr = params_buf; + msg.bodyval = 0; + msg.callback = wmi_process_fw_event_handler; + msg.flush_callback = wmi_discard_fw_event; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg)) { + qdf_nbuf_free(ev); + qdf_mem_free(params_buf); + return QDF_STATUS_E_FAULT; + } + + return QDF_STATUS_SUCCESS; +} + /** * wmi_get_pdev_ep: Get wmi handle based on endpoint * @soc: handle to wmi soc @@ -2235,9 +2335,10 @@ static void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet) if (exec_ctx == WMI_RX_WORK_CTX) { wmi_process_fw_event_worker_thread_ctx (wmi_handle, evt_buf); - } else if (exec_ctx > WMI_RX_WORK_CTX) { - wmi_process_fw_event_default_ctx - (wmi_handle, htc_packet, exec_ctx); + } else if (exec_ctx == WMI_RX_TASKLET_CTX) { + wmi_process_fw_event(wmi_handle, evt_buf); + } else if (exec_ctx == WMI_RX_SERIALIZER_CTX) { + wmi_process_fw_event_sched_thread_ctx(wmi_handle, evt_buf); } else { WMI_LOGE("Invalid event context %d", exec_ctx); qdf_nbuf_free(evt_buf);