Browse Source

qcacld-3.0: Add timer for resuming OS-netdev queues

1) Add timer callback function for resuming OS netdev queues once
they have been paused.
2) Add HDD function to register resume timer callback for High Latency
Data Path Flow Control.
HL netdev flow control will re-use some of the
QCA_LL_LEGACY_TX_FLOW_CONTROL functionality, hence some parts of the
legacy flow control code have been conditionally enabled for
QCA_HL_NETDEV_FLOW_CONTROL as well.

Change-Id: I4d4a03ddd5be980ce27fd0771fa9d6dc26138357
CRs-fixed: 2236321
Ajit Pal Singh 7 năm trước cách đây
mục cha
commit
106c14126e

+ 15 - 1
core/hdd/inc/wlan_hdd_main.h

@@ -1340,12 +1340,16 @@ struct hdd_adapter {
 	uint64_t prev_fwd_rx_packets;
 	int connection;
 #endif
-#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
+#if  defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \
+				defined(QCA_HL_NETDEV_FLOW_CONTROL)
 	qdf_mc_timer_t tx_flow_control_timer;
 	bool tx_flow_timer_initialized;
+#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL || QCA_HL_NETDEV_FLOW_CONTROL */
+#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
 	unsigned int tx_flow_low_watermark;
 	unsigned int tx_flow_high_watermark_offset;
 #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
+
 	bool offloads_configured;
 
 	/* DSCP to UP QoS Mapping */
@@ -2469,6 +2473,16 @@ void hdd_clean_up_pre_cac_interface(struct hdd_context *hdd_ctx);
 void wlan_hdd_txrx_pause_cb(uint8_t vdev_id,
 	enum netif_action_type action, enum netif_reason_type reason);
 
+#ifdef QCA_HL_NETDEV_FLOW_CONTROL
+void wlan_hdd_mod_fc_timer(struct hdd_adapter *adapter,
+			   enum netif_action_type action);
+#else
+static inline void wlan_hdd_mod_fc_timer(struct hdd_adapter *adapter,
+					 enum netif_action_type action)
+{
+}
+#endif /* QCA_HL_NETDEV_FLOW_CONTROL */
+
 int hdd_wlan_dump_stats(struct hdd_adapter *adapter, int value);
 void wlan_hdd_deinit_tx_rx_histogram(struct hdd_context *hdd_ctx);
 void wlan_hdd_display_tx_rx_histogram(struct hdd_context *hdd_ctx);

+ 24 - 4
core/hdd/inc/wlan_hdd_tx_rx.h

@@ -129,7 +129,6 @@ void hdd_tx_resume_cb(void *adapter_context, bool tx_resume);
  * Return: true if TX Q is paused by flow control
  */
 bool hdd_tx_flow_control_is_pause(void *adapter_context);
-void hdd_tx_resume_timer_expired_handler(void *adapter_context);
 
 /**
  * hdd_register_tx_flow_control() - Register TX Flow control
@@ -156,9 +155,6 @@ static inline bool hdd_tx_flow_control_is_pause(void *adapter_context)
 {
 	return false;
 }
-static inline void hdd_tx_resume_timer_expired_handler(void *adapter_context)
-{
-}
 static inline void hdd_register_tx_flow_control(struct hdd_adapter *adapter,
 		qdf_mc_timer_callback_t timer_callback,
 		ol_txrx_tx_flow_control_fp flowControl,
@@ -174,6 +170,30 @@ static inline void hdd_get_tx_resource(struct hdd_adapter *adapter,
 }
 #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
 
+#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \
+		defined(QCA_HL_NETDEV_FLOW_CONTROL)
+void hdd_tx_resume_timer_expired_handler(void *adapter_context);
+#else
+static inline void hdd_tx_resume_timer_expired_handler(void *adapter_context)
+{
+}
+#endif
+
+#ifdef QCA_HL_NETDEV_FLOW_CONTROL
+void hdd_register_hl_netdev_fc_timer(struct hdd_adapter *adapter,
+				     qdf_mc_timer_callback_t timer_callback);
+void hdd_deregister_hl_netdev_fc_timer(struct hdd_adapter *adapter);
+#else
+static inline void hdd_register_hl_netdev_fc_timer(struct hdd_adapter *adapter,
+						   qdf_mc_timer_callback_t
+						   timer_callback)
+{}
+
+static inline void
+	hdd_deregister_hl_netdev_fc_timer(struct hdd_adapter *adapter)
+{}
+#endif /* QCA_HL_NETDEV_FLOW_CONTROL */
+
 int hdd_get_peer_idx(struct hdd_station_ctx *sta_ctx,
 		     struct qdf_mac_addr *addr);
 

+ 32 - 1
core/hdd/src/wlan_hdd_main.c

@@ -321,6 +321,32 @@ static void hdd_set_rps_cpu_mask(struct hdd_context *hdd_ctx)
 		hdd_send_rps_ind(adapter);
 }
 
