From 4dcaf8b2392cd3814ba6132fa8adf0473f2c4789 Mon Sep 17 00:00:00 2001 From: bings Date: Fri, 11 Aug 2017 10:37:46 +0800 Subject: [PATCH] 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 --- dp/inc/cdp_txrx_cmn_struct.h | 9 +++++++++ dp/inc/cdp_txrx_flow_ctrl_legacy.h | 7 +++++-- dp/inc/cdp_txrx_mob_def.h | 9 +++++++++ dp/inc/cdp_txrx_ops.h | 3 ++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 19843eab16..57e6055482 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/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 diff --git a/dp/inc/cdp_txrx_flow_ctrl_legacy.h b/dp/inc/cdp_txrx_flow_ctrl_legacy.h index fdb8b4b9ee..7b3f023256 100644 --- a/dp/inc/cdp_txrx_flow_ctrl_legacy.h +++ b/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; } diff --git a/dp/inc/cdp_txrx_mob_def.h b/dp/inc/cdp_txrx_mob_def.h index 74e1811ab8..5a59f8c90c 100644 --- a/dp/inc/cdp_txrx_mob_def.h +++ b/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 diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index e1a610be4f..dcbdb444d2 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/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,