Эх сурвалжийг харах

qcacmn: Fix disconnection issue due to N/W queues pause

Due to DP flow control network queues are stuck in
paused state and not getting reset even after new connection.
This is causing DHCP packets to be dropped and resulting
immediate disconnection after every connection.

Fix this by properly pausing and unpausing the AC flow control
based network subqueues during disconnection/connection events.

Change-Id: I280e704d5a01b19d180c32aaa272c0cb731f8c0e
CRs-Fixed: 3078745
Karthik Kantamneni 3 жил өмнө
parent
commit
fcebc684e9

+ 8 - 2
dp/inc/cdp_txrx_mob_def.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. 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
@@ -108,8 +109,9 @@ enum netif_action_type {
 	WLAN_NETIF_VI_QUEUE_ON = 14,
 	WLAN_NETIF_VI_QUEUE_OFF = 15,
 	WLAN_NETIF_BE_BK_QUEUE_OFF = 16,
-	WLAN_WAKE_NON_PRIORITY_QUEUE = 17,
-	WLAN_STOP_NON_PRIORITY_QUEUE = 18,
+	WLAN_NETIF_BE_BK_QUEUE_ON = 17,
+	WLAN_WAKE_NON_PRIORITY_QUEUE = 18,
+	WLAN_STOP_NON_PRIORITY_QUEUE = 19,
 	WLAN_NETIF_ACTION_TYPE_MAX,
 };
 
@@ -132,6 +134,10 @@ enum netif_reason_type {
 	WLAN_PEER_UNAUTHORISED,
 	WLAN_THERMAL_MITIGATION,
 	WLAN_DATA_FLOW_CONTROL_PRIORITY,
+	WLAN_DATA_FLOW_CTRL_BE_BK,
+	WLAN_DATA_FLOW_CTRL_VI,
+	WLAN_DATA_FLOW_CTRL_VO,
+	WLAN_DATA_FLOW_CTRL_PRI,
 	WLAN_REASON_TYPE_MAX,
 };
 

+ 76 - 4
dp/wifi3.0/dp_tx_desc.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. 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
@@ -219,6 +220,58 @@ dp_tx_is_threshold_reached(struct dp_tx_desc_pool_s *pool, uint16_t avail_desc)
 		return false;
 }
 
+/**
+ * dp_tx_adjust_flow_pool_state() - Adjust flow pool state
+ *
+ * @soc: dp soc
+ * @pool: flow pool
+ */
+static inline void
+dp_tx_adjust_flow_pool_state(struct dp_soc *soc,
+			     struct dp_tx_desc_pool_s *pool)
+{
+	if (pool->avail_desc > pool->stop_th[DP_TH_BE_BK]) {
+		pool->status = FLOW_POOL_ACTIVE_UNPAUSED;
+		return;
+	} else if (pool->avail_desc <= pool->stop_th[DP_TH_BE_BK] &&
+		   pool->avail_desc > pool->stop_th[DP_TH_VI]) {
+		pool->status = FLOW_POOL_BE_BK_PAUSED;
+	} else if (pool->avail_desc <= pool->stop_th[DP_TH_VI] &&
+		   pool->avail_desc > pool->stop_th[DP_TH_VO]) {
+		pool->status = FLOW_POOL_VI_PAUSED;
+	} else if (pool->avail_desc <= pool->stop_th[DP_TH_VO] &&
+		   pool->avail_desc > pool->stop_th[DP_TH_HI]) {
+		pool->status = FLOW_POOL_VO_PAUSED;
+	} else if (pool->avail_desc <= pool->stop_th[DP_TH_HI]) {
+		pool->status = FLOW_POOL_ACTIVE_PAUSED;
+	}
+
+	switch (pool->status) {
+	case FLOW_POOL_ACTIVE_PAUSED:
+		soc->pause_cb(pool->flow_pool_id,
+			      WLAN_NETIF_PRIORITY_QUEUE_OFF,
+			      WLAN_DATA_FLOW_CTRL_PRI);
+
+	case FLOW_POOL_VO_PAUSED:
+		soc->pause_cb(pool->flow_pool_id,
+			      WLAN_NETIF_VO_QUEUE_OFF,
+			      WLAN_DATA_FLOW_CTRL_VO);
+
+	case FLOW_POOL_VI_PAUSED:
+		soc->pause_cb(pool->flow_pool_id,
+			      WLAN_NETIF_VI_QUEUE_OFF,
+			      WLAN_DATA_FLOW_CTRL_VI);
+
+	case FLOW_POOL_BE_BK_PAUSED:
+		soc->pause_cb(pool->flow_pool_id,
+			      WLAN_NETIF_BE_BK_QUEUE_OFF,
+			      WLAN_DATA_FLOW_CTRL_BE_BK);
+		break;
+	default:
+		dp_err("Invalid pool staus:%u to adjust", pool->status);
+	}
+}
+
 /**
  * dp_tx_desc_alloc() - Allocate a Software Tx descriptor from given pool
  *
@@ -235,39 +288,53 @@ dp_tx_desc_alloc(struct dp_soc *soc, uint8_t desc_pool_id)
 	bool is_pause = false;
 	enum netif_action_type act = WLAN_NETIF_ACTION_TYPE_NONE;
 	enum dp_fl_ctrl_threshold level = DP_TH_BE_BK;
+	enum netif_reason_type reason;
 
 	if (qdf_likely(pool)) {
 		qdf_spin_lock_bh(&pool->flow_pool_lock);
-		if (qdf_likely(pool->avail_desc)) {
+		if (qdf_likely(pool->avail_desc &&
+		    pool->status != FLOW_POOL_INVALID &&
+		    pool->status != FLOW_POOL_INACTIVE)) {
 			tx_desc = dp_tx_get_desc_flow_pool(pool);
 			tx_desc->pool_id = desc_pool_id;
 			tx_desc->flags = DP_TX_DESC_FLAG_ALLOCATED;
+
 			is_pause = dp_tx_is_threshold_reached(pool,
 							      pool->avail_desc);
 
+			if (qdf_unlikely(pool->status ==
+					 FLOW_POOL_ACTIVE_UNPAUSED_REATTACH)) {
+				dp_tx_adjust_flow_pool_state(soc, pool);
+				is_pause = false;
+			}
+
 			if (qdf_unlikely(is_pause)) {
 				switch (pool->status) {
 				case FLOW_POOL_ACTIVE_UNPAUSED:
 					/* pause network BE\BK queue */
 					act = WLAN_NETIF_BE_BK_QUEUE_OFF;
