Bläddra i källkod

qcacmn: Add RX defrag timeout handler

Add tid to the defrag waitlist & timeout if further fragments are not
received.

Change-Id: Iff2d2c23fe796cf70bcc6aa43ab02a308a33ee9f
CRs-Fixed: 2174750
psimha 7 år sedan
förälder
incheckning
fc2f91b86a
6 ändrade filer med 121 tillägg och 30 borttagningar
  1. 7 0
      dp/wifi3.0/dp_main.c
  2. 85 27
      dp/wifi3.0/dp_rx_defrag.c
  3. 5 1
      dp/wifi3.0/dp_rx_defrag.h
  4. 2 0
      dp/wifi3.0/dp_rx_err.c
  5. 16 1
      wlan_cfg/wlan_cfg.c
  6. 6 1
      wlan_cfg/wlan_cfg.h

+ 7 - 0
dp/wifi3.0/dp_main.c

@@ -1965,6 +1965,13 @@ static int dp_soc_cmn_setup(struct dp_soc *soc)
 		reo_params.rx_hash_enabled = true;
 	}
 
+	/* setup the global rx defrag waitlist */
+	TAILQ_INIT(&soc->rx.defrag.waitlist);
+	soc->rx.defrag.timeout_ms =
+		wlan_cfg_get_rx_defrag_min_timeout(soc->wlan_cfg_ctx);
+	soc->rx.flags.defrag_timeout_check =
+		wlan_cfg_get_defrag_timeout_check(soc->wlan_cfg_ctx);
+
 out:
 	hal_reo_setup(soc->hal_soc, &reo_params);
 

+ 85 - 27
dp/wifi3.0/dp_rx_defrag.c

@@ -83,7 +83,70 @@ static void dp_rx_clear_saved_desc_info(struct dp_peer *peer, unsigned tid)
 	peer->rx_tid[tid].dst_ring_desc = NULL;
 }
 
-#ifdef DEFRAG_TIMEOUT
+/*
+ * dp_rx_reorder_flush_frag(): Flush the frag list
+ * @peer: Pointer to the peer data structure
+ * @tid: Transmit ID (TID)
+ *
+ * Flush the per-TID frag list
+ *
+ * Returns: None
+ */
+void dp_rx_reorder_flush_frag(struct dp_peer *peer,
+			 unsigned int tid)
+{
+	struct dp_rx_reorder_array_elem *rx_reorder_array_elem;
+
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				FL("Flushing TID %d"), tid);
+
+	rx_reorder_array_elem = peer->rx_tid[tid].array;
+	if (rx_reorder_array_elem->head) {
+		dp_rx_defrag_frames_free(rx_reorder_array_elem->head);
+		rx_reorder_array_elem->head = NULL;
+		rx_reorder_array_elem->tail = NULL;
+	}
+}
+
+/*
+ * dp_rx_defrag_waitlist_flush(): Flush SOC defrag wait list
+ * @soc: DP SOC
+ *
+ * Flush fragments of all waitlisted TID's
+ *
+ * Returns: None
+ */
+void dp_rx_defrag_waitlist_flush(struct dp_soc *soc)
+{
+	struct dp_rx_tid *rx_reorder, *tmp;
+	uint32_t now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks());
+
+	TAILQ_FOREACH_SAFE(rx_reorder, &soc->rx.defrag.waitlist,
+			   defrag_waitlist_elem, tmp) {
+		struct dp_peer *peer;
+		struct dp_rx_tid *rx_reorder_base;
+		unsigned int tid;
+
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				FL("Current time  %u"), now_ms);
+
+		if (rx_reorder->defrag_timeout_ms > now_ms)
+			break;
+
+		tid = rx_reorder->tid;
+		/* get index 0 of the rx_reorder array */
+		rx_reorder_base = rx_reorder - tid;
+		peer =
+			container_of(rx_reorder_base, struct dp_peer,
+				     rx_tid[0]);
+
+		TAILQ_REMOVE(&soc->rx.defrag.waitlist, rx_reorder,
+			     defrag_waitlist_elem);
+		//dp_rx_defrag_waitlist_remove(peer, tid);
+		dp_rx_reorder_flush_frag(peer, tid);
+	}
+}
+
 /*
  * dp_rx_defrag_waitlist_add(): Update per-PDEV defrag wait list
  * @peer: Pointer to the peer data structure
@@ -98,6 +161,9 @@ static void dp_rx_defrag_waitlist_add(struct dp_peer *peer, unsigned tid)
 	struct dp_soc *psoc = peer->vdev->pdev->soc;
 	struct dp_rx_tid *rx_reorder = &peer->rx_tid[tid];
 
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				FL("Adding TID %u to waitlist"), tid);
+
 	/* TODO: use LIST macros instead of TAIL macros */
 	TAILQ_INSERT_TAIL(&psoc->rx.defrag.waitlist, rx_reorder,
 				defrag_waitlist_elem);
