Browse Source

qcacmn: Add support for back to back htt stats

In existing implementation when previous stats handling is under process
and a new stats event is received, new stats event is dropped.
Add support to queue any received stats message and process it
later in work queue context.

Change-Id: I7895a2f7ac49456c49374ce209da97c2148f43a2
CRs-Fixed: 2076552
Om Prakash Tripathi 7 years ago
parent
commit
121268292f
4 changed files with 118 additions and 39 deletions
  1. 71 29
      dp/wifi3.0/dp_htt.c
  2. 14 0
      dp/wifi3.0/dp_htt.h
  3. 15 4
      dp/wifi3.0/dp_main.c
  4. 18 6
      dp/wifi3.0/dp_types.h

+ 71 - 29
dp/wifi3.0/dp_htt.c

@@ -1035,7 +1035,7 @@ fail0:
 
 /**
  * dp_process_htt_stat_msg(): Process the list of buffers of HTT EXT stats
- * @soc: DP SOC handle
+ * @htt_stats: htt stats info
  *
  * The FW sends the HTT EXT STATS as a stream of T2H messages. Each T2H message
  * contains sub messages which are identified by a TLV header.
@@ -1053,7 +1053,7 @@ fail0:
  *
  * return: void
  */
-static inline void dp_process_htt_stat_msg(struct dp_soc *soc)
+static inline void dp_process_htt_stat_msg(struct htt_stats_context *htt_stats)
 {
 	htt_tlv_tag_t tlv_type = 0xff;
 	qdf_nbuf_t htt_msg = NULL;
@@ -1065,12 +1065,13 @@ static inline void dp_process_htt_stat_msg(struct dp_soc *soc)
 	uint32_t *tlv_start;
 
 	/* Process node in the HTT message queue */
-	while ((htt_msg = qdf_nbuf_queue_remove(&soc->htt_stats_msg)) != NULL) {
+	while ((htt_msg = qdf_nbuf_queue_remove(&htt_stats->msg))
+		!= NULL) {
 		msg_word = (uint32_t *) qdf_nbuf_data(htt_msg);
 		/* read 5th word */
 		msg_word = msg_word + 4;
-		msg_remain_len = qdf_min(soc->htt_msg_len,
-				(uint32_t)DP_EXT_MSG_LENGTH);
+		msg_remain_len = qdf_min(htt_stats->msg_len,
+				(uint32_t) DP_EXT_MSG_LENGTH);
 
 		/* Keep processing the node till node length is 0 */
 		while (msg_remain_len) {
@@ -1151,19 +1152,17 @@ static inline void dp_process_htt_stat_msg(struct dp_soc *soc)
 			}
 		}
 
-		if (soc->htt_msg_len >= DP_EXT_MSG_LENGTH) {
-			soc->htt_msg_len -= DP_EXT_MSG_LENGTH;
+		if (htt_stats->msg_len >= DP_EXT_MSG_LENGTH) {
+			htt_stats->msg_len -= DP_EXT_MSG_LENGTH;
 		}
 
 		qdf_nbuf_free(htt_msg);
 	}
-	soc->htt_msg_len = 0;
 	return;
 
 error:
 	qdf_nbuf_free(htt_msg);
-	soc->htt_msg_len = 0;
-	while ((htt_msg = qdf_nbuf_queue_remove(&soc->htt_stats_msg))
+	while ((htt_msg = qdf_nbuf_queue_remove(&htt_stats->msg))
 			!= NULL)
 		qdf_nbuf_free(htt_msg);
 }
@@ -1171,10 +1170,58 @@ error:
 void htt_t2h_stats_handler(void *context)
 {
 	struct dp_soc *soc = (struct dp_soc *)context;
+	struct htt_stats_context htt_stats;
+	uint32_t length;
+	uint32_t *msg_word;
+	qdf_nbuf_t htt_msg = NULL;
+	uint8_t done;
+	uint8_t rem_stats;
+
+	if (!soc || !qdf_atomic_read(&soc->cmn_init_done)) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+			"soc: 0x%p, init_done: %d", soc,
+			qdf_atomic_read(&soc->cmn_init_done));
+		return;
+	}
 
-	if (soc && qdf_atomic_read(&soc->cmn_init_done))
-		dp_process_htt_stat_msg(soc);
+	qdf_mem_zero(&htt_stats, sizeof(htt_stats));
+	qdf_nbuf_queue_init(&htt_stats.msg);
 
+	/* pull one completed stats from soc->htt_stats_msg and process */
+	qdf_spin_lock_bh(&soc->htt_stats.lock);
+	if (!soc->htt_stats.num_stats) {
+		qdf_spin_unlock_bh(&soc->htt_stats.lock);
+		return;
+	}
+	while ((htt_msg = qdf_nbuf_queue_remove(&soc->htt_stats.msg)) != NULL) {
+		msg_word = (uint32_t *) qdf_nbuf_data(htt_msg);
+		msg_word = msg_word + HTT_T2H_EXT_STATS_TLV_START_OFFSET;
+		length = HTT_T2H_EXT_STATS_CONF_TLV_LENGTH_GET(*msg_word);
+		done = HTT_T2H_EXT_STATS_CONF_TLV_DONE_GET(*msg_word);
+		qdf_nbuf_queue_add(&htt_stats.msg, htt_msg);
+		/*
+		 * HTT EXT stats response comes as stream of TLVs which span over
+		 * multiple T2H messages.
+		 * The first message will carry length of the response.
+		 * For rest of the messages length will be zero.
+		 */
+		if (length)
+			htt_stats.msg_len = length;
+		/*
+		 * Done bit signifies that this is the last T2H buffer in the
+		 * stream of HTT EXT STATS message
+		 */
+		if (done)
+			break;
+	}
+	rem_stats = --soc->htt_stats.num_stats;
+	qdf_spin_unlock_bh(&soc->htt_stats.lock);
+
+	dp_process_htt_stat_msg(&htt_stats);
+
+	/* If there are more stats to process, schedule stats work again */
+	if (rem_stats)
+		qdf_sched_work(0, &soc->htt_stats.work);
 }
 
 /**
@@ -1187,15 +1234,12 @@ void htt_t2h_stats_handler(void *context)
 static inline void dp_txrx_fw_stats_handler(struct dp_soc *soc,
 		qdf_nbuf_t htt_t2h_msg)
 {
-	uint32_t length;
 	uint8_t done;
 	qdf_nbuf_t msg_copy;
 	uint32_t *msg_word;
 
 	msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg);
 	msg_word = msg_word + 3;
-	done = 0;
-	length = HTT_T2H_EXT_STATS_CONF_TLV_LENGTH_GET(*msg_word);
 	done = HTT_T2H_EXT_STATS_CONF_TLV_DONE_GET(*msg_word);
 
 	/*
@@ -1203,14 +1247,7 @@ static inline void dp_txrx_fw_stats_handler(struct dp_soc *soc,
 	 * multiple T2H messages.
 	 * The first message will carry length of the response.
 	 * For rest of the messages length will be zero.
-	 */
-	if (soc->htt_msg_len && length)
-		goto error;
-
-	if (length)
-		soc->htt_msg_len = length;
-
-	/*
+	 *
 	 * Clone the T2H message buffer and store it in a list to process
 	 * it later.
 	 *
@@ -1222,26 +1259,31 @@ static inline void dp_txrx_fw_stats_handler(struct dp_soc *soc,
 	if (!msg_copy) {
 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
 				"T2H messge clone failed for HTT EXT STATS");
-		soc->htt_msg_len = 0;
 		goto error;
 	}
 
-	qdf_nbuf_queue_add(&soc->htt_stats_msg, msg_copy);
-
+	qdf_spin_lock_bh(&soc->htt_stats.lock);
+	qdf_nbuf_queue_add(&soc->htt_stats.msg, msg_copy);
 	/*
 	 * Done bit signifies that this is the last T2H buffer in the stream of
 	 * HTT EXT STATS message
 	 */
