Browse Source

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
bings 5 years ago
parent
commit
54a116dfa1
1 changed files with 101 additions and 86 deletions
  1. 101 86
      wmi/src/wmi_unified.c

+ 101 - 86
wmi/src/wmi_unified.c

@@ -1704,73 +1704,6 @@ static inline void wmi_unified_debug_dump(wmi_unified_t wmi_handle)
 						"WMI_NON_TLV_TARGET"));
 						"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,
 QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf,
 				   uint32_t len, uint32_t cmd_id,
 				   uint32_t len, uint32_t cmd_id,
 				   const char *func, uint32_t line)
 				   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
  * 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 id;
-	uint32_t idx = 0;
+	uint32_t idx;
 	enum wmi_rx_exec_ctx exec_ctx;
 	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);
 	id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID);
 	idx = wmi_unified_get_event_handler_ix(wmi_handle, id);
 	idx = wmi_unified_get_event_handler_ix(wmi_handle, id);
 	if (qdf_unlikely(idx == A_ERROR)) {
 	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_process_fw_event() - process any fw event
  * @wmi_handle: wmi handle
  * @wmi_handle: wmi handle