+					reason = WLAN_DATA_FLOW_CTRL_BE_BK;
 					level = DP_TH_BE_BK;
 					pool->status = FLOW_POOL_BE_BK_PAUSED;
 					break;
 				case FLOW_POOL_BE_BK_PAUSED:
 					/* pause network VI queue */
 					act = WLAN_NETIF_VI_QUEUE_OFF;
+					reason = WLAN_DATA_FLOW_CTRL_VI;
 					level = DP_TH_VI;
 					pool->status = FLOW_POOL_VI_PAUSED;
 					break;
 				case FLOW_POOL_VI_PAUSED:
 					/* pause network VO queue */
 					act = WLAN_NETIF_VO_QUEUE_OFF;
+					reason = WLAN_DATA_FLOW_CTRL_VO;
 					level = DP_TH_VO;
 					pool->status = FLOW_POOL_VO_PAUSED;
 					break;
 				case FLOW_POOL_VO_PAUSED:
 					/* pause network HI PRI queue */
 					act = WLAN_NETIF_PRIORITY_QUEUE_OFF;
+					reason = WLAN_DATA_FLOW_CTRL_PRI;
 					level = DP_TH_HI;
 					pool->status = FLOW_POOL_ACTIVE_PAUSED;
 					break;
@@ -285,7 +352,7 @@ dp_tx_desc_alloc(struct dp_soc *soc, uint8_t desc_pool_id)
 						qdf_get_system_timestamp();
 					soc->pause_cb(desc_pool_id,
 						      act,
-						      WLAN_DATA_FLOW_CONTROL);
+						      reason);
 				}
 			}
 		} else {
@@ -315,6 +382,7 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 	struct dp_tx_desc_pool_s *pool = &soc->tx_desc[desc_pool_id];
 	qdf_time_t unpause_time = qdf_get_system_timestamp(), pause_dur;
 	enum netif_action_type act = WLAN_WAKE_ALL_NETIF_QUEUE;
+	enum netif_reason_type reason;
 
 	qdf_spin_lock_bh(&pool->flow_pool_lock);
 	tx_desc->vdev_id = DP_INVALID_VDEV_ID;
@@ -325,6 +393,7 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 	case FLOW_POOL_ACTIVE_PAUSED:
 		if (pool->avail_desc > pool->start_th[DP_TH_HI]) {
 			act = WLAN_NETIF_PRIORITY_QUEUE_ON;
+			reason = WLAN_DATA_FLOW_CTRL_PRI;
 			pool->status = FLOW_POOL_VO_PAUSED;
 
 			/* Update maxinum pause duration for HI queue */
@@ -337,6 +406,7 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 	case FLOW_POOL_VO_PAUSED:
 		if (pool->avail_desc > pool->start_th[DP_TH_VO]) {
 			act = WLAN_NETIF_VO_QUEUE_ON;
+			reason = WLAN_DATA_FLOW_CTRL_VO;
 			pool->status = FLOW_POOL_VI_PAUSED;
 
 			/* Update maxinum pause duration for VO queue */
@@ -349,6 +419,7 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 	case FLOW_POOL_VI_PAUSED:
 		if (pool->avail_desc > pool->start_th[DP_TH_VI]) {
 			act = WLAN_NETIF_VI_QUEUE_ON;
+			reason = WLAN_DATA_FLOW_CTRL_VI;
 			pool->status = FLOW_POOL_BE_BK_PAUSED;
 
 			/* Update maxinum pause duration for VI queue */
@@ -360,7 +431,8 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 		break;
 	case FLOW_POOL_BE_BK_PAUSED:
 		if (pool->avail_desc > pool->start_th[DP_TH_BE_BK]) {
-			act = WLAN_WAKE_NON_PRIORITY_QUEUE;
+			act = WLAN_NETIF_BE_BK_QUEUE_ON;
+			reason = WLAN_DATA_FLOW_CTRL_BE_BK;
 			pool->status = FLOW_POOL_ACTIVE_UNPAUSED;
 
 			/* Update maxinum pause duration for BE_BK queue */
@@ -393,7 +465,7 @@ dp_tx_desc_free(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
 
 	if (act != WLAN_WAKE_ALL_NETIF_QUEUE)
 		soc->pause_cb(pool->flow_pool_id,
-			      act, WLAN_DATA_FLOW_CONTROL);
+			      act, reason);
 	qdf_spin_unlock_bh(&pool->flow_pool_lock);
 }
 #else /* QCA_AC_BASED_FLOW_CONTROL */

+ 51 - 14
dp/wifi3.0/dp_tx_flow_control.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. 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
@@ -90,20 +91,7 @@ dp_tx_flow_pool_reattach(struct dp_tx_desc_pool_s *pool)
 		  "%s: flow pool already allocated, attached %d times",
 		  __func__, pool->pool_create_cnt);
 
-	if (pool->avail_desc > pool->start_th[DP_TH_BE_BK])
-		pool->status = FLOW_POOL_ACTIVE_UNPAUSED;
-	else if (pool->avail_desc <= pool->start_th[DP_TH_BE_BK] &&
-		 pool->avail_desc > pool->start_th[DP_TH_VI])
-		pool->status = FLOW_POOL_BE_BK_PAUSED;
-	else if (pool->avail_desc <= pool->start_th[DP_TH_VI] &&
-		 pool->avail_desc > pool->start_th[DP_TH_VO])
-		pool->status = FLOW_POOL_VI_PAUSED;
-	else if (pool->avail_desc <= pool->start_th[DP_TH_VO] &&
-		 pool->avail_desc > pool->start_th[DP_TH_HI])
-		pool->status = FLOW_POOL_VO_PAUSED;
-	else
-		pool->status = FLOW_POOL_ACTIVE_PAUSED;
-
+	pool->status = FLOW_POOL_ACTIVE_UNPAUSED_REATTACH;
 	pool->pool_create_cnt++;
 }
 
@@ -131,6 +119,44 @@ dp_tx_flow_pool_dump_threshold(struct dp_tx_desc_pool_s *pool)
 	}
 }
 
