aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTrieu 'Andrew' Nguyen <trieux.t.nguyen@intel.com>2010-02-10 13:27:34 -0500
committerReinette Chatre <reinette.chatre@intel.com>2010-02-11 13:27:41 -0500
commit1db5950f1d0b82e07371b211a48317b8972da063 (patch)
tree6fc4f38f2c8cfd3a212c5eb18e326dd5d409ca2c /drivers
parenta9e10fb9b1c6ad16e73cf2656951fce3a817611e (diff)
iwlwifi: Monitor and recover the aggregation TX flow failure
This change 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 16, no tx packets (tcp, udp, or ping - icmp) can be delivered. The driver recovers from this situation by reseting the uCode firmware. If the actual_ack_count/expected_ ack_count ratio drops below 50% (but not 0) and the aggregated ba_timeout retries just exceed 5 (but not 16), then the driver can reset the radio to bring the throughput up. Signed-off-by: Trieu 'Andrew' Nguyen <trieux.t.nguyen@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c46
3 files changed, 62 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 31b156d58d7f..4157c6c8645f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2941,10 +2941,21 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
2941 return ret; 2941 return ret;
2942 case IEEE80211_AMPDU_TX_START: 2942 case IEEE80211_AMPDU_TX_START:
2943 IWL_DEBUG_HT(priv, "start Tx\n"); 2943 IWL_DEBUG_HT(priv, "start Tx\n");
2944 return iwl_tx_agg_start(priv, sta->addr, tid, ssn); 2944 ret = iwl_tx_agg_start(priv, sta->addr, tid, ssn);
2945 if (ret == 0) {
2946 priv->agg_tids_count++;
2947 IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
2948 priv->agg_tids_count);
2949 }
2950 return ret;
2945 case IEEE80211_AMPDU_TX_STOP: 2951 case IEEE80211_AMPDU_TX_STOP:
2946 IWL_DEBUG_HT(priv, "stop Tx\n"); 2952 IWL_DEBUG_HT(priv, "stop Tx\n");
2947 ret = iwl_tx_agg_stop(priv, sta->addr, tid); 2953 ret = iwl_tx_agg_stop(priv, sta->addr, tid);
2954 if ((ret == 0) && (priv->agg_tids_count > 0)) {
2955 priv->agg_tids_count--;
2956 IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
2957 priv->agg_tids_count);
2958 }
2948 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 2959 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
2949 return 0; 2960 return 0;
2950 else 2961 else
@@ -3364,6 +3375,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
3364 priv->iw_mode = NL80211_IFTYPE_STATION; 3375 priv->iw_mode = NL80211_IFTYPE_STATION;
3365 priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; 3376 priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
3366 priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; 3377 priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
3378 priv->agg_tids_count = 0;
3367 3379
3368 /* Choose which receivers/antennas to use */ 3380 /* Choose which receivers/antennas to use */
3369 if (priv->cfg->ops->hcmd->set_rxon_chain) 3381 if (priv->cfg->ops->hcmd->set_rxon_chain)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 71cf1558e640..f81317d478ee 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1072,6 +1072,9 @@ struct iwl_priv {
1072 /* storing the jiffies when the plcp error rate is received */ 1072 /* storing the jiffies when the plcp error rate is received */
1073 unsigned long plcp_jiffies; 1073 unsigned long plcp_jiffies;
1074 1074
1075 /* reporting the number of tids has AGG on. 0 means no AGGREGATION */
1076 u8 agg_tids_count;
1077
1075 /* force reset */ 1078 /* force reset */
1076 unsigned long last_force_reset_jiffies; 1079 unsigned long last_force_reset_jiffies;
1077 1080
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index aba8f4c20c1b..fed554accedc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -616,6 +616,11 @@ 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"
620void iwl_rx_statistics(struct iwl_priv *priv, 625void iwl_rx_statistics(struct iwl_priv *priv,
621 struct iwl_rx_mem_buffer *rxb) 626 struct iwl_rx_mem_buffer *rxb)
@@ -625,6 +630,9 @@ void iwl_rx_statistics(struct iwl_priv *priv,
625 int combined_plcp_delta; 630 int combined_plcp_delta;
626 unsigned int plcp_msec; 631 unsigned int plcp_msec;
627 unsigned long plcp_received_jiffies; 632 unsigned long plcp_received_jiffies;
633 int actual_ack_cnt_delta;
634 int expected_ack_cnt_delta;
635 int ba_timeout_delta;
628 636
629 IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", 637 IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
630 (int)sizeof(priv->statistics), 638 (int)sizeof(priv->statistics),
@@ -639,6 +647,44 @@ void iwl_rx_statistics(struct iwl_priv *priv,
639#ifdef CONFIG_IWLWIFI_DEBUG 647#ifdef CONFIG_IWLWIFI_DEBUG
640 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); 648 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
641#endif 649#endif
650 actual_ack_cnt_delta = le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
651 le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
652 expected_ack_cnt_delta = le32_to_cpu(
653 pkt->u.stats.tx.expected_ack_cnt) -
654 le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
655 ba_timeout_delta = le32_to_cpu(
656 pkt->u.stats.tx.agg.ba_timeout) -
657 le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
658 if ((priv->agg_tids_count > 0) &&
659 (expected_ack_cnt_delta > 0) &&
660 (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) <
661 ACK_CNT_RATIO) &&
662 (ba_timeout_delta > BA_TIMEOUT_CNT)) {
663 IWL_DEBUG_RADIO(priv,
664 "actual_ack_cnt delta = %d, expected_ack_cnt = %d\n",
665 actual_ack_cnt_delta, expected_ack_cnt_delta);
666
667#ifdef CONFIG_IWLWIFI_DEBUG
668 IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
669 priv->delta_statistics.tx.rx_detected_cnt);
670 IWL_DEBUG_RADIO(priv,
671 "ack_or_ba_timeout_collision delta = %d\n",
672 priv->delta_statistics.tx.ack_or_ba_timeout_collision);
673#endif
674 IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
675 ba_timeout_delta);
676 if ((actual_ack_cnt_delta == 0) &&
677 (ba_timeout_delta >=
678 BA_TIMEOUT_MAX)) {
679 IWL_DEBUG_RADIO(priv,
680 "call iwl_force_reset(IWL_FW_RESET)\n");
681 iwl_force_reset(priv, IWL_FW_RESET);
682 } else {
683 IWL_DEBUG_RADIO(priv,
684 "call iwl_force_reset(IWL_RF_RESET)\n");
685 iwl_force_reset(priv, IWL_RF_RESET);
686 }
687 }
642 /* 688 /*
643 * check for plcp_err and trigger radio reset if it exceeds 689 * check for plcp_err and trigger radio reset if it exceeds
644 * the plcp error threshold plcp_delta. 690 * the plcp error threshold plcp_delta.