Browse Source

qcacld-3.0: Fix buf replenish logic and handle error pkts

Fix replenishing logic by taking care of fragments as well
in monitor mode. Also drop the packets with mpdu_length_err
bit set in rx attention desc and don't send those packets to
upper layers.

Change-Id: Iaeeb0e40e4988ca5a2d4c5e7c98ed3f82dfca533
CRs-Fixed: 2037633
Himanshu Agarwal 8 years ago
parent
commit
5f5e16692d

+ 2 - 0
core/dp/htt/htt_internal.h

@@ -78,6 +78,8 @@ struct htt_host_rx_desc_base {
 	char rx_hdr_status[RX_HTT_HDR_STATUS_LEN];
 };
 
+#define RX_DESC_ATTN_MPDU_LEN_ERR_BIT   0x08000000
+
 #define RX_STD_DESC_ATTN_OFFSET	\
 	(offsetof(struct htt_host_rx_desc_base, attention))
 #define RX_STD_DESC_FRAG_INFO_OFFSET \

+ 63 - 13
core/dp/htt/htt_rx.c

@@ -1104,7 +1104,8 @@ void htt_set_checksum_result_hl(qdf_nbuf_t msdu,
 static int
 htt_rx_amsdu_pop_ll(htt_pdev_handle pdev,
 		    qdf_nbuf_t rx_ind_msg,
-		    qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu)
+		    qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
+		    uint32_t *msdu_count)
 {
 	int msdu_len, msdu_chaining = 0;
 	qdf_nbuf_t msdu;
@@ -1384,7 +1385,8 @@ htt_rx_amsdu_pop_hl(
 	htt_pdev_handle pdev,
 	qdf_nbuf_t rx_ind_msg,
 	qdf_nbuf_t *head_msdu,
-	qdf_nbuf_t *tail_msdu)
+	qdf_nbuf_t *tail_msdu,
+	uint32_t *msdu_count)
 {
 	pdev->rx_desc_size_hl =
 		(qdf_nbuf_data(rx_ind_msg))
@@ -1409,7 +1411,8 @@ htt_rx_frag_pop_hl(
 	htt_pdev_handle pdev,
 	qdf_nbuf_t frag_msg,
 	qdf_nbuf_t *head_msdu,
-	qdf_nbuf_t *tail_msdu)
+	qdf_nbuf_t *tail_msdu,
+	uint32_t *msdu_count)
 {
 	qdf_nbuf_pull_head(frag_msg, HTT_RX_FRAG_IND_BYTES);
 	pdev->rx_desc_size_hl =
@@ -1581,6 +1584,7 @@ htt_rx_offload_paddr_msdu_pop_ll(htt_pdev_handle pdev,
  * @pdev: Handle to htt_pdev_handle
  * @msg_word: Input and output variable, so pointer to HTT msg pointer
  * @amsdu_len: remaining length of all N-1 msdu msdu's
+ * @frag_cnt: number of frags handled
  *
  * This function handles the (N-1) msdu's of amsdu, N'th msdu is already
  * handled by calling function. N-1 msdu's are tied using frags_list.
@@ -1591,7 +1595,8 @@ htt_rx_offload_paddr_msdu_pop_ll(htt_pdev_handle pdev,
  */
 static
 int htt_mon_rx_handle_amsdu_packet(qdf_nbuf_t msdu, htt_pdev_handle pdev,
-				   uint32_t **msg_word, uint32_t amsdu_len)
+				   uint32_t **msg_word, uint32_t amsdu_len,
+				   uint32_t *frag_cnt)
 {
 	qdf_nbuf_t frag_nbuf;
 	qdf_nbuf_t prev_frag_nbuf;
@@ -1606,6 +1611,7 @@ int htt_mon_rx_handle_amsdu_packet(qdf_nbuf_t msdu, htt_pdev_handle pdev,
 		qdf_print("%s: netbuf pop failed!\n", __func__);
 		return 0;
 	}
+	*frag_cnt = *frag_cnt + 1;
 	last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *)*msg_word)->
 		msdu_info;
 	qdf_nbuf_append_ext_list(msdu, frag_nbuf, amsdu_len);
@@ -1633,6 +1639,7 @@ int htt_mon_rx_handle_amsdu_packet(qdf_nbuf_t msdu, htt_pdev_handle pdev,
 			prev_frag_nbuf->next = NULL;
 			return 0;
 		}
+		*frag_cnt = *frag_cnt + 1;
 		qdf_nbuf_set_pktlen(frag_nbuf, HTT_RX_BUF_SIZE);
 		qdf_nbuf_unmap(pdev->osdev, frag_nbuf, QDF_DMA_FROM_DEVICE);
 
@@ -1906,9 +1913,10 @@ static void htt_rx_mon_get_rx_status(htt_pdev_handle pdev,
 static int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
 					       qdf_nbuf_t rx_ind_msg,
 					       qdf_nbuf_t *head_msdu,
-					       qdf_nbuf_t *tail_msdu)
+					       qdf_nbuf_t *tail_msdu,
+					       uint32_t *replenish_cnt)
 {
-	qdf_nbuf_t msdu, next;
+	qdf_nbuf_t msdu, next, prev = NULL;
 	uint8_t *rx_ind_data;
 	uint32_t *msg_word;
 	uint32_t msdu_count;
@@ -1924,6 +1932,7 @@ static int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
 	rx_ind_data = qdf_nbuf_data(rx_ind_msg);
 	msg_word = (uint32_t *)rx_ind_data;
 
+	*replenish_cnt = 0;
 	HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX,
 					QDF_TRACE_LEVEL_INFO_HIGH,
 					(void *)rx_ind_data,
@@ -1936,13 +1945,15 @@ static int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
 	msg_word = (uint32_t *)(rx_ind_data +
 				 HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES);
 	paddr = htt_rx_in_ord_paddr_get(msg_word);
-	(*head_msdu) = msdu = htt_rx_in_order_netbuf_pop(pdev, paddr);
+	msdu = htt_rx_in_order_netbuf_pop(pdev, paddr);
 
 	if (qdf_unlikely(NULL == msdu)) {
 		qdf_print("%s: netbuf pop failed!\n", __func__);
 		*tail_msdu = NULL;
 		return 0;
 	}
+	*replenish_cnt = *replenish_cnt + 1;
+
 	while (msdu_count > 0) {
 
 		msdu_count--;
@@ -1958,6 +1969,36 @@ static int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
 		 * qdf_nbuf_unmap
 		 */
 		rx_desc = htt_rx_desc(msdu);
+		if ((unsigned int)(*(uint32_t *)&rx_desc->attention) &
+				RX_DESC_ATTN_MPDU_LEN_ERR_BIT) {
+			qdf_nbuf_free(msdu);
+			last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *)
+			     msg_word)->msdu_info;
+			while (!last_frag) {
+				msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS;
+				paddr = htt_rx_in_ord_paddr_get(msg_word);
+				msdu = htt_rx_in_order_netbuf_pop(pdev, paddr);
+				last_frag = ((struct
+					htt_rx_in_ord_paddr_ind_msdu_t *)
+					msg_word)->msdu_info;
+				if (qdf_unlikely(!msdu)) {
+					qdf_print("%s: netbuf pop failed!\n",
+						  __func__);
+					return 0;
+				}
+				*replenish_cnt = *replenish_cnt + 1;
+				qdf_nbuf_unmap(pdev->osdev, msdu,
+					       QDF_DMA_FROM_DEVICE);
+				qdf_nbuf_free(msdu);
+			}
+			msdu = prev;
+			goto next_pop;
+		}
+
+		if (!prev)
+			(*head_msdu) = msdu;
+		prev = msdu;
+
 		HTT_PKT_DUMP(htt_print_rx_desc(rx_desc));
 		/*
 		 * Make the netbuf's data pointer point to the payload rather
@@ -2001,12 +2042,15 @@ static int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
 			 */
 			if (!htt_mon_rx_handle_amsdu_packet(msdu, pdev,
 							    &msg_word,
-							    amsdu_len)) {
+							    amsdu_len,
+							    replenish_cnt)) {
 				qdf_print("%s: failed to handle amsdu packet\n",
 					     __func__);
 				return 0;
 			}
 		}
