Просмотр исходного кода

qcacmn: Add sequence number for WMI pipe

Add sequence number to each packet queued on wmi pipe and
match it against expected sequence number in wmi completion handler.
WMI packets are consumed internally, use the skb mark field to capture
the sequence number of the wmi packet.

Change-Id: I1421e3fcff0a2b326f6d899780c773950544ef26
CRs-Fixed: 2741465
Balaganapathy Palanisamy 4 лет назад
Родитель
Сommit
55650d9c02
5 измененных файлов с 181 добавлено и 29 удалено
  1. 23 0
      qdf/inc/qdf_nbuf.h
  2. 2 0
      qdf/inc/qdf_types.h
  3. 23 0
      qdf/linux/src/i_qdf_nbuf.h
  4. 8 0
      wmi/inc/wmi_unified_priv.h
  5. 125 29
      wmi/src/wmi_unified.c

+ 23 - 0
qdf/inc/qdf_nbuf.h

@@ -3756,6 +3756,29 @@ static inline void qdf_nbuf_trim_add_frag_size(qdf_nbuf_t nbuf, uint8_t idx,
 	__qdf_nbuf_trim_add_frag_size(nbuf, idx, size, truesize);
 }
 
+/**
+ * qdf_nbuf_set_mark() - Set nbuf mark
+ * @nbuf: qdf_nbuf_t
+ * @mark: Value to set mark
+ *
+ * Return: none
+ */
+static inline void qdf_nbuf_set_mark(qdf_nbuf_t nbuf, uint32_t mark)
+{
+	__qdf_nbuf_set_mark(nbuf, mark);
+}
+
+/**
+ * qdf_nbuf_get_mark() - Get nbuf mark
+ * @nbuf: qdf_nbuf_t
+ *
+ * Return: mark value
+ */
+static inline uint32_t qdf_nbuf_get_mark(qdf_nbuf_t nbuf)
+{
+	return __qdf_nbuf_get_mark(nbuf);
+}
+
 #ifdef NBUF_FRAG_MEMORY_DEBUG
 
 #define qdf_nbuf_move_frag_page_offset(f, i, o) \

+ 2 - 0
qdf/inc/qdf_types.h

