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
This commit is contained in:
Hanumanth Reddy Pothula 2017-07-03 14:06:11 +05:30 • committed by snandini
commit 2a8a740a4d
15 changed files with 98 additions and 113 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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));
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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.