ソースを参照

qcacmn: Fix race condition that Tx is paused by flow control forever

When hdd_get_tx_resource is called, if free Tx desc is lower than low water
mark, vdev->os_q_paused will be set as 1 and WLAN_STOP_ALL_NETIF_QUEUE will
be triggered after a while. Before WLAN_STOP_ALL_NETIF_QUEUE is triggered,
if ol_tx_flow_ct_unpause_os_q is called, WLAN_WAKE_ALL_NETIF_QUEUE will be
triggered and vdev->os_q_paused will be set as 0. In such case there will
be no flow control unpaused forever.

Tx should be paused by flow control when Tx desc is lower than low water
mark, and unpaused when Tx desc is bigger than high water mark or Tx is
already paused by flow control.

Change-Id: Ib60139fd94a4fb88c92a7f8aaf886ae9d3ca4c75
CRs-Fixed: 2090475
bings 7 年 前
コミット
4dcaf8b239

+ 9 - 0
dp/inc/cdp_txrx_cmn_struct.h

@@ -311,6 +311,15 @@ typedef qdf_nbuf_t (*ol_txrx_tx_fp)(void *data_vdev,
 typedef void (*ol_txrx_tx_flow_control_fp)(void *osif_dev,
 					    bool tx_resume);
 
+/**
+ * ol_txrx_tx_flow_control_is_pause_fp - is tx paused by flow control
+ * function from txrx to OS shim
+ * @osif_dev - the virtual device's OS shim object
+ *
+ * Return: true if tx is paused by flow control
+ */
+typedef bool (*ol_txrx_tx_flow_control_is_pause_fp)(void *osif_dev);
+
 /**
  * ol_txrx_rx_fp - receive function to hand batches of data
  * frames from txrx to OS shim

+ 5 - 2
dp/inc/cdp_txrx_flow_ctrl_legacy.h

@@ -40,6 +40,7 @@
  * @vdev_id - virtual interface id to register flow control
  * @flowControl - callback function pointer
  * @osif_fc_ctx - client context pointer
+ * @flow_control_is_pause: is vdev paused by flow control
  *
  * Register flow control callback function pointer and client context pointer
  *
@@ -47,7 +48,8 @@
  */
 static inline int
 cdp_fc_register(ol_txrx_soc_handle soc, uint8_t vdev_id,
-		ol_txrx_tx_flow_control_fp flowControl, void *osif_fc_ctx)
+		ol_txrx_tx_flow_control_fp flowControl, void *osif_fc_ctx,
+		ol_txrx_tx_flow_control_is_pause_fp flow_control_is_pause)
 {
 	if (!soc || !soc->ops || !soc->ops->l_flowctl_ops) {
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL,
@@ -57,7 +59,8 @@ cdp_fc_register(ol_txrx_soc_handle soc, uint8_t vdev_id,
 
 	if (soc->ops->l_flowctl_ops->register_tx_flow_control)
 		return soc->ops->l_flowctl_ops->register_tx_flow_control(
-			vdev_id, flowControl, osif_fc_ctx);
+			vdev_id, flowControl, osif_fc_ctx,
+			flow_control_is_pause);
 
 	return 0;
 }

+ 9 - 0
dp/inc/cdp_txrx_mob_def.h

@@ -393,6 +393,15 @@ typedef void (*ol_txrx_vdev_peer_remove_cb)(void *handle, uint8_t *bssid,
  */
 typedef void (*ol_txrx_tx_flow_control_fp)(void *osif_dev, bool tx_resume);
 
+/**
+ * ol_txrx_tx_flow_control_is_pause_fp - is tx paused by flow control
+ * function from txrx to OS shim
+ * @osif_dev - the virtual device's OS shim object
+ *
+ * Return: true if tx is paused by flow control
+ */
+typedef bool (*ol_txrx_tx_flow_control_is_pause_fp)(void *osif_dev);
+
 /**
  * ol_txrx_tx_flow_control_fp - tx flow control notification
  * function from txrx to OS shim

+ 2 - 1
dp/inc/cdp_txrx_ops.h

@@ -748,7 +748,8 @@ struct cdp_flowctl_ops {
  */
 struct cdp_lflowctl_ops {
 	int (*register_tx_flow_control)(uint8_t vdev_id,
-		ol_txrx_tx_flow_control_fp flowControl, void *osif_fc_ctx);
+		ol_txrx_tx_flow_control_fp flowControl, void *osif_fc_ctx,
+		ol_txrx_tx_flow_control_is_pause_fp flow_control_is_pause);
 	int (*deregister_tx_flow_control_cb)(uint8_t vdev_id);
 	void (*flow_control_cb)(struct cdp_vdev *vdev, bool tx_resume);
 	bool (*get_tx_resource)(uint8_t sta_id,