浏览代码

qcacmn: Add support for fragmented history recording

Currently the history recording for any debug purpose
is done using a contiguous memory chunk. For certain
history like tx_hw_ring, tx desc or tx completion desc
history, the amount of contiguous memory required is
very huge (order 7 or 8 allocation), which have a
higher probability of failing.

In order to mitigate the above scenario, introduce the
support for recording debug history into fragmented
chunks of memory, thereby reducing the requirement of
contiguous memory.

Change-Id: Iac4fb38b6d4b095766520899853e68b4c2b83afc
CRs-Fixed: 3282269
Rakesh Pillai 2 年之前
父节点
当前提交
d706698dd1
共有 5 个文件被更改,包括 183 次插入46 次删除
  1. 103 0
      dp/wifi3.0/dp_internal.h
  2. 24 23
      dp/wifi3.0/dp_main.c
  3. 21 9
      dp/wifi3.0/dp_tx.c
  4. 11 7
      dp/wifi3.0/dp_tx.h
  5. 24 7
      dp/wifi3.0/dp_types.h

+ 103 - 0
dp/wifi3.0/dp_internal.h

@@ -3657,6 +3657,109 @@ void dp_desc_multi_pages_mem_free(struct dp_soc *soc,
 }
 #endif
 
+/**
+ * struct dp_frag_history_opaque_atomic - Opaque struct for adding a fragmented
+ *					  history.
+ * @index: atomic index
+ * @num_entries_per_slot: Number of entries per slot
+ * @allocated: is allocated or not
+ * @entry: pointers to array of records
+ */
+struct dp_frag_history_opaque_atomic {
+	qdf_atomic_t index;
+	uint16_t num_entries_per_slot;
+	uint16_t allocated;
+	void *entry[0];
+};
+
+static inline QDF_STATUS
+dp_soc_frag_history_attach(struct dp_soc *soc, void *history_hdl,
+			   uint32_t max_slots, uint32_t max_entries_per_slot,
+			   uint32_t entry_size,
+			   bool attempt_prealloc, enum dp_ctxt_type ctxt_type)
+{
+	struct dp_frag_history_opaque_atomic *history =
+			(struct dp_frag_history_opaque_atomic *)history_hdl;
+	size_t alloc_size = max_entries_per_slot * entry_size;
+	int i;
+
+	for (i = 0; i < max_slots; i++) {
+		if (attempt_prealloc)
+			history->entry[i] = dp_context_alloc_mem(soc, ctxt_type,
+								 alloc_size);
+		else
+			history->entry[i] = qdf_mem_malloc(alloc_size);
+
+		if (!history->entry[i])
+			goto exit;
+	}
+
+	qdf_atomic_init(&history->index);
+	history->allocated = 1;
+	history->num_entries_per_slot = max_entries_per_slot;
+
+	return QDF_STATUS_SUCCESS;
+exit:
+	for (i = i - 1; i >= 0; i--) {
+		if (attempt_prealloc)
+			dp_context_free_mem(soc, ctxt_type, history->entry[i]);
+		else
+			qdf_mem_free(history->entry[i]);
+	}
+
+	return QDF_STATUS_E_NOMEM;
+}
+
+static inline
+void dp_soc_frag_history_detach(struct dp_soc *soc,
+				void *history_hdl, uint32_t max_slots,
+				bool attempt_prealloc,
+				enum dp_ctxt_type ctxt_type)
+{
+	struct dp_frag_history_opaque_atomic *history =
+			(struct dp_frag_history_opaque_atomic *)history_hdl;
+	int i;
+
+	for (i = 0; i < max_slots; i++) {
+		if (attempt_prealloc)
+			dp_context_free_mem(soc, ctxt_type, history->entry[i]);
+		else
+			qdf_mem_free(history->entry[i]);
+	}
+
+	history->allocated = 0;
+}
+
+/**
+ * dp_get_frag_hist_next_atomic_idx() - get the next entry index to record an
+ *					entry in a fragmented history with
+ *					index being atomic.
+ * @curr_idx: address of the current index where the last entry was written
+ * @next_idx: pointer to update the next index
+ * @slot: pointer to update the history slot to be selected
+ * @slot_shift: BITwise shift mask for slot (in index)
+ * @max_entries_per_slot: Max number of entries in a slot of history
+ * @max_entries: Total number of entries in the history (sum of all slots)
+ *
+ * This function assumes that the "max_entries_per_slot" and "max_entries"
+ * are a power-of-2.
+ *
+ * Return: None
+ */
+static inline void
+dp_get_frag_hist_next_atomic_idx(qdf_atomic_t *curr_idx, uint32_t *next_idx,
+				 uint16_t *slot, uint32_t slot_shift,
+				 uint32_t max_entries_per_slot,
+				 uint32_t max_entries)
+{
+	uint32_t idx;
+
+	idx = qdf_do_div_rem(qdf_atomic_inc_return(curr_idx), max_entries);
+
+	*slot = idx >> slot_shift;
+	*next_idx = idx & (max_entries_per_slot - 1);
+}
+
 #ifdef FEATURE_RUNTIME_PM
 /**
  * dp_runtime_get() - Get dp runtime refcount

+ 24 - 23
dp/wifi3.0/dp_main.c

@@ -5374,17 +5374,18 @@ static void dp_free_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
  */
 static void dp_soc_tx_hw_desc_history_attach(struct dp_soc *soc)
 {
-	soc->tx_hw_desc_history = dp_context_alloc_mem(
-			soc, DP_TX_HW_DESC_HIST_TYPE,
-			sizeof(*soc->tx_hw_desc_history));
-	if (soc->tx_hw_desc_history)
-		soc->tx_hw_desc_history->index = 0;
+	dp_soc_frag_history_attach(soc, &soc->tx_hw_desc_history,
+				   DP_TX_HW_DESC_HIST_MAX_SLOTS,
+				   DP_TX_HW_DESC_HIST_PER_SLOT_MAX,
+				   sizeof(struct dp_tx_hw_desc_evt),
+				   true, DP_TX_HW_DESC_HIST_TYPE);
 }
 
 static void dp_soc_tx_hw_desc_history_detach(struct dp_soc *soc)
 {
-	dp_context_free_mem(soc, DP_TX_HW_DESC_HIST_TYPE,
-			    soc->tx_hw_desc_history);
+	dp_soc_frag_history_detach(soc, &soc->tx_hw_desc_history,
+				   DP_TX_HW_DESC_HIST_MAX_SLOTS,
+				   true, DP_TX_HW_DESC_HIST_TYPE);
 }
 
 #else /* DP_TX_HW_DESC_HISTORY */
