Эх сурвалжийг харах

qcacmn: Host<->FW HTT interface for HW vdev stats in BE

Define the interface for Host and FW communication required for
configuration of HW vdev stats in BE architecture and add handler
for vdev stats received from FW.

Change-Id: I5f6a703596bd1fbb5e27e6261befda25aa0c3e12
CRs-Fixed: 3067843
Harsh Kumar Bijlani 4 жил өмнө
parent
commit
356b9766fd

+ 294 - 0
dp/wifi3.0/dp_htt.c

@@ -2076,6 +2076,176 @@ dp_pktlog_msg_handler(struct htt_soc *soc,
 }
 #endif
 
+#ifdef QCA_VDEV_STATS_HW_OFFLOAD_SUPPORT
+/*
+ * dp_vdev_txrx_hw_stats_handler - Handle vdev stats received from FW
+ * @soc - htt soc handle
+ * @ msg_word - buffer containing stats
+ *
+ * Return: void
+ */
+static void dp_vdev_txrx_hw_stats_handler(struct htt_soc *soc,
+					  uint32_t *msg_word)
+{
+	struct dp_soc *dpsoc = (struct dp_soc *)soc->dp_soc;
+	uint8_t pdev_id;
+	uint8_t vdev_id;
+	uint8_t target_pdev_id;
+	uint16_t payload_size;
+	struct dp_pdev *pdev;
+	struct dp_vdev *vdev;
+	uint8_t *tlv_buf;
+	uint32_t *tlv_buf_temp;
+	uint32_t *tag_buf;
+	htt_tlv_tag_t tlv_type;
+	uint16_t tlv_length;
+	uint64_t pkt_count = 0;
+	uint64_t byte_count = 0;
+	uint64_t soc_drop_cnt = 0;
+	struct cdp_pkt_info tx_comp = { 0 };
+	struct cdp_pkt_info tx_failed =  { 0 };
+
+	target_pdev_id =
+		HTT_T2H_VDEVS_TXRX_STATS_PERIODIC_IND_PDEV_ID_GET(*msg_word);
+	pdev_id = dp_get_host_pdev_id_for_target_pdev_id(dpsoc,
+							 target_pdev_id);
+
+	if (pdev_id >= MAX_PDEV_CNT)
+		return;
+
+	pdev = dpsoc->pdev_list[pdev_id];
+	if (!pdev) {
+		dp_err("PDEV is NULL for pdev_id:%d", pdev_id);
+		return;
+	}
+
+	payload_size =
+	HTT_T2H_VDEVS_TXRX_STATS_PERIODIC_IND_PAYLOAD_SIZE_GET(*msg_word);
+
+	qdf_trace_hex_dump(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
+			   (void *)msg_word, payload_size + 16);
+
+	/* Adjust msg_word to point to the first TLV in buffer */
+	msg_word = msg_word + 4;
+
+	/* Parse the received buffer till payload size reaches 0 */
+	while (payload_size > 0) {
+		tlv_buf = (uint8_t *)msg_word;
+		tlv_buf_temp = msg_word;
+		tlv_type = HTT_STATS_TLV_TAG_GET(*msg_word);
+		tlv_length = HTT_STATS_TLV_LENGTH_GET(*msg_word);
+
+		/* Add header size to tlv length*/
+		tlv_length += 4;
+
+		switch (tlv_type) {
+		case HTT_STATS_SOC_TXRX_STATS_COMMON_TAG:
+		{
+			tag_buf = tlv_buf_temp +
+					HTT_VDEV_STATS_GET_INDEX(SOC_DROP_CNT);
+			soc_drop_cnt = HTT_VDEV_GET_STATS_U64(tag_buf);
+			DP_STATS_UPD(dpsoc, tx.tqm_drop_no_peer, soc_drop_cnt);
+			break;
+		}
+		case HTT_STATS_VDEV_TXRX_STATS_HW_STATS_TAG:
+		{
+			tag_buf = tlv_buf_temp +
+					HTT_VDEV_STATS_GET_INDEX(VDEV_ID);
+			vdev_id = (uint8_t)(*tag_buf);
+			vdev = dp_vdev_get_ref_by_id(dpsoc, vdev_id,
+						     DP_MOD_ID_HTT);
+
+			if (!vdev)
+				goto invalid_vdev;
+
+			/* Extract received packet count from buffer */
+			tag_buf = tlv_buf_temp +
+					HTT_VDEV_STATS_GET_INDEX(RX_PKT_CNT);
+			pkt_count = HTT_VDEV_GET_STATS_U64(tag_buf);
+			DP_STATS_UPD(vdev, rx_i.reo_rcvd_pkt.num, pkt_count);
+
+			/* Extract received packet byte count from buffer */
+			tag_buf = tlv_buf_temp +
+					HTT_VDEV_STATS_GET_INDEX(RX_BYTE_CNT);
+			byte_count = HTT_VDEV_GET_STATS_U64(tag_buf);
+			DP_STATS_UPD(vdev, rx_i.reo_rcvd_pkt.bytes, byte_count);
+
+			/* Extract tx success packet count from buffer */
+			tag_buf = tlv_buf_temp +
+				HTT_VDEV_STATS_GET_INDEX(TX_SUCCESS_PKT_CNT);
+			pkt_count = HTT_VDEV_GET_STATS_U64(tag_buf);
+			tx_comp.num += pkt_count;
+
+			/* Extract tx success packet byte count from buffer */
+			tag_buf = tlv_buf_temp +
+				HTT_VDEV_STATS_GET_INDEX(TX_SUCCESS_BYTE_CNT);
+			byte_count = HTT_VDEV_GET_STATS_U64(tag_buf);
+			tx_comp.bytes += byte_count;
+
+			/* Extract tx retry packet count from buffer */
+			tag_buf = tlv_buf_temp +
+				HTT_VDEV_STATS_GET_INDEX(TX_RETRY_PKT_CNT);
+			pkt_count = HTT_VDEV_GET_STATS_U64(tag_buf);
+			tx_comp.num += pkt_count;
+			tx_failed.num += pkt_count;
+
+			/* Extract tx retry packet byte count from buffer */
+			tag_buf = tlv_buf_temp +
+				HTT_VDEV_STATS_GET_INDEX(TX_RETRY_BYTE_CNT);
+			pkt_count = HTT_VDEV_GET_STATS_U64(tag_buf);
+			tx_comp.bytes += byte_count;
+			tx_failed.bytes += byte_count;
+
+			/* Extract tx drop packet count from buffer */
+			tag_buf = tlv_buf_temp +
+				HTT_VDEV_STATS_GET_INDEX(TX_DROP_PKT_CNT);
+			pkt_count = HTT_VDEV_GET_STATS_U64(tag_buf);
+			tx_comp.num += pkt_count;
+			tx_failed.num += pkt_count;
+
+			/* Extract tx drop packet byte count from buffer */
+			tag_buf = tlv_buf_temp +
+				HTT_VDEV_STATS_GET_INDEX(TX_DROP_BYTE_CNT);
+			pkt_count = HTT_VDEV_GET_STATS_U64(tag_buf);
+			tx_comp.bytes += byte_count;
+			tx_failed.bytes += byte_count;
+
+			/* Extract tx age-out packet count from buffer */
+			tag_buf = tlv_buf_temp +
+				HTT_VDEV_STATS_GET_INDEX(TX_AGE_OUT_PKT_CNT);
+			pkt_count = HTT_VDEV_GET_STATS_U64(tag_buf);
+			tx_comp.num += pkt_count;
+			tx_failed.num += pkt_count;
+
+			/* Extract tx age-out packet byte count from buffer */
+			tag_buf = tlv_buf_temp +
+				HTT_VDEV_STATS_GET_INDEX(TX_AGE_OUT_BYTE_CNT);
+			pkt_count = HTT_VDEV_GET_STATS_U64(tag_buf);
+			tx_comp.bytes += byte_count;
+			tx_failed.bytes += byte_count;
+
+			DP_STATS_UPD(vdev, tx.comp_pkt.num, tx_comp.num);
+			DP_STATS_UPD(vdev, tx.comp_pkt.bytes, tx_comp.bytes);
+
+			DP_STATS_UPD(vdev, tx.tx_failed, tx_failed.num);
+
+			dp_vdev_unref_delete(dpsoc, vdev, DP_MOD_ID_HTT);
+			break;
+		}
+		default:
+			qdf_assert(0);
+		}
+invalid_vdev:
+		msg_word = (uint32_t *)((uint8_t *)tlv_buf + tlv_length);
+		payload_size -= tlv_length;
+	}
+}
+#else
+static void dp_vdev_txrx_hw_stats_handler(struct htt_soc *soc,
+					  uint32_t *msg_word)
+{}
+#endif
+
 /*
  * time_allow_print() - time allow print
  * @htt_ring_tt:	ringi_id array of timestamps
@@ -3052,6 +3222,11 @@ static void dp_htt_t2h_msg_handler(void *context, HTC_PACKET *pkt)
 		dp_rx_mlo_timestamp_ind_handler(soc->dp_soc, msg_word);
 		break;
 	}
+	case HTT_T2H_MSG_TYPE_VDEVS_TXRX_STATS_PERIODIC_IND:
+	{
+		dp_vdev_txrx_hw_stats_handler(soc, msg_word);
+		break;
+	}
 	default:
 		break;
 	};
@@ -3385,6 +3560,125 @@ QDF_STATUS dp_h2t_ext_stats_msg_send(struct dp_pdev *pdev,
 	return status;
 }
 
+#ifdef QCA_VDEV_STATS_HW_OFFLOAD_SUPPORT
+#define HTT_VDEV_TXRX_STATS_RESET_BITMASK_L32_MASK 0xFFFFFFFF
+#define HTT_VDEV_TXRX_STATS_RESET_BITMASK_U32_MASK 0xFFFFFFFF00000000
+#define HTT_VDEV_TXRX_STATS_RESET_BITMASK_U32_SHIFT 32
+
+QDF_STATUS dp_h2t_hw_vdev_stats_config_send(struct dp_soc *dpsoc,
+					    uint8_t pdev_id, bool enable,
+					    bool reset, uint64_t reset_bitmask)
+{
+	struct htt_soc *soc = dpsoc->htt_handle;
+	struct dp_htt_htc_pkt *pkt;
+	qdf_nbuf_t msg;
+	uint32_t *msg_word;
+	uint8_t *htt_logger_bufp;
+	QDF_STATUS status;
+	int duration;
+	uint32_t bitmask;
+	int target_pdev_id;
+
+	msg = qdf_nbuf_alloc(
+			soc->osdev,
+			HTT_MSG_BUF_SIZE(sizeof(struct htt_h2t_vdevs_txrx_stats_cfg)),
+			HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, true);
+
+	if (!msg) {
+		dp_htt_err("%pK: Fail to allocate "
+		"HTT_H2T_HW_VDEV_TXRX_STATS_CFG_MSG_SZ msg buffer", dpsoc);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	if (pdev_id != INVALID_PDEV_ID)
+		target_pdev_id = DP_SW2HW_MACID(pdev_id);
+	else
+		target_pdev_id = 0;
+
+	duration =
+	wlan_cfg_get_vdev_stats_hw_offload_timer(dpsoc->wlan_cfg_ctx);
+
+	/*
+	 * Set the length of the message.
+	 * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added
+	 * separately during the below call to qdf_nbuf_push_head.
+	 * The contribution from the HTC header is added separately inside HTC.
+	 */
+	if (!qdf_nbuf_put_tail(msg,
+			       sizeof(struct htt_h2t_vdevs_txrx_stats_cfg))) {
+		dp_htt_err("%pK: Failed to expand head for HTT_HW_VDEV_STATS"
+			   , dpsoc);
+		qdf_nbuf_free(msg);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	msg_word = (uint32_t *)qdf_nbuf_data(msg);
+
+	qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING);
+	htt_logger_bufp = (uint8_t *)msg_word;
+	*msg_word = 0;
+
+	HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_VDEVS_TXRX_STATS_CFG);
+	HTT_RX_VDEVS_TXRX_STATS_PDEV_ID_SET(*msg_word, target_pdev_id);
+
+	HTT_RX_VDEVS_TXRX_STATS_ENABLE_SET(*msg_word, enable);
+
+	HTT_RX_VDEVS_TXRX_STATS_PERIODIC_INTERVAL_SET(*msg_word,
+						      (duration >> 3));
+
+	HTT_RX_VDEVS_TXRX_STATS_RESET_STATS_BITS_SET(*msg_word, reset);
+
+	msg_word++;
+	*msg_word = 0;
+	bitmask = (reset_bitmask & HTT_VDEV_TXRX_STATS_RESET_BITMASK_L32_MASK);
+	*msg_word = bitmask;
+
+	msg_word++;
+	*msg_word = 0;
+	bitmask =
+		((reset_bitmask & HTT_VDEV_TXRX_STATS_RESET_BITMASK_U32_MASK) >>
+		 HTT_VDEV_TXRX_STATS_RESET_BITMASK_U32_SHIFT);
+	*msg_word = bitmask;
+
+	pkt = htt_htc_pkt_alloc(soc);
+	if (!pkt) {
+		dp_htt_err("%pK: Fail to allocate dp_htt_htc_pkt buffer",
+			   dpsoc);
+		qdf_assert(0);
+		qdf_nbuf_free(msg);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	pkt->soc_ctxt = NULL; /* not used during send-done callback */
+
+	SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt,
+			       dp_htt_h2t_send_complete_free_netbuf,
+			       qdf_nbuf_data(msg), qdf_nbuf_len(msg),
+			       soc->htc_endpoint,
+			       /* tag for no FW response msg */
+			       HTC_TX_PACKET_TAG_RUNTIME_PUT);
+
+	SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg);
+	status = DP_HTT_SEND_HTC_PKT(soc, pkt,
+				     HTT_H2T_MSG_TYPE_VDEVS_TXRX_STATS_CFG,
+				     htt_logger_bufp);
+
+	if (status != QDF_STATUS_SUCCESS) {
+		qdf_nbuf_free(msg);
+		htt_htc_pkt_free(soc, pkt);
+	}
+
+	return status;
+}
+#else
+QDF_STATUS dp_h2t_hw_vdev_stats_config_send(struct dp_soc *dpsoc,
+					    uint8_t pdev_id, bool enable,
+					    bool reset, uint64_t reset_bitmask)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * dp_h2t_3tuple_config_send(): function to contruct 3 tuple configuration
  * HTT message to pass to FW

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

