瀏覽代碼

qcacmn: add the tx_desc id checking

If host receive the tx completion with invalid tx_desc ID,
panic happened. add the tx desc ID check both on dp_tx_hw_enqueue
and dp_tx_comp_handler to know that how this invalid tx_desc ID
is generated by which reason of below two:
1. host tx desc is corrupted and fill in invalid id to TCL_DATA_CMD.
2. FW or HW generate invalid TX compl to host.

Change-Id: Id2b070697199b19f83e5d9fd89eadcfe0423d617
CRs-Fixed: 2243455
Jinwei Chen 7 年之前
父節點
當前提交
fc76555f2e
共有 2 個文件被更改,包括 97 次插入10 次删除
  1. 6 10
      dp/wifi3.0/dp_tx.c
  2. 91 0
      dp/wifi3.0/dp_tx_desc.h

+ 6 - 10
dp/wifi3.0/dp_tx.c

@@ -839,6 +839,10 @@ static QDF_STATUS dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev,
 	hal_tx_desc_set_fw_metadata(hal_tx_desc_cached, fw_metadata);
 	hal_tx_desc_set_buf_addr(hal_tx_desc_cached,
 			dma_addr , bm_id, tx_desc->id, type);
+
+	if (!dp_tx_is_desc_id_valid(soc, tx_desc->id))
+		return QDF_STATUS_E_RESOURCES;
+
 	hal_tx_desc_set_buf_length(hal_tx_desc_cached, length);
 	hal_tx_desc_set_buf_offset(hal_tx_desc_cached, tx_desc->pkt_offset);
 	hal_tx_desc_set_encap_type(hal_tx_desc_cached, tx_desc->tx_encap_type);
@@ -2815,16 +2819,8 @@ uint32_t dp_tx_comp_handler(struct dp_soc *soc, void *hal_srng, uint32_t quota)
 		pool_id = (tx_desc_id & DP_TX_DESC_ID_POOL_MASK) >>
 			DP_TX_DESC_ID_POOL_OS;
 
-		/* Pool ID is out of limit. Error */
-		if (pool_id > wlan_cfg_get_num_tx_desc_pool(
-					soc->wlan_cfg_ctx)) {
-			QDF_TRACE(QDF_MODULE_ID_DP,
-					QDF_TRACE_LEVEL_FATAL,
-					"Tx Comp pool id %d not valid",
-					pool_id);
-
-			qdf_assert_always(0);
-		}
+		if (!dp_tx_is_desc_id_valid(soc, tx_desc_id))
+			continue;
 
 		/* Find Tx descriptor */
 		tx_desc = dp_tx_desc_find(soc, pool_id,

+ 91 - 0
dp/wifi3.0/dp_tx_desc.h

@@ -56,6 +56,8 @@
 #define TX_DESC_LOCK_DESTROY(lock)
 #define TX_DESC_LOCK_LOCK(lock)
 #define TX_DESC_LOCK_UNLOCK(lock)
+#define IS_TX_DESC_POOL_STATUS_INACTIVE(pool) \
+	((pool)->status == FLOW_POOL_INACTIVE)
 #define TX_DESC_POOL_MEMBER_CLEAN(_tx_desc_pool)       \
 do {                                                   \
 	(_tx_desc_pool)->elem_size = 0;                \
@@ -71,6 +73,7 @@ do {                                                   \
 #define TX_DESC_LOCK_DESTROY(lock) qdf_spinlock_destroy(lock)
 #define TX_DESC_LOCK_LOCK(lock)    qdf_spin_lock_bh(lock)
 #define TX_DESC_LOCK_UNLOCK(lock)  qdf_spin_unlock_bh(lock)
+#define IS_TX_DESC_POOL_STATUS_INACTIVE(pool) (false)
 #define TX_DESC_POOL_MEMBER_CLEAN(_tx_desc_pool)       \
 do {                                                   \
 	(_tx_desc_pool)->elem_size = 0;                \
@@ -371,6 +374,94 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 }
 #endif /* QCA_LL_TX_FLOW_CONTROL_V2 */
 
+#ifdef QCA_DP_TX_DESC_ID_CHECK
+/**
+ * dp_tx_is_desc_id_valid() - check is the tx desc id valid
+ *
+ * @soc Handle to DP SoC structure
+ * @tx_desc_id
+ *
+ * Return: true or false
+ */
+static inline bool
+dp_tx_is_desc_id_valid(struct dp_soc *soc, uint32_t tx_desc_id)
+{
+	uint8_t pool_id;
+	uint16_t page_id, offset;
+	struct dp_tx_desc_pool_s *pool;
+
+	pool_id = (tx_desc_id & DP_TX_DESC_ID_POOL_MASK) >>
+			DP_TX_DESC_ID_POOL_OS;
+	/* Pool ID is out of limit */
+	if (pool_id > wlan_cfg_get_num_tx_desc_pool(
+				soc->wlan_cfg_ctx)) {
+		QDF_TRACE(QDF_MODULE_ID_DP,
+			  QDF_TRACE_LEVEL_FATAL,
+			  "%s:Tx Comp pool id %d not valid",
+			  __func__,
+			  pool_id);
+		goto warn_exit;
+	}
+
+	pool = &soc->tx_desc[pool_id];
+	/* the pool is freed */
+	if (IS_TX_DESC_POOL_STATUS_INACTIVE(pool)) {
+		QDF_TRACE(QDF_MODULE_ID_DP,
+			  QDF_TRACE_LEVEL_FATAL,
+			  "%s:the pool %d has been freed",
+			  __func__,
+			  pool_id);
+		goto warn_exit;
+	}
+
+	page_id = (tx_desc_id & DP_TX_DESC_ID_PAGE_MASK) >>
+				DP_TX_DESC_ID_PAGE_OS;
+	/* the page id is out of limit */
+	if (page_id >= pool->desc_pages.num_pages) {
+		QDF_TRACE(QDF_MODULE_ID_DP,
+			  QDF_TRACE_LEVEL_FATAL,
+			  "%s:the page id %d invalid, pool id %d, num_page %d",
+			  __func__,
+			  page_id,
+			  pool_id,
+			  pool->desc_pages.num_pages);
+		goto warn_exit;
+	}
+
+	offset = (tx_desc_id & DP_TX_DESC_ID_OFFSET_MASK) >>
+				DP_TX_DESC_ID_OFFSET_OS;
+	/* the offset is out of limit */
+	if (offset >= pool->desc_pages.num_element_per_page) {
+		QDF_TRACE(QDF_MODULE_ID_DP,
+			  QDF_TRACE_LEVEL_FATAL,
+			  "%s:offset %d invalid, pool%d,num_elem_per_page %d",
+			  __func__,
+			  offset,
+			  pool_id,
+			  pool->desc_pages.num_element_per_page);
+		goto warn_exit;
+	}
+
+	return true;
+
+warn_exit:
+	QDF_TRACE(QDF_MODULE_ID_DP,
+		  QDF_TRACE_LEVEL_FATAL,
+		  "%s:Tx desc id 0x%x not valid",
+		  __func__,
+		  tx_desc_id);
+	qdf_assert_always(0);
+	return false;
+}
+
+#else
+static inline bool
+dp_tx_is_desc_id_valid(struct dp_soc *soc, uint32_t tx_desc_id)
+{
+	return true;
+}
+#endif /* QCA_DP_TX_DESC_ID_CHECK */
+
 /**
  * dp_tx_desc_find() - find dp tx descriptor from cokie
  * @soc - handle for the device sending the data