-	if (done)
-		qdf_sched_work(0, &soc->htt_stats_work);
+	if (done) {
+		soc->htt_stats.num_stats++;
+		qdf_sched_work(0, &soc->htt_stats.work);
+	}
+	qdf_spin_unlock_bh(&soc->htt_stats.lock);
 
 	return;
 
 error:
-	while ((msg_copy = qdf_nbuf_queue_remove(&soc->htt_stats_msg))
+	qdf_spin_lock_bh(&soc->htt_stats.lock);
+	while ((msg_copy = qdf_nbuf_queue_remove(&soc->htt_stats.msg))
 			!= NULL) {
 		qdf_nbuf_free(msg_copy);
 	}
+	soc->htt_stats.num_stats = 0;
+	qdf_spin_unlock_bh(&soc->htt_stats.lock);
 	return;
 
 }

+ 14 - 0
dp/wifi3.0/dp_htt.h

@@ -46,6 +46,8 @@
 
 #define DP_HTT_HTC_PKT_MISCLIST_SIZE          256
 
+#define HTT_T2H_EXT_STATS_TLV_START_OFFSET    3
+
 struct dp_htt_htc_pkt {
 	void *soc_ctxt;
 	qdf_dma_addr_t nbuf_paddr;
@@ -157,4 +159,16 @@ int htt_h2t_rx_ring_cfg(void *htt_soc, int pdev_id, void *hal_srng,
  */
 void htt_t2h_stats_handler(void *context);
 
+/**
+ * struct htt_stats_context - htt stats information
+ * @soc: Size of each descriptor in the pool
+ * @msg: T2H Ext stats message queue
+ * @msg_len: T2H Ext stats message length
+ */
+struct htt_stats_context {
+	struct dp_soc *soc;
+	qdf_nbuf_queue_t msg;
+	uint32_t msg_len;
+};
+
 #endif /* _DP_HTT_H_ */

+ 15 - 4
dp/wifi3.0/dp_main.c

@@ -1763,7 +1763,7 @@ static int dp_soc_cmn_setup(struct dp_soc *soc)
 	hal_reo_setup(soc->hal_soc, &reo_params);
 
 	qdf_atomic_set(&soc->cmn_init_done, 1);
-	qdf_nbuf_queue_init(&soc->htt_stats_msg);
+	qdf_nbuf_queue_init(&soc->htt_stats.msg);
 	return 0;
 fail1:
 	/*
@@ -2356,8 +2356,11 @@ static void dp_soc_detach_wifi3(void *txrx_soc)
 
 	qdf_atomic_set(&soc->cmn_init_done, 0);
 
-	qdf_flush_work(0, &soc->htt_stats_work);
-	qdf_disable_work(0, &soc->htt_stats_work);
+	qdf_flush_work(0, &soc->htt_stats.work);
+	qdf_disable_work(0, &soc->htt_stats.work);
+
+	/* Free pending htt stats messages */
+	qdf_nbuf_queue_free(&soc->htt_stats.msg);
 
 	for (i = 0; i < MAX_PDEV_CNT; i++) {
 		if (soc->pdev_list[i])
@@ -2418,7 +2421,10 @@ static void dp_soc_detach_wifi3(void *txrx_soc)
 	dp_srng_cleanup(soc, &soc->reo_cmd_ring, REO_CMD, 0);
 	dp_srng_cleanup(soc, &soc->reo_status_ring, REO_STATUS, 0);
 
+	qdf_spinlock_destroy(&soc->rx.reo_cmd_lock);
 	qdf_spinlock_destroy(&soc->peer_ref_mutex);
+	qdf_spinlock_destroy(&soc->htt_stats.lock);
+
 	htt_soc_detach(soc->htt_handle);
 
 	dp_reo_cmdlist_destroy(soc);
@@ -2591,7 +2597,7 @@ static int dp_soc_attach_target_wifi3(struct cdp_soc_t *cdp_soc)
 	DP_STATS_INIT(soc);
 
 	/* initialize work queue for stats processing */
-	qdf_create_work(0, &soc->htt_stats_work, htt_t2h_stats_handler, soc);
+	qdf_create_work(0, &soc->htt_stats.work, htt_t2h_stats_handler, soc);
 
 	return 0;
 }
@@ -5072,6 +5078,11 @@ void *dp_soc_attach_wifi3(void *osif_soc, void *hif_handle,
 
 	/* fill the tx/rx cpu ring map*/
 	dp_soc_set_txrx_ring_map(soc);
+
+	qdf_spinlock_create(&soc->htt_stats.lock);
+	/* initialize work queue for stats processing */
+	qdf_create_work(0, &soc->htt_stats.work, htt_t2h_stats_handler, soc);
+
 	return (void *)soc;
 
 fail2:

+ 18 - 6
dp/wifi3.0/dp_types.h

@@ -533,6 +533,21 @@ struct dp_ast_entry {
 	TAILQ_ENTRY(dp_ast_entry) hash_list_elem;
 };
 
+/* SOC level htt stats */
+struct htt_t2h_stats {
+	/* lock to protect htt_stats_msg update */
+	qdf_spinlock_t lock;
+
+	/* work queue to process htt stats */
+	qdf_work_t work;
+
+	/* T2H Ext stats message queue */
+	qdf_nbuf_queue_t msg;
+
+	/* number of completed stats in htt_stats_msg */
+	uint32_t num_stats;
+};
+
 /* SOC level structure for data path */
 struct dp_soc {
 	/* Common base structure - Should be the first member */
@@ -758,12 +773,9 @@ struct dp_soc {
 	u_int16_t pdev_bs_inact_interval;
 	/* Inactivity timer */
 #endif /* QCA_SUPPORT_SON */
-	/* T2H Ext stats message queue */
-	qdf_nbuf_queue_t htt_stats_msg;
-	/* T2H Ext stats message length */
-	uint32_t htt_msg_len;
-	/* work queue to process htt stats */
-	qdf_work_t htt_stats_work;
+
+	/* htt stats */
+	struct htt_t2h_stats htt_stats;
 
 #ifdef IPA_OFFLOAD
 	/* IPA uC datapath offload Wlan Tx resources */