@@ -139,6 +139,35 @@ void htt_htc_pkt_pool_free(struct htt_soc *soc);
 #define HTT_GET_STATS_CMN_INDEX(index) \
 	HTT_PPDU_STATS_COMMON_TLV_##index##_OFFSET
 
+#define HTT_VDEV_STATS_TLV_SOC_DROP_CNT_OFFSET        1
+
+#define HTT_VDEV_STATS_TLV_HDR_OFFSET                 0
+#define HTT_VDEV_STATS_TLV_VDEV_ID_OFFSET             1
+#define HTT_VDEV_STATS_TLV_RX_BYTE_CNT_OFFSET         2
+#define HTT_VDEV_STATS_TLV_RX_PKT_CNT_OFFSET          4
+#define HTT_VDEV_STATS_TLV_TX_SUCCESS_BYTE_CNT_OFFSET 6
+#define HTT_VDEV_STATS_TLV_TX_SUCCESS_PKT_CNT_OFFSET  8
+#define HTT_VDEV_STATS_TLV_TX_RETRY_BYTE_CNT_OFFSET   10
+#define HTT_VDEV_STATS_TLV_TX_RETRY_PKT_CNT_OFFSET    12
+#define HTT_VDEV_STATS_TLV_TX_DROP_BYTE_CNT_OFFSET    14
+#define HTT_VDEV_STATS_TLV_TX_DROP_PKT_CNT_OFFSET     16
+#define HTT_VDEV_STATS_TLV_TX_AGE_OUT_BYTE_CNT_OFFSET 18
+#define HTT_VDEV_STATS_TLV_TX_AGE_OUT_PKT_CNT_OFFSET  20
+
+#define HTT_VDEV_STATS_GET_INDEX(index) \
+	HTT_VDEV_STATS_TLV_##index##_OFFSET
+
+#define HTT_VDEV_STATS_U32_SHIFT 0x20
+#define HTT_VDEV_STATS_U32_MASK  0xFFFFFFFF00000000
+#define HTT_VDEV_STATS_L32_MASK  0x00000000FFFFFFFF
+
+#define HTT_VDEV_GET_STATS_U64(msg_word) \
+	(((((uint64_t)(*(((uint32_t *)msg_word) + 1))) & HTT_VDEV_STATS_L32_MASK) << \
+	HTT_VDEV_STATS_U32_SHIFT) | ((*(uint32_t *)msg_word) & HTT_VDEV_STATS_L32_MASK))
+
+#define HTT_VDEV_GET_STATS_U32(msg_word) \
+	((*(uint32_t *)msg_word) & HTT_VDEV_STATS_L32_MASK)
+
 #define MAX_SCHED_STARVE 100000
 #define WRAP_DROP_TSF_DELTA 10000
 #define MAX_TSF_32 0xFFFFFFFF
