qcacld-3.0: Avoid recovery trigger while recovering

Currently, cds_trigger_recovery is unconditional. Instead, avoid
triggering recovery if recovery is already in progress.

Change-Id: I5c77048701930591e0e520e07275e6f8631108a0
CRs-Fixed: 2070845
This commit is contained in:
Dustin Brown
2017-07-10 11:48:40 -07:00
committed by Anjaneedevi Kapparapu
parent f7ffe94567
commit 100201ecca
9 changed files with 123 additions and 137 deletions

View File

@@ -345,13 +345,7 @@ bool cds_is_packet_log_enabled(void);
uint64_t cds_get_monotonic_boottime(void);
/**
* cds_trigger_recovery_wrapper() - a temp wrapper to trigger self recovery
*
* Return: none
*/
void cds_trigger_recovery_wrapper(void);
void cds_trigger_recovery(bool);
void cds_trigger_recovery(void);
void cds_set_wakelock_logging(bool value);
bool cds_is_wakelock_enabled(void);

View File

@@ -138,7 +138,7 @@ v_CONTEXT_t cds_init(void)
qdf_lock_stats_init();
qdf_mem_init();
qdf_mc_timer_manager_init();
qdf_register_self_recovery_callback(cds_trigger_recovery_wrapper);
qdf_register_self_recovery_callback(cds_trigger_recovery);
gp_cds_context = &g_cds_context;
@@ -1713,97 +1713,134 @@ bool cds_is_packet_log_enabled(void)
return pHddCtx->config->enablePacketLog;
}
/**
* cds_config_recovery_work() - configure self recovery
* @qdf_ctx: pointer of qdf context
*
* Return: none
*/
static void cds_config_recovery_work(qdf_device_t qdf_ctx)
static int cds_force_assert_target_via_pld(qdf_device_t qdf)
{
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 {
cds_set_recovery_in_progress(true);
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
"schedule recovery work!");
pld_schedule_recovery_work(qdf_ctx->dev,
PLD_REASON_DEFAULT);
}
int errno;
errno = pld_force_assert_target(qdf->dev);
if (errno == -EOPNOTSUPP)
cds_info("PLD does not support target force assert");
else if (errno)
cds_err("Failed PLD target force assert; errno %d", errno);
else
cds_info("Target force assert triggered via PLD");
return errno;
}
void cds_trigger_recovery_wrapper(void)
static QDF_STATUS cds_force_assert_target_via_wmi(qdf_device_t qdf)
{
cds_trigger_recovery(false);
QDF_STATUS status;
t_wma_handle *wma;
wma = cds_get_context(QDF_MODULE_ID_WMA);
if (!wma) {
cds_err("wma is null");
return QDF_STATUS_E_INVAL;
}
status = wma_crash_inject(wma, RECOVERY_SIM_SELF_RECOVERY, 0);
if (QDF_IS_STATUS_ERROR(status)) {
cds_err("Failed target force assert; status %d", status);
return status;
}
status = qdf_wait_single_event(&wma->recovery_event,
WMA_CRASH_INJECT_TIMEOUT);
if (QDF_IS_STATUS_ERROR(status)) {
cds_err("Failed target force assert wait; status %d", status);
return status;
}
return QDF_STATUS_SUCCESS;
}
/**
* cds_force_assert_target() - Send assert command to firmware
* @qdf: QDF device instance to assert
*
* An out-of-band recovery mechanism will cleanup and restart the entire wlan
* subsystem in the event of a firmware crash. This API injects a firmware
* crash to start this process when the wlan driver is known to be in a bad
* state. If a firmware assert inject fails, the wlan driver will schedule
* the driver recovery anyway, as a best effort attempt to return to a working
* state.
*
* Return: QDF_STATUS
*/
static QDF_STATUS cds_force_assert_target(qdf_device_t qdf)
{
int errno;
QDF_STATUS status;
/* first, try target assert inject via pld */
errno = cds_force_assert_target_via_pld(qdf);
if (!errno)
return QDF_STATUS_SUCCESS;
if (errno != -EOPNOTSUPP)
return QDF_STATUS_E_FAILURE;
/* pld assert is not supported, try target assert inject via wmi */
status = cds_force_assert_target_via_wmi(qdf);
if (QDF_IS_STATUS_SUCCESS(status))
return QDF_STATUS_SUCCESS;
/* wmi assert failed, start recovery without the firmware assert */
cds_err("Scheduling recovery work without firmware assert");
cds_set_recovery_in_progress(true);
pld_schedule_recovery_work(qdf->dev, PLD_REASON_DEFAULT);
return status;
}
/**
* cds_trigger_recovery() - trigger self recovery
* @skip_crash_inject: Boolean value to skip to send crash inject cmd
*
* Return: none
*/
void cds_trigger_recovery(bool skip_crash_inject)
void cds_trigger_recovery(void)
{
tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
QDF_STATUS status = QDF_STATUS_SUCCESS;
qdf_runtime_lock_t recovery_lock;
qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
QDF_STATUS status;
qdf_runtime_lock_t rtl;
qdf_device_t qdf;
if (!wma_handle) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
"WMA context is invalid!");
return;
}
if (!qdf_ctx) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
"QDF context is invalid!");
if (!cds_is_self_recovery_enabled()) {
cds_err("Recovery is not enabled");
QDF_BUG(0);
return;
}
status = qdf_runtime_lock_init(&recovery_lock);
if (QDF_STATUS_SUCCESS != status) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
"Could not acquire runtime pm lock: %d!", status);
if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
cds_err("Recovery in progress; ignoring recovery trigger");
return;
}
qdf_runtime_pm_prevent_suspend(&recovery_lock);
/*
* If force assert thru platform is available, trigger that interface.
* That should generate recovery by going thru the normal FW
* assert recovery model.
*/
if (!pld_force_assert_target(qdf_ctx->dev)) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
"Force assert triggered");
goto out;
qdf = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
if (!qdf) {
cds_err("Qdf context is null");
return;
}
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
"Force assert not available at platform");
if (!skip_crash_inject) {
wma_crash_inject(wma_handle, RECOVERY_SIM_SELF_RECOVERY, 0);
status = qdf_wait_single_event(&wma_handle->recovery_event,
WMA_CRASH_INJECT_TIMEOUT);
if (QDF_STATUS_SUCCESS != status) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
"CRASH_INJECT command is timed out!");
cds_config_recovery_work(qdf_ctx);
}
} else {
cds_config_recovery_work(qdf_ctx);
status = qdf_runtime_lock_init(&rtl);
if (QDF_IS_STATUS_ERROR(status)) {
cds_err("Failed to initialize runtime pm lock");
return;
}
out:
qdf_runtime_pm_allow_suspend(&recovery_lock);
qdf_runtime_lock_deinit(&recovery_lock);
status = qdf_runtime_pm_prevent_suspend(&rtl);
if (QDF_IS_STATUS_ERROR(status)) {
cds_err("Failed to acquire runtime pm lock");
goto deinit_rtl;
}
cds_force_assert_target(qdf);
status = qdf_runtime_pm_allow_suspend(&rtl);
if (QDF_IS_STATUS_ERROR(status))
cds_err("Failed to release runtime pm lock");
deinit_rtl:
qdf_runtime_lock_deinit(&rtl);
}
/**

View File

@@ -2504,21 +2504,11 @@ ol_txrx_peer_attach(struct cdp_vdev *pvdev, uint8_t *peer_mac_addr)
rc = qdf_wait_single_event(&vdev->wait_delete_comp,
PEER_DELETION_TIMEOUT);
if (QDF_STATUS_SUCCESS != rc) {
ol_txrx_err(
"error waiting for peer(%d) deletion, status %d\n",
vdev->wait_on_peer_id, (int) rc);
if (cds_is_self_recovery_enabled())
cds_trigger_recovery(false);
else
/*
* Add equivalent of following line when it
* becomes available.
* wma_peer_debug_dump();
*/
QDF_ASSERT(0);
ol_txrx_err("error waiting for peer(%d) deletion, status %d\n",
vdev->wait_on_peer_id, (int) rc);
cds_trigger_recovery();
vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID;
return NULL;
}
}
@@ -3407,19 +3397,7 @@ static QDF_STATUS ol_txrx_clear_peer(struct cdp_pdev *ppdev, uint8_t sta_id)
void peer_unmap_timer_work_function(void *param)
{
WMA_LOGE("Enter: %s", __func__);
/*
* wma_peer_debug_dump() will be replaced with a new routine.
* Add the equivalent of wma_peer_debug_dump() when available.
*/
if (cds_is_self_recovery_enabled()) {
if (!cds_is_driver_recovering())
cds_trigger_recovery(false);
else
WMA_LOGE("%s: Recovery is in progress, ignore!",
__func__);
} else {
QDF_BUG(0);
}
cds_trigger_recovery();
}
/**

View File

@@ -2645,7 +2645,7 @@ static int __iw_softap_set_two_ints_getnone(struct net_device *dev,
hdd_err("WE_SET_FW_CRASH_INJECT: %d %d",
value[1], value[2]);
if (value[1] == 3) {
cds_trigger_recovery(false);
cds_trigger_recovery();
return 0;
}
ret = wma_cli_set2_command(adapter->sessionId,

View File

@@ -144,11 +144,8 @@ static void hdd_scan_inactivity_timer_handler(void *scan_req)
else if (cds_is_driver_in_bad_state())
hdd_err("%s: Module in bad state; Ignore hdd scan req timeout",
__func__);
else if (cds_is_self_recovery_enabled())
cds_trigger_recovery(false);
else
QDF_BUG(0);
cds_trigger_recovery();
}
/**
@@ -919,13 +916,9 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy,
WLAN_LOG_REASON_SCAN_NOT_ALLOWED,
false,
pHddCtx->config->enableSelfRecovery);
} else if (pHddCtx->config->
enableSelfRecovery) {
hdd_err("Triggering SSR due to scan stuck");
cds_trigger_recovery(false);
} else {
hdd_err("QDF_BUG due to scan stuck");
QDF_BUG(0);
hdd_err("Triggering SSR due to scan stuck");
cds_trigger_recovery();
}
}
}

View File

@@ -12821,7 +12821,7 @@ static int __iw_set_two_ints_getnone(struct net_device *dev,
pr_err("SSR is triggered by iwpriv CRASH_INJECT: %d %d\n",
value[1], value[2]);
if (value[1] == 3) {
cds_trigger_recovery(false);
cds_trigger_recovery();
return 0;
}
ret = wma_cli_set2_command(pAdapter->sessionId,

View File

@@ -1538,25 +1538,19 @@ int pld_is_qmi_disable(struct device *dev)
*/
int pld_force_assert_target(struct device *dev)
{
int ret = 0;
enum pld_bus_type type = pld_get_bus_type(dev);
switch (type) {
case PLD_BUS_TYPE_SNOC:
ret = pld_snoc_force_assert_target(dev);
break;
return pld_snoc_force_assert_target(dev);
case PLD_BUS_TYPE_PCIE:
ret = pld_pcie_force_assert_target(dev);
break;
return pld_pcie_force_assert_target(dev);
case PLD_BUS_TYPE_SDIO:
ret = -EINVAL;
break;
return -EINVAL;
default:
pr_err("Invalid device type %d\n", type);
ret = -EINVAL;
break;
return -EINVAL;
}
return ret;
}
/**

View File

@@ -507,10 +507,8 @@ tSmeCmd *sme_get_command_buffer(tpAniSirGlobal pMac)
WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF,
false,
pMac->sme.enableSelfRecovery ? true : false);
else if (pMac->sme.enableSelfRecovery)
cds_trigger_recovery(false);
else
QDF_BUG(0);
cds_trigger_recovery();
}
/* memset to zero */

View File

@@ -3903,16 +3903,8 @@ static inline void wma_suspend_target_timeout(bool is_self_recovery_enabled)
if (cds_is_load_or_unload_in_progress())
WMA_LOGE("%s: Module (un)loading; Ignoring suspend timeout",
__func__);
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
QDF_BUG(0);
cds_trigger_recovery();
}
#ifdef FEATURE_WLAN_TDLS