diff --git a/qdf/inc/qdf_platform.h b/qdf/inc/qdf_platform.h index c50ba37c7382..e5a165ad22fe 100644 --- a/qdf/inc/qdf_platform.h +++ b/qdf/inc/qdf_platform.h @@ -61,6 +61,51 @@ void qdf_register_fw_down_callback(qdf_is_fw_down_callback is_fw_down); */ bool qdf_is_fw_down(void); +/** + * qdf_wmi_recv_qmi_cb() - callback to receive WMI over QMI + * @cb_ctx: WMI event recv callback context(wmi_handle) + * @buf: WMI buffer + * @len: WMI buffer len + * + * Return: 0 if success otherwise -EINVAL + */ +typedef int (*qdf_wmi_recv_qmi_cb)(void *cb_ctx, void *buf, int len); + +/** + * qdf_wmi_send_over_qmi_callback() - callback to send WMI over QMI + * @buf: WMI buffer + * @len: WMI buffer len + * @cb_ctx: WMI event recv callback context(wmi_handle) + * @wmi_rx_cb: WMI event receive call back + * + * Return: QDF_STATUS_SUCCESS if success otherwise QDF error code + */ +typedef QDF_STATUS (*qdf_wmi_send_over_qmi_callback)(void *buf, uint32_t len, + void *cb_ctx, + qdf_wmi_recv_qmi_cb + wmi_rx_cb); + +/** + * qdf_register_wmi_send_recv_qmi_callback() - Register WMI over QMI callback + * @qdf_wmi_send_over_qmi_callback: callback to send recv WMI data over QMI + * + * Return: none + */ +void qdf_register_wmi_send_recv_qmi_callback(qdf_wmi_send_over_qmi_callback + wmi_send_recv_qmi_cb); + +/** + * qdf_wmi_send_recv_qmi() - API to send receive WMI data over QMI + * @buf: WMI buffer + * @len: WMI buffer len + * @cb_ctx: WMI event recv callback context(wmi_handle) + * @wmi_rx_cb: WMI event receive call back + * + * Return: QDF STATUS of operation + */ +QDF_STATUS qdf_wmi_send_recv_qmi(void *buf, uint32_t len, void *cb_ctx, + qdf_wmi_recv_qmi_cb wmi_rx_cb); + /** * qdf_register_self_recovery_callback() - register self recovery callback * @callback: self recovery callback diff --git a/qdf/src/qdf_platform.c b/qdf/src/qdf_platform.c index fce06fc0f488..11554b8007ce 100644 --- a/qdf/src/qdf_platform.c +++ b/qdf/src/qdf_platform.c @@ -28,6 +28,7 @@ static qdf_self_recovery_callback self_recovery_cb; static qdf_is_fw_down_callback is_fw_down_cb; static qdf_is_recovering_callback is_recovering_cb; static qdf_is_drv_connected_callback is_drv_connected_cb; +static qdf_wmi_send_over_qmi_callback _wmi_send_recv_qmi_cb; void qdf_register_fw_down_callback(qdf_is_fw_down_callback is_fw_down) { @@ -46,9 +47,30 @@ bool qdf_is_fw_down(void) return is_fw_down_cb(); } - qdf_export_symbol(qdf_is_fw_down); +void qdf_register_wmi_send_recv_qmi_callback(qdf_wmi_send_over_qmi_callback + wmi_send_recv_qmi_cb) +{ + _wmi_send_recv_qmi_cb = wmi_send_recv_qmi_cb; +} + +qdf_export_symbol(qdf_register_wmi_send_recv_qmi_callback); + +QDF_STATUS qdf_wmi_send_recv_qmi(void *buf, uint32_t len, void *cb_ctx, + qdf_wmi_recv_qmi_cb wmi_recv_qmi_cb) +{ + if (!_wmi_send_recv_qmi_cb) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Platform callback for WMI over QMI not registered"); + return QDF_STATUS_E_INVAL; + } + + return _wmi_send_recv_qmi_cb(buf, len, cb_ctx, wmi_recv_qmi_cb); +} + +qdf_export_symbol(qdf_wmi_send_recv_qmi); + void qdf_register_self_recovery_callback(qdf_self_recovery_callback callback) { self_recovery_cb = callback; diff --git a/wmi/inc/wmi_unified_api.h b/wmi/inc/wmi_unified_api.h index e02ffde1741c..af5ceee7c70d 100644 --- a/wmi/inc/wmi_unified_api.h +++ b/wmi/inc/wmi_unified_api.h @@ -276,6 +276,45 @@ wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf, uint32_t buflen, uint32_t cmd_id, const char *func, uint32_t line); +#ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI +/** + * wmi_unified_cmd_send_over_qmi() - generic function to send unified WMI command + * over QMI + * @wmi_handle: handle to WMI. + * @buf: wmi command buffer + * @buflen: wmi command buffer length + * @cmd_id: WMI cmd id + * + * Return: QDF_STATUS + */ +QDF_STATUS wmi_unified_cmd_send_over_qmi(struct wmi_unified *wmi_handle, + wmi_buf_t buf, uint32_t buflen, + uint32_t cmd_id); + +/** + * wmi_process_qmi_fw_event() - Process WMI event received over QMI + * @wmi_cb_ctx: WMI handle received as call back context + * @buf: Pointer to WMI event buffer + * @len: Len of WMI buffer received + * + * Return: None + */ +int wmi_process_qmi_fw_event(void *wmi_cb_ctx, void *buf, int len); +#else +static inline +QDF_STATUS wmi_unified_cmd_send_over_qmi(struct wmi_unified *wmi_handle, + wmi_buf_t buf, uint32_t buflen, + uint32_t cmd_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline int wmi_process_qmi_fw_event(void *wmi_cb_ctx, void *buf, int len) +{ + return -EINVAL; +} +#endif + /** * wmi_unified_register_event() - WMI event handler * registration function for converged components diff --git a/wmi/src/wmi_unified.c b/wmi/src/wmi_unified.c index 50cc5d59d301..1dd07c9e13ba 100644 --- a/wmi/src/wmi_unified.c +++ b/wmi/src/wmi_unified.c @@ -1682,6 +1682,70 @@ static inline void wmi_unified_debug_dump(wmi_unified_t wmi_handle) "WMI_NON_TLV_TARGET")); } +#ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI +QDF_STATUS wmi_unified_cmd_send_over_qmi(struct wmi_unified *wmi_handle, + wmi_buf_t buf, uint32_t buflen, + uint32_t cmd_id) +{ + QDF_STATUS status; + + if (!qdf_nbuf_push_head(buf, sizeof(WMI_CMD_HDR))) { + wmi_err("Failed to send cmd %x, no memory", cmd_id); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_zero(qdf_nbuf_data(buf), sizeof(WMI_CMD_HDR)); + WMI_SET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID, cmd_id); + wmi_debug("Sending WMI_CMD_ID: %d over qmi", cmd_id); + status = qdf_wmi_send_recv_qmi(qdf_nbuf_data(buf), + buflen + sizeof(WMI_CMD_HDR), + wmi_handle, + wmi_process_qmi_fw_event); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_nbuf_pull_head(buf, sizeof(WMI_CMD_HDR)); + wmi_warn("WMI send on QMI failed. Retrying WMI on HTC"); + } else { + wmi_buf_free(buf); + } + + return status; +} + +static int __wmi_process_qmi_fw_event(void *wmi_cb_ctx, void *buf, int len) +{ + struct wmi_unified *wmi_handle = wmi_cb_ctx; + wmi_buf_t evt_buf; + uint32_t evt_id; + + if (!wmi_handle || !buf) + return -EINVAL; + + evt_buf = wmi_buf_alloc(wmi_handle, len); + if (!evt_buf) + return -ENOMEM; + + qdf_mem_copy(qdf_nbuf_data(evt_buf), buf, len); + evt_id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); + wmi_debug("Received WMI_EVT_ID: %d over qmi", evt_id); + wmi_process_fw_event(wmi_handle, evt_buf); + + return 0; +} + +int wmi_process_qmi_fw_event(void *wmi_cb_ctx, void *buf, int len) +{ + struct qdf_op_sync *op_sync; + int ret; + + if (qdf_op_protect(&op_sync)) + return -EINVAL; + ret = __wmi_process_qmi_fw_event(wmi_cb_ctx, buf, len); + qdf_op_unprotect(op_sync); + + return ret; +} +#endif + QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf, uint32_t len, uint32_t cmd_id, const char *func, uint32_t line) diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 04e70c4577f0..122257f8ec03 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -566,9 +566,32 @@ void wmi_mtrace(uint32_t message_id, uint16_t vdev_id, uint32_t data) qdf_mtrace(QDF_MODULE_ID_WMI, QDF_MODULE_ID_TARGET, mtrace_message_id, vdev_id, data); } - qdf_export_symbol(wmi_mtrace); +#ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI +static QDF_STATUS wmi_unified_cmd_send_pm_chk(struct wmi_unified *wmi_handle, + wmi_buf_t buf, + uint32_t buflen, uint32_t cmd_id) +{ + if (wmi_is_target_suspended(wmi_handle)) { + if (QDF_IS_STATUS_SUCCESS( + wmi_unified_cmd_send_over_qmi(wmi_handle, buf, + buflen, cmd_id))) + return QDF_STATUS_SUCCESS; + } + + return wmi_unified_cmd_send(wmi_handle, buf, buflen, cmd_id); +} +#else +static inline +QDF_STATUS wmi_unified_cmd_send_pm_chk(struct wmi_unified *wmi_handle, + wmi_buf_t buf, + uint32_t buflen, uint32_t cmd_id) +{ + return wmi_unified_cmd_send(wmi_handle, buf, buflen, cmd_id); +} +#endif + /** * send_vdev_create_cmd_tlv() - send VDEV create command to fw * @wmi_handle: wmi handle @@ -1975,8 +1998,8 @@ static QDF_STATUS send_stats_request_cmd_tlv(wmi_unified_t wmi_handle, cmd->stats_id, cmd->vdev_id, cmd->pdev_id); wmi_mtrace(WMI_REQUEST_STATS_CMDID, cmd->vdev_id, 0); - ret = wmi_unified_cmd_send(wmi_handle, buf, len, - WMI_REQUEST_STATS_CMDID); + ret = wmi_unified_cmd_send_pm_chk(wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID); if (ret) { WMI_LOGE("Failed to send status request to fw =%d", ret); @@ -4842,8 +4865,8 @@ static QDF_STATUS send_process_ll_stats_get_cmd_tlv(wmi_unified_t wmi_handle, WMI_LOGD("Peer MAC Addr: %pM", get_req->peer_macaddr.bytes); wmi_mtrace(WMI_REQUEST_LINK_STATS_CMDID, cmd->vdev_id, 0); - ret = wmi_unified_cmd_send(wmi_handle, buf, len, - WMI_REQUEST_LINK_STATS_CMDID); + ret = wmi_unified_cmd_send_pm_chk(wmi_handle, buf, len, + WMI_REQUEST_LINK_STATS_CMDID); if (ret) { WMI_LOGE("%s: Failed to send get link stats request", __func__); wmi_buf_free(buf); @@ -4922,8 +4945,8 @@ static QDF_STATUS send_snr_request_cmd_tlv(wmi_unified_t wmi_handle) (wmi_request_stats_cmd_fixed_param)); cmd->stats_id = WMI_REQUEST_VDEV_STAT; wmi_mtrace(WMI_REQUEST_STATS_CMDID, cmd->vdev_id, 0); - if (wmi_unified_cmd_send - (wmi_handle, buf, len, WMI_REQUEST_STATS_CMDID)) { + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID)) { WMI_LOGE("Failed to send host stats request to fw"); wmi_buf_free(buf); return QDF_STATUS_E_FAILURE;