diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-eeprom.c')
| -rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-eeprom.c | 75 |
1 files changed, 51 insertions, 24 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 8a0709e81a9f..3946e5c03f81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c | |||
| @@ -518,6 +518,11 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
| 518 | } | 518 | } |
| 519 | e = (u16 *)priv->eeprom; | 519 | e = (u16 *)priv->eeprom; |
| 520 | 520 | ||
| 521 | if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { | ||
| 522 | /* OTP reads require powered-up chip */ | ||
| 523 | priv->cfg->ops->lib->apm_ops.init(priv); | ||
| 524 | } | ||
| 525 | |||
| 521 | ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); | 526 | ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); |
| 522 | if (ret < 0) { | 527 | if (ret < 0) { |
| 523 | IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); | 528 | IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); |
| @@ -532,10 +537,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
| 532 | ret = -ENOENT; | 537 | ret = -ENOENT; |
| 533 | goto err; | 538 | goto err; |
| 534 | } | 539 | } |
| 535 | if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { | ||
| 536 | 540 | ||
| 537 | /* OTP reads require powered-up chip */ | 541 | if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { |
| 538 | priv->cfg->ops->lib->apm_ops.init(priv); | ||
| 539 | 542 | ||
| 540 | ret = iwl_init_otp_access(priv); | 543 | ret = iwl_init_otp_access(priv); |
| 541 | if (ret) { | 544 | if (ret) { |
| @@ -751,9 +754,6 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, | |||
| 751 | 754 | ||
| 752 | ch_info->ht40_eeprom = *eeprom_ch; | 755 | ch_info->ht40_eeprom = *eeprom_ch; |
| 753 | ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; | 756 | ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; |
| 754 | ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg; | ||
| 755 | ch_info->ht40_min_power = 0; | ||
| 756 | ch_info->ht40_scan_power = eeprom_ch->max_power_avg; | ||
| 757 | ch_info->ht40_flags = eeprom_ch->flags; | 757 | ch_info->ht40_flags = eeprom_ch->flags; |
| 758 | ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; | 758 | ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; |
| 759 | 759 | ||
| @@ -765,7 +765,8 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, | |||
| 765 | * find the highest tx power from all chains for the channel | 765 | * find the highest tx power from all chains for the channel |
| 766 | */ | 766 | */ |
| 767 | static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, | 767 | static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, |
| 768 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element) | 768 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, |
| 769 | int element, s8 *max_txpower_in_half_dbm) | ||
| 769 | { | 770 | { |
| 770 | s8 max_txpower_avg = 0; /* (dBm) */ | 771 | s8 max_txpower_avg = 0; /* (dBm) */ |
| 771 | 772 | ||
| @@ -797,10 +798,14 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, | |||
| 797 | (enhanced_txpower[element].mimo3_max > max_txpower_avg)) | 798 | (enhanced_txpower[element].mimo3_max > max_txpower_avg)) |
| 798 | max_txpower_avg = enhanced_txpower[element].mimo3_max; | 799 | max_txpower_avg = enhanced_txpower[element].mimo3_max; |
| 799 | 800 | ||
| 800 | /* max. tx power in EEPROM is in 1/2 dBm format | 801 | /* |
| 801 | * convert from 1/2 dBm to dBm | 802 | * max. tx power in EEPROM is in 1/2 dBm format |
| 803 | * convert from 1/2 dBm to dBm (round-up convert) | ||
| 804 | * but we also do not want to loss 1/2 dBm resolution which | ||
| 805 | * will impact performance | ||
| 802 | */ | 806 | */ |
| 803 | return max_txpower_avg >> 1; | 807 | *max_txpower_in_half_dbm = max_txpower_avg; |
| 808 | return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1); | ||
| 804 | } | 809 | } |
| 805 | 810 | ||
| 806 | /** | 811 | /** |
| @@ -809,7 +814,7 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, | |||
| 809 | */ | 814 | */ |
| 810 | static s8 iwl_update_common_txpower(struct iwl_priv *priv, | 815 | static s8 iwl_update_common_txpower(struct iwl_priv *priv, |
| 811 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, | 816 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, |
| 812 | int section, int element) | 817 | int section, int element, s8 *max_txpower_in_half_dbm) |
| 813 | { | 818 | { |
| 814 | struct iwl_channel_info *ch_info; | 819 | struct iwl_channel_info *ch_info; |
| 815 | int ch; | 820 | int ch; |
| @@ -823,25 +828,25 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv, | |||
| 823 | if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) | 828 | if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) |
| 824 | is_ht40 = true; | 829 | is_ht40 = true; |
| 825 | max_txpower_avg = | 830 | max_txpower_avg = |
| 826 | iwl_get_max_txpower_avg(priv, enhanced_txpower, element); | 831 | iwl_get_max_txpower_avg(priv, enhanced_txpower, |
| 832 | element, max_txpower_in_half_dbm); | ||
| 833 | |||
| 827 | ch_info = priv->channel_info; | 834 | ch_info = priv->channel_info; |
| 828 | 835 | ||
| 829 | for (ch = 0; ch < priv->channel_count; ch++) { | 836 | for (ch = 0; ch < priv->channel_count; ch++) { |
| 830 | /* find matching band and update tx power if needed */ | 837 | /* find matching band and update tx power if needed */ |
| 831 | if ((ch_info->band == enhinfo[section].band) && | 838 | if ((ch_info->band == enhinfo[section].band) && |
| 832 | (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) { | 839 | (ch_info->max_power_avg < max_txpower_avg) && |
| 840 | (!is_ht40)) { | ||
| 833 | /* Update regulatory-based run-time data */ | 841 | /* Update regulatory-based run-time data */ |
| 834 | ch_info->max_power_avg = ch_info->curr_txpow = | 842 | ch_info->max_power_avg = ch_info->curr_txpow = |
| 835 | max_txpower_avg; | 843 | max_txpower_avg; |
| 836 | ch_info->scan_power = max_txpower_avg; | 844 | ch_info->scan_power = max_txpower_avg; |
| 837 | } | 845 | } |
| 838 | if ((ch_info->band == enhinfo[section].band) && is_ht40 && | 846 | if ((ch_info->band == enhinfo[section].band) && is_ht40 && |
| 839 | ch_info->ht40_max_power_avg && | ||
| 840 | (ch_info->ht40_max_power_avg < max_txpower_avg)) { | 847 | (ch_info->ht40_max_power_avg < max_txpower_avg)) { |
| 841 | /* Update regulatory-based run-time data */ | 848 | /* Update regulatory-based run-time data */ |
| 842 | ch_info->ht40_max_power_avg = max_txpower_avg; | 849 | ch_info->ht40_max_power_avg = max_txpower_avg; |
| 843 | ch_info->ht40_curr_txpow = max_txpower_avg; | ||
| 844 | ch_info->ht40_scan_power = max_txpower_avg; | ||
| 845 | } | 850 | } |
| 846 | ch_info++; | 851 | ch_info++; |
| 847 | } | 852 | } |
| @@ -854,7 +859,7 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv, | |||
| 854 | */ | 859 | */ |
| 855 | static s8 iwl_update_channel_txpower(struct iwl_priv *priv, | 860 | static s8 iwl_update_channel_txpower(struct iwl_priv *priv, |
| 856 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, | 861 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, |
| 857 | int section, int element) | 862 | int section, int element, s8 *max_txpower_in_half_dbm) |
| 858 | { | 863 | { |
| 859 | struct iwl_channel_info *ch_info; | 864 | struct iwl_channel_info *ch_info; |
| 860 | int ch; | 865 | int ch; |
| @@ -863,7 +868,8 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, | |||
| 863 | 868 | ||
| 864 | channel = enhinfo[section].iwl_eeprom_section_channel[element]; | 869 | channel = enhinfo[section].iwl_eeprom_section_channel[element]; |
| 865 | max_txpower_avg = | 870 | max_txpower_avg = |
| 866 | iwl_get_max_txpower_avg(priv, enhanced_txpower, element); | 871 | iwl_get_max_txpower_avg(priv, enhanced_txpower, |
| 872 | element, max_txpower_in_half_dbm); | ||
| 867 | 873 | ||
| 868 | ch_info = priv->channel_info; | 874 | ch_info = priv->channel_info; |
| 869 | for (ch = 0; ch < priv->channel_count; ch++) { | 875 | for (ch = 0; ch < priv->channel_count; ch++) { |
| @@ -877,12 +883,9 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, | |||
| 877 | ch_info->scan_power = max_txpower_avg; | 883 | ch_info->scan_power = max_txpower_avg; |
| 878 | } | 884 | } |
| 879 | if ((enhinfo[section].is_ht40) && | 885 | if ((enhinfo[section].is_ht40) && |
| 880 | (ch_info->ht40_max_power_avg) && | ||
| 881 | (ch_info->ht40_max_power_avg < max_txpower_avg)) { | 886 | (ch_info->ht40_max_power_avg < max_txpower_avg)) { |
| 882 | /* Update regulatory-based run-time data */ | 887 | /* Update regulatory-based run-time data */ |
| 883 | ch_info->ht40_max_power_avg = max_txpower_avg; | 888 | ch_info->ht40_max_power_avg = max_txpower_avg; |
| 884 | ch_info->ht40_curr_txpow = max_txpower_avg; | ||
| 885 | ch_info->ht40_scan_power = max_txpower_avg; | ||
| 886 | } | 889 | } |
| 887 | break; | 890 | break; |
| 888 | } | 891 | } |
| @@ -901,6 +904,7 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) | |||
| 901 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; | 904 | struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; |
| 902 | u32 offset; | 905 | u32 offset; |
| 903 | s8 max_txpower_avg; /* (dBm) */ | 906 | s8 max_txpower_avg; /* (dBm) */ |
| 907 | s8 max_txpower_in_half_dbm; /* (half-dBm) */ | ||
| 904 | 908 | ||
| 905 | /* Loop through all the sections | 909 | /* Loop through all the sections |
| 906 | * adjust bands and channel's max tx power | 910 | * adjust bands and channel's max tx power |
| @@ -913,20 +917,43 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) | |||
| 913 | enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) | 917 | enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) |
| 914 | iwl_eeprom_query_addr(priv, offset); | 918 | iwl_eeprom_query_addr(priv, offset); |
| 915 | 919 | ||
| 920 | /* | ||
| 921 | * check for valid entry - | ||
| 922 | * different version of EEPROM might contain different set | ||
| 923 | * of enhanced tx power table | ||
| 924 | * always check for valid entry before process | ||
| 925 | * the information | ||
| 926 | */ | ||
| 927 | if (!enhanced_txpower->common || enhanced_txpower->reserved) | ||
| 928 | continue; | ||
| 929 | |||
| 916 | for (element = 0; element < eeprom_section_count; element++) { | 930 | for (element = 0; element < eeprom_section_count; element++) { |
| 917 | if (enhinfo[section].is_common) | 931 | if (enhinfo[section].is_common) |
| 918 | max_txpower_avg = | 932 | max_txpower_avg = |
| 919 | iwl_update_common_txpower(priv, | 933 | iwl_update_common_txpower(priv, |
| 920 | enhanced_txpower, section, element); | 934 | enhanced_txpower, section, |
| 935 | element, | ||
| 936 | &max_txpower_in_half_dbm); | ||
| 921 | else | 937 | else |
| 922 | max_txpower_avg = | 938 | max_txpower_avg = |
| 923 | iwl_update_channel_txpower(priv, | 939 | iwl_update_channel_txpower(priv, |
| 924 | enhanced_txpower, section, element); | 940 | enhanced_txpower, section, |
| 941 | element, | ||
| 942 | &max_txpower_in_half_dbm); | ||
| 925 | 943 | ||
| 926 | /* Update the tx_power_user_lmt to the highest power | 944 | /* Update the tx_power_user_lmt to the highest power |
| 927 | * supported by any channel */ | 945 | * supported by any channel */ |
| 928 | if (max_txpower_avg > priv->tx_power_user_lmt) | 946 | if (max_txpower_avg > priv->tx_power_user_lmt) |
| 929 | priv->tx_power_user_lmt = max_txpower_avg; | 947 | priv->tx_power_user_lmt = max_txpower_avg; |
| 948 | |||
| 949 | /* | ||
| 950 | * Update the tx_power_lmt_in_half_dbm to | ||
| 951 | * the highest power supported by any channel | ||
| 952 | */ | ||
| 953 | if (max_txpower_in_half_dbm > | ||
| 954 | priv->tx_power_lmt_in_half_dbm) | ||
| 955 | priv->tx_power_lmt_in_half_dbm = | ||
| 956 | max_txpower_in_half_dbm; | ||
| 930 | } | 957 | } |
| 931 | } | 958 | } |
| 932 | } | 959 | } |
