aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-calib.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.c316
1 files changed, 163 insertions, 153 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index c4c5691032a6..c9255def1080 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -5,7 +5,7 @@
5 * 5 *
6 * GPL LICENSE SUMMARY 6 * GPL LICENSE SUMMARY
7 * 7 *
8 * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. 8 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
9 * 9 *
10 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as 11 * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
30 * 30 *
31 * BSD LICENSE 31 * BSD LICENSE
32 * 32 *
33 * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. 33 * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
34 * All rights reserved. 34 * All rights reserved.
35 * 35 *
36 * Redistribution and use in source and binary forms, with or without 36 * Redistribution and use in source and binary forms, with or without
@@ -65,7 +65,7 @@
65 65
66#include "iwl-dev.h" 66#include "iwl-dev.h"
67#include "iwl-core.h" 67#include "iwl-core.h"
68#include "iwl-calib.h" 68#include "iwl-agn-calib.h"
69 69
70/***************************************************************************** 70/*****************************************************************************
71 * INIT calibrations framework 71 * INIT calibrations framework
@@ -87,14 +87,14 @@ int iwl_send_calib_results(struct iwl_priv *priv)
87 87
88 struct iwl_host_cmd hcmd = { 88 struct iwl_host_cmd hcmd = {
89 .id = REPLY_PHY_CALIBRATION_CMD, 89 .id = REPLY_PHY_CALIBRATION_CMD,
90 .flags = CMD_SIZE_HUGE,
91 }; 90 };
92 91
93 for (i = 0; i < IWL_CALIB_MAX; i++) { 92 for (i = 0; i < IWL_CALIB_MAX; i++) {
94 if ((BIT(i) & priv->hw_params.calib_init_cfg) && 93 if ((BIT(i) & priv->hw_params.calib_init_cfg) &&
95 priv->calib_results[i].buf) { 94 priv->calib_results[i].buf) {
96 hcmd.len = priv->calib_results[i].buf_len; 95 hcmd.len[0] = priv->calib_results[i].buf_len;
97 hcmd.data = priv->calib_results[i].buf; 96 hcmd.data[0] = priv->calib_results[i].buf;
97 hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
98 ret = iwl_send_cmd_sync(priv, &hcmd); 98 ret = iwl_send_cmd_sync(priv, &hcmd);
99 if (ret) { 99 if (ret) {
100 IWL_ERR(priv, "Error %d iteration %d\n", 100 IWL_ERR(priv, "Error %d iteration %d\n",
@@ -456,9 +456,9 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
456 struct iwl_sensitivity_data *data = NULL; 456 struct iwl_sensitivity_data *data = NULL;
457 struct iwl_host_cmd cmd_out = { 457 struct iwl_host_cmd cmd_out = {
458 .id = SENSITIVITY_CMD, 458 .id = SENSITIVITY_CMD,
459 .len = sizeof(struct iwl_sensitivity_cmd), 459 .len = { sizeof(struct iwl_sensitivity_cmd), },
460 .flags = CMD_ASYNC, 460 .flags = CMD_ASYNC,
461 .data = &cmd, 461 .data = { &cmd, },
462 }; 462 };
463 463
464 data = &(priv->sensitivity_data); 464 data = &(priv->sensitivity_data);
@@ -491,9 +491,9 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
491 struct iwl_sensitivity_data *data = NULL; 491 struct iwl_sensitivity_data *data = NULL;
492 struct iwl_host_cmd cmd_out = { 492 struct iwl_host_cmd cmd_out = {
493 .id = SENSITIVITY_CMD, 493 .id = SENSITIVITY_CMD,
494 .len = sizeof(struct iwl_enhance_sensitivity_cmd), 494 .len = { sizeof(struct iwl_enhance_sensitivity_cmd), },
495 .flags = CMD_ASYNC, 495 .flags = CMD_ASYNC,
496 .data = &cmd, 496 .data = { &cmd, },
497 }; 497 };
498 498
499 data = &(priv->sensitivity_data); 499 data = &(priv->sensitivity_data);
@@ -605,7 +605,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
605 IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret); 605 IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
606} 606}
607 607
608void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp) 608void iwl_sensitivity_calibration(struct iwl_priv *priv)
609{ 609{
610 u32 rx_enable_time; 610 u32 rx_enable_time;
611 u32 fa_cck; 611 u32 fa_cck;
@@ -625,22 +625,15 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
625 625
626 data = &(priv->sensitivity_data); 626 data = &(priv->sensitivity_data);
627 627
628 if (!iwl_is_associated(priv)) { 628 if (!iwl_is_any_associated(priv)) {
629 IWL_DEBUG_CALIB(priv, "<< - not associated\n"); 629 IWL_DEBUG_CALIB(priv, "<< - not associated\n");
630 return; 630 return;
631 } 631 }
632 632
633 spin_lock_irqsave(&priv->lock, flags); 633 spin_lock_irqsave(&priv->lock, flags);
634 if (priv->cfg->bt_statistics) { 634 rx_info = &priv->statistics.rx_non_phy;
635 rx_info = &(((struct iwl_bt_notif_statistics *)resp)-> 635 ofdm = &priv->statistics.rx_ofdm;
636 rx.general.common); 636 cck = &priv->statistics.rx_cck;
637 ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm);
638 cck = &(((struct iwl_bt_notif_statistics *)resp)->rx.cck);
639 } else {
640 rx_info = &(((struct iwl_notif_statistics *)resp)->rx.general);
641 ofdm = &(((struct iwl_notif_statistics *)resp)->rx.ofdm);
642 cck = &(((struct iwl_notif_statistics *)resp)->rx.cck);
643 }
644 if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { 637 if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
645 IWL_DEBUG_CALIB(priv, "<< invalid data.\n"); 638 IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
646 spin_unlock_irqrestore(&priv->lock, flags); 639 spin_unlock_irqrestore(&priv->lock, flags);
@@ -731,13 +724,127 @@ static inline u8 find_first_chain(u8 mask)
731 return CHAIN_C; 724 return CHAIN_C;
732} 725}
733 726
727/**
728 * Run disconnected antenna algorithm to find out which antennas are
729 * disconnected.
730 */
731static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
732 struct iwl_chain_noise_data *data)
733{
734 u32 active_chains = 0;
735 u32 max_average_sig;
736 u16 max_average_sig_antenna_i;
737 u8 num_tx_chains;
738 u8 first_chain;
739 u16 i = 0;
740
741 average_sig[0] = data->chain_signal_a /
742 priv->cfg->base_params->chain_noise_num_beacons;
743 average_sig[1] = data->chain_signal_b /
744 priv->cfg->base_params->chain_noise_num_beacons;
745 average_sig[2] = data->chain_signal_c /
746 priv->cfg->base_params->chain_noise_num_beacons;
747
748 if (average_sig[0] >= average_sig[1]) {
749 max_average_sig = average_sig[0];
750 max_average_sig_antenna_i = 0;
751 active_chains = (1 << max_average_sig_antenna_i);
752 } else {
753 max_average_sig = average_sig[1];
754 max_average_sig_antenna_i = 1;
755 active_chains = (1 << max_average_sig_antenna_i);
756 }
757
758 if (average_sig[2] >= max_average_sig) {
759 max_average_sig = average_sig[2];
760 max_average_sig_antenna_i = 2;
761 active_chains = (1 << max_average_sig_antenna_i);
762 }
763
764 IWL_DEBUG_CALIB(priv, "average_sig: a %d b %d c %d\n",
765 average_sig[0], average_sig[1], average_sig[2]);
766 IWL_DEBUG_CALIB(priv, "max_average_sig = %d, antenna %d\n",
767 max_average_sig, max_average_sig_antenna_i);
768
769 /* Compare signal strengths for all 3 receivers. */
770 for (i = 0; i < NUM_RX_CHAINS; i++) {
771 if (i != max_average_sig_antenna_i) {
772 s32 rssi_delta = (max_average_sig - average_sig[i]);
773
774 /* If signal is very weak, compared with
775 * strongest, mark it as disconnected. */
776 if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
777 data->disconn_array[i] = 1;
778 else
779 active_chains |= (1 << i);
780 IWL_DEBUG_CALIB(priv, "i = %d rssiDelta = %d "
781 "disconn_array[i] = %d\n",
782 i, rssi_delta, data->disconn_array[i]);
783 }
784 }
785
786 /*
787 * The above algorithm sometimes fails when the ucode
788 * reports 0 for all chains. It's not clear why that
789 * happens to start with, but it is then causing trouble
790 * because this can make us enable more chains than the
791 * hardware really has.
792 *
793 * To be safe, simply mask out any chains that we know
794 * are not on the device.
795 */
796 active_chains &= priv->hw_params.valid_rx_ant;
797
798 num_tx_chains = 0;
799 for (i = 0; i < NUM_RX_CHAINS; i++) {
800 /* loops on all the bits of
801 * priv->hw_setting.valid_tx_ant */
802 u8 ant_msk = (1 << i);
803 if (!(priv->hw_params.valid_tx_ant & ant_msk))
804 continue;
805
806 num_tx_chains++;
807 if (data->disconn_array[i] == 0)
808 /* there is a Tx antenna connected */
809 break;
810 if (num_tx_chains == priv->hw_params.tx_chains_num &&
811 data->disconn_array[i]) {
812 /*
813 * If all chains are disconnected
814 * connect the first valid tx chain
815 */
816 first_chain =
817 find_first_chain(priv->cfg->valid_tx_ant);
818 data->disconn_array[first_chain] = 0;
819 active_chains |= BIT(first_chain);
820 IWL_DEBUG_CALIB(priv,
821 "All Tx chains are disconnected W/A - declare %d as connected\n",
822 first_chain);
823 break;
824 }
825 }
826
827 if (active_chains != priv->hw_params.valid_rx_ant &&
828 active_chains != priv->chain_noise_data.active_chains)
829 IWL_DEBUG_CALIB(priv,
830 "Detected that not all antennas are connected! "
831 "Connected: %#x, valid: %#x.\n",
832 active_chains, priv->hw_params.valid_rx_ant);
833
834 /* Save for use within RXON, TX, SCAN commands, etc. */
835 data->active_chains = active_chains;
836 IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
837 active_chains);
838}
839
840
734/* 841/*
735 * Accumulate 20 beacons of signal and noise statistics for each of 842 * Accumulate 16 beacons of signal and noise statistics for each of
736 * 3 receivers/antennas/rx-chains, then figure out: 843 * 3 receivers/antennas/rx-chains, then figure out:
737 * 1) Which antennas are connected. 844 * 1) Which antennas are connected.
738 * 2) Differential rx gain settings to balance the 3 receivers. 845 * 2) Differential rx gain settings to balance the 3 receivers.
739 */ 846 */
740void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) 847void iwl_chain_noise_calibration(struct iwl_priv *priv)
741{ 848{
742 struct iwl_chain_noise_data *data = NULL; 849 struct iwl_chain_noise_data *data = NULL;
743 850
@@ -749,8 +856,6 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
749 u32 chain_sig_c; 856 u32 chain_sig_c;
750 u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; 857 u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
751 u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; 858 u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
752 u32 max_average_sig;
753 u16 max_average_sig_antenna_i;
754 u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE; 859 u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
755 u16 min_average_noise_antenna_i = INITIALIZATION_VALUE; 860 u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
756 u16 i = 0; 861 u16 i = 0;
@@ -758,11 +863,15 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
758 u16 stat_chnum = INITIALIZATION_VALUE; 863 u16 stat_chnum = INITIALIZATION_VALUE;
759 u8 rxon_band24; 864 u8 rxon_band24;
760 u8 stat_band24; 865 u8 stat_band24;
761 u32 active_chains = 0;
762 u8 num_tx_chains;
763 unsigned long flags; 866 unsigned long flags;
764 struct statistics_rx_non_phy *rx_info; 867 struct statistics_rx_non_phy *rx_info;
765 u8 first_chain; 868
869 /*
870 * MULTI-FIXME:
871 * When we support multiple interfaces on different channels,
872 * this must be modified/fixed.
873 */
874 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
766 875
767 if (priv->disable_chain_noise_cal) 876 if (priv->disable_chain_noise_cal)
768 return; 877 return;
@@ -780,34 +889,20 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
780 } 889 }
781 890
782 spin_lock_irqsave(&priv->lock, flags); 891 spin_lock_irqsave(&priv->lock, flags);
783 if (priv->cfg->bt_statistics) { 892
784 rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)-> 893 rx_info = &priv->statistics.rx_non_phy;
785 rx.general.common); 894
786 } else {
787 rx_info = &(((struct iwl_notif_statistics *)stat_resp)->
788 rx.general);
789 }
790 if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { 895 if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
791 IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n"); 896 IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
792 spin_unlock_irqrestore(&priv->lock, flags); 897 spin_unlock_irqrestore(&priv->lock, flags);
793 return; 898 return;
794 } 899 }
795 900
796 rxon_band24 = !!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK); 901 rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
797 rxon_chnum = le16_to_cpu(priv->staging_rxon.channel); 902 rxon_chnum = le16_to_cpu(ctx->staging.channel);
798 if (priv->cfg->bt_statistics) { 903 stat_band24 =
799 stat_band24 = !!(((struct iwl_bt_notif_statistics *) 904 !!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
800 stat_resp)->flag & 905 stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16;
801 STATISTICS_REPLY_FLG_BAND_24G_MSK);
802 stat_chnum = le32_to_cpu(((struct iwl_bt_notif_statistics *)
803 stat_resp)->flag) >> 16;
804 } else {
805 stat_band24 = !!(((struct iwl_notif_statistics *)
806 stat_resp)->flag &
807 STATISTICS_REPLY_FLG_BAND_24G_MSK);
808 stat_chnum = le32_to_cpu(((struct iwl_notif_statistics *)
809 stat_resp)->flag) >> 16;
810 }
811 906
812 /* Make sure we accumulate data for just the associated channel 907 /* Make sure we accumulate data for just the associated channel
813 * (even if scanning). */ 908 * (even if scanning). */
@@ -855,114 +950,29 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
855 /* If this is the "chain_noise_num_beacons", determine: 950 /* If this is the "chain_noise_num_beacons", determine:
856 * 1) Disconnected antennas (using signal strengths) 951 * 1) Disconnected antennas (using signal strengths)
857 * 2) Differential gain (using silence noise) to balance receivers */ 952 * 2) Differential gain (using silence noise) to balance receivers */
858 if (data->beacon_count != priv->cfg->chain_noise_num_beacons) 953 if (data->beacon_count !=
954 priv->cfg->base_params->chain_noise_num_beacons)
859 return; 955 return;
860 956
861 /* Analyze signal for disconnected antenna */ 957 /* Analyze signal for disconnected antenna */
862 average_sig[0] = 958 if (priv->cfg->bt_params &&
863 (data->chain_signal_a) / priv->cfg->chain_noise_num_beacons; 959 priv->cfg->bt_params->advanced_bt_coexist) {
864 average_sig[1] = 960 /* Disable disconnected antenna algorithm for advanced
865 (data->chain_signal_b) / priv->cfg->chain_noise_num_beacons; 961 bt coex, assuming valid antennas are connected */
866 average_sig[2] = 962 data->active_chains = priv->hw_params.valid_rx_ant;
867 (data->chain_signal_c) / priv->cfg->chain_noise_num_beacons; 963 for (i = 0; i < NUM_RX_CHAINS; i++)
868 964 if (!(data->active_chains & (1<<i)))
869 if (average_sig[0] >= average_sig[1]) {
870 max_average_sig = average_sig[0];
871 max_average_sig_antenna_i = 0;
872 active_chains = (1 << max_average_sig_antenna_i);
873 } else {
874 max_average_sig = average_sig[1];
875 max_average_sig_antenna_i = 1;
876 active_chains = (1 << max_average_sig_antenna_i);
877 }
878
879 if (average_sig[2] >= max_average_sig) {
880 max_average_sig = average_sig[2];
881 max_average_sig_antenna_i = 2;
882 active_chains = (1 << max_average_sig_antenna_i);
883 }
884
885 IWL_DEBUG_CALIB(priv, "average_sig: a %d b %d c %d\n",
886 average_sig[0], average_sig[1], average_sig[2]);
887 IWL_DEBUG_CALIB(priv, "max_average_sig = %d, antenna %d\n",
888 max_average_sig, max_average_sig_antenna_i);
889
890 /* Compare signal strengths for all 3 receivers. */
891 for (i = 0; i < NUM_RX_CHAINS; i++) {
892 if (i != max_average_sig_antenna_i) {
893 s32 rssi_delta = (max_average_sig - average_sig[i]);
894
895 /* If signal is very weak, compared with
896 * strongest, mark it as disconnected. */
897 if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
898 data->disconn_array[i] = 1; 965 data->disconn_array[i] = 1;
899 else 966 } else
900 active_chains |= (1 << i); 967 iwl_find_disconn_antenna(priv, average_sig, data);
901 IWL_DEBUG_CALIB(priv, "i = %d rssiDelta = %d "
902 "disconn_array[i] = %d\n",
903 i, rssi_delta, data->disconn_array[i]);
904 }
905 }
906
907 /*
908 * The above algorithm sometimes fails when the ucode
909 * reports 0 for all chains. It's not clear why that
910 * happens to start with, but it is then causing trouble
911 * because this can make us enable more chains than the
912 * hardware really has.
913 *
914 * To be safe, simply mask out any chains that we know
915 * are not on the device.
916 */
917 active_chains &= priv->hw_params.valid_rx_ant;
918
919 num_tx_chains = 0;
920 for (i = 0; i < NUM_RX_CHAINS; i++) {
921 /* loops on all the bits of
922 * priv->hw_setting.valid_tx_ant */
923 u8 ant_msk = (1 << i);
924 if (!(priv->hw_params.valid_tx_ant & ant_msk))
925 continue;
926
927 num_tx_chains++;
928 if (data->disconn_array[i] == 0)
929 /* there is a Tx antenna connected */
930 break;
931 if (num_tx_chains == priv->hw_params.tx_chains_num &&
932 data->disconn_array[i]) {
933 /*
934 * If all chains are disconnected
935 * connect the first valid tx chain
936 */
937 first_chain =
938 find_first_chain(priv->cfg->valid_tx_ant);
939 data->disconn_array[first_chain] = 0;
940 active_chains |= BIT(first_chain);
941 IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - declare %d as connected\n",
942 first_chain);
943 break;
944 }
945 }
946
947 if (active_chains != priv->hw_params.valid_rx_ant &&
948 active_chains != priv->chain_noise_data.active_chains)
949 IWL_DEBUG_CALIB(priv,
950 "Detected that not all antennas are connected! "
951 "Connected: %#x, valid: %#x.\n",
952 active_chains, priv->hw_params.valid_rx_ant);
953
954 /* Save for use within RXON, TX, SCAN commands, etc. */
955 priv->chain_noise_data.active_chains = active_chains;
956 IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
957 active_chains);
958 968
959 /* Analyze noise for rx balance */ 969 /* Analyze noise for rx balance */
960 average_noise[0] = 970 average_noise[0] = data->chain_noise_a /
961 ((data->chain_noise_a) / priv->cfg->chain_noise_num_beacons); 971 priv->cfg->base_params->chain_noise_num_beacons;
962 average_noise[1] = 972 average_noise[1] = data->chain_noise_b /
963 ((data->chain_noise_b) / priv->cfg->chain_noise_num_beacons); 973 priv->cfg->base_params->chain_noise_num_beacons;
964 average_noise[2] = 974 average_noise[2] = data->chain_noise_c /
965 ((data->chain_noise_c) / priv->cfg->chain_noise_num_beacons); 975 priv->cfg->base_params->chain_noise_num_beacons;
966 976
967 for (i = 0; i < NUM_RX_CHAINS; i++) { 977 for (i = 0; i < NUM_RX_CHAINS; i++) {
968 if (!(data->disconn_array[i]) && 978 if (!(data->disconn_array[i]) &&