diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h index d5e5f16ae3dd..56bcbc18f6a1 100644 --- a/core/hdd/inc/wlan_hdd_tx_rx.h +++ b/core/hdd/inc/wlan_hdd_tx_rx.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -66,6 +66,19 @@ QDF_STATUS hdd_get_peer_sta_id(struct hdd_station_ctx *sta_ctx, struct qdf_mac_addr *peer_mac_addr, uint8_t *sta_id); +/** + * hdd_tx_queue_cb() - Disable/Enable the Transmit Queues + * @context: HDD context + * @vdev_id: vdev id + * @action: Action to be taken on the Tx Queues + * @reason: Reason for the netif action + * + * Return: None + */ +void hdd_tx_queue_cb(void *context, uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason); + #ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL void hdd_tx_resume_cb(void *adapter_context, bool tx_resume); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 213ef3afb208..97ec690df260 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -10650,6 +10650,11 @@ int hdd_register_cb(struct hdd_context *hdd_ctx) if (!QDF_IS_STATUS_SUCCESS(status)) hdd_err("set bt activity info callback failed"); + status = sme_register_tx_queue_cb(hdd_ctx->hHal, + hdd_tx_queue_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Register tx queue callback failed"); + EXIT(); return ret; @@ -10670,6 +10675,7 @@ void hdd_deregister_cb(struct hdd_context *hdd_ctx) ENTER(); + sme_deregister_tx_queue_cb(hdd_ctx->hHal); status = sme_deregister_for_dcc_stats_event(hdd_ctx->hHal); if (!QDF_IS_STATUS_SUCCESS(status)) hdd_err("De-register of dcc stats callback failed: %d", diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index dedad19dc8dc..09ab1e6debb1 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1893,6 +1893,35 @@ void hdd_send_rps_disable_ind(struct hdd_adapter *adapter) cds_cfg->rps_enabled = false; } +void hdd_tx_queue_cb(void *context, uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)context; + struct hdd_adapter *adapter = NULL; + + /* + * Validating the context is not required here. + * if there is a driver unload/SSR in progress happening in a + * different context and it has been scheduled to run and + * driver got a firmware event of sta kick out, then it is + * good to disable the Tx Queue to stop the influx of traffic. + */ + if (hdd_ctx == NULL) { + hdd_err("Invalid context passed"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (adapter == NULL) { + hdd_err("vdev_id %d does not exist with host", vdev_id); + return; + } + hdd_debug("Tx Queue action %d on vdev %d", action, vdev_id); + + wlan_hdd_netif_queue_control(adapter, action, reason); +} + #ifdef MSM_PLATFORM /** * hdd_reset_tcp_delack() - Reset tcp delack value to default diff --git a/core/mac/src/pe/lim/lim_link_monitoring_algo.c b/core/mac/src/pe/lim/lim_link_monitoring_algo.c index 929a00cfa12e..0e4214c53951 100644 --- a/core/mac/src/pe/lim/lim_link_monitoring_algo.c +++ b/core/mac/src/pe/lim/lim_link_monitoring_algo.c @@ -485,15 +485,16 @@ void lim_handle_heart_beat_failure(tpAniSirGlobal mac_ctx, (session->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) && (session->limSmeState != eLIM_SME_WT_DISASSOC_STATE) && (session->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { - if (!mac_ctx->sys.gSysEnableLinkMonitorMode) - return; + if (!mac_ctx->sys.gSysEnableLinkMonitorMode) { + goto hb_handler_fail; + } /* Ignore HB if channel switch is in progress */ if (session->gLimSpecMgmt.dot11hChanSwState == eLIM_11H_CHANSW_RUNNING) { pe_debug("Ignore Heartbeat failure as Channel switch is in progress"); session->pmmOffloadInfo.bcnmiss = false; - return; + goto hb_handler_fail; } /* Beacon frame not received within heartbeat timeout. */ pe_warn("Heartbeat Failure"); @@ -561,4 +562,10 @@ void lim_handle_heart_beat_failure(tpAniSirGlobal mac_ctx, lim_print_mlm_state(mac_ctx, LOG1, session->limMlmState); mac_ctx->lim.gLimHBfailureCntInOtherStates++; } + +hb_handler_fail: + if (mac_ctx->sme.tx_queue_cb) + mac_ctx->sme.tx_queue_cb(mac_ctx->hHdd, session->smeSessionId, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); } diff --git a/core/mac/src/pe/lim/lim_process_message_queue.c b/core/mac/src/pe/lim/lim_process_message_queue.c index bf59755d2962..2887765fb836 100644 --- a/core/mac/src/pe/lim/lim_process_message_queue.c +++ b/core/mac/src/pe/lim/lim_process_message_queue.c @@ -1715,7 +1715,6 @@ static void lim_process_messages(tpAniSirGlobal mac_ctx, case SIR_LIM_PROBE_HB_FAILURE_TIMEOUT: lim_handle_heart_beat_failure_timeout(mac_ctx); break; - break; case SIR_LIM_CNF_WAIT_TIMEOUT: /* Does not receive CNF or dummy packet */ lim_handle_cnf_wait_timeout(mac_ctx, (uint16_t) msg->bodyval); diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c index 80fb7306b4ae..e27e91a6c186 100644 --- a/core/mac/src/pe/lim/lim_utils.c +++ b/core/mac/src/pe/lim/lim_utils.c @@ -5546,6 +5546,11 @@ void lim_handle_heart_beat_failure_timeout(tpAniSirGlobal mac_ctx) pe_err("Unexpected wt-probe-timeout in state"); lim_print_mlm_state(mac_ctx, LOGE, psession_entry->limMlmState); + if (mac_ctx->sme.tx_queue_cb) + mac_ctx->sme.tx_queue_cb(mac_ctx->hHdd, + psession_entry->smeSessionId, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); } } /* diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index d538c2ae594a..4f741df3326b 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1561,6 +1561,27 @@ QDF_STATUS sme_fast_reassoc(tHalHandle hal, tCsrRoamProfile *profile, QDF_STATUS sme_congestion_register_callback(tHalHandle hal, void (*congestion_cb)(void *, uint32_t congestion, uint32_t vdev_id)); +/** + * sme_register_tx_queue_cb(): Register tx queue callback + * @hal: handler for HAL + * @tx_queue_cb: Transmit Queues callback + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_register_tx_queue_cb(tHalHandle hal, + void (*tx_queue_cb)(void *, + uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason)); + +/** + * sme_deregister_tx_queue_cb() - Deregister the tx queue callback + * @hal: HAL handle + * + * Return: QDF status + */ +QDF_STATUS sme_deregister_tx_queue_cb(tHalHandle hal); + /** * sme_rso_cmd_status_cb() - Set RSO cmd status callback * @hal: HAL Handle diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index b4e0379193a1..b3503c182522 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -264,6 +264,9 @@ typedef struct tagSmeStruct { void (*get_arp_stats_cb)(void *, struct rsp_stats *); get_chain_rssi_callback get_chain_rssi_cb; void *get_chain_rssi_context; + void (*tx_queue_cb)(void *, uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason); } tSmeStruct, *tpSmeStruct; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index dd07a67329f8..fa2507d77074 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -15499,6 +15499,32 @@ QDF_STATUS sme_congestion_register_callback(tHalHandle hal, return status; } +QDF_STATUS sme_register_tx_queue_cb(tHalHandle hal, + void (*tx_queue_cb)(void *, + uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason)) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.tx_queue_cb = tx_queue_cb; + sme_release_global_lock(&mac->sme); + sme_debug("Tx queue callback set"); + } else { + sme_err("Aquiring lock failed %d", status); + } + + return status; +} + +QDF_STATUS sme_deregister_tx_queue_cb(tHalHandle hal) +{ + return sme_register_tx_queue_cb(hal, NULL); +} + QDF_STATUS sme_set_smps_cfg(uint32_t vdev_id, uint32_t param_id, uint32_t param_val) { diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index ac57170bae66..9d826f7bb4a2 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -2772,6 +2772,7 @@ void wma_set_keepalive_req(tp_wma_handle wma, void wma_beacon_miss_handler(tp_wma_handle wma, uint32_t vdev_id, int32_t rssi) { tSirSmeMissedBeaconInd *beacon_miss_ind; + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); beacon_miss_ind = (tSirSmeMissedBeaconInd *) qdf_mem_malloc (sizeof(tSirSmeMissedBeaconInd)); @@ -2780,6 +2781,10 @@ void wma_beacon_miss_handler(tp_wma_handle wma, uint32_t vdev_id, int32_t rssi) WMA_LOGE("%s: Memory allocation failure", __func__); return; } + if (mac && mac->sme.tx_queue_cb) + mac->sme.tx_queue_cb(mac->hHdd, vdev_id, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); beacon_miss_ind->messageType = WMA_MISSED_BEACON_IND; beacon_miss_ind->length = sizeof(tSirSmeMissedBeaconInd); beacon_miss_ind->bssIdx = vdev_id;