aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2010-03-04 16:38:59 -0500
committerReinette Chatre <reinette.chatre@intel.com>2010-03-19 16:41:26 -0400
commitd5a0ffa3eaf9e898f25a925813f1a723be7808f8 (patch)
tree37610c33a6802b6eac524cc2cd298705059cf18d /drivers/net/wireless
parentbeac5498b792ed8420885ee23e8d4f2885ee2d13 (diff)
iwlwifi: Recover TX flow failure
Monitors the tx statistics to detect the drop in throughput. When the throughput drops, the ratio of the actual_ack_count and the expected_ack_count also drops. At the same time, the aggregated ba_timeout (the number of ba timeout retries) also rises. If the actual_ack_count/expected_ack_count ratio is 0 and the number of ba timeout retries rises to BA_TIMEOUT_MAX, no tx packets can be delivered. Reloading the uCode and bring the system back to normal operational state. Signed-off-by: Trieu 'Andrew' Nguyen <trieux.t.nguyen@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c50
3 files changed, 67 insertions, 2 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 82b1a3fb54ef..e69e6256a41b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2916,10 +2916,21 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
2916 return ret; 2916 return ret;
2917 case IEEE80211_AMPDU_TX_START: 2917 case IEEE80211_AMPDU_TX_START:
2918 IWL_DEBUG_HT(priv, "start Tx\n"); 2918 IWL_DEBUG_HT(priv, "start Tx\n");
2919 return iwl_tx_agg_start(priv, sta->addr, tid, ssn); 2919 ret = iwl_tx_agg_start(priv, sta->addr, tid, ssn);
2920 if (ret == 0) {
2921 priv->_agn.agg_tids_count++;
2922 IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
2923 priv->_agn.agg_tids_count);
2924 }
2925 return ret;
2920 case IEEE80211_AMPDU_TX_STOP: 2926 case IEEE80211_AMPDU_TX_STOP:
2921 IWL_DEBUG_HT(priv, "stop Tx\n"); 2927 IWL_DEBUG_HT(priv, "stop Tx\n");
2922 ret = iwl_tx_agg_stop(priv, sta->addr, tid); 2928 ret = iwl_tx_agg_stop(priv, sta->addr, tid);
2929 if ((ret == 0) && (priv->_agn.agg_tids_count > 0)) {
2930 priv->_agn.agg_tids_count--;
2931 IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
2932 priv->_agn.agg_tids_count);
2933 }
2923 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 2934 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
2924 return 0; 2935 return 0;
2925 else 2936 else
@@ -3303,6 +3314,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
3303 priv->iw_mode = NL80211_IFTYPE_STATION; 3314 priv->iw_mode = NL80211_IFTYPE_STATION;
3304 priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; 3315 priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
3305 priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; 3316 priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
3317 priv->_agn.agg_tids_count = 0;
3306 3318
3307 /* initialize force reset */ 3319 /* initialize force reset */
3308 priv->force_reset[IWL_RF_RESET].reset_duration = 3320 priv->force_reset[IWL_RF_RESET].reset_duration =
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index bb4cba508acf..e847e6197a3d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1300,6 +1300,11 @@ struct iwl_priv {
1300 int ict_index; 1300 int ict_index;
1301 u32 inta; 1301 u32 inta;
1302 bool use_ict; 1302 bool use_ict;
1303 /*
1304 * reporting the number of tids has AGG on. 0 means
1305 * no AGGREGATION
1306 */
1307 u8 agg_tids_count;
1303 } _agn; 1308 } _agn;
1304#endif 1309#endif
1305 }; 1310 };
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index d368b8df8d87..7aef285d2818 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -616,9 +616,18 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
616 616
617#define REG_RECALIB_PERIOD (60) 617#define REG_RECALIB_PERIOD (60)
618 618
619/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
620#define ACK_CNT_RATIO (50)
621#define BA_TIMEOUT_CNT (5)
622#define BA_TIMEOUT_MAX (16)
623
619#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n" 624#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n"
620/* 625/*
621 * This function checks for plcp error. 626 * This function checks for plcp error, ACK count ratios, aggregated BA
627 * timeout retries.
628 * - When the ACK count ratio is 0 and aggregated BA timeout retries is
629 * exceeding the BA_TIMEOUT_MAX, it will recover the failure by resetting
630 * the firmware.
622 * - When the plcp error is exceeding the thresholds, it will reset the radio 631 * - When the plcp error is exceeding the thresholds, it will reset the radio
623 * to improve the throughput. 632 * to improve the throughput.
624 */ 633 */
@@ -628,6 +637,45 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
628 int combined_plcp_delta; 637 int combined_plcp_delta;
629 unsigned int plcp_msec; 638 unsigned int plcp_msec;
630 unsigned long plcp_received_jiffies; 639 unsigned long plcp_received_jiffies;
640 int actual_ack_cnt_delta;
641 int expected_ack_cnt_delta;
642 int ba_timeout_delta;
643
644 actual_ack_cnt_delta =
645 le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
646 le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
647 expected_ack_cnt_delta =
648 le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) -
649 le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
650 ba_timeout_delta =
651 le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) -
652 le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
653 if ((priv->_agn.agg_tids_count > 0) &&
654 (expected_ack_cnt_delta > 0) &&
655 (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta)
656 < ACK_CNT_RATIO) &&
657 (ba_timeout_delta > BA_TIMEOUT_CNT)) {
658 IWL_DEBUG_RADIO(priv, "actual_ack_cnt delta = %d,"
659 " expected_ack_cnt = %d\n",
660 actual_ack_cnt_delta, expected_ack_cnt_delta);
661
662#ifdef CONFIG_IWLWIFI_DEBUG
663 IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
664 priv->delta_statistics.tx.rx_detected_cnt);
665 IWL_DEBUG_RADIO(priv,
666 "ack_or_ba_timeout_collision delta = %d\n",
667 priv->delta_statistics.tx.
668 ack_or_ba_timeout_collision);
669#endif
670 IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
671 ba_timeout_delta);
672 if ((actual_ack_cnt_delta == 0) &&
673 (ba_timeout_delta >= BA_TIMEOUT_MAX)) {
674 IWL_DEBUG_RADIO(priv,
675 "call iwl_force_reset(IWL_FW_RESET)\n");
676 iwl_force_reset(priv, IWL_FW_RESET);
677 }
678 }
631 679
632 /* 680 /*
633 * check for plcp_err and trigger radio reset if it exceeds 681 * check for plcp_err and trigger radio reset if it exceeds