qcacld-3.0: Add logic in host to detect msdu_id duplication

Add logic in host to detect if host is using
musdu_id which is already in use.

CRs-Fixed: 929428
Change-Id: I10413ed4b5b76e16211aa0cbb9012cfb8f26cae0
diff --git a/Kbuild b/Kbuild
index f2764c9..1503d74 100755
--- a/Kbuild
+++ b/Kbuild
@@ -1117,6 +1117,10 @@
 CDEFINES += -DWLAN_FEATURE_LPSS
 endif
 
+ifneq ($(TARGET_BUILD_VARIANT),user)
+CDEFINES += -DDESC_DUP_DETECT_DEBUG
+endif
+
 ifeq ($(PANIC_ON_BUG),1)
 CDEFINES += -DPANIC_ON_BUG
 endif
diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c
index 4708461..152beec 100644
--- a/core/dp/txrx/ol_tx_desc.c
+++ b/core/dp/txrx/ol_tx_desc.c
@@ -122,6 +122,7 @@
 	qdf_spin_lock_bh(&pdev->tx_mutex);
 	if (pdev->tx_desc.freelist) {
 		tx_desc = ol_tx_get_desc_global_pool(pdev);
+		ol_tx_desc_dup_detect_set(pdev, tx_desc);
 		ol_tx_desc_sanity_checks(pdev, tx_desc);
 		ol_tx_desc_compute_delay(tx_desc);
 	}
@@ -165,6 +166,7 @@
 		qdf_spin_lock_bh(&pool->flow_pool_lock);
 		if (pool->avail_desc) {
 			tx_desc = ol_tx_get_desc_flow_pool(pool);
+			ol_tx_desc_dup_detect_set(pdev, tx_desc);
 			if (qdf_unlikely(pool->avail_desc < pool->stop_th)) {
 				pool->status = FLOW_POOL_ACTIVE_PAUSED;
 				qdf_spin_unlock_bh(&pool->flow_pool_lock);
@@ -239,6 +241,7 @@
 			ol_tso_free_segment(pdev, tx_desc->tso_desc);
 		}
 	}
+	ol_tx_desc_dup_detect_reset(pdev, tx_desc);
 	ol_tx_desc_reset_pkt_type(tx_desc);
 	ol_tx_desc_reset_timestamp(tx_desc);
 
@@ -271,6 +274,7 @@
 	ol_tx_desc_reset_timestamp(tx_desc);
 
 	qdf_spin_lock_bh(&pool->flow_pool_lock);
+	ol_tx_desc_dup_detect_reset(pdev, tx_desc);
 	ol_tx_put_desc_flow_pool(pool, tx_desc);
 	switch (pool->status) {
 	case FLOW_POOL_ACTIVE_PAUSED:
@@ -366,7 +370,6 @@
 	}
 
 	/* initialize the HW tx descriptor */
-
 	htt_tx_desc_init(pdev->htt_pdev, tx_desc->htt_tx_desc,
 			 tx_desc->htt_tx_desc_paddr,
 			 ol_tx_desc_id(pdev, tx_desc), netbuf, &msdu_info->htt,
diff --git a/core/dp/txrx/ol_tx_desc.h b/core/dp/txrx/ol_tx_desc.h
index 9b0cf42..ed72650 100644
--- a/core/dp/txrx/ol_tx_desc.h
+++ b/core/dp/txrx/ol_tx_desc.h
@@ -37,6 +37,11 @@
 #include <cdp_txrx_cmn.h>       /* ol_txrx_vdev_t, etc. */
 #include <ol_txrx_internal.h>   /*TXRX_ASSERT2 */
 
+#define DIV_BY_8	3
+#define DIV_BY_32	5
+#define MOD_BY_8	0x7
+#define MOD_BY_32	0x1F
+
 struct ol_tx_desc_t *
 ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev,
 			 struct ol_txrx_vdev_t *vdev,
@@ -253,4 +258,120 @@
 }
 #endif
 