@@ -112,7 +178,7 @@ static void dp_rx_defrag_waitlist_add(struct dp_peer *peer, unsigned tid)
  *
  * Returns: None
  */
-static void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid)
+void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid)
 {
 	struct dp_pdev *pdev = peer->vdev->pdev;
 	struct dp_soc *soc = pdev->soc;
@@ -125,23 +191,16 @@ static void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid)
 		return;
 	}
 
-	rx_reorder = &peer->rx_tid[tid];
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				FL("Remove TID %u from waitlist"), tid);
 
-	if (rx_reorder->defrag_waitlist_elem.tqe_next != NULL) {
-
-		TAILQ_REMOVE(&soc->rx.defrag.waitlist, rx_reorder,
-				defrag_waitlist_elem);
-		rx_reorder->defrag_waitlist_elem.tqe_next = NULL;
-		rx_reorder->defrag_waitlist_elem.tqe_prev = NULL;
-	} else if (rx_reorder->defrag_waitlist_elem.tqe_prev == NULL) {
-
-		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
-			"waitlist->tqe_prev is NULL");
-		rx_reorder->defrag_waitlist_elem.tqe_next = NULL;
-		qdf_assert(0);
+	TAILQ_FOREACH(rx_reorder, &soc->rx.defrag.waitlist,
+			   defrag_waitlist_elem) {
+		if (rx_reorder->tid == tid)
+			TAILQ_REMOVE(&soc->rx.defrag.waitlist,
+				rx_reorder, defrag_waitlist_elem);
 	}
 }
-#endif
 
 /*
  * dp_rx_defrag_fraglist_insert(): Create a per-sequence fragment list
@@ -1257,17 +1316,18 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
 			rx_reorder_array_elem->head = NULL;
 			rx_reorder_array_elem->tail = NULL;
 
+			QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+				"%s mismatch, dropping earlier sequence ",
+				(rxseq == rx_tid->curr_seq_num)
+				? "address"
+				: "seq number");
+
 			/*
 			 * The sequence number for this fragment becomes the
 			 * new sequence number to be processed
 			 */
 			rx_tid->curr_seq_num = rxseq;
 
-			QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
-				"%s mismatch, dropping earlier sequence ",
-				(rxseq == rx_tid->curr_seq_num)
-				? "address"
-				: "seq number");
 		}
 	} else {
 		/* Start of a new sequence */
@@ -1314,13 +1374,9 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
 
 	}
 
-#ifdef DEFRAG_TIMEOUT
-	/* TODO: handle fragment timeout gracefully */
-	if (pdev->soc->rx.flags.defrag_timeout_check) {
+	if (pdev->soc->rx.flags.defrag_timeout_check)
 		dp_rx_defrag_waitlist_remove(peer, tid);
-		goto end;
-	}
-#endif
+
 	/* Yet to receive more fragments for this sequence number */
 	if (!all_frag_present) {
 		uint32_t now_ms =
@@ -1329,6 +1385,8 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
 		peer->rx_tid[tid].defrag_timeout_ms =
 			now_ms + pdev->soc->rx.defrag.timeout_ms;
 
+		dp_rx_defrag_waitlist_add(peer, tid);
+
 		return QDF_STATUS_SUCCESS;
 	}
 

