aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c97
6 files changed, 85 insertions, 40 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index c6d6a0c2cd3..9e392896005 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -213,7 +213,8 @@ static struct iwl_lib_ops iwl1000_lib = {
213 }, 213 },
214 .add_bcast_station = iwl_add_bcast_station, 214 .add_bcast_station = iwl_add_bcast_station,
215 .recover_from_tx_stall = iwl_bg_monitor_recover, 215 .recover_from_tx_stall = iwl_bg_monitor_recover,
216 .recover_from_statistics = iwl_recover_from_statistics, 216 .check_plcp_health = iwl_good_plcp_health,
217 .check_ack_health = iwl_good_ack_health,
217}; 218};
218 219
219static const struct iwl_ops iwl1000_ops = { 220static const struct iwl_ops iwl1000_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 5efd60a5b98..3949133d9ee 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2221,7 +2221,7 @@ static struct iwl_lib_ops iwl4965_lib = {
2221 .set_ct_kill = iwl4965_set_ct_threshold, 2221 .set_ct_kill = iwl4965_set_ct_threshold,
2222 }, 2222 },
2223 .add_bcast_station = iwl_add_bcast_station, 2223 .add_bcast_station = iwl_add_bcast_station,
2224 .recover_from_statistics = iwl_recover_from_statistics, 2224 .check_plcp_health = iwl_good_plcp_health,
2225}; 2225};
2226 2226
2227static const struct iwl_ops iwl4965_ops = { 2227static const struct iwl_ops iwl4965_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 75f2a5156be..2267cad49cb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1500,7 +1500,8 @@ struct iwl_lib_ops iwl5000_lib = {
1500 }, 1500 },
1501 .add_bcast_station = iwl_add_bcast_station, 1501 .add_bcast_station = iwl_add_bcast_station,
1502 .recover_from_tx_stall = iwl_bg_monitor_recover, 1502 .recover_from_tx_stall = iwl_bg_monitor_recover,
1503 .recover_from_statistics = iwl_recover_from_statistics, 1503 .check_plcp_health = iwl_good_plcp_health,
1504 .check_ack_health = iwl_good_ack_health,
1504}; 1505};
1505 1506
1506static struct iwl_lib_ops iwl5150_lib = { 1507static struct iwl_lib_ops iwl5150_lib = {
@@ -1556,7 +1557,8 @@ static struct iwl_lib_ops iwl5150_lib = {
1556 }, 1557 },
1557 .add_bcast_station = iwl_add_bcast_station, 1558 .add_bcast_station = iwl_add_bcast_station,
1558 .recover_from_tx_stall = iwl_bg_monitor_recover, 1559 .recover_from_tx_stall = iwl_bg_monitor_recover,
1559 .recover_from_statistics = iwl_recover_from_statistics, 1560 .check_plcp_health = iwl_good_plcp_health,
1561 .check_ack_health = iwl_good_ack_health,
1560}; 1562};
1561 1563
1562static const struct iwl_ops iwl5000_ops = { 1564static const struct iwl_ops iwl5000_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index b1f0e5c7e28..d75799946a7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -279,7 +279,8 @@ static struct iwl_lib_ops iwl6000_lib = {
279 }, 279 },
280 .add_bcast_station = iwl_add_bcast_station, 280 .add_bcast_station = iwl_add_bcast_station,
281 .recover_from_tx_stall = iwl_bg_monitor_recover, 281 .recover_from_tx_stall = iwl_bg_monitor_recover,
282 .recover_from_statistics = iwl_recover_from_statistics, 282 .check_plcp_health = iwl_good_plcp_health,
283 .check_ack_health = iwl_good_ack_health,
283}; 284};
284 285
285static const struct iwl_ops iwl6000_ops = { 286static const struct iwl_ops iwl6000_ops = {
@@ -346,7 +347,8 @@ static struct iwl_lib_ops iwl6050_lib = {
346 }, 347 },
347 .add_bcast_station = iwl_add_bcast_station, 348 .add_bcast_station = iwl_add_bcast_station,
348 .recover_from_tx_stall = iwl_bg_monitor_recover, 349 .recover_from_tx_stall = iwl_bg_monitor_recover,
349 .recover_from_statistics = iwl_recover_from_statistics, 350 .check_plcp_health = iwl_good_plcp_health,
351 .check_ack_health = iwl_good_ack_health,
350}; 352};
351 353
352static const struct iwl_ops iwl6050_ops = { 354static const struct iwl_ops iwl6050_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 4251afb8bf5..b3e698b576e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -193,8 +193,11 @@ struct iwl_lib_ops {
193 void (*add_bcast_station)(struct iwl_priv *priv); 193 void (*add_bcast_station)(struct iwl_priv *priv);
194 /* recover from tx queue stall */ 194 /* recover from tx queue stall */
195 void (*recover_from_tx_stall)(unsigned long data); 195 void (*recover_from_tx_stall)(unsigned long data);
196 /* recover from errors showed in statistics */ 196 /* check for plcp health */
197 void (*recover_from_statistics)(struct iwl_priv *priv, 197 bool (*check_plcp_health)(struct iwl_priv *priv,
198 struct iwl_rx_packet *pkt);
199 /* check for ack health */
200 bool (*check_ack_health)(struct iwl_priv *priv,
198 struct iwl_rx_packet *pkt); 201 struct iwl_rx_packet *pkt);
199}; 202};
200 203
@@ -437,7 +440,9 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
437 struct iwl_rx_mem_buffer *rxb); 440 struct iwl_rx_mem_buffer *rxb);
438void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, 441void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
439 struct iwl_rx_mem_buffer *rxb); 442 struct iwl_rx_mem_buffer *rxb);
440void iwl_recover_from_statistics(struct iwl_priv *priv, 443bool iwl_good_plcp_health(struct iwl_priv *priv,
444 struct iwl_rx_packet *pkt);
445bool iwl_good_ack_health(struct iwl_priv *priv,
441 struct iwl_rx_packet *pkt); 446 struct iwl_rx_packet *pkt);
442void iwl_rx_statistics(struct iwl_priv *priv, 447void iwl_rx_statistics(struct iwl_priv *priv,
443 struct iwl_rx_mem_buffer *rxb); 448 struct iwl_rx_mem_buffer *rxb);
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 7aef285d281..b6a64d83718 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,
621#define BA_TIMEOUT_CNT (5) 621#define BA_TIMEOUT_CNT (5)
622#define BA_TIMEOUT_MAX (16) 622#define BA_TIMEOUT_MAX (16)
623 623
624#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n" 624/**
625/* 625 * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries.
626 * This function checks for plcp error, ACK count ratios, aggregated BA 626 *
627 * timeout retries. 627 * When the ACK count ratio is 0 and aggregated BA timeout retries exceeding
628 * - When the ACK count ratio is 0 and aggregated BA timeout retries is 628 * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
629 * exceeding the BA_TIMEOUT_MAX, it will recover the failure by resetting 629 * operation state.
630 * the firmware.
631 * - When the plcp error is exceeding the thresholds, it will reset the radio
632 * to improve the throughput.
633 */ 630 */
634void iwl_recover_from_statistics(struct iwl_priv *priv, 631bool iwl_good_ack_health(struct iwl_priv *priv,
635 struct iwl_rx_packet *pkt) 632 struct iwl_rx_packet *pkt)
636{ 633{
637 int combined_plcp_delta; 634 bool rc = true;
638 unsigned int plcp_msec; 635 int actual_ack_cnt_delta, expected_ack_cnt_delta;
639 unsigned long plcp_received_jiffies;
640 int actual_ack_cnt_delta;
641 int expected_ack_cnt_delta;
642 int ba_timeout_delta; 636 int ba_timeout_delta;
643 637
644 actual_ack_cnt_delta = 638 actual_ack_cnt_delta =
@@ -669,13 +663,27 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
669#endif 663#endif
670 IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n", 664 IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
671 ba_timeout_delta); 665 ba_timeout_delta);
672 if ((actual_ack_cnt_delta == 0) && 666 if (!actual_ack_cnt_delta &&
673 (ba_timeout_delta >= BA_TIMEOUT_MAX)) { 667 (ba_timeout_delta >= BA_TIMEOUT_MAX))
674 IWL_DEBUG_RADIO(priv, 668 rc = false;
675 "call iwl_force_reset(IWL_FW_RESET)\n");
676 iwl_force_reset(priv, IWL_FW_RESET);
677 }
678 } 669 }
670 return rc;
671}
672EXPORT_SYMBOL(iwl_good_ack_health);
673
674/**
675 * iwl_good_plcp_health - checks for plcp error.
676 *
677 * When the plcp error is exceeding the thresholds, reset the radio
678 * to improve the throughput.
679 */
680bool iwl_good_plcp_health(struct iwl_priv *priv,
681 struct iwl_rx_packet *pkt)
682{
683 bool rc = true;
684 int combined_plcp_delta;
685 unsigned int plcp_msec;
686 unsigned long plcp_received_jiffies;
679 687
680 /* 688 /*
681 * check for plcp_err and trigger radio reset if it exceeds 689 * check for plcp_err and trigger radio reset if it exceeds
@@ -710,7 +718,8 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
710 * combined_plcp_delta, 718 * combined_plcp_delta,
711 * plcp_msec 719 * plcp_msec
712 */ 720 */
713 IWL_DEBUG_RADIO(priv, PLCP_MSG, 721 IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
722 "%u, %u, %u, %u, %d, %u mSecs\n",
714 priv->cfg->plcp_delta_threshold, 723 priv->cfg->plcp_delta_threshold,
715 le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err), 724 le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
716 le32_to_cpu(priv->statistics.rx.ofdm.plcp_err), 725 le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
@@ -718,15 +727,42 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
718 le32_to_cpu( 727 le32_to_cpu(
719 priv->statistics.rx.ofdm_ht.plcp_err), 728 priv->statistics.rx.ofdm_ht.plcp_err),
720 combined_plcp_delta, plcp_msec); 729 combined_plcp_delta, plcp_msec);
721 /* 730 rc = false;
722 * Reset the RF radio due to the high plcp 731 }
723 * error rate 732 }
724 */ 733 return rc;
725 iwl_force_reset(priv, IWL_RF_RESET); 734}
735EXPORT_SYMBOL(iwl_good_plcp_health);
736
737static void iwl_recover_from_statistics(struct iwl_priv *priv,
738 struct iwl_rx_packet *pkt)
739{
740 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
741 return;
742 if (iwl_is_associated(priv)) {
743 if (priv->cfg->ops->lib->check_ack_health) {
744 if (!priv->cfg->ops->lib->check_ack_health(
745 priv, pkt)) {
746 /*
747 * low ack count detected
748 * restart Firmware
749 */
750 IWL_ERR(priv, "low ack count detected, "
751 "restart firmware\n");
752 iwl_force_reset(priv, IWL_FW_RESET);
753 }
754 } else if (priv->cfg->ops->lib->check_plcp_health) {
755 if (!priv->cfg->ops->lib->check_plcp_health(
756 priv, pkt)) {
757 /*
758 * high plcp error detected
759 * reset Radio
760 */
761 iwl_force_reset(priv, IWL_RF_RESET);
762 }
726 } 763 }
727 } 764 }
728} 765}
729EXPORT_SYMBOL(iwl_recover_from_statistics);
730 766
731void iwl_rx_statistics(struct iwl_priv *priv, 767void iwl_rx_statistics(struct iwl_priv *priv,
732 struct iwl_rx_mem_buffer *rxb) 768 struct iwl_rx_mem_buffer *rxb)
@@ -748,8 +784,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
748#ifdef CONFIG_IWLWIFI_DEBUG 784#ifdef CONFIG_IWLWIFI_DEBUG
749 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); 785 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
750#endif 786#endif
751 if (priv->cfg->ops->lib->recover_from_statistics) 787 iwl_recover_from_statistics(priv, pkt);
752 priv->cfg->ops->lib->recover_from_statistics(priv, pkt);
753 788
754 memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); 789 memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
755 790