diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 97 |
1 files changed, 66 insertions, 31 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 7aef285d2818..b6a64d83718a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -621,24 +621,18 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, #define BA_TIMEOUT_CNT (5) #define BA_TIMEOUT_MAX (16) -#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n" -/* - * This function checks for plcp error, ACK count ratios, aggregated BA - * timeout retries. - * - When the ACK count ratio is 0 and aggregated BA timeout retries is - * exceeding the BA_TIMEOUT_MAX, it will recover the failure by resetting - * the firmware. - * - When the plcp error is exceeding the thresholds, it will reset the radio - * to improve the throughput. +/** + * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries. + * + * When the ACK count ratio is 0 and aggregated BA timeout retries exceeding + * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal + * operation state. */ -void iwl_recover_from_statistics(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) +bool iwl_good_ack_health(struct iwl_priv *priv, + struct iwl_rx_packet *pkt) { - int combined_plcp_delta; - unsigned int plcp_msec; - unsigned long plcp_received_jiffies; - int actual_ack_cnt_delta; - int expected_ack_cnt_delta; + bool rc = true; + int actual_ack_cnt_delta, expected_ack_cnt_delta; int ba_timeout_delta; actual_ack_cnt_delta = @@ -669,13 +663,27 @@ void iwl_recover_from_statistics(struct iwl_priv *priv, #endif IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n", ba_timeout_delta); - if ((actual_ack_cnt_delta == 0) && - (ba_timeout_delta >= BA_TIMEOUT_MAX)) { - IWL_DEBUG_RADIO(priv, - "call iwl_force_reset(IWL_FW_RESET)\n"); - iwl_force_reset(priv, IWL_FW_RESET); - } + if (!actual_ack_cnt_delta && + (ba_timeout_delta >= BA_TIMEOUT_MAX)) + rc = false; } + return rc; +} +EXPORT_SYMBOL(iwl_good_ack_health); + +/** + * iwl_good_plcp_health - checks for plcp error. + * + * When the plcp error is exceeding the thresholds, reset the radio + * to improve the throughput. + */ +bool iwl_good_plcp_health(struct iwl_priv *priv, + struct iwl_rx_packet *pkt) +{ + bool rc = true; + int combined_plcp_delta; + unsigned int plcp_msec; + unsigned long plcp_received_jiffies; /* * check for plcp_err and trigger radio reset if it exceeds @@ -710,7 +718,8 @@ void iwl_recover_from_statistics(struct iwl_priv *priv, * combined_plcp_delta, * plcp_msec */ - IWL_DEBUG_RADIO(priv, PLCP_MSG, + IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " + "%u, %u, %u, %u, %d, %u mSecs\n", priv->cfg->plcp_delta_threshold, le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err), le32_to_cpu(priv->statistics.rx.ofdm.plcp_err), @@ -718,15 +727,42 @@ void iwl_recover_from_statistics(struct iwl_priv *priv, le32_to_cpu( priv->statistics.rx.ofdm_ht.plcp_err), combined_plcp_delta, plcp_msec); - /* - * Reset the RF radio due to the high plcp - * error rate - */ - iwl_force_reset(priv, IWL_RF_RESET); + rc = false; + } + } + return rc; +} +EXPORT_SYMBOL(iwl_good_plcp_health); + +static void iwl_recover_from_statistics(struct iwl_priv *priv, + struct iwl_rx_packet *pkt) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + if (iwl_is_associated(priv)) { + if (priv->cfg->ops->lib->check_ack_health) { + if (!priv->cfg->ops->lib->check_ack_health( + priv, pkt)) { + /* + * low ack count detected + * restart Firmware + */ + IWL_ERR(priv, "low ack count detected, " + "restart firmware\n"); + iwl_force_reset(priv, IWL_FW_RESET); + } + } else if (priv->cfg->ops->lib->check_plcp_health) { + if (!priv->cfg->ops->lib->check_plcp_health( + priv, pkt)) { + /* + * high plcp error detected + * reset Radio + */ + iwl_force_reset(priv, IWL_RF_RESET); + } } } } -EXPORT_SYMBOL(iwl_recover_from_statistics); void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) @@ -748,8 +784,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); #endif - if (priv->cfg->ops->lib->recover_from_statistics) - priv->cfg->ops->lib->recover_from_statistics(priv, pkt); + iwl_recover_from_statistics(priv, pkt); memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); |