@@ -885,4 +914,19 @@ dp_htt_rx_flow_fse_operation(struct dp_pdev *pdev,
 int htt_h2t_full_mon_cfg(struct htt_soc *htt_soc,
 			 uint8_t pdev_id,
 			 enum dp_full_mon_config);
+
+/**
+ * dp_h2t_hw_vdev_stats_config_send: Send HTT command to FW for config
+				     of HW vdev stats
+ * @dpsoc: Datapath soc handle
+ * @pdev_id: INVALID_PDEV_ID for all pdevs or 0,1,2 for individual pdev
+ * @enable: flag to specify enable/disable of stats
+ * @reset: flag to specify if command is for reset of stats
+ * @reset_bitmask: bitmask of vdev_id(s) for reset of HW stats
+ *
+ *  Return: QDF_STATUS
+ */
+QDF_STATUS dp_h2t_hw_vdev_stats_config_send(struct dp_soc *dpsoc,
+					    uint8_t pdev_id, bool enable,
+					    bool reset, uint64_t reset_bitmask);
 #endif /* _DP_HTT_H_ */

+ 66 - 0
dp/wifi3.0/dp_main.c

@@ -5141,6 +5141,66 @@ static void dp_pdev_flush_pending_vdevs(struct dp_pdev *pdev)
 }
 #endif
 