+/**
+ * dp_tx_flow_ctrl_reset_subqueues() - Reset subqueues to orginal state
+ * @soc: dp soc
+ * @pool: flow pool
+ * @pool_status: flow pool status
+ *
+ * Return: none
+ */
+static inline void
+dp_tx_flow_ctrl_reset_subqueues(struct dp_soc *soc,
+				struct dp_tx_desc_pool_s *pool,
+				enum flow_pool_status pool_status)
+{
+	switch (pool_status) {
+	case FLOW_POOL_ACTIVE_PAUSED:
+		soc->pause_cb(pool->flow_pool_id,
+			      WLAN_NETIF_PRIORITY_QUEUE_ON,
+			      WLAN_DATA_FLOW_CTRL_PRI);
+
+	case FLOW_POOL_VO_PAUSED:
+		soc->pause_cb(pool->flow_pool_id,
+			      WLAN_NETIF_VO_QUEUE_ON,
+			      WLAN_DATA_FLOW_CTRL_VO);
+
+	case FLOW_POOL_VI_PAUSED:
+		soc->pause_cb(pool->flow_pool_id,
+			      WLAN_NETIF_VI_QUEUE_ON,
+			      WLAN_DATA_FLOW_CTRL_VI);
+
+	case FLOW_POOL_BE_BK_PAUSED:
+		soc->pause_cb(pool->flow_pool_id,
+			      WLAN_NETIF_BE_BK_QUEUE_ON,
+			      WLAN_DATA_FLOW_CTRL_BE_BK);
+	default:
+		break;
+	}
+}
+
 #else
 static inline void
 dp_tx_initialize_threshold(struct dp_tx_desc_pool_s *pool,
@@ -166,6 +192,13 @@ dp_tx_flow_pool_dump_threshold(struct dp_tx_desc_pool_s *pool)
 	pool->start_th, pool->stop_th);
 }
 
