diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c index 7664b8ea5979..fd9c42c863b0 100644 --- a/core/dp/txrx/ol_tx_send.c +++ b/core/dp/txrx/ol_tx_send.c @@ -127,6 +127,21 @@ void ol_txrx_flow_control_cb(struct cdp_vdev *pvdev, bool tx_resume) return; } +/** + * ol_txrx_flow_control_is_pause() - is osif paused by flow control + * @vdev: vdev handle + * + * Return: true if osif is paused by flow control + */ +static bool ol_txrx_flow_control_is_pause(ol_txrx_vdev_handle vdev) +{ + bool is_pause = false; + if ((vdev->osif_flow_control_is_pause) && (vdev->osif_fc_ctx)) + is_pause = vdev->osif_flow_control_is_pause(vdev->osif_fc_ctx); + + return is_pause; +} + /** * ol_tx_flow_ct_unpause_os_q() - Unpause OS Q * @pdev: physical device object @@ -139,8 +154,9 @@ static void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) struct ol_txrx_vdev_t *vdev; TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { - if (qdf_atomic_read(&vdev->os_q_paused) && - (vdev->tx_fl_hwm != 0)) { + if ((qdf_atomic_read(&vdev->os_q_paused) && + (vdev->tx_fl_hwm != 0)) || + ol_txrx_flow_control_is_pause(vdev)) { qdf_spin_lock(&pdev->tx_mutex); if (pdev->tx_desc.num_free > vdev->tx_fl_hwm) { qdf_atomic_set(&vdev->os_q_paused, 0); diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index 5a89b74d69e5..b101ecb8dce8 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -2078,6 +2078,7 @@ ol_txrx_vdev_attach(struct cdp_pdev *ppdev, sizeof(union ol_txrx_align_mac_addr_t)); qdf_spinlock_create(&vdev->flow_control_lock); vdev->osif_flow_control_cb = NULL; + vdev->osif_flow_control_is_pause = NULL; vdev->osif_fc_ctx = NULL; /* Default MAX Q depth for every VDEV */ @@ -2264,6 +2265,7 @@ ol_txrx_vdev_detach(struct cdp_vdev *pvdev, qdf_spin_lock_bh(&vdev->flow_control_lock); vdev->osif_flow_control_cb = NULL; + vdev->osif_flow_control_is_pause = NULL; vdev->osif_fc_ctx = NULL; qdf_spin_unlock_bh(&vdev->flow_control_lock); qdf_spinlock_destroy(&vdev->flow_control_lock); @@ -4404,12 +4406,13 @@ static ol_txrx_vdev_handle ol_txrx_get_vdev_from_sta_id(uint8_t sta_id) * @vdev_id: vdev_id * @flowControl: flow control callback * @osif_fc_ctx: callback context + * @flow_control_is_pause: is vdev paused by flow control * * Return: 0 for sucess or error code */ static int ol_txrx_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) { struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); @@ -4422,6 +4425,7 @@ static int ol_txrx_register_tx_flow_control(uint8_t vdev_id, qdf_spin_lock_bh(&vdev->flow_control_lock); vdev->osif_flow_control_cb = flowControl; + vdev->osif_flow_control_is_pause = flow_control_is_pause; vdev->osif_fc_ctx = osif_fc_ctx; qdf_spin_unlock_bh(&vdev->flow_control_lock); return 0; @@ -4447,6 +4451,7 @@ static int ol_txrx_deregister_tx_flow_control_cb(uint8_t vdev_id) qdf_spin_lock_bh(&vdev->flow_control_lock); vdev->osif_flow_control_cb = NULL; + vdev->osif_flow_control_is_pause = NULL; vdev->osif_fc_ctx = NULL; qdf_spin_unlock_bh(&vdev->flow_control_lock); return 0; diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h index ae5e4806d3af..03031ffd9b83 100644 --- a/core/dp/txrx/ol_txrx_types.h +++ b/core/dp/txrx/ol_txrx_types.h @@ -1061,6 +1061,7 @@ struct ol_txrx_vdev_t { uint16_t tx_fl_hwm; qdf_spinlock_t flow_control_lock; ol_txrx_tx_flow_control_fp osif_flow_control_cb; + ol_txrx_tx_flow_control_is_pause_fp osif_flow_control_is_pause; void *osif_fc_ctx; #if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h index dc3629fdd9a5..4044acf40dc0 100644 --- a/core/hdd/inc/wlan_hdd_tx_rx.h +++ b/core/hdd/inc/wlan_hdd_tx_rx.h @@ -71,10 +71,29 @@ QDF_STATUS hdd_get_peer_sta_id(hdd_station_ctx_t *sta_ctx, #ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL void hdd_tx_resume_cb(void *adapter_context, bool tx_resume); + +/** + * hdd_tx_flow_control_is_pause() - Is TX Q paused by flow control + * @adapter_context: pointer to vdev apdapter + * + * 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 + * @adapter: adapter handle + * @timer_callback: timer callback + * @flow_control_fp: txrx flow control + * @flow_control_is_pause_fp: is txrx paused by flow control + * + * Return: none + */ void hdd_register_tx_flow_control(hdd_adapter_t *adapter, qdf_mc_timer_callback_t timer_callback, - ol_txrx_tx_flow_control_fp flowControl); + ol_txrx_tx_flow_control_fp flowControl, + ol_txrx_tx_flow_control_is_pause_fp flow_control_is_pause); void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter); void hdd_get_tx_resource(hdd_adapter_t *adapter, uint8_t STAId, uint16_t timer_value); @@ -83,12 +102,17 @@ void hdd_get_tx_resource(hdd_adapter_t *adapter, static inline void hdd_tx_resume_cb(void *adapter_context, bool tx_resume) { } +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(hdd_adapter_t *adapter, qdf_mc_timer_callback_t timer_callback, - ol_txrx_tx_flow_control_fp flowControl) + ol_txrx_tx_flow_control_fp flowControl, + ol_txrx_tx_flow_control_is_pause_fp flow_control_is_pause) { } static inline void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter) diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 2d29dfcc2167..e80fa0bcd5bb 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -1172,7 +1172,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, hdd_register_tx_flow_control(pHostapdAdapter, hdd_softap_tx_resume_timer_expired_handler, - hdd_softap_tx_resume_cb); + hdd_softap_tx_resume_cb, + hdd_tx_flow_control_is_pause); /* @@@ need wep logic here to set privacy bit */ qdf_status = diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index d90669d3dda7..5edc42787ef8 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -4872,7 +4872,8 @@ QDF_STATUS hdd_start_all_adapters(hdd_context_t *hdd_ctx) hdd_register_tx_flow_control(adapter, hdd_tx_resume_timer_expired_handler, - hdd_tx_resume_cb); + hdd_tx_resume_cb, + hdd_tx_flow_control_is_pause); break; @@ -7798,7 +7799,8 @@ int hdd_start_station_adapter(hdd_adapter_t *adapter) hdd_register_tx_flow_control(adapter, hdd_tx_resume_timer_expired_handler, - hdd_tx_resume_cb); + hdd_tx_resume_cb, + hdd_tx_flow_control_is_pause); EXIT(); return 0; @@ -7827,7 +7829,8 @@ int hdd_start_ap_adapter(hdd_adapter_t *adapter) hdd_register_tx_flow_control(adapter, hdd_softap_tx_resume_timer_expired_handler, - hdd_softap_tx_resume_cb); + hdd_softap_tx_resume_cb, + hdd_tx_flow_control_is_pause); EXIT(); return 0; diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index 10d54d562bd0..fdc3d826d979 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -206,17 +206,23 @@ void hdd_tx_resume_cb(void *adapter_context, bool tx_resume) hdd_tx_resume_false(pAdapter, tx_resume); } -/** - * hdd_register_tx_flow_control() - Register TX Flow control - * @adapter: adapter handle - * @timer_callback: timer callback - * @flow_control_fp: txrx flow control - * - * Return: none - */ +bool hdd_tx_flow_control_is_pause(void *adapter_context) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context; + + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + /* INVALID ARG */ + hdd_err("invalid adapter %p", pAdapter); + return false; + } + + return pAdapter->pause_map & (1 << WLAN_DATA_FLOW_CONTROL); +} + void hdd_register_tx_flow_control(hdd_adapter_t *adapter, qdf_mc_timer_callback_t timer_callback, - ol_txrx_tx_flow_control_fp flow_control_fp) + ol_txrx_tx_flow_control_fp flow_control_fp, + ol_txrx_tx_flow_control_is_pause_fp flow_control_is_pause_fp) { if (adapter->tx_flow_timer_initialized == false) { qdf_mc_timer_init(&adapter->tx_flow_control_timer, @@ -226,7 +232,8 @@ void hdd_register_tx_flow_control(hdd_adapter_t *adapter, adapter->tx_flow_timer_initialized = true; } cdp_fc_register(cds_get_context(QDF_MODULE_ID_SOC), - adapter->sessionId, flow_control_fp, adapter); + adapter->sessionId, flow_control_fp, adapter, + flow_control_is_pause_fp); } /**