diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 104 |
1 files changed, 94 insertions, 10 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 6f36b6e79f5e..5df66382d922 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | * | 2 | * |
3 | * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. |
4 | * | 4 | * |
5 | * Portions of this file are derived from the ipw3945 project, as well | 5 | * Portions of this file are derived from the ipw3945 project, as well |
6 | * as portions of the ieee80211 subsystem header files. | 6 | * as portions of the ieee80211 subsystem header files. |
@@ -473,8 +473,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) | |||
473 | (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| | 473 | (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| |
474 | (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); | 474 | (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); |
475 | 475 | ||
476 | /* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */ | 476 | /* Set interrupt coalescing timer to default (2048 usecs) */ |
477 | iwl_write8(priv, CSR_INT_COALESCING, 0x40); | 477 | iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); |
478 | 478 | ||
479 | return 0; | 479 | return 0; |
480 | } | 480 | } |
@@ -499,9 +499,10 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, | |||
499 | struct iwl_missed_beacon_notif *missed_beacon; | 499 | struct iwl_missed_beacon_notif *missed_beacon; |
500 | 500 | ||
501 | missed_beacon = &pkt->u.missed_beacon; | 501 | missed_beacon = &pkt->u.missed_beacon; |
502 | if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { | 502 | if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) > |
503 | priv->missed_beacon_threshold) { | ||
503 | IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n", | 504 | IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n", |
504 | le32_to_cpu(missed_beacon->consequtive_missed_beacons), | 505 | le32_to_cpu(missed_beacon->consecutive_missed_beacons), |
505 | le32_to_cpu(missed_beacon->total_missed_becons), | 506 | le32_to_cpu(missed_beacon->total_missed_becons), |
506 | le32_to_cpu(missed_beacon->num_recvd_beacons), | 507 | le32_to_cpu(missed_beacon->num_recvd_beacons), |
507 | le32_to_cpu(missed_beacon->num_expected_beacons)); | 508 | le32_to_cpu(missed_beacon->num_expected_beacons)); |
@@ -511,6 +512,24 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, | |||
511 | } | 512 | } |
512 | EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); | 513 | EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); |
513 | 514 | ||
515 | void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, | ||
516 | struct iwl_rx_mem_buffer *rxb) | ||
517 | { | ||
518 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
519 | struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); | ||
520 | |||
521 | if (!report->state) { | ||
522 | IWL_DEBUG_11H(priv, | ||
523 | "Spectrum Measure Notification: Start\n"); | ||
524 | return; | ||
525 | } | ||
526 | |||
527 | memcpy(&priv->measure_report, report, sizeof(*report)); | ||
528 | priv->measurement_status |= MEASUREMENT_READY; | ||
529 | } | ||
530 | EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif); | ||
531 | |||
532 | |||
514 | 533 | ||
515 | /* Calculate noise level, based on measurements during network silence just | 534 | /* Calculate noise level, based on measurements during network silence just |
516 | * before arriving beacon. This measurement can be done only if we know | 535 | * before arriving beacon. This measurement can be done only if we know |
@@ -564,15 +583,24 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, | |||
564 | int i; | 583 | int i; |
565 | __le32 *prev_stats; | 584 | __le32 *prev_stats; |
566 | u32 *accum_stats; | 585 | u32 *accum_stats; |
586 | u32 *delta, *max_delta; | ||
567 | 587 | ||
568 | prev_stats = (__le32 *)&priv->statistics; | 588 | prev_stats = (__le32 *)&priv->statistics; |
569 | accum_stats = (u32 *)&priv->accum_statistics; | 589 | accum_stats = (u32 *)&priv->accum_statistics; |
590 | delta = (u32 *)&priv->delta_statistics; | ||
591 | max_delta = (u32 *)&priv->max_delta; | ||
570 | 592 | ||
571 | for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics); | 593 | for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics); |
572 | i += sizeof(__le32), stats++, prev_stats++, accum_stats++) | 594 | i += sizeof(__le32), stats++, prev_stats++, delta++, |
573 | if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) | 595 | max_delta++, accum_stats++) { |
574 | *accum_stats += (le32_to_cpu(*stats) - | 596 | if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { |
597 | *delta = (le32_to_cpu(*stats) - | ||
575 | le32_to_cpu(*prev_stats)); | 598 | le32_to_cpu(*prev_stats)); |
599 | *accum_stats += *delta; | ||
600 | if (*delta > *max_delta) | ||
601 | *max_delta = *delta; | ||
602 | } | ||
603 | } | ||
576 | 604 | ||
577 | /* reset accumulative statistics for "no-counter" type statistics */ | 605 | /* reset accumulative statistics for "no-counter" type statistics */ |
578 | priv->accum_statistics.general.temperature = | 606 | priv->accum_statistics.general.temperature = |
@@ -592,11 +620,15 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, | |||
592 | 620 | ||
593 | #define REG_RECALIB_PERIOD (60) | 621 | #define REG_RECALIB_PERIOD (60) |
594 | 622 | ||
623 | #define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n" | ||
595 | void iwl_rx_statistics(struct iwl_priv *priv, | 624 | void iwl_rx_statistics(struct iwl_priv *priv, |
596 | struct iwl_rx_mem_buffer *rxb) | 625 | struct iwl_rx_mem_buffer *rxb) |
597 | { | 626 | { |
598 | int change; | 627 | int change; |
599 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 628 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
629 | int combined_plcp_delta; | ||
630 | unsigned int plcp_msec; | ||
631 | unsigned long plcp_received_jiffies; | ||
600 | 632 | ||
601 | IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", | 633 | IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", |
602 | (int)sizeof(priv->statistics), | 634 | (int)sizeof(priv->statistics), |
@@ -611,6 +643,56 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
611 | #ifdef CONFIG_IWLWIFI_DEBUG | 643 | #ifdef CONFIG_IWLWIFI_DEBUG |
612 | iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); | 644 | iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); |
613 | #endif | 645 | #endif |
646 | /* | ||
647 | * check for plcp_err and trigger radio reset if it exceeds | ||
648 | * the plcp error threshold plcp_delta. | ||
649 | */ | ||
650 | plcp_received_jiffies = jiffies; | ||
651 | plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies - | ||
652 | (long) priv->plcp_jiffies); | ||
653 | priv->plcp_jiffies = plcp_received_jiffies; | ||
654 | /* | ||
655 | * check to make sure plcp_msec is not 0 to prevent division | ||
656 | * by zero. | ||
657 | */ | ||
658 | if (plcp_msec) { | ||
659 | combined_plcp_delta = | ||
660 | (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) - | ||
661 | le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) + | ||
662 | (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) - | ||
663 | le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err)); | ||
664 | |||
665 | if ((combined_plcp_delta > 0) && | ||
666 | ((combined_plcp_delta * 100) / plcp_msec) > | ||
667 | priv->cfg->plcp_delta_threshold) { | ||
668 | /* | ||
669 | * if plcp_err exceed the threshold, the following | ||
670 | * data is printed in csv format: | ||
671 | * Text: plcp_err exceeded %d, | ||
672 | * Received ofdm.plcp_err, | ||
673 | * Current ofdm.plcp_err, | ||
674 | * Received ofdm_ht.plcp_err, | ||
675 | * Current ofdm_ht.plcp_err, | ||
676 | * combined_plcp_delta, | ||
677 | * plcp_msec | ||
678 | */ | ||
679 | IWL_DEBUG_RADIO(priv, PLCP_MSG, | ||
680 | priv->cfg->plcp_delta_threshold, | ||
681 | le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err), | ||
682 | le32_to_cpu(priv->statistics.rx.ofdm.plcp_err), | ||
683 | le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err), | ||
684 | le32_to_cpu( | ||
685 | priv->statistics.rx.ofdm_ht.plcp_err), | ||
686 | combined_plcp_delta, plcp_msec); | ||
687 | |||
688 | /* | ||
689 | * Reset the RF radio due to the high plcp | ||
690 | * error rate | ||
691 | */ | ||
692 | iwl_force_rf_reset(priv); | ||
693 | } | ||
694 | } | ||
695 | |||
614 | memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); | 696 | memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); |
615 | 697 | ||
616 | set_bit(STATUS_STATISTICS, &priv->status); | 698 | set_bit(STATUS_STATISTICS, &priv->status); |
@@ -638,11 +720,13 @@ void iwl_reply_statistics(struct iwl_priv *priv, | |||
638 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 720 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
639 | 721 | ||
640 | if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { | 722 | if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { |
641 | memset(&priv->statistics, 0, | ||
642 | sizeof(struct iwl_notif_statistics)); | ||
643 | #ifdef CONFIG_IWLWIFI_DEBUG | 723 | #ifdef CONFIG_IWLWIFI_DEBUG |
644 | memset(&priv->accum_statistics, 0, | 724 | memset(&priv->accum_statistics, 0, |
645 | sizeof(struct iwl_notif_statistics)); | 725 | sizeof(struct iwl_notif_statistics)); |
726 | memset(&priv->delta_statistics, 0, | ||
727 | sizeof(struct iwl_notif_statistics)); | ||
728 | memset(&priv->max_delta, 0, | ||
729 | sizeof(struct iwl_notif_statistics)); | ||
646 | #endif | 730 | #endif |
647 | IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); | 731 | IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); |
648 | } | 732 | } |