Bläddra i källkod

qcacmn: Fix RXDMA null buffer address access issue

During mon_pdev_init RX monitor status buffers will be attached
to status ring. In case of buffer allocation failure HP will be
pointing to null buffer address entry and during ring process
this index slot will be skipped. This will lead to RXDMA accessing
null buffer address descriptor.

Fix this by adjusting the HP of monitor status ring during RX
buffer allocation failures.

Change-Id: I290a724fefc6f65be058a84c97b9e6d51a08ef39
CRs-Fixed: 3268663
Karthik Kantamneni 1 år sedan
förälder
incheckning
3600a51a25
2 ändrade filer med 41 tillägg och 1 borttagningar
  1. 13 1
      dp/wifi3.0/monitor/1.0/dp_rx_mon_status_1.0.c
  2. 28 0
      hal/wifi3.0/hal_api.h

+ 13 - 1
dp/wifi3.0/monitor/1.0/dp_rx_mon_status_1.0.c

@@ -1033,6 +1033,7 @@ QDF_STATUS dp_rx_mon_status_buffers_replenish(struct dp_soc *dp_soc,
 	union dp_rx_desc_list_elem_t *next;
 	void *rxdma_srng;
 	struct dp_pdev *dp_pdev = dp_get_pdev_for_lmac_id(dp_soc, mac_id);
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
 	if (!dp_pdev) {
 		dp_rx_mon_status_debug("%pK: pdev is null for mac_id = %d",
@@ -1094,6 +1095,17 @@ QDF_STATUS dp_rx_mon_status_buffers_replenish(struct dp_soc *dp_soc,
 		if (qdf_unlikely(!rx_netbuf)) {
 			dp_rx_mon_status_err("%pK: qdf_nbuf allocate or map fail, count %d",
 					     dp_soc, count);
+			/*
+			 * If buffer allocation fails on current HP, then
+			 * decrement HP so it will be set to previous index
+			 * where proper buffer is attached.
+			 */
+			if (!count)
+				status = QDF_STATUS_E_NOMEM;
+			else
+				hal_srng_src_dec_hp(dp_soc->hal_soc,
+						    rxdma_srng);
+
 			break;
 		}
 
@@ -1148,7 +1160,7 @@ QDF_STATUS dp_rx_mon_status_buffers_replenish(struct dp_soc *dp_soc,
 			mac_id, rx_desc_pool);
 	}
 
-	return QDF_STATUS_SUCCESS;
+	return status;
 }
 
 #if !defined(DISABLE_MON_CONFIG) && defined(MON_ENABLE_DROP_FOR_MAC)

+ 28 - 0
hal/wifi3.0/hal_api.h

@@ -2178,6 +2178,34 @@ void *hal_srng_src_peek_n_get_next(hal_soc_handle_t hal_soc_hdl,
 	return NULL;
 }
 
+/**
+ * hal_srng_src_dec_hp - Decrement source srng HP to previous index
+ * @hal_soc_hdl: Opaque HAL SOC handle
+ * @hal_ring_hdl: Source ring pointer
+ *
+ * Return: None
+ */
+static inline
+void hal_srng_src_dec_hp(hal_soc_handle_t hal_soc_hdl,
+			 hal_ring_handle_t hal_ring_hdl)
+{
+	struct hal_srng *srng = (struct hal_srng *)hal_ring_hdl;
+	uint32_t hp = srng->u.src_ring.hp;
+
+	/* This HP adjustment is mostly done in error cases.
+	 * Only local HP is being decremented not the value
+	 * communicated to consumer or H.W.
+	 */
+	if (hp == srng->u.src_ring.cached_tp)
+		return;
+	else if (hp == 0)
+		hp = srng->ring_size - srng->entry_size;
+	else
+		hp = (hp - srng->entry_size) % srng->ring_size;
+
+	srng->u.src_ring.hp = hp;
+}
+
 /**
  * hal_srng_src_peek_n_get_next_next() - Get next to next, i.e HP + 2 entry from
  *                                       a ring without moving head pointer.