aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-11-13 14:56:30 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-18 17:09:05 -0500
commitae16fc3c3184bf27f0462e1951df918122498829 (patch)
tree6bfe0c4d2f7bd7572d9dcbe7c28f788d78d868ac
parent4d6ccbf57ff7653217b7149976aa31e19f996544 (diff)
iwlwifi: eliminate the possible 1/2 dBm tx power loss in 6x00 & 6x50 series
In both 6x00 and 6x50 series, the enhanced/extended tx power table in EEPROM is used to set the max. tx power limit. This new tx power table is in 1/2 dBm format, which creates an issue of possibility of 1/2 dBm loss when driver set the tx power limit; because of driver keep track and report the tx power in dBm format. In order to prevent the 1/2 dBm loss, keep track of the true max tx power in 1/2 dBm format in driver; do the comparison and adjust the tx power if needed when send tx power command to uCode. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c49
3 files changed, 52 insertions, 14 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 6eaf26b07636..48982fb44995 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1250,6 +1250,22 @@ int iwl5000_send_tx_power(struct iwl_priv *priv)
1250 1250
1251 /* half dBm need to multiply */ 1251 /* half dBm need to multiply */
1252 tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt); 1252 tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
1253
1254 if (priv->tx_power_lmt_in_half_dbm &&
1255 priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
1256 /*
1257 * For the newer devices which using enhanced/extend tx power
1258 * table in EEPROM, the format is in half dBm. driver need to
1259 * convert to dBm format before report to mac80211.
1260 * By doing so, there is a possibility of 1/2 dBm resolution
1261 * lost. driver will perform "round-up" operation before
1262 * reporting, but it will cause 1/2 dBm tx power over the
1263 * regulatory limit. Perform the checking here, if the
1264 * "tx_power_user_lmt" is higher than EEPROM value (in
1265 * half-dBm format), lower the tx power based on EEPROM
1266 */
1267 tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
1268 }
1253 tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED; 1269 tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
1254 tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO; 1270 tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
1255 1271
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 774a315996e6..a474383ec0b8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1247,6 +1247,7 @@ struct iwl_priv {
1247 /* TX Power */ 1247 /* TX Power */
1248 s8 tx_power_user_lmt; 1248 s8 tx_power_user_lmt;
1249 s8 tx_power_device_lmt; 1249 s8 tx_power_device_lmt;
1250 s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */
1250 1251
1251 1252
1252#ifdef CONFIG_IWLWIFI_DEBUG 1253#ifdef CONFIG_IWLWIFI_DEBUG
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index e42eb6499f0e..ac88ff042d46 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -762,7 +762,8 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
762 * find the highest tx power from all chains for the channel 762 * find the highest tx power from all chains for the channel
763 */ 763 */
764static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, 764static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
765 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element) 765 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
766 int element, s8 *max_txpower_in_half_dbm)
766{ 767{
767 s8 max_txpower_avg = 0; /* (dBm) */ 768 s8 max_txpower_avg = 0; /* (dBm) */
768 769
@@ -794,10 +795,14 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
794 (enhanced_txpower[element].mimo3_max > max_txpower_avg)) 795 (enhanced_txpower[element].mimo3_max > max_txpower_avg))
795 max_txpower_avg = enhanced_txpower[element].mimo3_max; 796 max_txpower_avg = enhanced_txpower[element].mimo3_max;
796 797
797 /* max. tx power in EEPROM is in 1/2 dBm format 798 /*
798 * convert from 1/2 dBm to dBm 799 * max. tx power in EEPROM is in 1/2 dBm format
800 * convert from 1/2 dBm to dBm (round-up convert)
801 * but we also do not want to loss 1/2 dBm resolution which
802 * will impact performance
799 */ 803 */
800 return max_txpower_avg >> 1; 804 *max_txpower_in_half_dbm = max_txpower_avg;
805 return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
801} 806}
802 807
803/** 808/**
@@ -806,7 +811,7 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
806 */ 811 */
807static s8 iwl_update_common_txpower(struct iwl_priv *priv, 812static s8 iwl_update_common_txpower(struct iwl_priv *priv,
808 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, 813 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
809 int section, int element) 814 int section, int element, s8 *max_txpower_in_half_dbm)
810{ 815{
811 struct iwl_channel_info *ch_info; 816 struct iwl_channel_info *ch_info;
812 int ch; 817 int ch;
@@ -820,20 +825,22 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv,
820 if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) 825 if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
821 is_ht40 = true; 826 is_ht40 = true;
822 max_txpower_avg = 827 max_txpower_avg =
823 iwl_get_max_txpower_avg(priv, enhanced_txpower, element); 828 iwl_get_max_txpower_avg(priv, enhanced_txpower,
829 element, max_txpower_in_half_dbm);
830
824 ch_info = priv->channel_info; 831 ch_info = priv->channel_info;
825 832
826 for (ch = 0; ch < priv->channel_count; ch++) { 833 for (ch = 0; ch < priv->channel_count; ch++) {
827 /* find matching band and update tx power if needed */ 834 /* find matching band and update tx power if needed */
828 if ((ch_info->band == enhinfo[section].band) && 835 if ((ch_info->band == enhinfo[section].band) &&
829 (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) { 836 (ch_info->max_power_avg < max_txpower_avg) &&
837 (!is_ht40)) {
830 /* Update regulatory-based run-time data */ 838 /* Update regulatory-based run-time data */
831 ch_info->max_power_avg = ch_info->curr_txpow = 839 ch_info->max_power_avg = ch_info->curr_txpow =
832 max_txpower_avg; 840 max_txpower_avg;
833 ch_info->scan_power = max_txpower_avg; 841 ch_info->scan_power = max_txpower_avg;
834 } 842 }
835 if ((ch_info->band == enhinfo[section].band) && is_ht40 && 843 if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
836 ch_info->ht40_max_power_avg &&
837 (ch_info->ht40_max_power_avg < max_txpower_avg)) { 844 (ch_info->ht40_max_power_avg < max_txpower_avg)) {
838 /* Update regulatory-based run-time data */ 845 /* Update regulatory-based run-time data */
839 ch_info->ht40_max_power_avg = max_txpower_avg; 846 ch_info->ht40_max_power_avg = max_txpower_avg;
@@ -849,7 +856,7 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv,
849 */ 856 */
850static s8 iwl_update_channel_txpower(struct iwl_priv *priv, 857static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
851 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, 858 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
852 int section, int element) 859 int section, int element, s8 *max_txpower_in_half_dbm)
853{ 860{
854 struct iwl_channel_info *ch_info; 861 struct iwl_channel_info *ch_info;
855 int ch; 862 int ch;
@@ -858,7 +865,8 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
858 865
859 channel = enhinfo[section].iwl_eeprom_section_channel[element]; 866 channel = enhinfo[section].iwl_eeprom_section_channel[element];
860 max_txpower_avg = 867 max_txpower_avg =
861 iwl_get_max_txpower_avg(priv, enhanced_txpower, element); 868 iwl_get_max_txpower_avg(priv, enhanced_txpower,
869 element, max_txpower_in_half_dbm);
862 870
863 ch_info = priv->channel_info; 871 ch_info = priv->channel_info;
864 for (ch = 0; ch < priv->channel_count; ch++) { 872 for (ch = 0; ch < priv->channel_count; ch++) {
@@ -872,7 +880,6 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
872 ch_info->scan_power = max_txpower_avg; 880 ch_info->scan_power = max_txpower_avg;
873 } 881 }
874 if ((enhinfo[section].is_ht40) && 882 if ((enhinfo[section].is_ht40) &&
875 (ch_info->ht40_max_power_avg) &&
876 (ch_info->ht40_max_power_avg < max_txpower_avg)) { 883 (ch_info->ht40_max_power_avg < max_txpower_avg)) {
877 /* Update regulatory-based run-time data */ 884 /* Update regulatory-based run-time data */
878 ch_info->ht40_max_power_avg = max_txpower_avg; 885 ch_info->ht40_max_power_avg = max_txpower_avg;
@@ -894,6 +901,7 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
894 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; 901 struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
895 u32 offset; 902 u32 offset;
896 s8 max_txpower_avg; /* (dBm) */ 903 s8 max_txpower_avg; /* (dBm) */
904 s8 max_txpower_in_half_dbm; /* (half-dBm) */
897 905
898 /* Loop through all the sections 906 /* Loop through all the sections
899 * adjust bands and channel's max tx power 907 * adjust bands and channel's max tx power
@@ -920,16 +928,29 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
920 if (enhinfo[section].is_common) 928 if (enhinfo[section].is_common)
921 max_txpower_avg = 929 max_txpower_avg =
922 iwl_update_common_txpower(priv, 930 iwl_update_common_txpower(priv,
923 enhanced_txpower, section, element); 931 enhanced_txpower, section,
932 element,
933 &max_txpower_in_half_dbm);
924 else 934 else
925 max_txpower_avg = 935 max_txpower_avg =
926 iwl_update_channel_txpower(priv, 936 iwl_update_channel_txpower(priv,
927 enhanced_txpower, section, element); 937 enhanced_txpower, section,
938 element,
939 &max_txpower_in_half_dbm);
928 940
929 /* Update the tx_power_user_lmt to the highest power 941 /* Update the tx_power_user_lmt to the highest power
930 * supported by any channel */ 942 * supported by any channel */
931 if (max_txpower_avg > priv->tx_power_user_lmt) 943 if (max_txpower_avg > priv->tx_power_user_lmt)
932 priv->tx_power_user_lmt = max_txpower_avg; 944 priv->tx_power_user_lmt = max_txpower_avg;
945
946 /*
947 * Update the tx_power_lmt_in_half_dbm to
948 * the highest power supported by any channel
949 */
950 if (max_txpower_in_half_dbm >
951 priv->tx_power_lmt_in_half_dbm)
952 priv->tx_power_lmt_in_half_dbm =
953 max_txpower_in_half_dbm;
933 } 954 }
934 } 955 }
935} 956}