@@ -1338,6 +1338,7 @@ enum qdf_suspend_type {
  * @QDF_VDEV_STOP_RESPONSE_TIMED_OUT: Stop response timeout from FW
  * @QDF_VDEV_DELETE_RESPONSE_TIMED_OUT: Delete response timeout from FW
  * @QDF_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT: Peer delete all resp timeout
+ * @QDF_WMI_BUF_SEQUENCE_MISMATCH: WMI Tx completion buffer sequence mismatch
  */
 enum qdf_hang_reason {
 	QDF_REASON_UNSPECIFIED,
@@ -1360,6 +1361,7 @@ enum qdf_hang_reason {
 	QDF_VDEV_STOP_RESPONSE_TIMED_OUT,
 	QDF_VDEV_DELETE_RESPONSE_TIMED_OUT,
 	QDF_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT,
+	QDF_WMI_BUF_SEQUENCE_MISMATCH,
 };
 
 /**

+ 23 - 0
qdf/linux/src/i_qdf_nbuf.h

@@ -2451,6 +2451,29 @@ void __qdf_nbuf_add_rx_frag(__qdf_frag_t buf, __qdf_nbuf_t nbuf,
 			    int offset, int frag_len,
 			    unsigned int truesize, bool take_frag_ref);
 
+/**
+ * __qdf_nbuf_set_mark() - Set nbuf mark
+ * @buf: Pointer to nbuf
+ * @mark: Value to set mark
+ *
+ * Return: None
+ */
+static inline void __qdf_nbuf_set_mark(__qdf_nbuf_t buf, uint32_t mark)
+{
+	buf->mark = mark;
+}
+
+/**
+ * __qdf_nbuf_get_mark() - Get nbuf mark
+ * @buf: Pointer to nbuf
+ *
+ * Return: Value of mark
+ */
+static inline uint32_t __qdf_nbuf_get_mark(__qdf_nbuf_t buf)
+{
+	return buf->mark;
+}
+
 #ifdef CONFIG_NBUF_AP_PLATFORM
 #include <i_qdf_nbuf_w.h>
 #else

+ 8 - 0
wmi/inc/wmi_unified_priv.h

@@ -2543,6 +2543,14 @@ struct wmi_unified {
 	uint32_t *evt_pdev_id_map;
 	uint32_t *cmd_phy_id_map;
 	uint32_t *evt_phy_id_map;
+#ifdef WMI_INTERFACE_SEQUENCE_CHECK
+	/* wmi next transmit sequence number */
+	uint32_t wmi_sequence;
+	/* wmi completion expected sequence number */
+	uint32_t wmi_exp_sequence;
+	qdf_spinlock_t wmi_seq_lock;
+#endif /*WMI_INTERFACE_SEQUENCE_CHECK*/
+
 	qdf_atomic_t num_stats_over_qmi;
 };
 

+ 125 - 29
wmi/src/wmi_unified.c

@@ -1709,6 +1709,101 @@ static bool wmi_is_legacy_d0wow_disable_cmd(wmi_buf_t buf, uint32_t cmd_id)
 
 #endif
 
+#ifdef WMI_INTERFACE_SEQUENCE_CHECK
+static inline void wmi_interface_sequence_init(struct wmi_unified *wmi_handle)
+{
+	qdf_spinlock_create(&wmi_handle->wmi_seq_lock);
+	wmi_handle->wmi_sequence = 0;
+	wmi_handle->wmi_exp_sequence = 0;
+}
+
+static inline void wmi_interface_sequence_deinit(struct wmi_unified *wmi_handle)
+{
+	qdf_spinlock_destroy(&wmi_handle->wmi_seq_lock);
+}
+
+static inline QDF_STATUS wmi_htc_send_pkt(struct wmi_unified *wmi_handle,
+					  HTC_PACKET *pkt,
+					  const char *func, uint32_t line)
+{
+	wmi_buf_t buf = GET_HTC_PACKET_NET_BUF_CONTEXT(pkt);
+	QDF_STATUS status;
+
+	qdf_spin_lock_bh(&wmi_handle->wmi_seq_lock);
+	status = htc_send_pkt(wmi_handle->htc_handle, pkt);
+	if (QDF_STATUS_SUCCESS != status) {
+		qdf_spin_unlock_bh(&wmi_handle->wmi_seq_lock);
+		qdf_atomic_dec(&wmi_handle->pending_cmds);
+		wmi_nofl_err("%s:%d, htc_send_pkt failed, status:%d",
+			     func, line, status);
+		qdf_mem_free(pkt);
+		return status;
+	}
+	/* Record the sequence number in the SKB */
+	qdf_nbuf_set_mark(buf, wmi_handle->wmi_sequence);
+	/* Increment the sequence number */
+	wmi_handle->wmi_sequence = (wmi_handle->wmi_sequence + 1)
+				   & (wmi_handle->wmi_max_cmds - 1);
+	qdf_spin_unlock_bh(&wmi_handle->wmi_seq_lock);
+
+	return status;
+}
+
+static inline void wmi_interface_sequence_check(struct wmi_unified *wmi_handle,
+						wmi_buf_t buf)
+{
+	qdf_spin_lock_bh(&wmi_handle->wmi_seq_lock);
+	/* Match the completion sequence and expected sequence number */
+	if (qdf_nbuf_get_mark(buf) != wmi_handle->wmi_exp_sequence) {
+		qdf_spin_unlock_bh(&wmi_handle->wmi_seq_lock);
+		wmi_nofl_err("WMI Tx Completion Sequence number mismatch");
+		wmi_nofl_err("Expected %d Received %d",
+			     wmi_handle->wmi_exp_sequence,
+			     qdf_nbuf_get_mark(buf));
+		/* Trigger Recovery */
+		qdf_trigger_self_recovery(wmi_handle->soc,
+					  QDF_WMI_BUF_SEQUENCE_MISMATCH);
+	} else {
+		/* Increment the expected sequence number */
+		wmi_handle->wmi_exp_sequence =
+				(wmi_handle->wmi_exp_sequence + 1)
+				& (wmi_handle->wmi_max_cmds - 1);
+		qdf_spin_unlock_bh(&wmi_handle->wmi_seq_lock);
+	}
+}
+#else
+static inline void wmi_interface_sequence_init(struct wmi_unified *wmi_handle)
+{
+}
+
+static inline void wmi_interface_sequence_deinit(struct wmi_unified *wmi_handle)
+{
+}
+
+static inline QDF_STATUS wmi_htc_send_pkt(struct wmi_unified *wmi_handle,
+					  HTC_PACKET *pkt,
+					  const char *func, uint32_t line)
+{
+	QDF_STATUS status;
+
+	status = htc_send_pkt(wmi_handle->htc_handle, pkt);
+	if (QDF_STATUS_SUCCESS != status) {
+		qdf_atomic_dec(&wmi_handle->pending_cmds);
+		wmi_nofl_err("%s:%d, htc_send_pkt failed, status:%d",
+			     func, line, status);
+		qdf_mem_free(pkt);
+		return status;
+	}
+
+	return status;
+}
+
+static inline void wmi_interface_sequence_check(struct wmi_unified *wmi_handle,
+						wmi_buf_t buf)
+{
+}
+#endif
+
 static inline void wmi_unified_debug_dump(wmi_unified_t wmi_handle)
 {
 	wmi_nofl_err("Endpoint ID = %d, Tx Queue Depth = %d, soc_id = %u, target type = %s",
@@ -1726,7 +1821,6 @@ QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf,
 				   const char *func, uint32_t line)
 {
 	HTC_PACKET *pkt;
-	QDF_STATUS status;
 	uint16_t htc_tag = 0;
 
 	if (wmi_get_runtime_pm_inprogress(wmi_handle)) {
@@ -1816,21 +1910,11 @@ QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf,
 			WMI_COMMAND_RECORD(wmi_handle, cmd_id, tmpbuf);
 			wmi_specific_cmd_record(wmi_handle, cmd_id, tmpbuf);
 		}
+
 		qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
 	}
 #endif
-
-	status = htc_send_pkt(wmi_handle->htc_handle, pkt);
-
-	if (QDF_STATUS_SUCCESS != status) {
-		qdf_atomic_dec(&wmi_handle->pending_cmds);
-		wmi_nofl_err("%s:%d, htc_send_pkt failed, status:%d",
-			     func, line, status);
-		qdf_mem_free(pkt);
-		return status;
-	}
-
-	return QDF_STATUS_SUCCESS;
+	return wmi_htc_send_pkt(wmi_handle, pkt, func, line);
 }
 qdf_export_symbol(wmi_unified_cmd_send_fl);
 
@@ -2669,6 +2753,8 @@ void *wmi_unified_get_pdev_handle(struct wmi_soc *soc, uint32_t pdev_idx)
 		wmi_handle->target_type = soc->target_type;
 		wmi_handle->wmi_max_cmds = soc->wmi_max_cmds;
 
+		wmi_interface_sequence_init(wmi_handle);
+
 		soc->wmi_pdev[pdev_idx] = wmi_handle;
 	} else
 		wmi_handle = soc->wmi_pdev[pdev_idx];
@@ -2804,6 +2890,7 @@ void *wmi_unified_attach(void *scn_handle,
 		WMI_LOGE("wmi attach is not registered");
 		goto error;
 	}
+	wmi_interface_sequence_init(wmi_handle);
 	/* Assign target cookie capablity */
 	wmi_handle->use_cookie = param->use_cookie;
 	wmi_handle->osdev = param->osdev;
@@ -2813,7 +2900,6 @@ void *wmi_unified_attach(void *scn_handle,
 	/* Increase the ref count once refcount infra is present */
 	soc->wmi_psoc = param->psoc;
 	qdf_spinlock_create(&soc->ctx_lock);
-
 	soc->ops = wmi_handle->ops;
 	soc->wmi_pdev[0] = wmi_handle;
 	if (wmi_ext_dbgfs_init(wmi_handle) != QDF_STATUS_SUCCESS)
@@ -2875,6 +2961,9 @@ void wmi_unified_detach(struct wmi_unified *wmi_handle)
 					soc->wmi_pdev[i]->events_logs_list);
 
 			qdf_spinlock_destroy(&soc->wmi_pdev[i]->eventq_lock);
+
+			wmi_interface_sequence_deinit(soc->wmi_pdev[i]);
+
 			qdf_mem_free(soc->wmi_pdev[i]);
 		}
 	}