+#ifdef DESC_DUP_DETECT_DEBUG
+/**
+ * ol_tx_desc_dup_detect_init() - initialize descriptor duplication logic
+ * @pdev: pdev handle
+ * @pool_size: global pool size
+ *
+ * Return: none
+ */
+static inline
+void ol_tx_desc_dup_detect_init(struct ol_txrx_pdev_t *pdev, uint16_t pool_size)
+{
+	uint16_t size = (pool_size >> DIV_BY_8) +
+			((pool_size & MOD_BY_8) ? 1 : 0);
+	pdev->tx_desc.free_list_bitmap = qdf_mem_malloc(size);
+	if (!pdev->tx_desc.free_list_bitmap)
+		qdf_print("%s: malloc failed", __func__);
+}
+
+/**
+ * ol_tx_desc_dup_detect_deinit() - deinit descriptor duplication logic
+ * @pdev: pdev handle
+ *
+ * Return: none
+ */
+static inline
+void ol_tx_desc_dup_detect_deinit(struct ol_txrx_pdev_t *pdev)
+{
+	qdf_print("%s: pool_size %d num_free %d\n", __func__,
+		pdev->tx_desc.pool_size, pdev->tx_desc.num_free);
+	if (pdev->tx_desc.free_list_bitmap)
+		qdf_mem_free(pdev->tx_desc.free_list_bitmap);
+}
+
+/**
+ * ol_tx_desc_dup_detect_set() - set bit for msdu_id
+ * @pdev: pdev handle
+ * @tx_desc: tx descriptor
+ *
+ * Return: none
+ */
+static inline
+void ol_tx_desc_dup_detect_set(struct ol_txrx_pdev_t *pdev,
+				struct ol_tx_desc_t *tx_desc)
+{
+	uint16_t msdu_id = ol_tx_desc_id(pdev, tx_desc);
+	uint16_t index = msdu_id >> DIV_BY_32;
+	uint8_t pos = msdu_id & MOD_BY_32;
+
+	if (!pdev->tx_desc.free_list_bitmap)
+		return;
+
+	if (qdf_unlikely(pdev->tx_desc.free_list_bitmap[index] & (1 << pos))) {
+		uint16_t size = (pdev->tx_desc.pool_size >> DIV_BY_8) +
+			((pdev->tx_desc.pool_size & MOD_BY_8) ? 1 : 0);
+		qdf_print("duplicate msdu_id %d detected !!\n", msdu_id);
+		qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+		(void *)pdev->tx_desc.free_list_bitmap, size);
+		QDF_BUG(0);
+	}
+	pdev->tx_desc.free_list_bitmap[index] |= (1 << pos);
+}
+
+/**
+ * ol_tx_desc_dup_detect_reset() - reset bit for msdu_id
+ * @pdev: pdev handle
+ * @tx_desc: tx descriptor
+ *
+ * Return: none
+ */
+static inline
+void ol_tx_desc_dup_detect_reset(struct ol_txrx_pdev_t *pdev,
+				 struct ol_tx_desc_t *tx_desc)
+{
+	uint16_t msdu_id = ol_tx_desc_id(pdev, tx_desc);
+	uint16_t index = msdu_id >> DIV_BY_32;
+	uint8_t pos = msdu_id & MOD_BY_32;
+
+	if (!pdev->tx_desc.free_list_bitmap)
+		return;
+
+	if (qdf_unlikely(!
+		(pdev->tx_desc.free_list_bitmap[index] & (1 << pos)))) {
+		uint16_t size = (pdev->tx_desc.pool_size >> DIV_BY_8) +
+			((pdev->tx_desc.pool_size & MOD_BY_8) ? 1 : 0);
+		qdf_print("duplicate free msg received for msdu_id %d!!\n",
+								 msdu_id);
+		qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+		(void *)pdev->tx_desc.free_list_bitmap, size);
+		QDF_BUG(0);
+	}
+	pdev->tx_desc.free_list_bitmap[index] &= ~(1 << pos);
+}
+#else
+static inline
+void ol_tx_desc_dup_detect_init(struct ol_txrx_pdev_t *pdev, uint16_t size)
+{
+}
+
+static inline
+void ol_tx_desc_dup_detect_deinit(struct ol_txrx_pdev_t *pdev)
+{
+}
+
+static inline
+void ol_tx_desc_dup_detect_set(struct ol_txrx_pdev_t *pdev,
+				struct ol_tx_desc_t *tx_desc)
+{
+}
+
+static inline
+void ol_tx_desc_dup_detect_reset(struct ol_txrx_pdev_t *pdev,
+				 struct ol_tx_desc_t *tx_desc)
+{
+}
+#endif
+
 #endif /* _OL_TX_DESC__H_ */
diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c
index 7c9c94c..a3bd7be 100644
--- a/core/dp/txrx/ol_txrx.c
+++ b/core/dp/txrx/ol_txrx.c
@@ -548,6 +548,8 @@
 
 	desc_pool_size = ol_tx_get_desc_global_pool_size(pdev);
 
+	ol_tx_desc_dup_detect_init(pdev, desc_pool_size);
+
 	setup_fastpath_ce_handles(osc, pdev);
 
 	ret = htt_attach(pdev->htt_pdev, desc_pool_size);
@@ -1081,6 +1083,8 @@
 	htt_detach(pdev->htt_pdev);
 	htt_pdev_free(pdev->htt_pdev);
 
+	ol_tx_desc_dup_detect_deinit(pdev);
+
 	ol_txrx_peer_find_detach(pdev);
 
 	qdf_spinlock_destroy(&pdev->tx_mutex);
diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h
index 87e4ac8..ff36e19 100644
--- a/core/dp/txrx/ol_txrx_types.h
+++ b/core/dp/txrx/ol_txrx_types.h
@@ -564,6 +564,9 @@
 		uint8_t page_divider;
 		uint32_t offset_filter;
 		struct qdf_mem_multi_page_t desc_pages;
+#ifdef DESC_DUP_DETECT_DEBUG
+		uint32_t *free_list_bitmap;
+#endif
 	} tx_desc;
 
 	uint8_t is_mgmt_over_wmi_enabled;