From 2a8a740a4da8c632995715bce78bb983d17ca5e5 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Mon, 3 Jul 2017 14:06:11 +0530 Subject: [PATCH] qcacld-3.0: Add support for SSR within SSR Add below changes to support SSR within SSR, 1.Add new driver state, CDS_DRIVER_STATE_BAD, which will be set on re-init failure and reset on re-init success and if this state is set, don't allow any north-bound calls. 2.Don't de-register wiphy/netdev on re-init failure. 3.BUG_ON if re-init or probe fails successively for two times. 4.During driver unload, don't wait for SSR to be completed. Change-Id: Id05a3e4b592664c9b56c7dd83b965b973f1d5ca5 CRs-Fixed: 2037628 --- core/bmi/src/ol_fw.c | 2 +- core/cds/inc/cds_api.h | 28 +++++++++ core/cds/src/cds_api.c | 10 +-- core/hdd/src/wlan_hdd_driver_ops.c | 31 +++++++-- core/hdd/src/wlan_hdd_ioctl.c | 2 +- core/hdd/src/wlan_hdd_main.c | 12 +++- core/hdd/src/wlan_hdd_power.c | 94 ++-------------------------- core/hdd/src/wlan_hdd_regulatory.c | 3 +- core/hdd/src/wlan_hdd_scan.c | 2 +- core/hdd/src/wlan_hdd_softap_tx_rx.c | 4 +- core/hdd/src/wlan_hdd_tdls.c | 3 +- core/hdd/src/wlan_hdd_tx_rx.c | 2 +- core/hdd/src/wlan_hdd_wext.c | 4 +- core/wma/src/wma_features.c | 3 + core/wma/src/wma_mgmt.c | 11 ++++ 15 files changed, 98 insertions(+), 113 deletions(-) diff --git a/core/bmi/src/ol_fw.c b/core/bmi/src/ol_fw.c index 2926d9e5de5a..bcf208eaa188 100644 --- a/core/bmi/src/ol_fw.c +++ b/core/bmi/src/ol_fw.c @@ -623,7 +623,7 @@ void ol_target_failure(void *instance, QDF_STATUS status) return; } - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { BMI_ERR("%s: Recovery in progress, ignore!\n", __func__); return; } diff --git a/core/cds/inc/cds_api.h b/core/cds/inc/cds_api.h index d8b4de196fff..d54a7c388f95 100644 --- a/core/cds/inc/cds_api.h +++ b/core/cds/inc/cds_api.h @@ -64,6 +64,7 @@ * CDS_DRIVER_STATE_LOADING: Driver probe is in progress. * CDS_DRIVER_STATE_UNLOADING: Driver remove is in progress. * CDS_DRIVER_STATE_RECOVERING: Recovery in progress. + * CDS_DRIVER_STATE_BAD: Driver in bad state. */ enum cds_driver_state { CDS_DRIVER_STATE_UNINITIALIZED = 0, @@ -71,6 +72,7 @@ enum cds_driver_state { CDS_DRIVER_STATE_LOADING = BIT(1), CDS_DRIVER_STATE_UNLOADING = BIT(2), CDS_DRIVER_STATE_RECOVERING = BIT(3), + CDS_DRIVER_STATE_BAD = BIT(4) }; #define __CDS_IS_DRIVER_STATE(_state, _mask) (((_state) & (_mask)) == (_mask)) @@ -171,6 +173,18 @@ static inline bool cds_is_driver_recovering(void) return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_RECOVERING); } +/** + * cds_is_driver_in_bad_state() - is driver in bad state + * + * Return: true if driver is in bad state and false otherwise. + */ +static inline bool cds_is_driver_in_bad_state(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_BAD); +} + /** * cds_is_load_or_unload_in_progress() - Is driver load OR unload in progress * @@ -224,6 +238,20 @@ static inline void cds_set_recovery_in_progress(uint8_t value) cds_clear_driver_state(CDS_DRIVER_STATE_RECOVERING); } +/** + * cds_set_driver_in_bad_state() - Set driver state + * @value: value to set + * + * Return: none + */ +static inline void cds_set_driver_in_bad_state(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_BAD); + else + cds_clear_driver_state(CDS_DRIVER_STATE_BAD); +} + /** * cds_set_load_in_progress() - Set load in progress * @value: value to set diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c index 0ff093c76e23..1c1f40fa0c9f 100644 --- a/core/cds/src/cds_api.c +++ b/core/cds/src/cds_api.c @@ -1002,8 +1002,8 @@ QDF_STATUS cds_post_disable(void) * - Clean up CE tasklets. */ - cds_info("send denint sequence to firmware"); - if (!cds_is_driver_recovering()) + cds_info("send deinit sequence to firmware"); + if (!(cds_is_driver_recovering() || cds_is_driver_in_bad_state())) cds_suspend_target(wma_handle); hif_disable_isr(hif_ctx); hif_reset_soc(hif_ctx); @@ -1718,7 +1718,7 @@ bool cds_is_packet_log_enabled(void) static void cds_config_recovery_work(qdf_device_t qdf_ctx) { - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "Recovery is in progress, ignore!"); } else { @@ -2118,7 +2118,7 @@ uint32_t cds_get_log_indicator(void) } if (cds_is_load_or_unload_in_progress() || - cds_is_driver_recovering()) { + cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { return WLAN_LOG_INDICATOR_UNUSED; } @@ -2179,7 +2179,7 @@ QDF_STATUS cds_flush_logs(uint32_t is_fatal, return QDF_STATUS_E_FAILURE; } if (cds_is_load_or_unload_in_progress() || - cds_is_driver_recovering()) { + cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: un/Load/SSR in progress", __func__); return QDF_STATUS_E_FAILURE; diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index 98e0f6d01a55..f2d09a55e874 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -56,6 +56,9 @@ #define DISABLE_KRAIT_IDLE_PS_VAL 1 +#define SSR_MAX_FAIL_CNT 2 +static uint8_t re_init_fail_cnt, probe_fail_cnt; + /* * In BMI Phase we are only sending small chunk (256 bytes) of the FW image at * a time, and wait for the completion interrupt to start the next transfer. @@ -349,10 +352,15 @@ static int wlan_hdd_probe(struct device *dev, void *bdev, hdd_init_qdf_ctx(dev, bdev, bus_type, (const struct hif_bus_id *)bid); - if (reinit) + if (reinit) { ret = hdd_wlan_re_init(); - else + if (ret) + re_init_fail_cnt++; + } else { ret = hdd_wlan_startup(dev); + if (ret) + probe_fail_cnt++; + } if (ret) goto err_hdd_deinit; @@ -370,14 +378,27 @@ static int wlan_hdd_probe(struct device *dev, void *bdev, cds_set_fw_down(false); + cds_set_driver_in_bad_state(false); + probe_fail_cnt = 0; + re_init_fail_cnt = 0; + return 0; err_hdd_deinit: - if (reinit) + pr_err("probe/reinit failure counts %hhu/%hhu", + probe_fail_cnt, re_init_fail_cnt); + if (probe_fail_cnt >= SSR_MAX_FAIL_CNT || + re_init_fail_cnt >= SSR_MAX_FAIL_CNT) + QDF_BUG(0); + + if (reinit) { + cds_set_driver_in_bad_state(true); cds_set_recovery_in_progress(false); + } else cds_set_load_in_progress(false); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT); hdd_remove_pm_qos(dev); @@ -404,7 +425,6 @@ static void wlan_hdd_remove(struct device *dev) pr_info("%s: Removing driver v%s\n", WLAN_MODULE_NAME, QWLAN_VERSIONSTR); - cds_set_driver_loaded(false); cds_set_unload_in_progress(true); @@ -420,6 +440,7 @@ static void wlan_hdd_remove(struct device *dev) __hdd_wlan_exit(); } + cds_set_driver_in_bad_state(false); cds_set_unload_in_progress(false); pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME); @@ -846,7 +867,7 @@ static int __wlan_hdd_bus_resume(void) return 0; out: - if (cds_is_driver_recovering()) + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) return 0; QDF_BUG(false); diff --git a/core/hdd/src/wlan_hdd_ioctl.c b/core/hdd/src/wlan_hdd_ioctl.c index a8fbc17369e4..1b5ff2bf38e8 100644 --- a/core/hdd/src/wlan_hdd_ioctl.c +++ b/core/hdd/src/wlan_hdd_ioctl.c @@ -2304,7 +2304,7 @@ static int wlan_hdd_get_link_status(hdd_adapter_t *adapter) .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS, }; - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!", cds_get_driver_state()); return 0; diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 7d75c21c9c05..9a341ff4550a 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -414,7 +414,7 @@ static int __hdd_netdev_notifier_call(struct notifier_block *nb, QDF_ASSERT(0); return NOTIFY_DONE; } - if (cds_is_driver_recovering()) + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) return NOTIFY_DONE; hdd_debug("%s New Net Device State = %lu", @@ -627,6 +627,12 @@ int wlan_hdd_validate_context(hdd_context_t *hdd_ctx) return -EAGAIN; } + if (cds_is_driver_in_bad_state()) { + hdd_debug("%pS driver in bad State: 0x%x Ignore!!!", + (void *)_RET_IP_, cds_get_driver_state()); + return -ENODEV; + } + return 0; } @@ -1487,7 +1493,7 @@ void hdd_update_tgt_cfg(void *context, void *param) hdd_warn("ini BandCapability not supported by the target"); } - if (!cds_is_driver_recovering()) { + if (!cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { hdd_ctx->reg.reg_domain = cfg->reg_domain; hdd_ctx->reg.eeprom_rd_ext = cfg->eeprom_rd_ext; } @@ -5587,7 +5593,7 @@ static void hdd_wlan_exit(hdd_context_t *hdd_ctx) */ qdf_status = cds_sched_close(p_cds_context); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { - hdd_err("Failed to close CDS Scheduler"); + hdd_alert("Failed to close CDS Scheduler"); QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); } diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 6a635d88a1bb..a30eeb1ca990 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -135,9 +135,6 @@ void hdd_wlan_offload_event(uint8_t type, uint8_t state) extern struct notifier_block hdd_netdev_notifier; -static struct timer_list ssr_timer; -static bool ssr_timer_started; - /** * hdd_enable_gtk_offload() - enable GTK offload * @adapter: pointer to the adapter @@ -1081,7 +1078,7 @@ hdd_suspend_wlan(void) return -EINVAL; } - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!", cds_get_driver_state()); return -EINVAL; @@ -1140,7 +1137,7 @@ static int hdd_resume_wlan(void) return -EINVAL; } - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!", cds_get_driver_state()); return -EINVAL; @@ -1180,66 +1177,6 @@ next_adapter: return 0; } -/** - * DOC: SSR Timer - * - * When SSR is initiated, an SSR timer is started. Under normal - * circumstances SSR should complete amd the timer should be deleted - * before it fires. If the SSR timer does fire, it indicates SSR has - * taken too long, and our only recourse is to invoke the QDF_BUG() - * API which can allow a crashdump to be captured. - */ - -/** - * hdd_ssr_timer_init() - Initialize SSR Timer - * - * Return: None. - */ -static void hdd_ssr_timer_init(void) -{ - init_timer(&ssr_timer); -} - -/** - * hdd_ssr_timer_del() - Delete SSR Timer - * - * Return: None. - */ -static void hdd_ssr_timer_del(void) -{ - del_timer(&ssr_timer); - ssr_timer_started = false; -} - -/** - * hdd_ssr_timer_cb() - SSR Timer callback function - * @data: opaque data registered with timer infrastructure - * - * Return: None. - */ -static void hdd_ssr_timer_cb(unsigned long data) -{ - hdd_info("HDD SSR timer expired!"); - QDF_BUG(0); -} - -/** - * hdd_ssr_timer_start() - Start SSR Timer - * @msec: Timer timeout value in milliseconds - * - * Return: None. - */ -static void hdd_ssr_timer_start(int msec) -{ - if (ssr_timer_started) { - hdd_debug("Trying to start SSR timer when " "it's running!"); - } - ssr_timer.expires = jiffies + msecs_to_jiffies(msec); - ssr_timer.function = hdd_ssr_timer_cb; - add_timer(&ssr_timer); - ssr_timer_started = true; -} - /** * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace * @@ -1312,10 +1249,6 @@ QDF_STATUS hdd_wlan_shutdown(void) hdd_info("WLAN driver shutting down!"); - /* If SSR never completes, then do kernel panic. */ - hdd_ssr_timer_init(); - hdd_ssr_timer_start(HDD_SSR_BRING_UP_TIME); - /* Get the global CDS context. */ p_cds_context = cds_get_global_context(); if (!p_cds_context) { @@ -1459,7 +1392,7 @@ QDF_STATUS hdd_wlan_re_init(void) ret = hdd_wlan_start_modules(pHddCtx, pAdapter, true); if (ret) { hdd_err("Failed to start wlan after error"); - goto err_wiphy_unregister; + goto err_re_init; } hdd_wlan_get_version(pHddCtx, NULL, NULL); @@ -1498,26 +1431,7 @@ QDF_STATUS hdd_wlan_re_init(void) err_cds_disable: hdd_wlan_stop_modules(pHddCtx, false); -err_wiphy_unregister: - if (bug_on_reinit_failure) - QDF_BUG(0); - - if (pHddCtx) { - /* Unregister the Notifier's */ - hdd_unregister_notifiers(pHddCtx); - ptt_sock_deactivate_svc(); - nl_srv_exit(); - - hdd_close_all_adapters(pHddCtx, false); - wlan_hdd_cfg80211_deinit(pHddCtx->wiphy); - hdd_lpass_notify_stop(pHddCtx); - wlan_hdd_deinit_tx_rx_histogram(pHddCtx); - wiphy_unregister(pHddCtx->wiphy); - - } - err_re_init: - hdd_ssr_timer_del(); /* Allow the phone to go to sleep */ hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); if (bug_on_reinit_failure) @@ -1527,7 +1441,7 @@ err_re_init: success: if (pHddCtx->config->sap_internal_restart) hdd_ssr_restart_sap(pHddCtx); - hdd_ssr_timer_del(); + hdd_wlan_ssr_reinit_event(); return QDF_STATUS_SUCCESS; } diff --git a/core/hdd/src/wlan_hdd_regulatory.c b/core/hdd/src/wlan_hdd_regulatory.c index daa6c7b34ad3..6749e1d239a2 100644 --- a/core/hdd/src/wlan_hdd_regulatory.c +++ b/core/hdd/src/wlan_hdd_regulatory.c @@ -696,7 +696,8 @@ void hdd_reg_notifier(struct wiphy *wiphy, return; } - if (cds_is_driver_unloading() || cds_is_driver_recovering()) { + if (cds_is_driver_unloading() || cds_is_driver_recovering() || + cds_is_driver_in_bad_state()) { hdd_err("%s: unloading or ssr in progress, ignore", __func__); return; diff --git a/core/hdd/src/wlan_hdd_scan.c b/core/hdd/src/wlan_hdd_scan.c index 7bffcaca03a3..aaeccef2da3f 100644 --- a/core/hdd/src/wlan_hdd_scan.c +++ b/core/hdd/src/wlan_hdd_scan.c @@ -1958,7 +1958,7 @@ static int __wlan_hdd_cfg80211_sched_scan_stop(struct net_device *dev) * clean up of the second interface will have the dev pointer corresponding * to the first one leading to a crash. */ - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { hdd_info("Recovery in Progress. State: 0x%x Ignore!!!", cds_get_driver_state()); return 0; diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c index b6d36d2868fd..191a22cf6df3 100644 --- a/core/hdd/src/wlan_hdd_softap_tx_rx.c +++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -262,7 +262,7 @@ static int __hdd_softap_hard_start_xmit(struct sk_buff *skb, * context may not be reinitialized at this time which may * lead to a crash. */ - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH, "%s: Recovery in Progress. Ignore!!!", __func__); goto drop_pkt; @@ -526,7 +526,7 @@ static void __hdd_softap_tx_timeout(struct net_device *dev) * recovery here */ hdd_ctx = WLAN_HDD_GET_CTX(adapter); - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, "%s: Recovery in Progress. Ignore!!!", __func__); return; diff --git a/core/hdd/src/wlan_hdd_tdls.c b/core/hdd/src/wlan_hdd_tdls.c index 07ab30367059..2f4b092f4988 100644 --- a/core/hdd/src/wlan_hdd_tdls.c +++ b/core/hdd/src/wlan_hdd_tdls.c @@ -4408,7 +4408,8 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, !rc ? "Mgmt Tx Completion timed out" : "Mgmt Tx Completion failed", rc, pAdapter->mgmtTxCompletionStatus); - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || + cds_is_driver_in_bad_state()) { hdd_err("Recovery in Progress. State: 0x%x Ignore!!!", cds_get_driver_state()); return -EAGAIN; diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index d53290c85336..a7bb5ca36349 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -538,7 +538,7 @@ static int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) #endif ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled; - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, "Recovery in progress, dropping the packet"); goto drop_pkt; diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index 2a67e2fa60e2..dcd5c67a5b3f 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -3547,7 +3547,7 @@ QDF_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, int8_t *rssi_value) hdd_err("Invalid context, pAdapter"); return QDF_STATUS_E_FAULT; } - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { hdd_err("Recovery in Progress. State: 0x%x Ignore!!!", cds_get_driver_state()); /* return a cached value */ @@ -6135,7 +6135,7 @@ QDF_STATUS wlan_hdd_get_class_astats(hdd_adapter_t *pAdapter) hdd_err("pAdapter is NULL"); return QDF_STATUS_E_FAULT; } - if (cds_is_driver_recovering()) { + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { hdd_debug("Recovery in Progress. State: 0x%x Ignore!!!", cds_get_driver_state()); return QDF_STATUS_SUCCESS; diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index c216be762354..56394a115ee6 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -3877,6 +3877,9 @@ static inline void wma_suspend_target_timeout(bool is_self_recovery_enabled) else if (cds_is_driver_recovering()) WMA_LOGE("%s: Module recovering; Ignoring suspend timeout", __func__); + else if (cds_is_driver_in_bad_state()) + WMA_LOGE("%s: Module in bad state; Ignoring suspend timeout", + __func__); else if (is_self_recovery_enabled) cds_trigger_recovery(false); else diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index 9eec633b9d66..bf343597fe83 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -3490,6 +3490,17 @@ int wma_form_rx_packet(qdf_nbuf_t buf, return -EINVAL; } + if (cds_is_driver_in_bad_state()) { + limit_prints_recovery++; + if (limit_prints_recovery == RATE_LIMIT) { + WMA_LOGD(FL("Driver in bad state")); + limit_prints_recovery = 0; + } + qdf_nbuf_free(buf); + qdf_mem_free(rx_pkt); + return -EINVAL; + } + /* * Fill in meta information needed by pe/lim * TODO: Try to maintain rx metainfo as part of skb->data.