+
+next_pop:
 		/* check if this is the last msdu */
 		if (msdu_count) {
 			msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS;
@@ -2018,11 +2062,14 @@ static int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
 				*tail_msdu = NULL;
 				return 0;
 			}
-			qdf_nbuf_set_next(msdu, next);
+			*replenish_cnt = *replenish_cnt + 1;
+			if (msdu)
+				qdf_nbuf_set_next(msdu, next);
 			msdu = next;
 		} else {
 			*tail_msdu = msdu;
-			qdf_nbuf_set_next(msdu, NULL);
+			if (msdu)
+				qdf_nbuf_set_next(msdu, NULL);
 		}
 	}
 
@@ -2057,7 +2104,8 @@ uint32_t htt_rx_amsdu_rx_in_order_get_pktlog(qdf_nbuf_t rx_ind_msg)
 static int
 htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev,
 				qdf_nbuf_t rx_ind_msg,
-				qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu)
+				qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
+				uint32_t *replenish_cnt)
 {
 	qdf_nbuf_t msdu, next, prev = NULL;
 	uint8_t *rx_ind_data;
@@ -2635,7 +2683,8 @@ int16_t htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev, void *mpdu_desc)
  */
 int (*htt_rx_amsdu_pop)(htt_pdev_handle pdev,
 			qdf_nbuf_t rx_ind_msg,
-			qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu);
+			qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
+			uint32_t *msdu_count);
 
 /*
  * htt_rx_frag_pop -
@@ -2644,7 +2693,8 @@ int (*htt_rx_amsdu_pop)(htt_pdev_handle pdev,
  */
 int (*htt_rx_frag_pop)(htt_pdev_handle pdev,
 		       qdf_nbuf_t rx_ind_msg,
-		       qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu);
+		       qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
+		       uint32_t *msdu_count);
 
 int
 (*htt_rx_offload_msdu_pop)(htt_pdev_handle pdev,

+ 4 - 2
core/dp/ol/inc/ol_htt_rx_api.h

@@ -655,12 +655,14 @@ extern bool
 extern int
 (*htt_rx_amsdu_pop)(htt_pdev_handle pdev,
 		    qdf_nbuf_t rx_ind_msg,
-		    qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu);
+		    qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
+		    uint32_t *msdu_count);
 
 extern int
 (*htt_rx_frag_pop)(htt_pdev_handle pdev,
 		   qdf_nbuf_t rx_ind_msg,
-		   qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu);
+		   qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu,
+		   uint32_t *msdu_count);
 
 /**
  * @brief Return a linked list of buffers holding one MSDU

+ 14 - 5
core/dp/txrx/ol_rx.c

@@ -466,6 +466,7 @@ ol_rx_indication_handler(ol_txrx_pdev_handle pdev,
 	uint16_t chan2;
 	uint8_t phymode;
 	bool ret;
+	uint32_t msdu_count = 0;
 
 	htt_pdev = pdev->htt_pdev;
 	peer = ol_txrx_peer_find_by_id(pdev, peer_id);
@@ -585,7 +586,8 @@ ol_rx_indication_handler(ol_txrx_pdev_handle pdev,
 					htt_rx_amsdu_pop(htt_pdev,
 							 rx_ind_msg,
 							 &head_msdu,
-							 &tail_msdu);
+							 &tail_msdu,
+							 &msdu_count);
 #ifdef HTT_RX_RESTORE
 				if (htt_pdev->rx_ring.rx_reset) {
 					ol_rx_trigger_restore(htt_pdev,
@@ -643,7 +645,7 @@ ol_rx_indication_handler(ol_txrx_pdev_handle pdev,
 			for (i = 0; i < num_mpdus; i++) {
 				/* pull the MPDU's MSDUs off the buffer queue */
 				htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &msdu,