+#ifdef QCA_HL_NETDEV_FLOW_CONTROL
+void wlan_hdd_mod_fc_timer(struct hdd_adapter *adapter,
+			   enum netif_action_type action)
+{
+	if (!adapter->tx_flow_timer_initialized)
+		return;
+
+	if (action == WLAN_WAKE_NON_PRIORITY_QUEUE) {
+		qdf_mc_timer_stop(&adapter->tx_flow_control_timer);
+	} else if (action == WLAN_STOP_NON_PRIORITY_QUEUE) {
+		QDF_STATUS status =
+		qdf_mc_timer_start(&adapter->tx_flow_control_timer,
+				   WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME);
+
+		if (!QDF_IS_STATUS_SUCCESS(status))
+			hdd_err("Failed to start tx_flow_control_timer");
+		else
+			adapter->
+			hdd_stats.tx_rx_stats.txflow_timer_cnt++;
+
+		adapter->hdd_stats.tx_rx_stats.txflow_pause_cnt++;
+		adapter->hdd_stats.tx_rx_stats.is_txflow_paused = true;
+	}
+}
+#endif /* QCA_HL_NETDEV_FLOW_CONTROL */
+
 /**
  * wlan_hdd_txrx_pause_cb() - pause callback from txrx layer
  * @vdev_id: vdev_id
@@ -340,7 +366,7 @@ void wlan_hdd_txrx_pause_cb(uint8_t vdev_id,
 		return;
 	}
 	adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
-
+	wlan_hdd_mod_fc_timer(adapter, action);
 	wlan_hdd_netif_queue_control(adapter, action, reason);
 }
 
@@ -4807,6 +4833,9 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
 		hdd_err("Interface %s wow debug_fs init failed",
 			netdev_name(adapter->dev));
 
+	hdd_register_hl_netdev_fc_timer(adapter,
+					hdd_tx_resume_timer_expired_handler);
+
 	hdd_info("%s interface created. iftype: %d", netdev_name(adapter->dev),
 		 session_type);
 
@@ -5200,6 +5229,8 @@ QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx,
 		break;
 	}
 
+	hdd_deregister_hl_netdev_fc_timer(adapter);
+
 	if (adapter->scan_info.default_scan_ies) {
 		qdf_mem_free(adapter->scan_info.default_scan_ies);
 		adapter->scan_info.default_scan_ies = NULL;

+ 51 - 0
core/hdd/src/wlan_hdd_tx_rx.c

@@ -85,6 +85,57 @@ const uint8_t hdd_qdisc_ac_to_tl_ac[] = {
 
 #endif
 
+#ifdef QCA_HL_NETDEV_FLOW_CONTROL
+void hdd_register_hl_netdev_fc_timer(struct hdd_adapter *adapter,
+				     qdf_mc_timer_callback_t timer_callback)
+{
+	if (!adapter->tx_flow_timer_initialized) {
+		qdf_mc_timer_init(&adapter->tx_flow_control_timer,
+				  QDF_TIMER_TYPE_SW, timer_callback, adapter);
+		adapter->tx_flow_timer_initialized = true;
+	}
+}
+
+/**
+ * hdd_deregister_hl_netdev_fc_timer() - Deregister HL Flow Control Timer
+ * @adapter: adapter handle
+ *
+ * Return: none
+ */
+void hdd_deregister_hl_netdev_fc_timer(struct hdd_adapter *adapter)
+{
+	if (adapter->tx_flow_timer_initialized) {
+		qdf_mc_timer_stop(&adapter->tx_flow_control_timer);
+		qdf_mc_timer_destroy(&adapter->tx_flow_control_timer);
+		adapter->tx_flow_timer_initialized = false;
+	}
+}
+
+/**
+ * hdd_tx_resume_timer_expired_handler() - TX Q resume timer handler
+ * @adapter_context: pointer to vdev adapter
+ *
+ * If Blocked OS Q is not resumed during timeout period, to prevent
+ * permanent stall, resume OS Q forcefully.
+ *
+ * Return: None
+ */
+void hdd_tx_resume_timer_expired_handler(void *adapter_context)
+{
+	struct hdd_adapter *adapter = (struct hdd_adapter *)adapter_context;
+
+	if (!adapter) {
+		/* INVALID ARG */
+		return;
+	}
+
+	hdd_debug("Enabling queues");
+	wlan_hdd_netif_queue_control(adapter, WLAN_WAKE_NON_PRIORITY_QUEUE,
+				     WLAN_DATA_FLOW_CONTROL);
+}
+
+#endif /* QCA_HL_NETDEV_FLOW_CONTROL */
+
 #ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
 /**
  * hdd_tx_resume_timer_expired_handler() - TX Q resume timer handler