@@ -2942,7 +3031,9 @@ static void wmi_htc_tx_complete(void *ctx, HTC_PACKET *htc_pkt)
 	u_int32_t len;
 	struct wmi_unified *wmi_handle;
 #ifdef WMI_INTERFACE_EVENT_LOGGING
+	struct wmi_debug_log_info *log_info;
 	uint32_t cmd_id;
+	uint8_t *offset_ptr;
 #endif
 
 	ASSERT(wmi_cmd_buf);
@@ -2952,28 +3043,33 @@ static void wmi_htc_tx_complete(void *ctx, HTC_PACKET *htc_pkt)
 		QDF_ASSERT(0);
 		return;
 	}
+	buf_ptr = (u_int8_t *)wmi_buf_data(wmi_cmd_buf);
 #ifdef WMI_INTERFACE_EVENT_LOGGING
-	if (wmi_handle && wmi_handle->log_info.wmi_logging_enable) {
+	log_info = &wmi_handle->log_info;
+
+	if (wmi_handle && log_info->wmi_logging_enable) {
 		cmd_id = WMI_GET_FIELD(qdf_nbuf_data(wmi_cmd_buf),
 				WMI_CMD_HDR, COMMANDID);
 
-	qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
-	/* Record 16 bytes of WMI cmd tx complete data
-	- exclude TLV and WMI headers */
-	if (wmi_handle->ops->is_management_record(cmd_id)) {
-		WMI_MGMT_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id,
-			qdf_nbuf_data(wmi_cmd_buf) +
-			wmi_handle->soc->buf_offset_command);
-	} else {
-		WMI_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id,
-			qdf_nbuf_data(wmi_cmd_buf) +
-			wmi_handle->soc->buf_offset_command);
-	}
+		qdf_spin_lock_bh(&log_info->wmi_record_lock);
+		/* Record 16 bytes of WMI cmd tx complete data
+		 * - exclude TLV and WMI headers
+		 */
+		offset_ptr = buf_ptr + wmi_handle->soc->buf_offset_command;
+		if (wmi_handle->ops->is_management_record(cmd_id)) {
+			WMI_MGMT_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id,
+						       offset_ptr);
+		} else {
+			WMI_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id,
+						  offset_ptr);
+		}
 
-	qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
+		qdf_spin_unlock_bh(&log_info->wmi_record_lock);
 	}
 #endif
-	buf_ptr = (u_int8_t *) wmi_buf_data(wmi_cmd_buf);
+
+	wmi_interface_sequence_check(wmi_handle, wmi_cmd_buf);
+
 	len = qdf_nbuf_len(wmi_cmd_buf);
 	qdf_mem_zero(buf_ptr, len);
 	wmi_buf_free(wmi_cmd_buf);