+ 5 - 1
dp/wifi3.0/dp_rx_defrag.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -139,4 +139,8 @@ uint8_t dp_rx_get_pkt_dir(uint8_t *rx_desc_info)
 	return mac_hdr->i_fc[1] & IEEE80211_FC1_DIR_MASK;
 }
 
+void dp_rx_defrag_waitlist_flush(struct dp_soc *soc);
+void dp_rx_reorder_flush_frag(struct dp_peer *peer,
+			 unsigned int tid);
+void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid);
 #endif /* _DP_RX_DEFRAG_H */

+ 2 - 0
dp/wifi3.0/dp_rx_err.c

@@ -879,6 +879,8 @@ dp_rx_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota)
 done:
 	hal_srng_access_end(hal_soc, hal_ring);
 
+	if (soc->rx.flags.defrag_timeout_check)
+		dp_rx_defrag_waitlist_flush(soc);
 
 	/* Assume MAC id = 0, owner = 0 */
 	if (rx_bufs_used) {

+ 16 - 1
wlan_cfg/wlan_cfg.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -187,6 +187,7 @@
 #define WLAN_CFG_HTT_PKT_TYPE 2
 #define WLAN_CFG_MAX_PEER_ID 64
 
+#define WLAN_CFG_RX_DEFRAG_TIMEOUT 100
 
 #ifdef CONFIG_MCL
 static const int tx_ring_mask[WLAN_CFG_INT_NUM_CONTEXTS] = {
@@ -351,6 +352,9 @@ struct wlan_cfg_dp_soc_ctxt *wlan_cfg_soc_attach()
 	/*Enable checksum offload by default*/
 	wlan_cfg_ctx->tcp_udp_checksumoffload = 1;
 
+	wlan_cfg_ctx->defrag_timeout_check = 1;
+	wlan_cfg_ctx->rx_defrag_min_timeout = WLAN_CFG_RX_DEFRAG_TIMEOUT;
+
 	return wlan_cfg_ctx;
 }
 
@@ -697,6 +701,17 @@ int wlan_cfg_get_checksum_offload(struct wlan_cfg_dp_soc_ctxt *cfg)
 {
 	return cfg->tcp_udp_checksumoffload;
 }
+
+int wlan_cfg_get_rx_defrag_min_timeout(struct wlan_cfg_dp_soc_ctxt *cfg)
+{
+	return cfg->rx_defrag_min_timeout;
+}
+
+int wlan_cfg_get_defrag_timeout_check(struct wlan_cfg_dp_soc_ctxt *cfg)
+{
+	return cfg->defrag_timeout_check;
+}
+
 #ifdef QCA_LL_TX_FLOW_CONTROL_V2
 /**
  * wlan_cfg_get_tx_flow_stop_queue_th() - Get flow control stop threshold

+ 6 - 1
wlan_cfg/wlan_cfg.h

@@ -1,5 +1,5 @@
 /*
-* * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
+* * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
  * 
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -146,11 +146,13 @@ struct wlan_cfg_dp_soc_ctxt {
 	bool tso_enabled;
 	bool napi_enabled;
 	bool tcp_udp_checksumoffload;
+	bool defrag_timeout_check;
 	int nss_cfg;
 #ifdef QCA_LL_TX_FLOW_CONTROL_V2
 	uint32_t tx_flow_stop_queue_threshold;
 	uint32_t tx_flow_start_queue_offset;
 #endif
+	uint32_t rx_defrag_min_timeout;
 };
 
 /**
@@ -663,4 +665,7 @@ int wlan_cfg_get_tx_flow_stop_queue_th(struct wlan_cfg_dp_soc_ctxt *cfg);
 
 int wlan_cfg_get_tx_flow_start_queue_offset(struct wlan_cfg_dp_soc_ctxt *cfg);
 #endif /* QCA_LL_TX_FLOW_CONTROL_V2 */
+int wlan_cfg_get_rx_defrag_min_timeout(struct wlan_cfg_dp_soc_ctxt *cfg);
+
+int wlan_cfg_get_defrag_timeout_check(struct wlan_cfg_dp_soc_ctxt *cfg);
 #endif