@@ -5561,20 +5562,16 @@ static void dp_soc_mon_status_ring_history_detach(struct dp_soc *soc)
  */
 static void dp_soc_tx_history_attach(struct dp_soc *soc)
 {
-	uint32_t tx_tcl_hist_size;
-	uint32_t tx_comp_hist_size;
-
-	tx_tcl_hist_size = sizeof(*soc->tx_tcl_history);
-	soc->tx_tcl_history = dp_context_alloc_mem(soc, DP_TX_TCL_HIST_TYPE,
-						   tx_tcl_hist_size);
-	if (soc->tx_tcl_history)
-		qdf_atomic_init(&soc->tx_tcl_history->index);
-
-	tx_comp_hist_size = sizeof(*soc->tx_comp_history);
-	soc->tx_comp_history = dp_context_alloc_mem(soc, DP_TX_COMP_HIST_TYPE,
-						    tx_comp_hist_size);
-	if (soc->tx_comp_history)
-		qdf_atomic_init(&soc->tx_comp_history->index);
+	dp_soc_frag_history_attach(soc, &soc->tx_tcl_history,
+				   DP_TX_TCL_HIST_MAX_SLOTS,
+				   DP_TX_TCL_HIST_PER_SLOT_MAX,
+				   sizeof(struct dp_tx_desc_event),
+				   true, DP_TX_TCL_HIST_TYPE);
+	dp_soc_frag_history_attach(soc, &soc->tx_comp_history,
+				   DP_TX_COMP_HIST_MAX_SLOTS,
+				   DP_TX_COMP_HIST_PER_SLOT_MAX,
+				   sizeof(struct dp_tx_desc_event),
+				   true, DP_TX_COMP_HIST_TYPE);
 }
 
 /**
@@ -5588,8 +5585,12 @@ static void dp_soc_tx_history_attach(struct dp_soc *soc)
  */
 static void dp_soc_tx_history_detach(struct dp_soc *soc)
 {
-	dp_context_free_mem(soc, DP_TX_TCL_HIST_TYPE, soc->tx_tcl_history);
-	dp_context_free_mem(soc, DP_TX_COMP_HIST_TYPE, soc->tx_comp_history);
+	dp_soc_frag_history_detach(soc, &soc->tx_tcl_history,
+				   DP_TX_TCL_HIST_MAX_SLOTS,
+				   true, DP_TX_TCL_HIST_TYPE);
+	dp_soc_frag_history_detach(soc, &soc->tx_comp_history,
+				   DP_TX_COMP_HIST_MAX_SLOTS,
+				   true, DP_TX_COMP_HIST_TYPE);
 }
 
 #else

