aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-rx.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-03-29 16:50:10 -0400
committerDavid S. Miller <davem@davemloft.net>2010-03-29 16:50:10 -0400
commit7905e357ebe67a26d9dc8caa1a0b8346431b5f0d (patch)
tree134442df2f062caa6cebda1b352948b8209efcec /drivers/net/wireless/iwlwifi/iwl-rx.c
parent083ba279d52bcad20f1dfa3cefd4255cbe82d521 (diff)
parent76232ebf898c4d5e657f2b663fbf7108bca80ded (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c155
1 files changed, 127 insertions, 28 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 8116aa0d767..2fa30dfb7c5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -616,29 +616,77 @@ 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#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n" 619/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
620void iwl_rx_statistics(struct iwl_priv *priv, 620#define ACK_CNT_RATIO (50)
621 struct iwl_rx_mem_buffer *rxb) 621#define BA_TIMEOUT_CNT (5)
622#define BA_TIMEOUT_MAX (16)
623
624#if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE)
625/**
626 * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries.
627 *
628 * When the ACK count ratio is 0 and aggregated BA timeout retries exceeding
629 * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
630 * operation state.
631 */
632bool iwl_good_ack_health(struct iwl_priv *priv,
633 struct iwl_rx_packet *pkt)
622{ 634{
623 int change; 635 bool rc = true;
624 struct iwl_rx_packet *pkt = rxb_addr(rxb); 636 int actual_ack_cnt_delta, expected_ack_cnt_delta;
637 int ba_timeout_delta;
638
639 actual_ack_cnt_delta =
640 le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
641 le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
642 expected_ack_cnt_delta =
643 le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) -
644 le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
645 ba_timeout_delta =
646 le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) -
647 le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
648 if ((priv->_agn.agg_tids_count > 0) &&
649 (expected_ack_cnt_delta > 0) &&
650 (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta)
651 < ACK_CNT_RATIO) &&
652 (ba_timeout_delta > BA_TIMEOUT_CNT)) {
653 IWL_DEBUG_RADIO(priv, "actual_ack_cnt delta = %d,"
654 " expected_ack_cnt = %d\n",
655 actual_ack_cnt_delta, expected_ack_cnt_delta);
656
657#ifdef CONFIG_IWLWIFI_DEBUG
658 IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
659 priv->delta_statistics.tx.rx_detected_cnt);
660 IWL_DEBUG_RADIO(priv,
661 "ack_or_ba_timeout_collision delta = %d\n",
662 priv->delta_statistics.tx.
663 ack_or_ba_timeout_collision);
664#endif
665 IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
666 ba_timeout_delta);
667 if (!actual_ack_cnt_delta &&
668 (ba_timeout_delta >= BA_TIMEOUT_MAX))
669 rc = false;
670 }
671 return rc;
672}
673EXPORT_SYMBOL(iwl_good_ack_health);
674#endif
675
676/**
677 * iwl_good_plcp_health - checks for plcp error.
678 *
679 * When the plcp error is exceeding the thresholds, reset the radio
680 * to improve the throughput.
681 */
682bool iwl_good_plcp_health(struct iwl_priv *priv,
683 struct iwl_rx_packet *pkt)
684{
685 bool rc = true;
625 int combined_plcp_delta; 686 int combined_plcp_delta;
626 unsigned int plcp_msec; 687 unsigned int plcp_msec;
627 unsigned long plcp_received_jiffies; 688 unsigned long plcp_received_jiffies;
628 689
629 IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
630 (int)sizeof(priv->statistics),
631 le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
632
633 change = ((priv->statistics.general.temperature !=
634 pkt->u.stats.general.temperature) ||
635 ((priv->statistics.flag &
636 STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
637 (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
638
639#ifdef CONFIG_IWLWIFI_DEBUG
640 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
641#endif
642 /* 690 /*
643 * check for plcp_err and trigger radio reset if it exceeds 691 * check for plcp_err and trigger radio reset if it exceeds
644 * the plcp error threshold plcp_delta. 692 * the plcp error threshold plcp_delta.
@@ -659,11 +707,11 @@ void iwl_rx_statistics(struct iwl_priv *priv,
659 le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err)); 707 le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));
660 708
661 if ((combined_plcp_delta > 0) && 709 if ((combined_plcp_delta > 0) &&
662 ((combined_plcp_delta * 100) / plcp_msec) > 710 ((combined_plcp_delta * 100) / plcp_msec) >
663 priv->cfg->plcp_delta_threshold) { 711 priv->cfg->plcp_delta_threshold) {
664 /* 712 /*
665 * if plcp_err exceed the threshold, the following 713 * if plcp_err exceed the threshold,
666 * data is printed in csv format: 714 * the following data is printed in csv format:
667 * Text: plcp_err exceeded %d, 715 * Text: plcp_err exceeded %d,
668 * Received ofdm.plcp_err, 716 * Received ofdm.plcp_err,
669 * Current ofdm.plcp_err, 717 * Current ofdm.plcp_err,
@@ -672,22 +720,73 @@ void iwl_rx_statistics(struct iwl_priv *priv,
672 * combined_plcp_delta, 720 * combined_plcp_delta,
673 * plcp_msec 721 * plcp_msec
674 */ 722 */
675 IWL_DEBUG_RADIO(priv, PLCP_MSG, 723 IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
724 "%u, %u, %u, %u, %d, %u mSecs\n",
676 priv->cfg->plcp_delta_threshold, 725 priv->cfg->plcp_delta_threshold,
677 le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err), 726 le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
678 le32_to_cpu(priv->statistics.rx.ofdm.plcp_err), 727 le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
679 le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err), 728 le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
680 le32_to_cpu( 729 le32_to_cpu(
681 priv->statistics.rx.ofdm_ht.plcp_err), 730 priv->statistics.rx.ofdm_ht.plcp_err),
682 combined_plcp_delta, plcp_msec); 731 combined_plcp_delta, plcp_msec);
732 rc = false;
733 }
734 }
735 return rc;
736}
737EXPORT_SYMBOL(iwl_good_plcp_health);
683 738
684 /* 739static void iwl_recover_from_statistics(struct iwl_priv *priv,
685 * Reset the RF radio due to the high plcp 740 struct iwl_rx_packet *pkt)
686 * error rate 741{
687 */ 742 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
688 iwl_force_reset(priv, IWL_RF_RESET); 743 return;
744 if (iwl_is_associated(priv)) {
745 if (priv->cfg->ops->lib->check_ack_health) {
746 if (!priv->cfg->ops->lib->check_ack_health(
747 priv, pkt)) {
748 /*
749 * low ack count detected
750 * restart Firmware
751 */
752 IWL_ERR(priv, "low ack count detected, "
753 "restart firmware\n");
754 iwl_force_reset(priv, IWL_FW_RESET);
755 }
756 } else if (priv->cfg->ops->lib->check_plcp_health) {
757 if (!priv->cfg->ops->lib->check_plcp_health(
758 priv, pkt)) {
759 /*
760 * high plcp error detected
761 * reset Radio
762 */
763 iwl_force_reset(priv, IWL_RF_RESET);
764 }
689 } 765 }
690 } 766 }
767}
768
769void iwl_rx_statistics(struct iwl_priv *priv,
770 struct iwl_rx_mem_buffer *rxb)
771{
772 int change;
773 struct iwl_rx_packet *pkt = rxb_addr(rxb);
774
775
776 IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
777 (int)sizeof(priv->statistics),
778 le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
779
780 change = ((priv->statistics.general.temperature !=
781 pkt->u.stats.general.temperature) ||
782 ((priv->statistics.flag &
783 STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
784 (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
785
786#ifdef CONFIG_IWLWIFI_DEBUG
787 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
788#endif
789 iwl_recover_from_statistics(priv, pkt);
691 790
692 memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); 791 memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
693 792