aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-rx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-04-08 11:14:56 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2011-04-08 11:19:00 -0400
commit0da0e5bf1522d75d446f5124e17016628d0a149e (patch)
tree86d9c4986be873fb834b54a4d9075330743c0f03 /drivers/net/wireless/iwlwifi/iwl-rx.c
parent703bc583cb98a24eeedd297ee59dfa12852897d1 (diff)
iwlagn: clean up & autodetect statistics
There's no need to keep both normal and BT statistics versions around all the time in memory when we only use a subset of both. So keep only the subsets that we need in memory, depending on the debug config). Also, in doing so, we can remove all the calls to iwl_bt_statistics() in the driver as we'll just access the copied statistics now. Finally, also remove this call from the one place where it might still be needed and automatically detect what kind of statistics the device is sending based on their size. This way, we don't need to keep track of which devices do what any more, which is good since this is subject to change based on the ucode version (as some ucode even for non-BT devices will in fact use BT statistics). Warn upon encountering a statistics command from the ucode that isn't known, so we will find such issues earlier in the future. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Tested-by: Don Fry <donald.h.fry@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c298
1 files changed, 155 insertions, 143 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 4472761fc591..b49819ca2cd6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -390,21 +390,16 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
390 * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal 390 * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
391 * operation state. 391 * operation state.
392 */ 392 */
393static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt) 393static bool iwl_good_ack_health(struct iwl_priv *priv,
394 struct statistics_tx *cur)
394{ 395{
395 int actual_delta, expected_delta, ba_timeout_delta; 396 int actual_delta, expected_delta, ba_timeout_delta;
396 struct statistics_tx *cur, *old; 397 struct statistics_tx *old;
397 398
398 if (priv->_agn.agg_tids_count) 399 if (priv->_agn.agg_tids_count)
399 return true; 400 return true;
400 401
401 if (iwl_bt_statistics(priv)) { 402 old = &priv->statistics.tx;
402 cur = &pkt->u.stats_bt.tx;
403 old = &priv->_agn.statistics_bt.tx;
404 } else {
405 cur = &pkt->u.stats.tx;
406 old = &priv->_agn.statistics.tx;
407 }
408 403
409 actual_delta = le32_to_cpu(cur->actual_ack_cnt) - 404 actual_delta = le32_to_cpu(cur->actual_ack_cnt) -
410 le32_to_cpu(old->actual_ack_cnt); 405 le32_to_cpu(old->actual_ack_cnt);
@@ -430,10 +425,10 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt
430 * DEBUG is not, these will just compile out. 425 * DEBUG is not, these will just compile out.
431 */ 426 */
432 IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n", 427 IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n",
433 priv->_agn.delta_statistics.tx.rx_detected_cnt); 428 priv->delta_stats.tx.rx_detected_cnt);
434 IWL_DEBUG_RADIO(priv, 429 IWL_DEBUG_RADIO(priv,
435 "ack_or_ba_timeout_collision delta %d\n", 430 "ack_or_ba_timeout_collision delta %d\n",
436 priv->_agn.delta_statistics.tx.ack_or_ba_timeout_collision); 431 priv->delta_stats.tx.ack_or_ba_timeout_collision);
437#endif 432#endif
438 433
439 if (ba_timeout_delta >= BA_TIMEOUT_MAX) 434 if (ba_timeout_delta >= BA_TIMEOUT_MAX)
@@ -450,7 +445,9 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt
450 * to improve the throughput. 445 * to improve the throughput.
451 */ 446 */
452static bool iwl_good_plcp_health(struct iwl_priv *priv, 447static bool iwl_good_plcp_health(struct iwl_priv *priv,
453 struct iwl_rx_packet *pkt, unsigned int msecs) 448 struct statistics_rx_phy *cur_ofdm,
449 struct statistics_rx_ht_phy *cur_ofdm_ht,
450 unsigned int msecs)
454{ 451{
455 int delta; 452 int delta;
456 int threshold = priv->cfg->base_params->plcp_delta_threshold; 453 int threshold = priv->cfg->base_params->plcp_delta_threshold;
@@ -460,29 +457,12 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv,
460 return true; 457 return true;
461 } 458 }
462 459
463 if (iwl_bt_statistics(priv)) { 460 delta = le32_to_cpu(cur_ofdm->plcp_err) -
464 struct statistics_rx_bt *cur, *old; 461 le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) +
465 462 le32_to_cpu(cur_ofdm_ht->plcp_err) -
466 cur = &pkt->u.stats_bt.rx; 463 le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err);
467 old = &priv->_agn.statistics_bt.rx;
468
469 delta = le32_to_cpu(cur->ofdm.plcp_err) -
470 le32_to_cpu(old->ofdm.plcp_err) +
471 le32_to_cpu(cur->ofdm_ht.plcp_err) -
472 le32_to_cpu(old->ofdm_ht.plcp_err);
473 } else {
474 struct statistics_rx *cur, *old;
475
476 cur = &pkt->u.stats.rx;
477 old = &priv->_agn.statistics.rx;
478
479 delta = le32_to_cpu(cur->ofdm.plcp_err) -
480 le32_to_cpu(old->ofdm.plcp_err) +
481 le32_to_cpu(cur->ofdm_ht.plcp_err) -
482 le32_to_cpu(old->ofdm_ht.plcp_err);
483 }
484 464
485 /* Can be negative if firmware reseted statistics */ 465 /* Can be negative if firmware reset statistics */
486 if (delta <= 0) 466 if (delta <= 0)
487 return true; 467 return true;
488 468
@@ -497,44 +477,36 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv,
497} 477}
498 478
499static void iwl_recover_from_statistics(struct iwl_priv *priv, 479static void iwl_recover_from_statistics(struct iwl_priv *priv,
500 struct iwl_rx_packet *pkt) 480 struct statistics_rx_phy *cur_ofdm,
481 struct statistics_rx_ht_phy *cur_ofdm_ht,
482 struct statistics_tx *tx,
483 unsigned long stamp)
501{ 484{
502 const struct iwl_mod_params *mod_params = priv->cfg->mod_params; 485 const struct iwl_mod_params *mod_params = priv->cfg->mod_params;
503 unsigned int msecs; 486 unsigned int msecs;
504 unsigned long stamp;
505 487
506 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 488 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
507 return; 489 return;
508 490
509 stamp = jiffies;
510 msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies); 491 msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies);
511 492
512 /* Only gather statistics and update time stamp when not associated */ 493 /* Only gather statistics and update time stamp when not associated */
513 if (!iwl_is_any_associated(priv)) 494 if (!iwl_is_any_associated(priv))
514 goto out; 495 return;
515 496
516 /* Do not check/recover when do not have enough statistics data */ 497 /* Do not check/recover when do not have enough statistics data */
517 if (msecs < 99) 498 if (msecs < 99)
518 return; 499 return;
519 500
520 if (mod_params->ack_check && !iwl_good_ack_health(priv, pkt)) { 501 if (mod_params->ack_check && !iwl_good_ack_health(priv, tx)) {
521 IWL_ERR(priv, "low ack count detected, restart firmware\n"); 502 IWL_ERR(priv, "low ack count detected, restart firmware\n");
522 if (!iwl_force_reset(priv, IWL_FW_RESET, false)) 503 if (!iwl_force_reset(priv, IWL_FW_RESET, false))
523 return; 504 return;
524 } 505 }
525 506
526 if (mod_params->plcp_check && !iwl_good_plcp_health(priv, pkt, msecs)) 507 if (mod_params->plcp_check &&
508 !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
527 iwl_force_reset(priv, IWL_RF_RESET, false); 509 iwl_force_reset(priv, IWL_RF_RESET, false);
528
529out:
530 if (iwl_bt_statistics(priv))
531 memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt,
532 sizeof(priv->_agn.statistics_bt));
533 else
534 memcpy(&priv->_agn.statistics, &pkt->u.stats,
535 sizeof(priv->_agn.statistics));
536
537 priv->rx_statistics_jiffies = stamp;
538} 510}
539 511
540/* Calculate noise level, based on measurements during network silence just 512/* Calculate noise level, based on measurements during network silence just
@@ -548,10 +520,8 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
548 int bcn_silence_a, bcn_silence_b, bcn_silence_c; 520 int bcn_silence_a, bcn_silence_b, bcn_silence_c;
549 int last_rx_noise; 521 int last_rx_noise;
550 522
551 if (iwl_bt_statistics(priv)) 523 rx_info = &priv->statistics.rx_non_phy;
552 rx_info = &(priv->_agn.statistics_bt.rx.general.common); 524
553 else
554 rx_info = &(priv->_agn.statistics.rx.general);
555 bcn_silence_a = 525 bcn_silence_a =
556 le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; 526 le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
557 bcn_silence_b = 527 bcn_silence_b =
@@ -583,105 +553,153 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
583 last_rx_noise); 553 last_rx_noise);
584} 554}
585 555
556#ifdef CONFIG_IWLWIFI_DEBUGFS
586/* 557/*
587 * based on the assumption of all statistics counter are in DWORD 558 * based on the assumption of all statistics counter are in DWORD
588 * FIXME: This function is for debugging, do not deal with 559 * FIXME: This function is for debugging, do not deal with
589 * the case of counters roll-over. 560 * the case of counters roll-over.
590 */ 561 */
591static void iwl_accumulative_statistics(struct iwl_priv *priv, 562static void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta,
592 __le32 *stats) 563 __le32 *max_delta, __le32 *accum, int size)
593{ 564{
594#ifdef CONFIG_IWLWIFI_DEBUGFS 565 int i;
595 int i, size; 566
596 __le32 *prev_stats; 567 for (i = 0;
597 u32 *accum_stats; 568 i < size / sizeof(__le32);
598 u32 *delta, *max_delta; 569 i++, prev++, cur++, delta++, max_delta++, accum++) {
599 struct statistics_general_common *general, *accum_general; 570 if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) {
600 struct statistics_tx *tx, *accum_tx; 571 *delta = cpu_to_le32(
601 572 le32_to_cpu(*cur) - le32_to_cpu(*prev));
602 if (iwl_bt_statistics(priv)) { 573 le32_add_cpu(accum, le32_to_cpu(*delta));
603 prev_stats = (__le32 *)&priv->_agn.statistics_bt; 574 if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta))
604 accum_stats = (u32 *)&priv->_agn.accum_statistics_bt;
605 size = sizeof(struct iwl_bt_notif_statistics);
606 general = &priv->_agn.statistics_bt.general.common;
607 accum_general = &priv->_agn.accum_statistics_bt.general.common;
608 tx = &priv->_agn.statistics_bt.tx;
609 accum_tx = &priv->_agn.accum_statistics_bt.tx;
610 delta = (u32 *)&priv->_agn.delta_statistics_bt;
611 max_delta = (u32 *)&priv->_agn.max_delta_bt;
612 } else {
613 prev_stats = (__le32 *)&priv->_agn.statistics;
614 accum_stats = (u32 *)&priv->_agn.accum_statistics;
615 size = sizeof(struct iwl_notif_statistics);
616 general = &priv->_agn.statistics.general.common;
617 accum_general = &priv->_agn.accum_statistics.general.common;
618 tx = &priv->_agn.statistics.tx;
619 accum_tx = &priv->_agn.accum_statistics.tx;
620 delta = (u32 *)&priv->_agn.delta_statistics;
621 max_delta = (u32 *)&priv->_agn.max_delta;
622 }
623 for (i = sizeof(__le32); i < size;
624 i += sizeof(__le32), stats++, prev_stats++, delta++,
625 max_delta++, accum_stats++) {
626 if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
627 *delta = (le32_to_cpu(*stats) -
628 le32_to_cpu(*prev_stats));
629 *accum_stats += *delta;
630 if (*delta > *max_delta)
631 *max_delta = *delta; 575 *max_delta = *delta;
632 } 576 }
633 } 577 }
578}
634 579
635 /* reset accumulative statistics for "no-counter" type statistics */ 580static void
636 accum_general->temperature = general->temperature; 581iwl_accumulative_statistics(struct iwl_priv *priv,
637 accum_general->temperature_m = general->temperature_m; 582 struct statistics_general_common *common,
638 accum_general->ttl_timestamp = general->ttl_timestamp; 583 struct statistics_rx_non_phy *rx_non_phy,
639 accum_tx->tx_power.ant_a = tx->tx_power.ant_a; 584 struct statistics_rx_phy *rx_ofdm,
640 accum_tx->tx_power.ant_b = tx->tx_power.ant_b; 585 struct statistics_rx_ht_phy *rx_ofdm_ht,
641 accum_tx->tx_power.ant_c = tx->tx_power.ant_c; 586 struct statistics_rx_phy *rx_cck,
642#endif 587 struct statistics_tx *tx,
588 struct statistics_bt_activity *bt_activity)
589{
590#define ACCUM(_name) \
591 accum_stats((__le32 *)&priv->statistics._name, \
592 (__le32 *)_name, \
593 (__le32 *)&priv->delta_stats._name, \
594 (__le32 *)&priv->max_delta_stats._name, \
595 (__le32 *)&priv->accum_stats._name, \
596 sizeof(*_name));
597
598 ACCUM(common);
599 ACCUM(rx_non_phy);
600 ACCUM(rx_ofdm);
601 ACCUM(rx_ofdm_ht);
602 ACCUM(rx_cck);
603 ACCUM(tx);
604 if (bt_activity)
605 ACCUM(bt_activity);
606#undef ACCUM
643} 607}
608#else
609static inline void
610iwl_accumulative_statistics(struct iwl_priv *priv,
611 struct statistics_general_common *common,
612 struct statistics_rx_non_phy *rx_non_phy,
613 struct statistics_rx_phy *rx_ofdm,
614 struct statistics_rx_ht_phy *rx_ofdm_ht,
615 struct statistics_rx_phy *rx_cck,
616 struct statistics_tx *tx,
617 struct statistics_bt_activity *bt_activity)
618{
619}
620#endif
644 621
645static void iwl_rx_statistics(struct iwl_priv *priv, 622static void iwl_rx_statistics(struct iwl_priv *priv,
646 struct iwl_rx_mem_buffer *rxb) 623 struct iwl_rx_mem_buffer *rxb)
647{ 624{
625 unsigned long stamp = jiffies;
648 const int reg_recalib_period = 60; 626 const int reg_recalib_period = 60;
649 int change; 627 int change;
650 struct iwl_rx_packet *pkt = rxb_addr(rxb); 628 struct iwl_rx_packet *pkt = rxb_addr(rxb);
629 u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
630 __le32 *flag;
631 struct statistics_general_common *common;
632 struct statistics_rx_non_phy *rx_non_phy;
633 struct statistics_rx_phy *rx_ofdm;
634 struct statistics_rx_ht_phy *rx_ofdm_ht;
635 struct statistics_rx_phy *rx_cck;
636 struct statistics_tx *tx;
637 struct statistics_bt_activity *bt_activity;
638
639 len -= sizeof(struct iwl_cmd_header); /* skip header */
640
641 IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n",
642 len);
643
644 if (len == sizeof(struct iwl_bt_notif_statistics)) {
645 struct iwl_bt_notif_statistics *stats;
646 stats = &pkt->u.stats_bt;
647 flag = &stats->flag;
648 common = &stats->general.common;
649 rx_non_phy = &stats->rx.general.common;
650 rx_ofdm = &stats->rx.ofdm;
651 rx_ofdm_ht = &stats->rx.ofdm_ht;
652 rx_cck = &stats->rx.cck;
653 tx = &stats->tx;
654 bt_activity = &stats->general.activity;
651 655
652 if (iwl_bt_statistics(priv)) { 656#ifdef CONFIG_IWLWIFI_DEBUGFS
653 IWL_DEBUG_RX(priv, 657 /* handle this exception directly */
654 "Statistics notification received (%d vs %d).\n", 658 priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills;
655 (int)sizeof(struct iwl_bt_notif_statistics), 659 le32_add_cpu(&priv->statistics.accum_num_bt_kills,
656 le32_to_cpu(pkt->len_n_flags) & 660 le32_to_cpu(stats->rx.general.num_bt_kills));
657 FH_RSCSR_FRAME_SIZE_MSK); 661#endif
658 662 } else if (len == sizeof(struct iwl_notif_statistics)) {
659 change = ((priv->_agn.statistics_bt.general.common.temperature != 663 struct iwl_notif_statistics *stats;
660 pkt->u.stats_bt.general.common.temperature) || 664 stats = &pkt->u.stats;
661 ((priv->_agn.statistics_bt.flag & 665 flag = &stats->flag;
662 STATISTICS_REPLY_FLG_HT40_MODE_MSK) != 666 common = &stats->general.common;
663 (pkt->u.stats_bt.flag & 667 rx_non_phy = &stats->rx.general;
664 STATISTICS_REPLY_FLG_HT40_MODE_MSK))); 668 rx_ofdm = &stats->rx.ofdm;
665 669 rx_ofdm_ht = &stats->rx.ofdm_ht;
666 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt); 670 rx_cck = &stats->rx.cck;
671 tx = &stats->tx;
672 bt_activity = NULL;
667 } else { 673 } else {
668 IWL_DEBUG_RX(priv, 674 WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
669 "Statistics notification received (%d vs %d).\n", 675 len, sizeof(struct iwl_bt_notif_statistics),
670 (int)sizeof(struct iwl_notif_statistics), 676 sizeof(struct iwl_notif_statistics));
671 le32_to_cpu(pkt->len_n_flags) & 677 return;
672 FH_RSCSR_FRAME_SIZE_MSK);
673
674 change = ((priv->_agn.statistics.general.common.temperature !=
675 pkt->u.stats.general.common.temperature) ||
676 ((priv->_agn.statistics.flag &
677 STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
678 (pkt->u.stats.flag &
679 STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
680
681 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
682 } 678 }
683 679
684 iwl_recover_from_statistics(priv, pkt); 680 change = common->temperature != priv->statistics.common.temperature ||
681 (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
682 (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK);
683
684 iwl_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm,
685 rx_ofdm_ht, rx_cck, tx, bt_activity);
686
687 iwl_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp);
688
689 priv->statistics.flag = *flag;
690 memcpy(&priv->statistics.common, common, sizeof(*common));
691 memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy));
692 memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm));
693 memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht));
694 memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck));
695 memcpy(&priv->statistics.tx, tx, sizeof(*tx));
696#ifdef CONFIG_IWLWIFI_DEBUGFS
697 if (bt_activity)
698 memcpy(&priv->statistics.bt_activity, bt_activity,
699 sizeof(*bt_activity));
700#endif
701
702 priv->rx_statistics_jiffies = stamp;
685 703
686 set_bit(STATUS_STATISTICS, &priv->status); 704 set_bit(STATUS_STATISTICS, &priv->status);
687 705
@@ -708,18 +726,12 @@ static void iwl_rx_reply_statistics(struct iwl_priv *priv,
708 726
709 if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { 727 if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
710#ifdef CONFIG_IWLWIFI_DEBUGFS 728#ifdef CONFIG_IWLWIFI_DEBUGFS
711 memset(&priv->_agn.accum_statistics, 0, 729 memset(&priv->accum_stats, 0,
712 sizeof(struct iwl_notif_statistics)); 730 sizeof(priv->accum_stats));
713 memset(&priv->_agn.delta_statistics, 0, 731 memset(&priv->delta_stats, 0,
714 sizeof(struct iwl_notif_statistics)); 732 sizeof(priv->delta_stats));
715 memset(&priv->_agn.max_delta, 0, 733 memset(&priv->max_delta_stats, 0,
716 sizeof(struct iwl_notif_statistics)); 734 sizeof(priv->max_delta_stats));
717 memset(&priv->_agn.accum_statistics_bt, 0,
718 sizeof(struct iwl_bt_notif_statistics));
719 memset(&priv->_agn.delta_statistics_bt, 0,
720 sizeof(struct iwl_bt_notif_statistics));
721 memset(&priv->_agn.max_delta_bt, 0,
722 sizeof(struct iwl_bt_notif_statistics));
723#endif 735#endif
724 IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); 736 IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
725 } 737 }