+ 21 - 9
dp/wifi3.0/dp_tx.c

@@ -142,27 +142,39 @@ dp_tx_desc_history_add(struct dp_soc *soc, dma_addr_t paddr,
 		       qdf_nbuf_t skb, uint32_t sw_cookie,
 		       enum dp_tx_event_type type)
 {
+	struct dp_tx_tcl_history *tx_tcl_history = &soc->tx_tcl_history;
+	struct dp_tx_comp_history *tx_comp_history = &soc->tx_comp_history;
 	struct dp_tx_desc_event *entry;
 	uint32_t idx;
-
-	if (qdf_unlikely(!soc->tx_tcl_history || !soc->tx_comp_history))
-		return;
+	uint16_t slot;
 
 	switch (type) {
 	case DP_TX_COMP_UNMAP:
 	case DP_TX_COMP_UNMAP_ERR:
 	case DP_TX_COMP_MSDU_EXT:
-		idx = dp_history_get_next_index(&soc->tx_comp_history->index,
-						DP_TX_COMP_HISTORY_SIZE);
-		entry = &soc->tx_comp_history->entry[idx];
+		if (qdf_unlikely(!tx_comp_history->allocated))
+			return;
+
+		dp_get_frag_hist_next_atomic_idx(&tx_comp_history->index, &idx,
+						 &slot,
+						 DP_TX_COMP_HIST_SLOT_SHIFT,
+						 DP_TX_COMP_HIST_PER_SLOT_MAX,
+						 DP_TX_COMP_HISTORY_SIZE);
+		entry = &tx_comp_history->entry[slot][idx];
 		break;
 	case DP_TX_DESC_MAP:
 	case DP_TX_DESC_UNMAP:
 	case DP_TX_DESC_COOKIE:
 	case DP_TX_DESC_FLUSH:
-		idx = dp_history_get_next_index(&soc->tx_tcl_history->index,
-						DP_TX_TCL_HISTORY_SIZE);
-		entry = &soc->tx_tcl_history->entry[idx];
+		if (qdf_unlikely(!tx_tcl_history->allocated))
+			return;
+
+		dp_get_frag_hist_next_atomic_idx(&tx_tcl_history->index, &idx,
+						 &slot,
+						 DP_TX_TCL_HIST_SLOT_SHIFT,
+						 DP_TX_TCL_HIST_PER_SLOT_MAX,
+						 DP_TX_TCL_HISTORY_SIZE);
+		entry = &tx_tcl_history->entry[slot][idx];
 		break;
 	default:
 		dp_info_rl("Invalid dp_tx_event_type: %d", type);

+ 11 - 7
dp/wifi3.0/dp_tx.h

@@ -904,18 +904,22 @@ dp_tx_hw_desc_update_evt(uint8_t *hal_tx_desc_cached,
 			 hal_ring_handle_t hal_ring_hdl,
 			 struct dp_soc *soc)
 {
+	struct dp_tx_hw_desc_history *tx_hw_desc_history =
+						&soc->tx_hw_desc_history;
 	struct dp_tx_hw_desc_evt *evt;
-	uint64_t idx = 0;
+	uint32_t idx = 0;
+	uint16_t slot = 0;
 
-	if (!soc->tx_hw_desc_history)
+	if (!tx_hw_desc_history->allocated)
 		return;
 
-	idx = ++soc->tx_hw_desc_history->index;
-	if (idx == DP_TX_HW_DESC_HIST_MAX)
-		soc->tx_hw_desc_history->index = 0;
-	idx = qdf_do_div_rem(idx, DP_TX_HW_DESC_HIST_MAX);
+	dp_get_frag_hist_next_atomic_idx(&tx_hw_desc_history->index, &idx,
+					 &slot,
+					 DP_TX_HW_DESC_HIST_SLOT_SHIFT,
+					 DP_TX_HW_DESC_HIST_PER_SLOT_MAX,
+					 DP_TX_HW_DESC_HIST_MAX);
 
-	evt = &soc->tx_hw_desc_history->entry[idx];
+	evt = &tx_hw_desc_history->entry[slot][idx];
 	qdf_mem_copy(evt->tcl_desc, hal_tx_desc_cached, HAL_TX_DESC_LEN_BYTES);
 	evt->posted = qdf_get_log_timestamp();
 	hal_get_sw_hptp(soc->hal_soc, hal_ring_hdl, &evt->tp, &evt->hp);

+ 24 - 7
dp/wifi3.0/dp_types.h

@@ -1392,6 +1392,9 @@ struct rx_refill_buff_pool {
 
 #ifdef DP_TX_HW_DESC_HISTORY
 #define DP_TX_HW_DESC_HIST_MAX 6144
+#define DP_TX_HW_DESC_HIST_PER_SLOT_MAX 2048
+#define DP_TX_HW_DESC_HIST_MAX_SLOTS 3
+#define DP_TX_HW_DESC_HIST_SLOT_SHIFT 11
 
 struct dp_tx_hw_desc_evt {
 	uint8_t tcl_desc[HAL_TX_DESC_LEN_BYTES];
@@ -1405,8 +1408,10 @@ struct dp_tx_hw_desc_evt {
  * @entry: history entries
  */
 struct dp_tx_hw_desc_history {
-	uint64_t index;
-	struct dp_tx_hw_desc_evt entry[DP_TX_HW_DESC_HIST_MAX];
+	qdf_atomic_t index;
+	uint16_t num_entries_per_slot;
+	uint16_t allocated;
+	struct dp_tx_hw_desc_evt *entry[DP_TX_HW_DESC_HIST_MAX_SLOTS];
 };
 #endif
 
@@ -1556,7 +1561,15 @@ enum dp_tx_event_type {
 #ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY
 /* Size must be in 2 power, for bitwise index rotation */
 #define DP_TX_TCL_HISTORY_SIZE 0x4000
+#define DP_TX_TCL_HIST_PER_SLOT_MAX 2048
+#define DP_TX_TCL_HIST_MAX_SLOTS 8
+#define DP_TX_TCL_HIST_SLOT_SHIFT 11
+
+/* Size must be in 2 power, for bitwise index rotation */
 #define DP_TX_COMP_HISTORY_SIZE 0x4000
+#define DP_TX_COMP_HIST_PER_SLOT_MAX 2048
+#define DP_TX_COMP_HIST_MAX_SLOTS 8
+#define DP_TX_COMP_HIST_SLOT_SHIFT 11
 
 struct dp_tx_desc_event {
 	qdf_nbuf_t skb;
@@ -1568,12 +1581,16 @@ struct dp_tx_desc_event {
 
 struct dp_tx_tcl_history {
 	qdf_atomic_t index;
-	struct dp_tx_desc_event entry[DP_TX_TCL_HISTORY_SIZE];
+	uint16_t num_entries_per_slot;
+	uint16_t allocated;
+	struct dp_tx_desc_event *entry[DP_TX_TCL_HIST_MAX_SLOTS];
 };
 
 struct dp_tx_comp_history {
 	qdf_atomic_t index;
-	struct dp_tx_desc_event entry[DP_TX_COMP_HISTORY_SIZE];
+	uint16_t num_entries_per_slot;
+	uint16_t allocated;
+	struct dp_tx_desc_event *entry[DP_TX_COMP_HIST_MAX_SLOTS];
 };
 #endif /* WLAN_FEATURE_DP_TX_DESC_HISTORY */
 
@@ -2289,7 +2306,7 @@ struct dp_soc {
 	} ast_hash;
 
 #ifdef DP_TX_HW_DESC_HISTORY
-	struct dp_tx_hw_desc_history *tx_hw_desc_history;
+	struct dp_tx_hw_desc_history tx_hw_desc_history;
 #endif
 
 #ifdef WLAN_FEATURE_DP_RX_RING_HISTORY
@@ -2304,8 +2321,8 @@ struct dp_soc {
 #endif
 
 #ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY
-	struct dp_tx_tcl_history *tx_tcl_history;
-	struct dp_tx_comp_history *tx_comp_history;
+	struct dp_tx_tcl_history tx_tcl_history;
+	struct dp_tx_comp_history tx_comp_history;
 #endif
 
 	qdf_spinlock_t ast_lock;