+static inline void
+dp_tx_flow_ctrl_reset_subqueues(struct dp_soc *soc,
+				struct dp_tx_desc_pool_s *pool,
+				enum flow_pool_status pool_status)
+{
+}
+
 #endif
 
 /**
@@ -356,6 +389,7 @@ int dp_tx_delete_flow_pool(struct dp_soc *soc, struct dp_tx_desc_pool_s *pool,
 	bool force)
 {
 	struct dp_vdev *vdev;
+	enum flow_pool_status pool_status;
 
 	if (!soc || !pool) {
 		dp_err("pool or soc is NULL");
@@ -381,7 +415,10 @@ int dp_tx_delete_flow_pool(struct dp_soc *soc, struct dp_tx_desc_pool_s *pool,
 	}
 
 	if (pool->avail_desc < pool->pool_size) {
+		pool_status = pool->status;
 		pool->status = FLOW_POOL_INVALID;
+		dp_tx_flow_ctrl_reset_subqueues(soc, pool, pool_status);
+
 		qdf_spin_unlock_bh(&pool->flow_pool_lock);
 		/* Reset TX desc associated to this Vdev as NULL */
 		vdev = dp_vdev_get_ref_by_id(soc, pool->flow_pool_id,

+ 26 - 0
dp/wifi3.0/dp_types.h

@@ -568,6 +568,7 @@ struct dp_tx_desc_s {
 	struct hal_tx_desc_comp_s comp;
 };
 
+#ifdef QCA_AC_BASED_FLOW_CONTROL
 /**
  * enum flow_pool_status - flow pool status
  * @FLOW_POOL_ACTIVE_UNPAUSED : pool is active (can take/put descriptors)
@@ -576,6 +577,8 @@ struct dp_tx_desc_s {
  *			   and network queues are paused
  * @FLOW_POOL_INVALID: pool is invalid (put descriptor)
  * @FLOW_POOL_INACTIVE: pool is inactive (pool is free)
+ * @FLOW_POOL_ACTIVE_UNPAUSED_REATTACH: pool is reattached but network
+ *					queues are not paused
  */
 enum flow_pool_status {
 	FLOW_POOL_ACTIVE_UNPAUSED = 0,
@@ -585,8 +588,31 @@ enum flow_pool_status {
 	FLOW_POOL_VO_PAUSED = 4,
 	FLOW_POOL_INVALID = 5,
 	FLOW_POOL_INACTIVE = 6,
+	FLOW_POOL_ACTIVE_UNPAUSED_REATTACH = 7,
 };
 
+#else
+/**
+ * enum flow_pool_status - flow pool status
+ * @FLOW_POOL_ACTIVE_UNPAUSED : pool is active (can take/put descriptors)
+ *				and network queues are unpaused
+ * @FLOW_POOL_ACTIVE_PAUSED: pool is active (can take/put descriptors)
+ *			   and network queues are paused
+ * @FLOW_POOL_INVALID: pool is invalid (put descriptor)
+ * @FLOW_POOL_INACTIVE: pool is inactive (pool is free)
+ */
+enum flow_pool_status {
+	FLOW_POOL_ACTIVE_UNPAUSED = 0,
+	FLOW_POOL_ACTIVE_PAUSED = 1,
+	FLOW_POOL_BE_BK_PAUSED = 2,
+	FLOW_POOL_VI_PAUSED = 3,
+	FLOW_POOL_VO_PAUSED = 4,
+	FLOW_POOL_INVALID = 5,
+	FLOW_POOL_INACTIVE = 6,
+};
+
+#endif
+
 /**
  * struct dp_tx_tso_seg_pool_s
  * @pool_size: total number of pool elements