qcacmn: Add common wmi event path for wmi event from htc and qmi

Crash happens if wma_handle->link_stats_results is allocated and
freed by two threads at the same time.

WMI event should be handled uniformly whether it is from htc or qmi

Change-Id: I415fd228d15c1342944e77a74e564fe46dd9a5c5
CRs-Fixed: 2648865
This commit is contained in:
bings
2020-03-26 16:06:03 +08:00
committed by nshrivas
parent 8cf020f44a
commit 54a116dfa1

View File

@@ -1704,73 +1704,6 @@ 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;
int32_t ret;
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 {
ret = qdf_atomic_inc_return(&wmi_handle->num_stats_over_qmi);
wmi_debug("num stats over qmi: %d", ret);
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)
@@ -2297,32 +2230,20 @@ static void wmi_mtrace_rx(uint32_t message_id, uint16_t vdev_id, uint32_t data)
}
/**
* wmi_control_rx() - process fw events callbacks
* @ctx: handle to wmi
* @htc_packet: pointer to htc packet
* wmi_process_control_rx() - process fw events callbacks
* @wmi_handle: handle to wmi_unified
* @evt_buf: handle to wmi_buf_t
*
* Return: none
*/
static void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet)
static void wmi_process_control_rx(struct wmi_unified *wmi_handle,
wmi_buf_t evt_buf)
{
struct wmi_soc *soc = (struct wmi_soc *) ctx;
struct wmi_unified *wmi_handle;
wmi_buf_t evt_buf;
struct wmi_soc *soc = wmi_handle->soc;
uint32_t id;
uint32_t idx = 0;
uint32_t idx;
enum wmi_rx_exec_ctx exec_ctx;
evt_buf = (wmi_buf_t) htc_packet->pPktContext;
wmi_handle = wmi_get_pdev_ep(soc, htc_packet->Endpoint);
if (!wmi_handle) {
WMI_LOGE
("unable to get wmi_handle to Endpoint %d\n",
htc_packet->Endpoint);
qdf_nbuf_free(evt_buf);
return;
}
id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID);
idx = wmi_unified_get_event_handler_ix(wmi_handle, id);
if (qdf_unlikely(idx == A_ERROR)) {
@@ -2372,6 +2293,100 @@ static void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet)
}
/**
* wmi_control_rx() - process fw events callbacks
* @ctx: handle to wmi
* @htc_packet: pointer to htc packet
*
* Return: none
*/
static void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet)
{
struct wmi_soc *soc = (struct wmi_soc *)ctx;
struct wmi_unified *wmi_handle;
wmi_buf_t evt_buf;
evt_buf = (wmi_buf_t)htc_packet->pPktContext;
wmi_handle = wmi_get_pdev_ep(soc, htc_packet->Endpoint);
if (!wmi_handle) {
WMI_LOGE
("unable to get wmi_handle to Endpoint %d\n",
htc_packet->Endpoint);
qdf_nbuf_free(evt_buf);
return;
}
wmi_process_control_rx(wmi_handle, evt_buf);
}
#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;
int32_t ret;
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 {
ret = qdf_atomic_inc_return(&wmi_handle->num_stats_over_qmi);
wmi_debug("num stats over qmi: %d", ret);
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_control_rx(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
/**
* wmi_process_fw_event() - process any fw event
* @wmi_handle: wmi handle