diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2009-11-13 14:56:30 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-11-18 17:09:05 -0500 |
commit | ae16fc3c3184bf27f0462e1951df918122498829 (patch) | |
tree | 6bfe0c4d2f7bd7572d9dcbe7c28f788d78d868ac | |
parent | 4d6ccbf57ff7653217b7149976aa31e19f996544 (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.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-eeprom.c | 49 |
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 | */ |
764 | static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, | 764 | static 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 | */ |
807 | static s8 iwl_update_common_txpower(struct iwl_priv *priv, | 812 | static 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 | */ |
850 | static s8 iwl_update_channel_txpower(struct iwl_priv *priv, | 857 | static 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 | } |