-						 &tail_msdu);
+						 &tail_msdu, &msdu_count);
 #ifdef HTT_RX_RESTORE
 				if (htt_pdev->rx_ring.rx_reset) {
 					ol_rx_trigger_restore(htt_pdev, msdu,
@@ -1404,7 +1406,7 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
 	struct ol_txrx_peer_t *peer = NULL;
 	htt_pdev_handle htt_pdev = NULL;
 	int status;
-	qdf_nbuf_t head_msdu, tail_msdu = NULL;
+	qdf_nbuf_t head_msdu = NULL, tail_msdu = NULL;
 	uint8_t *rx_ind_data;
 	uint32_t *msg_word;
 	uint32_t msdu_count;
@@ -1446,11 +1448,12 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
 	 * This also attaches each rx MSDU descriptor to the
 	 * corresponding rx MSDU network buffer.
 	 */
-	status = htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &head_msdu, &tail_msdu);
+	status = htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &head_msdu,
+				  &tail_msdu, &msdu_count);
 	ol_rx_ind_record_event(status, OL_RX_INDICATION_POP_END);
 
 	if (qdf_unlikely(0 == status)) {
-		ol_txrx_warn("%s: Pop status is 0, returning here\n", __func__);
+		ol_txrx_warn("%s: Pop status is 0, returning here", __func__);
 		return;
 	}
 
@@ -1460,6 +1463,12 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev,
 	filled = htt_rx_msdu_buff_in_order_replenish(htt_pdev, msdu_count);
 	ol_rx_ind_record_event(filled, OL_RX_INDICATION_BUF_REPLENISH);
 
+	if (!head_msdu) {
+		ol_txrx_warn("%s: No packet to send to HDD",
+			     __func__);
+		return;
+	}
+
 	/* Send the chain of MSDUs to the OS */
 	/* rx_opt_proc takes a NULL-terminated list of msdu netbufs */
 	qdf_nbuf_set_next(tail_msdu, NULL);

+ 3 - 2
core/dp/txrx/ol_rx_defrag.c

@@ -332,6 +332,7 @@ ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev,
 	qdf_nbuf_t head_msdu, tail_msdu;
 	void *rx_mpdu_desc;
 	uint8_t pktlog_bit;
+	uint32_t msdu_count = 0;
 
 	htt_pdev = pdev->htt_pdev;
 	peer = ol_txrx_peer_find_by_id(pdev, peer_id);
@@ -352,7 +353,7 @@ ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev,
 		(htt_rx_amsdu_rx_in_order_get_pktlog(rx_frag_ind_msg) == 0x01);
 	if (peer) {
 		htt_rx_frag_pop(htt_pdev, rx_frag_ind_msg, &head_msdu,
-				&tail_msdu);
+				&tail_msdu, &msdu_count);
 		qdf_assert(head_msdu == tail_msdu);
 		if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) {
 			rx_mpdu_desc =
@@ -370,7 +371,7 @@ ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev,
 	} else {
 		/* invalid frame - discard it */
 		htt_rx_frag_pop(htt_pdev, rx_frag_ind_msg, &head_msdu,
-				&tail_msdu);
+				&tail_msdu, &msdu_count);
 		if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev))
 			htt_rx_msdu_desc_retrieve(htt_pdev, head_msdu);
 		else