+#ifdef QCA_VDEV_STATS_HW_OFFLOAD_SUPPORT
+/**
+ * dp_vdev_stats_hw_offload_target_config() - Send HTT command to FW
+ *                                          for enable/disable of HW vdev stats
+ * @soc: Datapath soc handle
+ * @pdev_id: INVALID_PDEV_ID for all pdevs or 0,1,2 for individual pdev
+ * @enable: flag to reprsent enable/disable of hw vdev stats
+ *
+ * Return: none
+ */
+static void dp_vdev_stats_hw_offload_target_config(struct dp_soc *soc,
+						   uint8_t pdev_id,
+						   bool enable)
+{
+	/* Check SOC level config for HW offload vdev stats support */
+	if (!wlan_cfg_get_vdev_stats_hw_offload_config(soc->wlan_cfg_ctx)) {
+		dp_debug("%pK: HW vdev offload stats is disabled", soc);
+		return;
+	}
+
+	/* Send HTT command to FW for enable of stats */
+	dp_h2t_hw_vdev_stats_config_send(soc, pdev_id, enable, false, 0);
+}
+
+/**
+ * dp_vdev_stats_hw_offload_target_clear() - Clear HW vdev stats on target
+ * @soc: Datapath soc handle
+ * @pdev_id: pdev_id (0,1,2)
+ * @bitmask: bitmask with vdev_id(s) for which stats are to be cleared on HW
+ *
+ * Return: none
+ */
+static
+void dp_vdev_stats_hw_offload_target_clear(struct dp_soc *soc, uint8_t pdev_id,
+					   uint64_t vdev_id_bitmask)
+{
+	/* Check SOC level config for HW offload vdev stats support */
+	if (!wlan_cfg_get_vdev_stats_hw_offload_config(soc->wlan_cfg_ctx)) {
+		dp_debug("%pK: HW vdev offload stats is disabled", soc);
+		return;
+	}
+
+	/* Send HTT command to FW for reset of stats */
+	dp_h2t_hw_vdev_stats_config_send(soc, pdev_id, true, true,
+					 vdev_id_bitmask);
+}
+#else
+static void
+dp_vdev_stats_hw_offload_target_config(struct dp_soc *soc, uint8_t pdev_id,
+				       bool enable)
+{
+}
+
+static
+void dp_vdev_stats_hw_offload_target_clear(struct dp_soc *soc, uint8_t pdev_id,
+					   uint64_t vdev_id_bitmask)
+{
+}
+#endif /*QCA_VDEV_STATS_HW_OFFLOAD_SUPPORT */
+
 /**
  * dp_pdev_deinit() - Deinit txrx pdev
  * @txrx_pdev: Datapath PDEV handle
@@ -5863,6 +5923,9 @@ dp_soc_attach_target_wifi3(struct cdp_soc_t *cdp_soc)
 
 	dp_runtime_init(soc);
 
+	/* Enable HW vdev offload stats if feature is supported */
+	dp_vdev_stats_hw_offload_target_config(soc, INVALID_PDEV_ID, true);
+
 	/* initialize work queue for stats processing */
 	qdf_create_work(0, &soc->htt_stats.work, htt_t2h_stats_handler, soc);
 
@@ -8594,6 +8657,9 @@ dp_txrx_host_stats_clr(struct dp_vdev *vdev, struct dp_soc *soc)
 							   vdev->vdev_id);
 	}
 
+	dp_vdev_stats_hw_offload_target_clear(soc, vdev->pdev->pdev_id,
+					      vdev->vdev_id);
+
 	DP_STATS_CLR(vdev->pdev);
 	DP_STATS_CLR(vdev->pdev->soc);
 	DP_STATS_CLR(vdev);