From: Gabor Juhos Date: Mon, 16 Feb 2009 19:43:55 +0000 (+0000) Subject: mac80211: reorder patches X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=b234ca85f19e0edfe7db759fd8d7a33a82909119;p=openwrt%2Fstaging%2Fldir.git mac80211: reorder patches SVN-Revision: 14533 --- diff --git a/package/mac80211/patches/007-remove_unused_stuff.patch b/package/mac80211/patches/007-remove_unused_stuff.patch new file mode 100644 index 0000000000..e7ab07469a --- /dev/null +++ b/package/mac80211/patches/007-remove_unused_stuff.patch @@ -0,0 +1,82 @@ +--- a/config.mk ++++ b/config.mk +@@ -90,10 +90,10 @@ CONFIG_MAC80211_MESH=y + CONFIG_CFG80211=m + # CONFIG_CFG80211_REG_DEBUG is not set + +-CONFIG_LIB80211=m +-CONFIG_LIB80211_CRYPT_WEP=m +-CONFIG_LIB80211_CRYPT_CCMP=m +-CONFIG_LIB80211_CRYPT_TKIP=m ++# CONFIG_LIB80211=m ++# CONFIG_LIB80211_CRYPT_WEP=m ++# CONFIG_LIB80211_CRYPT_CCMP=m ++# CONFIG_LIB80211_CRYPT_TKIP=m + + CONFIG_NL80211=y + +@@ -133,16 +133,16 @@ CONFIG_IWL3945_LEDS=y + CONFIG_B43=m + CONFIG_B43_PCI_AUTOSELECT=y + CONFIG_B43_PCICORE_AUTOSELECT=y +-CONFIG_B43_PCMCIA=y ++# CONFIG_B43_PCMCIA=y + CONFIG_B43_PIO=y +-CONFIG_B43_LEDS=y ++# CONFIG_B43_LEDS=y + # CONFIG_B43_RFKILL=y + # CONFIG_B43_DEBUG is not set + + CONFIG_B43LEGACY=m + CONFIG_B43LEGACY_PCI_AUTOSELECT=y + CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +-CONFIG_B43LEGACY_LEDS=y ++# CONFIG_B43LEGACY_LEDS=y + # CONFIG_B43LEGACY_RFKILL=y + # CONFIG_B43LEGACY_DEBUG=y + CONFIG_B43LEGACY_DMA=y +@@ -152,17 +152,17 @@ CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y + # CONFIG_B43LEGACY_PIO_MODE is not set + + # The Intel ipws +-CONFIG_LIBIPW=m ++# CONFIG_LIBIPW=m + # CONFIG_LIBIPW_DEBUG is not set + +-CONFIG_IPW2100=m +-CONFIG_IPW2100_MONITOR=y ++# CONFIG_IPW2100=m ++# CONFIG_IPW2100_MONITOR=y + # CONFIG_IPW2100_DEBUG is not set +-CONFIG_IPW2200=m +-CONFIG_IPW2200_MONITOR=y +-CONFIG_IPW2200_RADIOTAP=y +-CONFIG_IPW2200_PROMISCUOUS=y +-CONFIG_IPW2200_QOS=y ++# CONFIG_IPW2200=m ++# CONFIG_IPW2200_MONITOR=y ++# CONFIG_IPW2200_RADIOTAP=y ++# CONFIG_IPW2200_PROMISCUOUS=y ++# CONFIG_IPW2200_QOS=y + # CONFIG_IPW2200_DEBUG is not set + # The above enables use a second interface prefixed 'rtap'. + # Example usage: +@@ -284,15 +284,15 @@ CONFIG_SSB_SPROM=y + ifneq ($(CONFIG_USB),) + ifneq ($(CONFIG_LIBERTAS_THINFIRM_USB),m) + CONFIG_LIBERTAS_USB=m +-NEED_LIBERTAS=y ++#NEED_LIBERTAS=y + endif + endif + ifneq ($(CONFIG_PCMCIA),) + CONFIG_LIBERTAS_CS=m +-NEED_LIBERTAS=y ++#NEED_LIBERTAS=y + endif + ifeq ($(NEED_LIBERTAS),y) +-CONFIG_LIBERTAS=m ++#CONFIG_LIBERTAS=m + # Libertas uses the old stack but not fully, it will soon + # be cleaned. + endif diff --git a/package/mac80211/patches/201-ath5k_eeprom.patch b/package/mac80211/patches/201-ath5k_eeprom.patch new file mode 100644 index 0000000000..3f62eefb92 --- /dev/null +++ b/package/mac80211/patches/201-ath5k_eeprom.patch @@ -0,0 +1,494 @@ +Clean up the eeprom parsing code and prepare the pdgain +data for 2413, which will be required for power calibration code. +Also clean up some ugly line wrapping to make the code easier on +the eyes. + +Signed-off-by: Felix Fietkau + +--- a/drivers/net/wireless/ath5k/eeprom.c ++++ b/drivers/net/wireless/ath5k/eeprom.c +@@ -541,31 +541,30 @@ ath5k_eeprom_read_freq_list(struct ath5k + { + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int o = *offset; +- int i = 0; ++ int i; + u8 freq1, freq2; + int ret; + u16 val; + ++ ee->ee_n_piers[mode] = 0; + while(i < max) { + AR5K_EEPROM_READ(o++, val); + +- freq1 = (val >> 8) & 0xff; +- freq2 = val & 0xff; +- +- if (freq1) { +- pc[i++].freq = ath5k_eeprom_bin2freq(ee, +- freq1, mode); +- ee->ee_n_piers[mode]++; +- } ++ freq1 = val & 0xff; ++ if (!freq1) ++ break; + +- if (freq2) { +- pc[i++].freq = ath5k_eeprom_bin2freq(ee, +- freq2, mode); +- ee->ee_n_piers[mode]++; +- } ++ pc[i++].freq = ath5k_eeprom_bin2freq(ee, ++ freq1, mode); ++ ee->ee_n_piers[mode]++; + +- if (!freq1 || !freq2) ++ freq2 = (val >> 8) & 0xff; ++ if (!freq2) + break; ++ ++ pc[i++].freq = ath5k_eeprom_bin2freq(ee, ++ freq2, mode); ++ ee->ee_n_piers[mode]++; + } + + /* return new offset */ +@@ -918,84 +917,46 @@ ath5k_cal_data_offset_2413(struct ath5k_ + * curves on eeprom. The final curve (higher power) has an extra + * point for better accuracy like RF5112. + */ ++ + static int +-ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) ++ath5k_eeprom_parse_pcal_info_2413(struct ath5k_hw *ah, int mode, u32 offset, ++ struct ath5k_chan_pcal_info *chinfo) + { + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; +- struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info; +- struct ath5k_chan_pcal_info *gen_chan_info; +- unsigned int i, c; +- u32 offset; ++ struct ath5k_chan_pcal_info_rf2413 *pcinfo; ++ unsigned int i; + int ret; + u16 val; +- u8 pd_gains = 0; +- +- if (ee->ee_x_gain[mode] & 0x1) pd_gains++; +- if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++; +- if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++; +- if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++; +- ee->ee_pd_gains[mode] = pd_gains; ++ u8 pd_gains; + +- offset = ath5k_cal_data_offset_2413(ee, mode); +- ee->ee_n_piers[mode] = 0; +- switch (mode) { +- case AR5K_EEPROM_MODE_11A: +- if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) +- return 0; +- +- ath5k_eeprom_init_11a_pcal_freq(ah, offset); +- offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; +- gen_chan_info = ee->ee_pwr_cal_a; +- break; +- case AR5K_EEPROM_MODE_11B: +- if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) +- return 0; +- +- ath5k_eeprom_init_11bg_2413(ah, mode, offset); +- offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; +- gen_chan_info = ee->ee_pwr_cal_b; +- break; +- case AR5K_EEPROM_MODE_11G: +- if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) +- return 0; +- +- ath5k_eeprom_init_11bg_2413(ah, mode, offset); +- offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; +- gen_chan_info = ee->ee_pwr_cal_g; +- break; +- default: +- return -EINVAL; +- } ++ pd_gains = ee->ee_pd_gains[mode]; + + if (pd_gains == 0) + return 0; + + for (i = 0; i < ee->ee_n_piers[mode]; i++) { +- chan_pcal_info = &gen_chan_info[i].rf2413_info; ++ pcinfo = &chinfo[i].rf2413_info; + + /* + * Read pwr_i, pddac_i and the first + * 2 pd points (pwr, pddac) + */ + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr_i[0] = val & 0x1f; +- chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f; +- chan_pcal_info->pwr[0][0] = +- (val >> 12) & 0xf; ++ pcinfo->pwr_i[0] = val & 0x1f; ++ pcinfo->pddac_i[0] = (val >> 5) & 0x7f; ++ pcinfo->pwr[0][0] = (val >> 12) & 0xf; + + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[0][0] = val & 0x3f; +- chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf; +- chan_pcal_info->pddac[0][1] = +- (val >> 10) & 0x3f; ++ pcinfo->pddac[0][0] = val & 0x3f; ++ pcinfo->pwr[0][1] = (val >> 6) & 0xf; ++ pcinfo->pddac[0][1] = (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr[0][2] = val & 0xf; +- chan_pcal_info->pddac[0][2] = +- (val >> 4) & 0x3f; ++ pcinfo->pwr[0][2] = val & 0xf; ++ pcinfo->pddac[0][2] = (val >> 4) & 0x3f; + +- chan_pcal_info->pwr[0][3] = 0; +- chan_pcal_info->pddac[0][3] = 0; ++ pcinfo->pwr[0][3] = 0; ++ pcinfo->pddac[0][3] = 0; + + if (pd_gains > 1) { + /* +@@ -1003,44 +964,36 @@ ath5k_eeprom_read_pcal_info_2413(struct + * so it only has 2 pd points. + * Continue wih pd gain 1. + */ +- chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f; ++ pcinfo->pwr_i[1] = (val >> 10) & 0x1f; + +- chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1; ++ pcinfo->pddac_i[1] = (val >> 15) & 0x1; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1; ++ pcinfo->pddac_i[1] |= (val & 0x3F) << 1; + +- chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf; +- chan_pcal_info->pddac[1][0] = +- (val >> 10) & 0x3f; ++ pcinfo->pwr[1][0] = (val >> 6) & 0xf; ++ pcinfo->pddac[1][0] = (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr[1][1] = val & 0xf; +- chan_pcal_info->pddac[1][1] = +- (val >> 4) & 0x3f; +- chan_pcal_info->pwr[1][2] = +- (val >> 10) & 0xf; ++ pcinfo->pwr[1][1] = val & 0xf; ++ pcinfo->pddac[1][1] = (val >> 4) & 0x3f; ++ pcinfo->pwr[1][2] = (val >> 10) & 0xf; + +- chan_pcal_info->pddac[1][2] = +- (val >> 14) & 0x3; ++ pcinfo->pddac[1][2] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[1][2] |= +- (val & 0xF) << 2; ++ pcinfo->pddac[1][2] |= (val & 0xF) << 2; + +- chan_pcal_info->pwr[1][3] = 0; +- chan_pcal_info->pddac[1][3] = 0; ++ pcinfo->pwr[1][3] = 0; ++ pcinfo->pddac[1][3] = 0; + } else if (pd_gains == 1) { + /* + * Pd gain 0 is the last one so + * read the extra point. + */ +- chan_pcal_info->pwr[0][3] = +- (val >> 10) & 0xf; ++ pcinfo->pwr[0][3] = (val >> 10) & 0xf; + +- chan_pcal_info->pddac[0][3] = +- (val >> 14) & 0x3; ++ pcinfo->pddac[0][3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[0][3] |= +- (val & 0xF) << 2; ++ pcinfo->pddac[0][3] |= (val & 0xF) << 2; + } + + /* +@@ -1048,105 +1001,159 @@ ath5k_eeprom_read_pcal_info_2413(struct + * as above. + */ + if (pd_gains > 2) { +- chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f; +- chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f; ++ pcinfo->pwr_i[2] = (val >> 4) & 0x1f; ++ pcinfo->pddac_i[2] = (val >> 9) & 0x7f; + + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr[2][0] = +- (val >> 0) & 0xf; +- chan_pcal_info->pddac[2][0] = +- (val >> 4) & 0x3f; +- chan_pcal_info->pwr[2][1] = +- (val >> 10) & 0xf; +- +- chan_pcal_info->pddac[2][1] = +- (val >> 14) & 0x3; +- AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[2][1] |= +- (val & 0xF) << 2; +- +- chan_pcal_info->pwr[2][2] = +- (val >> 4) & 0xf; +- chan_pcal_info->pddac[2][2] = +- (val >> 8) & 0x3f; ++ pcinfo->pwr[2][0] = (val >> 0) & 0xf; ++ pcinfo->pddac[2][0] = (val >> 4) & 0x3f; ++ pcinfo->pwr[2][1] = (val >> 10) & 0xf; + +- chan_pcal_info->pwr[2][3] = 0; +- chan_pcal_info->pddac[2][3] = 0; ++ pcinfo->pddac[2][1] = (val >> 14) & 0x3; ++ AR5K_EEPROM_READ(offset++, val); ++ pcinfo->pddac[2][1] |= (val & 0xF) << 2; ++ ++ pcinfo->pwr[2][2] = (val >> 4) & 0xf; ++ pcinfo->pddac[2][2] = (val >> 8) & 0x3f; ++ ++ pcinfo->pwr[2][3] = 0; ++ pcinfo->pddac[2][3] = 0; + } else if (pd_gains == 2) { +- chan_pcal_info->pwr[1][3] = +- (val >> 4) & 0xf; +- chan_pcal_info->pddac[1][3] = +- (val >> 8) & 0x3f; ++ pcinfo->pwr[1][3] = (val >> 4) & 0xf; ++ pcinfo->pddac[1][3] = (val >> 8) & 0x3f; + } + + if (pd_gains > 3) { +- chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3; ++ pcinfo->pwr_i[3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2; ++ pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2; + +- chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f; +- chan_pcal_info->pwr[3][0] = +- (val >> 10) & 0xf; +- chan_pcal_info->pddac[3][0] = +- (val >> 14) & 0x3; ++ pcinfo->pddac_i[3] = (val >> 3) & 0x7f; ++ pcinfo->pwr[3][0] = (val >> 10) & 0xf; ++ pcinfo->pddac[3][0] = (val >> 14) & 0x3; + + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[3][0] |= +- (val & 0xF) << 2; +- chan_pcal_info->pwr[3][1] = +- (val >> 4) & 0xf; +- chan_pcal_info->pddac[3][1] = +- (val >> 8) & 0x3f; ++ pcinfo->pddac[3][0] |= (val & 0xF) << 2; ++ pcinfo->pwr[3][1] = (val >> 4) & 0xf; ++ pcinfo->pddac[3][1] = (val >> 8) & 0x3f; + +- chan_pcal_info->pwr[3][2] = +- (val >> 14) & 0x3; ++ pcinfo->pwr[3][2] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr[3][2] |= +- ((val >> 0) & 0x3) << 2; ++ pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2; + +- chan_pcal_info->pddac[3][2] = +- (val >> 2) & 0x3f; +- chan_pcal_info->pwr[3][3] = +- (val >> 8) & 0xf; ++ pcinfo->pddac[3][2] = (val >> 2) & 0x3f; ++ pcinfo->pwr[3][3] = (val >> 8) & 0xf; + +- chan_pcal_info->pddac[3][3] = +- (val >> 12) & 0xF; ++ pcinfo->pddac[3][3] = (val >> 12) & 0xF; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pddac[3][3] |= +- ((val >> 0) & 0x3) << 4; ++ pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4; + } else if (pd_gains == 3) { +- chan_pcal_info->pwr[2][3] = +- (val >> 14) & 0x3; ++ pcinfo->pwr[2][3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); +- chan_pcal_info->pwr[2][3] |= +- ((val >> 0) & 0x3) << 2; ++ pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2; + +- chan_pcal_info->pddac[2][3] = +- (val >> 2) & 0x3f; ++ pcinfo->pddac[2][3] = (val >> 2) & 0x3f; + } ++ } ++ return 0; ++} ++ ++static int ++ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, ++ struct ath5k_chan_pcal_info *chinfo, ++ unsigned int *xgains) ++{ ++ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; ++ struct ath5k_chan_pcal_info_rf2413 *pcinfo; ++ unsigned int i, j, k; + +- for (c = 0; c < pd_gains; c++) { +- /* Recreate pwr table for this channel using pwr steps */ +- chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2; +- chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0]; +- chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1]; +- chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2]; +- if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2]) +- chan_pcal_info->pwr[c][3] = 0; +- +- /* Recreate pddac table for this channel using pddac steps */ +- chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c]; +- chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0]; +- chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1]; +- chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2]; +- if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2]) +- chan_pcal_info->pddac[c][3] = 0; ++ /* prepare the raw values */ ++ for (i = 0; i < ee->ee_n_piers[mode]; i++) { ++ pcinfo = &chinfo[i].rf2413_info; ++ for (j = 0; j < ee->ee_pd_gains[mode]; j++) { ++ unsigned int idx = xgains[j]; ++ struct ath5k_pdgain_info *pd = &pcinfo->pdgains[idx]; ++ ++ /* one more point for the highest power (lowest gain) */ ++ if (j == ee->ee_pd_gains[mode] - 1) { ++ pd->n_vpd = AR5K_EEPROM_N_PD_POINTS; ++ } else { ++ pd->n_vpd = AR5K_EEPROM_N_PD_POINTS - 1; ++ } ++ ++ pd->vpd[0] = pcinfo->pddac_i[j]; ++ pd->pwr_t4[0] = 4 * pcinfo->pwr_i[j]; ++ for (k = 1; k < pd->n_vpd; k++) { ++ pd->pwr_t4[k] = pd->pwr_t4[k - 1] + 2 * pcinfo->pwr[j][k - 1]; ++ pd->vpd[k] = pd->vpd[k - 1] + pcinfo->pddac[j][k - 1]; ++ } + } + } + + return 0; + } + ++static int ++ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) ++{ ++ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; ++ struct ath5k_chan_pcal_info *chinfo; ++ unsigned int xgains[AR5K_EEPROM_N_PD_GAINS]; ++ u32 offset; ++ u8 pd_gains = 0; ++ int i, ret; ++ ++ memset(xgains, 0, sizeof(xgains)); ++ for (i = 0; i < AR5K_EEPROM_N_PD_GAINS; i++) { ++ int idx = AR5K_EEPROM_N_PD_GAINS - i - 1; ++ ++ if ((ee->ee_x_gain[mode] >> idx) & 0x1) ++ xgains[pd_gains++] = idx; ++ } ++ ee->ee_pd_gains[mode] = pd_gains; ++ ++ offset = ath5k_cal_data_offset_2413(ee, mode); ++ switch (mode) { ++ case AR5K_EEPROM_MODE_11A: ++ if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) ++ return 0; ++ ++ ath5k_eeprom_init_11a_pcal_freq(ah, offset); ++ offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; ++ chinfo = ee->ee_pwr_cal_a; ++ break; ++ case AR5K_EEPROM_MODE_11B: ++ if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) ++ return 0; ++ ++ ath5k_eeprom_init_11bg_2413(ah, mode, offset); ++ offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; ++ chinfo = ee->ee_pwr_cal_b; ++ break; ++ case AR5K_EEPROM_MODE_11G: ++ if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) ++ return 0; ++ ++ ath5k_eeprom_init_11bg_2413(ah, mode, offset); ++ offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; ++ chinfo = ee->ee_pwr_cal_g; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ++ ret = ath5k_eeprom_parse_pcal_info_2413(ah, mode, offset, chinfo); ++ if (ret) ++ return ret; ++ ++ ret = ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo, xgains); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ + /* + * Read per rate target power (this is the maximum tx power + * supported by the card). This info is used when setting +@@ -1264,6 +1271,7 @@ ath5k_eeprom_read_pcal_info(struct ath5k + else + read_pcal = ath5k_eeprom_read_pcal_info_5111; + ++ + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { + err = read_pcal(ah, mode); + if (err) +--- a/drivers/net/wireless/ath5k/eeprom.h ++++ b/drivers/net/wireless/ath5k/eeprom.h +@@ -266,15 +266,27 @@ struct ath5k_chan_pcal_info_rf5112 { + u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; + }; + ++ ++struct ath5k_pdgain_info { ++ u16 n_vpd; ++ u16 vpd[AR5K_EEPROM_N_PD_POINTS]; ++ s16 pwr_t4[AR5K_EEPROM_N_PD_POINTS]; ++}; ++ + struct ath5k_chan_pcal_info_rf2413 { ++ /* --- EEPROM VALUES --- */ + /* Starting pwr/pddac values */ +- s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; +- u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; ++ s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; ++ u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; + /* (pwr,pddac) points */ +- s8 pwr[AR5K_EEPROM_N_PD_GAINS] +- [AR5K_EEPROM_N_PD_POINTS]; +- u8 pddac[AR5K_EEPROM_N_PD_GAINS] +- [AR5K_EEPROM_N_PD_POINTS]; ++ s8 pwr[AR5K_EEPROM_N_PD_GAINS] ++ [AR5K_EEPROM_N_PD_POINTS]; ++ u8 pddac[AR5K_EEPROM_N_PD_GAINS] ++ [AR5K_EEPROM_N_PD_POINTS]; ++ ++ /* --- RAW VALUES --- */ ++ struct ath5k_pdgain_info pdgains ++ [AR5K_EEPROM_N_PD_GAINS]; + }; + + struct ath5k_chan_pcal_info { diff --git a/package/mac80211/patches/202-ath5k_txpower_2413.patch b/package/mac80211/patches/202-ath5k_txpower_2413.patch new file mode 100644 index 0000000000..ddecd9e071 --- /dev/null +++ b/package/mac80211/patches/202-ath5k_txpower_2413.patch @@ -0,0 +1,672 @@ +Implement the power curve interpolation, which is required for +proper tx on 2413 and newer RF designs. + +Signed-off-by: Felix Fietkau + +--- a/drivers/net/wireless/ath5k/phy.c ++++ b/drivers/net/wireless/ath5k/phy.c +@@ -4,6 +4,7 @@ + * Copyright (c) 2004-2007 Reyk Floeter + * Copyright (c) 2006-2009 Nick Kossifidis + * Copyright (c) 2007-2008 Jiri Slaby ++ * Copyright (c) 2008-2009 Felix Fietkau + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -1438,31 +1439,449 @@ unsigned int ath5k_hw_get_def_antenna(st + */ + + /* +- * Initialize the tx power table (not fully implemented) ++ * find the lower and upper index of the values in the table surrounding the target value + */ +-static void ath5k_txpower_table(struct ath5k_hw *ah, +- struct ieee80211_channel *channel, s16 max_power) ++static void ++ath5k_get_table_index(const u16 *tbl, unsigned int tbl_sz, u16 target, ++ unsigned int idx[2]) + { +- unsigned int i, min, max, n; +- u16 txpower, *rates; ++ const u16 *ti; + +- rates = ah->ah_txpower.txp_rates; ++ if (target < tbl[0]) { ++ idx[0] = idx[1] = 0; ++ return; ++ } ++ ++ if (target > tbl[tbl_sz - 1]) { ++ idx[0] = idx[1] = tbl_sz - 1; ++ return; ++ } ++ ++ /* look for the surrounding values */ ++ for (ti = tbl; ti < &tbl[tbl_sz - 1]; ti++) { ++ ++ /* if the value is equal to the target, set lo = hi = index */ ++ if (*ti == target) { ++ idx[0] = idx[1] = ti - tbl; ++ return; ++ } ++ ++ /* if the target is between the current value and the next one, ++ * set lo = cur, hi = lo + 1 */ ++ if (target < ti[1]) { ++ idx[0] = ti - tbl; ++ idx[1] = idx[0] + 1; ++ return; ++ } ++ } ++} ++ ++/* find the lower and upper frequency info */ ++static void ++ath5k_get_freq_tables(struct ath5k_hw *ah, struct ieee80211_channel *channel, ++ struct ath5k_chan_pcal_info **pcinfo_l, ++ struct ath5k_chan_pcal_info **pcinfo_r, ++ struct ath5k_rate_pcal_info *rates) ++{ ++ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; ++ struct ath5k_chan_pcal_info *pcinfo; ++ unsigned int idx_l, idx_r; ++ int mode, max, i; ++ unsigned int target = channel->center_freq; ++ struct ath5k_rate_pcal_info *rpinfo; ++ ++ if (!(channel->hw_value & CHANNEL_OFDM)) { ++ pcinfo = ee->ee_pwr_cal_b; ++ rpinfo = ee->ee_rate_tpwr_b; ++ mode = AR5K_EEPROM_MODE_11B; ++ } else if (channel->hw_value & CHANNEL_2GHZ) { ++ pcinfo = ee->ee_pwr_cal_g; ++ rpinfo = ee->ee_rate_tpwr_g; ++ mode = AR5K_EEPROM_MODE_11G; ++ } else { ++ pcinfo = ee->ee_pwr_cal_a; ++ rpinfo = ee->ee_rate_tpwr_a; ++ mode = AR5K_EEPROM_MODE_11A; ++ } ++ max = ee->ee_n_piers[mode] - 1; ++ ++ if (target < pcinfo[0].freq) { ++ idx_l = idx_r = 0; ++ goto done; ++ } ++ ++ if (target > pcinfo[max].freq) { ++ idx_l = idx_r = max; ++ goto done; ++ } ++ ++ /* look for the surrounding values */ ++ for (i = 0; i <= max; i++) { ++ ++ /* if the value is equal to the target, set lo = hi = index */ ++ if (pcinfo[i].freq == target) { ++ idx_l = idx_r = i; ++ goto done; ++ } ++ ++ /* if the target is between the current value and the next one, ++ * set lo = cur, hi = lo + 1 */ ++ if (target < pcinfo[i].freq) { ++ idx_l = i; ++ idx_r = idx_l + 1; ++ goto done; ++ } ++ } ++ ++done: ++ *pcinfo_l = &pcinfo[idx_l]; ++ *pcinfo_r = &pcinfo[idx_r]; ++ ++ if (!rates) ++ return; ++ ++ /* rate info minimum values */ ++ rates->freq = channel->center_freq; ++ rates->target_power_6to24 = ++ min(rpinfo[idx_l].target_power_6to24, ++ rpinfo[idx_r].target_power_6to24); ++ rates->target_power_36 = ++ min(rpinfo[idx_l].target_power_36, ++ rpinfo[idx_r].target_power_36); ++ rates->target_power_48 = ++ min(rpinfo[idx_l].target_power_48, ++ rpinfo[idx_r].target_power_48); ++ rates->target_power_54 = ++ min(rpinfo[idx_l].target_power_54, ++ rpinfo[idx_r].target_power_54); ++} ++ ++ ++/* Fill the VPD table for all indices between pmin and pmax */ ++static void ++ath5k_fill_vpdtable(s16 pmin, s16 pmax, const s16 *pwr, ++ const u16 *vpd, unsigned int intercepts, ++ u16 vpdtable[AR5K_EEPROM_POWER_TABLE_SIZE]) ++{ ++ unsigned int idx[2] = { 0, 0 }; ++ s16 cur_pwr = 2 * pmin; ++ int i; ++ ++ if (intercepts < 2) ++ return; ++ ++ for(i = 0; i <= (pmax - pmin); i++) { ++ ath5k_get_table_index(pwr, intercepts, cur_pwr, idx); ++ ++ if (!idx[1]) ++ idx[1] = 1; ++ ++ if (idx[0] == intercepts - 1) ++ idx[0] = intercepts - 2; ++ ++ if (pwr[idx[0]] == pwr[idx[1]]) ++ vpdtable[i] = vpd[idx[0]]; ++ else ++ vpdtable[i] = (((cur_pwr - pwr[idx[0]]) * vpd[idx[1]] + ++ (pwr[idx[1]] - cur_pwr) * vpd[idx[0]]) / ++ (pwr[idx[1]] - pwr[idx[0]])); ++ ++ cur_pwr += 2; ++ } ++} ++ ++static inline s16 ++ath5k_interpolate_signed(u16 ref, u16 ref_l, u16 ref_r, s16 val_l, s16 val_r) ++{ ++ if (ref_l == ref_r) ++ return val_l; ++ ++ return ((ref - ref_l)*val_r + (ref_r - ref)*val_l) / (ref_r - ref_l); ++} ++ ++static inline s16 ++ath5k_get_min_power_2413(struct ath5k_chan_pcal_info *pcinfo) ++{ ++ struct ath5k_pdgain_info *pd; ++ int i; ++ ++ /* backwards - highest pdgain == lowest power */ ++ for (i = AR5K_EEPROM_N_PD_GAINS - 1; i >= 0; i--) { ++ pd = &pcinfo->rf2413_info.pdgains[i]; ++ if (!pd->n_vpd) ++ continue; ++ ++ return pd->pwr_t4[0]; ++ } ++ return 0; ++} ++ ++static inline s16 ++ath5k_get_max_power_2413(struct ath5k_chan_pcal_info *pcinfo) ++{ ++ struct ath5k_pdgain_info *pd; ++ int i; ++ ++ /* forwards: lowest pdgain == highest power */ ++ for (i = 0; i < AR5K_EEPROM_N_PD_GAINS; i++) { ++ pd = &pcinfo->rf2413_info.pdgains[i]; ++ if (!pd->n_vpd) ++ continue; ++ ++ return pd->pwr_t4[pd->n_vpd]; ++ } ++ return 0; ++} ++ ++ ++ ++static int ++ath5k_txpower_table_2413(struct ath5k_hw *ah, struct ieee80211_channel *ch, ++ struct ath5k_chan_pcal_info *pcinfo_l, ++ struct ath5k_chan_pcal_info *pcinfo_r) ++{ ++ struct ath5k_pdgain_info *pd_l, *pd_r; ++ u16 gain_boundaries[4]; ++ u16 *xpd = ah->ah_txpower.txp_xpd; ++ int n_xpd = 0; ++ s16 pmin_t2[AR5K_EEPROM_N_PD_GAINS]; ++ s16 pmax_t2[AR5K_EEPROM_N_PD_GAINS]; ++ u16 *pdadc_out = ah->ah_txpower.txp_pcdac; ++ unsigned int gain_overlap; ++ unsigned int vpd_size, target_idx, max_idx; ++ unsigned int n_pdadc = 0; ++ u16 vpd_step; ++ u16 *pcdacL; ++ u16 *pcdacR; ++ int i, j, s; ++ u32 reg; ++ s16 ch_pmin, ch_pmax; ++ ++ gain_overlap = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) & ++ AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP; ++ ++ /* loop backwards over pdgains (highest pdgain == lowest power) */ ++ for (i = AR5K_EEPROM_N_PD_GAINS - 1; i >= 0; i--) { ++ pd_l = &pcinfo_l->rf2413_info.pdgains[i]; ++ pd_r = &pcinfo_r->rf2413_info.pdgains[i]; ++ pcdacL = ah->ah_txpower.txp_rfdata.rf2413.pcdacL[n_xpd]; ++ pcdacR = ah->ah_txpower.txp_rfdata.rf2413.pcdacR[n_xpd]; ++ ++ if (!pd_l->n_vpd) ++ continue; ++ ++ xpd[n_xpd] = i; ++ ++ pmin_t2[n_xpd] = min(pd_l->pwr_t4[0], pd_r->pwr_t4[0]) / 2; ++ pmax_t2[n_xpd] = min(pd_l->pwr_t4[pd_l->n_vpd - 1], ++ pd_r->pwr_t4[pd_r->n_vpd - 1]) / 2; ++ ++ if ((u16) (pmax_t2[n_xpd] - pmin_t2[n_xpd]) > 64) ++ continue; ++ ++ /* fill vpd tables for left and right frequency info */ ++ ath5k_fill_vpdtable(pmin_t2[n_xpd], pmax_t2[n_xpd], ++ pd_l->pwr_t4, pd_l->vpd, pd_l->n_vpd, pcdacL); ++ ++ /* check if interpolation is necessary */ ++ if (pcinfo_l == pcinfo_r) ++ continue; ++ ++ ath5k_fill_vpdtable(pmin_t2[n_xpd], pmax_t2[n_xpd], ++ pd_r->pwr_t4, pd_r->vpd, pd_r->n_vpd, pcdacR); ++ ++ /* interpolate pcdac values, ++ * reuse pcdacL table for interpolation output */ ++ for (j = 0; j < (u16) (pmax_t2[n_xpd] - pmin_t2[n_xpd]); j++) { ++ pcdacL[j] = ath5k_interpolate_signed(ch->center_freq, ++ pcinfo_l->freq, pcinfo_r->freq, ++ (s16) pcdacL[j], (s16) pcdacR[j]); ++ } ++ n_xpd++; ++ } ++ ++ if (!n_xpd) ++ return 0; ++ ++ /* create final table */ ++ for (i = 0, n_pdadc = 0; i < n_xpd; i++) { ++ pcdacL = ah->ah_txpower.txp_rfdata.rf2413.pcdacL[i]; ++ ++ if (i == n_xpd - 1) { ++ /* 2 db boundary stretch */ ++ gain_boundaries[i] = pmax_t2[i] + 4; ++ } else { ++ gain_boundaries[i] = (pmax_t2[i] + pmin_t2[i + 1]) / 2; ++ } ++ ++ if (gain_boundaries[i] > AR5K_TUNE_MAX_TXPOWER) ++ gain_boundaries[i] = AR5K_TUNE_MAX_TXPOWER; ++ ++ /* find starting index */ ++ if (i == 0) ++ s = 0; ++ else ++ s = (gain_boundaries[i - 1] - pmin_t2[i]) - ++ gain_overlap; ++ ++ if (pcdacL[1] > pcdacL[0]) ++ vpd_step = pcdacL[1] - pcdacL[0]; ++ else ++ vpd_step = 1; ++ ++ /* if s is below 0, we need to extrapolate below this pdgain */ ++ while ((s < 0) && (n_pdadc < 128)) { ++ s16 tmp = pcdacL[0] + s * vpd_step; ++ pdadc_out[n_pdadc++] = (u16) ((tmp < 0) ? 0 : tmp); ++ s++; ++ } ++ ++ vpd_size = pmax_t2[i] - pmin_t2[i]; ++ target_idx = gain_boundaries[i] + gain_overlap - pmin_t2[i]; ++ max_idx = (target_idx < vpd_size) ? target_idx : vpd_size; ++ ++ while ((s < (s16) max_idx) && (n_pdadc < 128)) ++ pdadc_out[n_pdadc++] = pcdacL[s++]; ++ ++ /* need to extrapolate above this pdgain? */ ++ if (target_idx <= max_idx) ++ continue; + +- txpower = AR5K_TUNE_DEFAULT_TXPOWER * 2; +- if (max_power > txpower) +- txpower = max_power > AR5K_TUNE_MAX_TXPOWER ? +- AR5K_TUNE_MAX_TXPOWER : max_power; ++ if (pcdacL[vpd_size - 1] > pcdacL[vpd_size - 2]) ++ vpd_step = pcdacL[vpd_size - 1] - pcdacL[vpd_size - 2]; ++ else ++ vpd_step = 1; + +- for (i = 0; i < AR5K_MAX_RATES; i++) +- rates[i] = txpower; ++ while ((s < (s16) target_idx) && (n_pdadc < 128)) { ++ int tmp = pcdacL[vpd_size - 1] + ++ (s - max_idx) * vpd_step; ++ pdadc_out[n_pdadc++] = (tmp > 127) ? 127 : tmp; ++ s++; ++ } ++ } + +- /* XXX setup target powers by rate */ ++ while (i < AR5K_EEPROM_N_PD_GAINS) { ++ gain_boundaries[i] = gain_boundaries[i - 1]; ++ i++; ++ } ++ ++ while (n_pdadc < 128) { ++ pdadc_out[n_pdadc] = pdadc_out[n_pdadc - 1]; ++ n_pdadc++; ++ } ++ ++ /* select the right xpdgain curves */ ++ reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1); ++ reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 | ++ AR5K_PHY_TPC_RG1_PDGAIN_2 | ++ AR5K_PHY_TPC_RG1_PDGAIN_3 | ++ AR5K_PHY_TPC_RG1_NUM_PD_GAIN); ++ reg |= AR5K_REG_SM(n_xpd, AR5K_PHY_TPC_RG1_NUM_PD_GAIN); ++ switch(n_xpd) { ++ case 3: ++ reg |= AR5K_REG_SM(xpd[2], AR5K_PHY_TPC_RG1_PDGAIN_3); ++ /* fall through */ ++ case 2: ++ reg |= AR5K_REG_SM(xpd[1], AR5K_PHY_TPC_RG1_PDGAIN_2); ++ /* fall through */ ++ case 1: ++ reg |= AR5K_REG_SM(xpd[0], AR5K_PHY_TPC_RG1_PDGAIN_1); ++ break; ++ } ++ ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1); + ++ /* ++ * Write TX power values ++ */ ++ reg = AR5K_PHY_PDADC_TXPOWER_BASE; ++ for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { ++ ath5k_hw_reg_write(ah, ++ ((pdadc_out[4*i + 0] & 0xff) << 0) | ++ ((pdadc_out[4*i + 1] & 0xff) << 8) | ++ ((pdadc_out[4*i + 2] & 0xff) << 16) | ++ ((pdadc_out[4*i + 3] & 0xff) << 24), reg); ++ reg += 4; ++ } ++ ++ ath5k_hw_reg_write(ah, ++ AR5K_REG_SM(gain_overlap, ++ AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) | ++ AR5K_REG_SM(gain_boundaries[0], ++ AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) | ++ AR5K_REG_SM(gain_boundaries[1], ++ AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) | ++ AR5K_REG_SM(gain_boundaries[2], ++ AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) | ++ AR5K_REG_SM(gain_boundaries[3], ++ AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4), ++ AR5K_PHY_TPC_RG5); ++ ++ ah->ah_txpower.txp_offset = pmin_t2[0]; ++ ++ /* look up power boundaries for this channel */ ++ ch_pmin = ath5k_get_min_power_2413(pcinfo_l); ++ ch_pmax = ath5k_get_max_power_2413(pcinfo_l); ++ ++ if (pcinfo_l != pcinfo_r) { ++ s16 pwr_r; ++ ++ pwr_r = ath5k_get_min_power_2413(pcinfo_r); ++ ch_pmin = ath5k_interpolate_signed(ch->center_freq, ++ pcinfo_l->freq, pcinfo_r->freq, ++ ch_pmin, pwr_r); ++ ++ pwr_r = ath5k_get_max_power_2413(pcinfo_r); ++ ch_pmax = ath5k_interpolate_signed(ch->center_freq, ++ pcinfo_l->freq, pcinfo_r->freq, ++ ch_pmax, pwr_r); ++ } ++ ah->ah_txpower.txp_min = ch_pmin; ++ ah->ah_txpower.txp_max = ch_pmax; ++ ++ return 0; ++} ++ ++static void ++ath5k_setup_rate_table(struct ath5k_hw *ah, u16 max_pwr, ++ struct ath5k_rate_pcal_info *rate_info) ++{ ++ unsigned int i; ++ u16 *rates; ++ ++ max_pwr *= 2; ++ max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max); ++ ++ /* apply rate limits */ ++ rates = ah->ah_txpower.txp_rates; ++ for (i = 0; i < 5; i++) { ++ rates[i] = min(max_pwr, rate_info->target_power_6to24); ++ } ++ rates[5] = min(rates[0], rate_info->target_power_36); ++ rates[6] = min(rates[0], rate_info->target_power_48); ++ rates[7] = min(rates[0], rate_info->target_power_54); ++ rates[8] = min(rates[0], rate_info->target_power_6to24); ++ rates[9] = min(rates[0], rate_info->target_power_36); ++ rates[10] = min(rates[0], rate_info->target_power_36); ++ rates[11] = min(rates[0], rate_info->target_power_48); ++ rates[12] = min(rates[0], rate_info->target_power_48); ++ rates[13] = min(rates[0], rate_info->target_power_54); ++ rates[14] = min(rates[0], rate_info->target_power_54); ++ ++ ah->ah_txpower.txp_tpc = max_pwr; + ah->ah_txpower.txp_min = rates[7]; +- ah->ah_txpower.txp_max = rates[0]; +- ah->ah_txpower.txp_ofdm = rates[0]; ++ ah->ah_txpower.txp_max = min(ah->ah_txpower.txp_max, ++ (s16) rate_info->target_power_36); ++ ah->ah_txpower.txp_ofdm = ah->ah_txpower.txp_max; ++} ++ ++static int ++ath5k_txpower_table(struct ath5k_hw *ah, struct ieee80211_channel *ch, ++ struct ath5k_chan_pcal_info *pcinfo_l, ++ struct ath5k_chan_pcal_info *pcinfo_r, ++ u16 max_pwr) ++{ ++ unsigned int i, min, max, n; + +- /* Calculate the power table */ + n = ARRAY_SIZE(ah->ah_txpower.txp_pcdac); + min = AR5K_EEPROM_PCDAC_START; + max = AR5K_EEPROM_PCDAC_STOP; +@@ -1473,51 +1892,64 @@ static void ath5k_txpower_table(struct a + #else + min; + #endif ++ ++ /* ++ * Write TX power values ++ */ ++ for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { ++ ath5k_hw_reg_write(ah, ++ ((((ah->ah_txpower.txp_pcdac[(i << 1) + 1] << 8) | ++ 0xff) & 0xffff) << 16) | ++ (((ah->ah_txpower.txp_pcdac[(i << 1) ] << 8) | ++ 0xff) & 0xffff), ++ AR5K_PHY_PCDAC_TXPOWER(i)); ++ } ++ return 0; + } + ++ + /* + * Set transmition power + */ +-int /*O.K. - txpower_table is unimplemented so this doesn't work*/ ++int + ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, + unsigned int txpower) + { ++ struct ath5k_chan_pcal_info *pcinfo_l, *pcinfo_r; ++ struct ath5k_rate_pcal_info rate_info; + bool tpc = ah->ah_txpower.txp_tpc; +- unsigned int i; + + ATH5K_TRACE(ah->ah_sc); + if (txpower > AR5K_TUNE_MAX_TXPOWER) { + ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); + return -EINVAL; + } +- +- /* +- * RF2413 for some reason can't +- * transmit anything if we call +- * this funtion, so we skip it +- * until we fix txpower. +- * +- * XXX: Assume same for RF2425 +- * to be safe. +- */ +- if ((ah->ah_radio == AR5K_RF2413) || (ah->ah_radio == AR5K_RF2425)) +- return 0; ++ if (txpower == 0) ++ txpower = AR5K_TUNE_MAX_TXPOWER; + + /* Reset TX power values */ + memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); + ah->ah_txpower.txp_tpc = tpc; ++ ah->ah_txpower.txp_min = 0; ++ ah->ah_txpower.txp_max = AR5K_TUNE_MAX_TXPOWER; + +- /* Initialize TX power table */ +- ath5k_txpower_table(ah, channel, txpower); ++ /* find matching frequency info */ ++ ath5k_get_freq_tables(ah, channel, &pcinfo_l, &pcinfo_r, &rate_info); ++ ath5k_setup_rate_table(ah, txpower, &rate_info); + +- /* +- * Write TX power values +- */ +- for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { +- ath5k_hw_reg_write(ah, +- ((((ah->ah_txpower.txp_pcdac[(i << 1) + 1] << 8) | 0xff) & 0xffff) << 16) | +- (((ah->ah_txpower.txp_pcdac[(i << 1) ] << 8) | 0xff) & 0xffff), +- AR5K_PHY_PCDAC_TXPOWER(i)); ++ /* Initialize TX power table */ ++ switch(ah->ah_radio) { ++ case AR5K_RF2413: ++ case AR5K_RF5413: ++ ath5k_txpower_table_2413(ah, channel, pcinfo_l, pcinfo_r); ++ break; ++ case AR5K_RF2425: ++ /* unimplemented */ ++ return 0; ++ default: ++ /* Default power table */ ++ ath5k_txpower_table(ah, channel, pcinfo_l, pcinfo_r, txpower); ++ break; + } + + ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) | +@@ -1536,12 +1968,19 @@ ath5k_hw_txpower(struct ath5k_hw *ah, st + AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | + AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); + +- if (ah->ah_txpower.txp_tpc) ++ if (ah->ah_txpower.txp_tpc) { + ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | + AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); +- else ++ ++ ath5k_hw_reg_write(ah, ++ AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) | ++ AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) | ++ AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP), ++ AR5K_TPC); ++ } else { + ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | + AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); ++ } + + return 0; + } +--- a/drivers/net/wireless/ath5k/ath5k.h ++++ b/drivers/net/wireless/ath5k/ath5k.h +@@ -204,7 +204,7 @@ + #define AR5K_TUNE_CWMAX_11B 1023 + #define AR5K_TUNE_CWMAX_XR 7 + #define AR5K_TUNE_NOISE_FLOOR -72 +-#define AR5K_TUNE_MAX_TXPOWER 60 ++#define AR5K_TUNE_MAX_TXPOWER 63 + #define AR5K_TUNE_DEFAULT_TXPOWER 30 + #define AR5K_TUNE_TPC_TXPOWER true + #define AR5K_TUNE_ANT_DIVERSITY true +@@ -1085,11 +1085,23 @@ struct ath5k_hw { + struct ath5k_gain ah_gain; + u8 ah_offset[AR5K_MAX_RF_BANKS]; + ++ + struct { +- u16 txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE]; ++ union { ++ struct { ++ /* Temporary PCDAC tables for interpolation */ ++ u16 pcdacL[AR5K_EEPROM_N_PD_GAINS] ++ [AR5K_EEPROM_POWER_TABLE_SIZE]; ++ u16 pcdacR[AR5K_EEPROM_N_PD_GAINS] ++ [AR5K_EEPROM_POWER_TABLE_SIZE]; ++ } rf2413; ++ } txp_rfdata; ++ u16 txp_xpd[AR5K_EEPROM_N_XPD_PER_CHANNEL]; ++ u16 txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE * 2]; + u16 txp_rates[AR5K_MAX_RATES]; + s16 txp_min; + s16 txp_max; ++ s16 txp_offset; + bool txp_tpc; + s16 txp_ofdm; + } ah_txpower; +--- a/drivers/net/wireless/ath5k/reg.h ++++ b/drivers/net/wireless/ath5k/reg.h +@@ -1552,6 +1552,15 @@ + + + /*===5212 Specific PCU registers===*/ ++#define AR5K_TPC 0x80e8 ++#define AR5K_TPC_ACK 0x0000003f /* ack frames */ ++#define AR5K_TPC_ACK_S 0 ++#define AR5K_TPC_CTS 0x00003f00 /* cts frames */ ++#define AR5K_TPC_CTS_S 8 ++#define AR5K_TPC_CHIRP 0x003f0000 /* chirp frames */ ++#define AR5K_TPC_CHIRP_S 16 ++#define AR5K_TPC_DOPPLER 0x0f000000 /* doppler chirp span */ ++#define AR5K_TPC_DOPPLER_S 24 + + /* + * XR (eXtended Range) mode register +@@ -2550,6 +2559,12 @@ + #define AR5K_PHY_TPC_RG1 0xa258 + #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN 0x0000c000 + #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S 14 ++#define AR5K_PHY_TPC_RG1_PDGAIN_1 0x00030000 ++#define AR5K_PHY_TPC_RG1_PDGAIN_1_S 16 ++#define AR5K_PHY_TPC_RG1_PDGAIN_2 0x000c0000 ++#define AR5K_PHY_TPC_RG1_PDGAIN_2_S 18 ++#define AR5K_PHY_TPC_RG1_PDGAIN_3 0x00300000 ++#define AR5K_PHY_TPC_RG1_PDGAIN_3_S 20 + + #define AR5K_PHY_TPC_RG5 0xa26C + #define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP 0x0000000F +--- a/drivers/net/wireless/ath5k/desc.c ++++ b/drivers/net/wireless/ath5k/desc.c +@@ -194,6 +194,10 @@ static int ath5k_hw_setup_4word_tx_desc( + return -EINVAL; + } + ++ tx_power += ah->ah_txpower.txp_offset; ++ if (tx_power > AR5K_TUNE_MAX_TXPOWER) ++ tx_power = AR5K_TUNE_MAX_TXPOWER; ++ + /* Clear descriptor */ + memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); + diff --git a/package/mac80211/patches/210-remove_unused_stuff.patch b/package/mac80211/patches/210-remove_unused_stuff.patch deleted file mode 100644 index e7ab07469a..0000000000 --- a/package/mac80211/patches/210-remove_unused_stuff.patch +++ /dev/null @@ -1,82 +0,0 @@ ---- a/config.mk -+++ b/config.mk -@@ -90,10 +90,10 @@ CONFIG_MAC80211_MESH=y - CONFIG_CFG80211=m - # CONFIG_CFG80211_REG_DEBUG is not set - --CONFIG_LIB80211=m --CONFIG_LIB80211_CRYPT_WEP=m --CONFIG_LIB80211_CRYPT_CCMP=m --CONFIG_LIB80211_CRYPT_TKIP=m -+# CONFIG_LIB80211=m -+# CONFIG_LIB80211_CRYPT_WEP=m -+# CONFIG_LIB80211_CRYPT_CCMP=m -+# CONFIG_LIB80211_CRYPT_TKIP=m - - CONFIG_NL80211=y - -@@ -133,16 +133,16 @@ CONFIG_IWL3945_LEDS=y - CONFIG_B43=m - CONFIG_B43_PCI_AUTOSELECT=y - CONFIG_B43_PCICORE_AUTOSELECT=y --CONFIG_B43_PCMCIA=y -+# CONFIG_B43_PCMCIA=y - CONFIG_B43_PIO=y --CONFIG_B43_LEDS=y -+# CONFIG_B43_LEDS=y - # CONFIG_B43_RFKILL=y - # CONFIG_B43_DEBUG is not set - - CONFIG_B43LEGACY=m - CONFIG_B43LEGACY_PCI_AUTOSELECT=y - CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y --CONFIG_B43LEGACY_LEDS=y -+# CONFIG_B43LEGACY_LEDS=y - # CONFIG_B43LEGACY_RFKILL=y - # CONFIG_B43LEGACY_DEBUG=y - CONFIG_B43LEGACY_DMA=y -@@ -152,17 +152,17 @@ CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y - # CONFIG_B43LEGACY_PIO_MODE is not set - - # The Intel ipws --CONFIG_LIBIPW=m -+# CONFIG_LIBIPW=m - # CONFIG_LIBIPW_DEBUG is not set - --CONFIG_IPW2100=m --CONFIG_IPW2100_MONITOR=y -+# CONFIG_IPW2100=m -+# CONFIG_IPW2100_MONITOR=y - # CONFIG_IPW2100_DEBUG is not set --CONFIG_IPW2200=m --CONFIG_IPW2200_MONITOR=y --CONFIG_IPW2200_RADIOTAP=y --CONFIG_IPW2200_PROMISCUOUS=y --CONFIG_IPW2200_QOS=y -+# CONFIG_IPW2200=m -+# CONFIG_IPW2200_MONITOR=y -+# CONFIG_IPW2200_RADIOTAP=y -+# CONFIG_IPW2200_PROMISCUOUS=y -+# CONFIG_IPW2200_QOS=y - # CONFIG_IPW2200_DEBUG is not set - # The above enables use a second interface prefixed 'rtap'. - # Example usage: -@@ -284,15 +284,15 @@ CONFIG_SSB_SPROM=y - ifneq ($(CONFIG_USB),) - ifneq ($(CONFIG_LIBERTAS_THINFIRM_USB),m) - CONFIG_LIBERTAS_USB=m --NEED_LIBERTAS=y -+#NEED_LIBERTAS=y - endif - endif - ifneq ($(CONFIG_PCMCIA),) - CONFIG_LIBERTAS_CS=m --NEED_LIBERTAS=y -+#NEED_LIBERTAS=y - endif - ifeq ($(NEED_LIBERTAS),y) --CONFIG_LIBERTAS=m -+#CONFIG_LIBERTAS=m - # Libertas uses the old stack but not fully, it will soon - # be cleaned. - endif diff --git a/package/mac80211/patches/330-ath5k_eeprom.patch b/package/mac80211/patches/330-ath5k_eeprom.patch deleted file mode 100644 index 3f62eefb92..0000000000 --- a/package/mac80211/patches/330-ath5k_eeprom.patch +++ /dev/null @@ -1,494 +0,0 @@ -Clean up the eeprom parsing code and prepare the pdgain -data for 2413, which will be required for power calibration code. -Also clean up some ugly line wrapping to make the code easier on -the eyes. - -Signed-off-by: Felix Fietkau - ---- a/drivers/net/wireless/ath5k/eeprom.c -+++ b/drivers/net/wireless/ath5k/eeprom.c -@@ -541,31 +541,30 @@ ath5k_eeprom_read_freq_list(struct ath5k - { - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - int o = *offset; -- int i = 0; -+ int i; - u8 freq1, freq2; - int ret; - u16 val; - -+ ee->ee_n_piers[mode] = 0; - while(i < max) { - AR5K_EEPROM_READ(o++, val); - -- freq1 = (val >> 8) & 0xff; -- freq2 = val & 0xff; -- -- if (freq1) { -- pc[i++].freq = ath5k_eeprom_bin2freq(ee, -- freq1, mode); -- ee->ee_n_piers[mode]++; -- } -+ freq1 = val & 0xff; -+ if (!freq1) -+ break; - -- if (freq2) { -- pc[i++].freq = ath5k_eeprom_bin2freq(ee, -- freq2, mode); -- ee->ee_n_piers[mode]++; -- } -+ pc[i++].freq = ath5k_eeprom_bin2freq(ee, -+ freq1, mode); -+ ee->ee_n_piers[mode]++; - -- if (!freq1 || !freq2) -+ freq2 = (val >> 8) & 0xff; -+ if (!freq2) - break; -+ -+ pc[i++].freq = ath5k_eeprom_bin2freq(ee, -+ freq2, mode); -+ ee->ee_n_piers[mode]++; - } - - /* return new offset */ -@@ -918,84 +917,46 @@ ath5k_cal_data_offset_2413(struct ath5k_ - * curves on eeprom. The final curve (higher power) has an extra - * point for better accuracy like RF5112. - */ -+ - static int --ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) -+ath5k_eeprom_parse_pcal_info_2413(struct ath5k_hw *ah, int mode, u32 offset, -+ struct ath5k_chan_pcal_info *chinfo) - { - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; -- struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info; -- struct ath5k_chan_pcal_info *gen_chan_info; -- unsigned int i, c; -- u32 offset; -+ struct ath5k_chan_pcal_info_rf2413 *pcinfo; -+ unsigned int i; - int ret; - u16 val; -- u8 pd_gains = 0; -- -- if (ee->ee_x_gain[mode] & 0x1) pd_gains++; -- if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++; -- if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++; -- if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++; -- ee->ee_pd_gains[mode] = pd_gains; -+ u8 pd_gains; - -- offset = ath5k_cal_data_offset_2413(ee, mode); -- ee->ee_n_piers[mode] = 0; -- switch (mode) { -- case AR5K_EEPROM_MODE_11A: -- if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) -- return 0; -- -- ath5k_eeprom_init_11a_pcal_freq(ah, offset); -- offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; -- gen_chan_info = ee->ee_pwr_cal_a; -- break; -- case AR5K_EEPROM_MODE_11B: -- if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) -- return 0; -- -- ath5k_eeprom_init_11bg_2413(ah, mode, offset); -- offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; -- gen_chan_info = ee->ee_pwr_cal_b; -- break; -- case AR5K_EEPROM_MODE_11G: -- if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) -- return 0; -- -- ath5k_eeprom_init_11bg_2413(ah, mode, offset); -- offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; -- gen_chan_info = ee->ee_pwr_cal_g; -- break; -- default: -- return -EINVAL; -- } -+ pd_gains = ee->ee_pd_gains[mode]; - - if (pd_gains == 0) - return 0; - - for (i = 0; i < ee->ee_n_piers[mode]; i++) { -- chan_pcal_info = &gen_chan_info[i].rf2413_info; -+ pcinfo = &chinfo[i].rf2413_info; - - /* - * Read pwr_i, pddac_i and the first - * 2 pd points (pwr, pddac) - */ - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pwr_i[0] = val & 0x1f; -- chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f; -- chan_pcal_info->pwr[0][0] = -- (val >> 12) & 0xf; -+ pcinfo->pwr_i[0] = val & 0x1f; -+ pcinfo->pddac_i[0] = (val >> 5) & 0x7f; -+ pcinfo->pwr[0][0] = (val >> 12) & 0xf; - - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pddac[0][0] = val & 0x3f; -- chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf; -- chan_pcal_info->pddac[0][1] = -- (val >> 10) & 0x3f; -+ pcinfo->pddac[0][0] = val & 0x3f; -+ pcinfo->pwr[0][1] = (val >> 6) & 0xf; -+ pcinfo->pddac[0][1] = (val >> 10) & 0x3f; - - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pwr[0][2] = val & 0xf; -- chan_pcal_info->pddac[0][2] = -- (val >> 4) & 0x3f; -+ pcinfo->pwr[0][2] = val & 0xf; -+ pcinfo->pddac[0][2] = (val >> 4) & 0x3f; - -- chan_pcal_info->pwr[0][3] = 0; -- chan_pcal_info->pddac[0][3] = 0; -+ pcinfo->pwr[0][3] = 0; -+ pcinfo->pddac[0][3] = 0; - - if (pd_gains > 1) { - /* -@@ -1003,44 +964,36 @@ ath5k_eeprom_read_pcal_info_2413(struct - * so it only has 2 pd points. - * Continue wih pd gain 1. - */ -- chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f; -+ pcinfo->pwr_i[1] = (val >> 10) & 0x1f; - -- chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1; -+ pcinfo->pddac_i[1] = (val >> 15) & 0x1; - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1; -+ pcinfo->pddac_i[1] |= (val & 0x3F) << 1; - -- chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf; -- chan_pcal_info->pddac[1][0] = -- (val >> 10) & 0x3f; -+ pcinfo->pwr[1][0] = (val >> 6) & 0xf; -+ pcinfo->pddac[1][0] = (val >> 10) & 0x3f; - - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pwr[1][1] = val & 0xf; -- chan_pcal_info->pddac[1][1] = -- (val >> 4) & 0x3f; -- chan_pcal_info->pwr[1][2] = -- (val >> 10) & 0xf; -+ pcinfo->pwr[1][1] = val & 0xf; -+ pcinfo->pddac[1][1] = (val >> 4) & 0x3f; -+ pcinfo->pwr[1][2] = (val >> 10) & 0xf; - -- chan_pcal_info->pddac[1][2] = -- (val >> 14) & 0x3; -+ pcinfo->pddac[1][2] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pddac[1][2] |= -- (val & 0xF) << 2; -+ pcinfo->pddac[1][2] |= (val & 0xF) << 2; - -- chan_pcal_info->pwr[1][3] = 0; -- chan_pcal_info->pddac[1][3] = 0; -+ pcinfo->pwr[1][3] = 0; -+ pcinfo->pddac[1][3] = 0; - } else if (pd_gains == 1) { - /* - * Pd gain 0 is the last one so - * read the extra point. - */ -- chan_pcal_info->pwr[0][3] = -- (val >> 10) & 0xf; -+ pcinfo->pwr[0][3] = (val >> 10) & 0xf; - -- chan_pcal_info->pddac[0][3] = -- (val >> 14) & 0x3; -+ pcinfo->pddac[0][3] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pddac[0][3] |= -- (val & 0xF) << 2; -+ pcinfo->pddac[0][3] |= (val & 0xF) << 2; - } - - /* -@@ -1048,105 +1001,159 @@ ath5k_eeprom_read_pcal_info_2413(struct - * as above. - */ - if (pd_gains > 2) { -- chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f; -- chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f; -+ pcinfo->pwr_i[2] = (val >> 4) & 0x1f; -+ pcinfo->pddac_i[2] = (val >> 9) & 0x7f; - - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pwr[2][0] = -- (val >> 0) & 0xf; -- chan_pcal_info->pddac[2][0] = -- (val >> 4) & 0x3f; -- chan_pcal_info->pwr[2][1] = -- (val >> 10) & 0xf; -- -- chan_pcal_info->pddac[2][1] = -- (val >> 14) & 0x3; -- AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pddac[2][1] |= -- (val & 0xF) << 2; -- -- chan_pcal_info->pwr[2][2] = -- (val >> 4) & 0xf; -- chan_pcal_info->pddac[2][2] = -- (val >> 8) & 0x3f; -+ pcinfo->pwr[2][0] = (val >> 0) & 0xf; -+ pcinfo->pddac[2][0] = (val >> 4) & 0x3f; -+ pcinfo->pwr[2][1] = (val >> 10) & 0xf; - -- chan_pcal_info->pwr[2][3] = 0; -- chan_pcal_info->pddac[2][3] = 0; -+ pcinfo->pddac[2][1] = (val >> 14) & 0x3; -+ AR5K_EEPROM_READ(offset++, val); -+ pcinfo->pddac[2][1] |= (val & 0xF) << 2; -+ -+ pcinfo->pwr[2][2] = (val >> 4) & 0xf; -+ pcinfo->pddac[2][2] = (val >> 8) & 0x3f; -+ -+ pcinfo->pwr[2][3] = 0; -+ pcinfo->pddac[2][3] = 0; - } else if (pd_gains == 2) { -- chan_pcal_info->pwr[1][3] = -- (val >> 4) & 0xf; -- chan_pcal_info->pddac[1][3] = -- (val >> 8) & 0x3f; -+ pcinfo->pwr[1][3] = (val >> 4) & 0xf; -+ pcinfo->pddac[1][3] = (val >> 8) & 0x3f; - } - - if (pd_gains > 3) { -- chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3; -+ pcinfo->pwr_i[3] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2; -+ pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2; - -- chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f; -- chan_pcal_info->pwr[3][0] = -- (val >> 10) & 0xf; -- chan_pcal_info->pddac[3][0] = -- (val >> 14) & 0x3; -+ pcinfo->pddac_i[3] = (val >> 3) & 0x7f; -+ pcinfo->pwr[3][0] = (val >> 10) & 0xf; -+ pcinfo->pddac[3][0] = (val >> 14) & 0x3; - - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pddac[3][0] |= -- (val & 0xF) << 2; -- chan_pcal_info->pwr[3][1] = -- (val >> 4) & 0xf; -- chan_pcal_info->pddac[3][1] = -- (val >> 8) & 0x3f; -+ pcinfo->pddac[3][0] |= (val & 0xF) << 2; -+ pcinfo->pwr[3][1] = (val >> 4) & 0xf; -+ pcinfo->pddac[3][1] = (val >> 8) & 0x3f; - -- chan_pcal_info->pwr[3][2] = -- (val >> 14) & 0x3; -+ pcinfo->pwr[3][2] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pwr[3][2] |= -- ((val >> 0) & 0x3) << 2; -+ pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2; - -- chan_pcal_info->pddac[3][2] = -- (val >> 2) & 0x3f; -- chan_pcal_info->pwr[3][3] = -- (val >> 8) & 0xf; -+ pcinfo->pddac[3][2] = (val >> 2) & 0x3f; -+ pcinfo->pwr[3][3] = (val >> 8) & 0xf; - -- chan_pcal_info->pddac[3][3] = -- (val >> 12) & 0xF; -+ pcinfo->pddac[3][3] = (val >> 12) & 0xF; - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pddac[3][3] |= -- ((val >> 0) & 0x3) << 4; -+ pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4; - } else if (pd_gains == 3) { -- chan_pcal_info->pwr[2][3] = -- (val >> 14) & 0x3; -+ pcinfo->pwr[2][3] = (val >> 14) & 0x3; - AR5K_EEPROM_READ(offset++, val); -- chan_pcal_info->pwr[2][3] |= -- ((val >> 0) & 0x3) << 2; -+ pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2; - -- chan_pcal_info->pddac[2][3] = -- (val >> 2) & 0x3f; -+ pcinfo->pddac[2][3] = (val >> 2) & 0x3f; - } -+ } -+ return 0; -+} -+ -+static int -+ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, -+ struct ath5k_chan_pcal_info *chinfo, -+ unsigned int *xgains) -+{ -+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; -+ struct ath5k_chan_pcal_info_rf2413 *pcinfo; -+ unsigned int i, j, k; - -- for (c = 0; c < pd_gains; c++) { -- /* Recreate pwr table for this channel using pwr steps */ -- chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2; -- chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0]; -- chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1]; -- chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2]; -- if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2]) -- chan_pcal_info->pwr[c][3] = 0; -- -- /* Recreate pddac table for this channel using pddac steps */ -- chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c]; -- chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0]; -- chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1]; -- chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2]; -- if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2]) -- chan_pcal_info->pddac[c][3] = 0; -+ /* prepare the raw values */ -+ for (i = 0; i < ee->ee_n_piers[mode]; i++) { -+ pcinfo = &chinfo[i].rf2413_info; -+ for (j = 0; j < ee->ee_pd_gains[mode]; j++) { -+ unsigned int idx = xgains[j]; -+ struct ath5k_pdgain_info *pd = &pcinfo->pdgains[idx]; -+ -+ /* one more point for the highest power (lowest gain) */ -+ if (j == ee->ee_pd_gains[mode] - 1) { -+ pd->n_vpd = AR5K_EEPROM_N_PD_POINTS; -+ } else { -+ pd->n_vpd = AR5K_EEPROM_N_PD_POINTS - 1; -+ } -+ -+ pd->vpd[0] = pcinfo->pddac_i[j]; -+ pd->pwr_t4[0] = 4 * pcinfo->pwr_i[j]; -+ for (k = 1; k < pd->n_vpd; k++) { -+ pd->pwr_t4[k] = pd->pwr_t4[k - 1] + 2 * pcinfo->pwr[j][k - 1]; -+ pd->vpd[k] = pd->vpd[k - 1] + pcinfo->pddac[j][k - 1]; -+ } - } - } - - return 0; - } - -+static int -+ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) -+{ -+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; -+ struct ath5k_chan_pcal_info *chinfo; -+ unsigned int xgains[AR5K_EEPROM_N_PD_GAINS]; -+ u32 offset; -+ u8 pd_gains = 0; -+ int i, ret; -+ -+ memset(xgains, 0, sizeof(xgains)); -+ for (i = 0; i < AR5K_EEPROM_N_PD_GAINS; i++) { -+ int idx = AR5K_EEPROM_N_PD_GAINS - i - 1; -+ -+ if ((ee->ee_x_gain[mode] >> idx) & 0x1) -+ xgains[pd_gains++] = idx; -+ } -+ ee->ee_pd_gains[mode] = pd_gains; -+ -+ offset = ath5k_cal_data_offset_2413(ee, mode); -+ switch (mode) { -+ case AR5K_EEPROM_MODE_11A: -+ if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) -+ return 0; -+ -+ ath5k_eeprom_init_11a_pcal_freq(ah, offset); -+ offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; -+ chinfo = ee->ee_pwr_cal_a; -+ break; -+ case AR5K_EEPROM_MODE_11B: -+ if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) -+ return 0; -+ -+ ath5k_eeprom_init_11bg_2413(ah, mode, offset); -+ offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; -+ chinfo = ee->ee_pwr_cal_b; -+ break; -+ case AR5K_EEPROM_MODE_11G: -+ if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) -+ return 0; -+ -+ ath5k_eeprom_init_11bg_2413(ah, mode, offset); -+ offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; -+ chinfo = ee->ee_pwr_cal_g; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ -+ ret = ath5k_eeprom_parse_pcal_info_2413(ah, mode, offset, chinfo); -+ if (ret) -+ return ret; -+ -+ ret = ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo, xgains); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ - /* - * Read per rate target power (this is the maximum tx power - * supported by the card). This info is used when setting -@@ -1264,6 +1271,7 @@ ath5k_eeprom_read_pcal_info(struct ath5k - else - read_pcal = ath5k_eeprom_read_pcal_info_5111; - -+ - for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { - err = read_pcal(ah, mode); - if (err) ---- a/drivers/net/wireless/ath5k/eeprom.h -+++ b/drivers/net/wireless/ath5k/eeprom.h -@@ -266,15 +266,27 @@ struct ath5k_chan_pcal_info_rf5112 { - u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; - }; - -+ -+struct ath5k_pdgain_info { -+ u16 n_vpd; -+ u16 vpd[AR5K_EEPROM_N_PD_POINTS]; -+ s16 pwr_t4[AR5K_EEPROM_N_PD_POINTS]; -+}; -+ - struct ath5k_chan_pcal_info_rf2413 { -+ /* --- EEPROM VALUES --- */ - /* Starting pwr/pddac values */ -- s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; -- u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; -+ s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; -+ u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; - /* (pwr,pddac) points */ -- s8 pwr[AR5K_EEPROM_N_PD_GAINS] -- [AR5K_EEPROM_N_PD_POINTS]; -- u8 pddac[AR5K_EEPROM_N_PD_GAINS] -- [AR5K_EEPROM_N_PD_POINTS]; -+ s8 pwr[AR5K_EEPROM_N_PD_GAINS] -+ [AR5K_EEPROM_N_PD_POINTS]; -+ u8 pddac[AR5K_EEPROM_N_PD_GAINS] -+ [AR5K_EEPROM_N_PD_POINTS]; -+ -+ /* --- RAW VALUES --- */ -+ struct ath5k_pdgain_info pdgains -+ [AR5K_EEPROM_N_PD_GAINS]; - }; - - struct ath5k_chan_pcal_info { diff --git a/package/mac80211/patches/340-ath5k_txpower_2413.patch b/package/mac80211/patches/340-ath5k_txpower_2413.patch deleted file mode 100644 index ddecd9e071..0000000000 --- a/package/mac80211/patches/340-ath5k_txpower_2413.patch +++ /dev/null @@ -1,672 +0,0 @@ -Implement the power curve interpolation, which is required for -proper tx on 2413 and newer RF designs. - -Signed-off-by: Felix Fietkau - ---- a/drivers/net/wireless/ath5k/phy.c -+++ b/drivers/net/wireless/ath5k/phy.c -@@ -4,6 +4,7 @@ - * Copyright (c) 2004-2007 Reyk Floeter - * Copyright (c) 2006-2009 Nick Kossifidis - * Copyright (c) 2007-2008 Jiri Slaby -+ * Copyright (c) 2008-2009 Felix Fietkau - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above -@@ -1438,31 +1439,449 @@ unsigned int ath5k_hw_get_def_antenna(st - */ - - /* -- * Initialize the tx power table (not fully implemented) -+ * find the lower and upper index of the values in the table surrounding the target value - */ --static void ath5k_txpower_table(struct ath5k_hw *ah, -- struct ieee80211_channel *channel, s16 max_power) -+static void -+ath5k_get_table_index(const u16 *tbl, unsigned int tbl_sz, u16 target, -+ unsigned int idx[2]) - { -- unsigned int i, min, max, n; -- u16 txpower, *rates; -+ const u16 *ti; - -- rates = ah->ah_txpower.txp_rates; -+ if (target < tbl[0]) { -+ idx[0] = idx[1] = 0; -+ return; -+ } -+ -+ if (target > tbl[tbl_sz - 1]) { -+ idx[0] = idx[1] = tbl_sz - 1; -+ return; -+ } -+ -+ /* look for the surrounding values */ -+ for (ti = tbl; ti < &tbl[tbl_sz - 1]; ti++) { -+ -+ /* if the value is equal to the target, set lo = hi = index */ -+ if (*ti == target) { -+ idx[0] = idx[1] = ti - tbl; -+ return; -+ } -+ -+ /* if the target is between the current value and the next one, -+ * set lo = cur, hi = lo + 1 */ -+ if (target < ti[1]) { -+ idx[0] = ti - tbl; -+ idx[1] = idx[0] + 1; -+ return; -+ } -+ } -+} -+ -+/* find the lower and upper frequency info */ -+static void -+ath5k_get_freq_tables(struct ath5k_hw *ah, struct ieee80211_channel *channel, -+ struct ath5k_chan_pcal_info **pcinfo_l, -+ struct ath5k_chan_pcal_info **pcinfo_r, -+ struct ath5k_rate_pcal_info *rates) -+{ -+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; -+ struct ath5k_chan_pcal_info *pcinfo; -+ unsigned int idx_l, idx_r; -+ int mode, max, i; -+ unsigned int target = channel->center_freq; -+ struct ath5k_rate_pcal_info *rpinfo; -+ -+ if (!(channel->hw_value & CHANNEL_OFDM)) { -+ pcinfo = ee->ee_pwr_cal_b; -+ rpinfo = ee->ee_rate_tpwr_b; -+ mode = AR5K_EEPROM_MODE_11B; -+ } else if (channel->hw_value & CHANNEL_2GHZ) { -+ pcinfo = ee->ee_pwr_cal_g; -+ rpinfo = ee->ee_rate_tpwr_g; -+ mode = AR5K_EEPROM_MODE_11G; -+ } else { -+ pcinfo = ee->ee_pwr_cal_a; -+ rpinfo = ee->ee_rate_tpwr_a; -+ mode = AR5K_EEPROM_MODE_11A; -+ } -+ max = ee->ee_n_piers[mode] - 1; -+ -+ if (target < pcinfo[0].freq) { -+ idx_l = idx_r = 0; -+ goto done; -+ } -+ -+ if (target > pcinfo[max].freq) { -+ idx_l = idx_r = max; -+ goto done; -+ } -+ -+ /* look for the surrounding values */ -+ for (i = 0; i <= max; i++) { -+ -+ /* if the value is equal to the target, set lo = hi = index */ -+ if (pcinfo[i].freq == target) { -+ idx_l = idx_r = i; -+ goto done; -+ } -+ -+ /* if the target is between the current value and the next one, -+ * set lo = cur, hi = lo + 1 */ -+ if (target < pcinfo[i].freq) { -+ idx_l = i; -+ idx_r = idx_l + 1; -+ goto done; -+ } -+ } -+ -+done: -+ *pcinfo_l = &pcinfo[idx_l]; -+ *pcinfo_r = &pcinfo[idx_r]; -+ -+ if (!rates) -+ return; -+ -+ /* rate info minimum values */ -+ rates->freq = channel->center_freq; -+ rates->target_power_6to24 = -+ min(rpinfo[idx_l].target_power_6to24, -+ rpinfo[idx_r].target_power_6to24); -+ rates->target_power_36 = -+ min(rpinfo[idx_l].target_power_36, -+ rpinfo[idx_r].target_power_36); -+ rates->target_power_48 = -+ min(rpinfo[idx_l].target_power_48, -+ rpinfo[idx_r].target_power_48); -+ rates->target_power_54 = -+ min(rpinfo[idx_l].target_power_54, -+ rpinfo[idx_r].target_power_54); -+} -+ -+ -+/* Fill the VPD table for all indices between pmin and pmax */ -+static void -+ath5k_fill_vpdtable(s16 pmin, s16 pmax, const s16 *pwr, -+ const u16 *vpd, unsigned int intercepts, -+ u16 vpdtable[AR5K_EEPROM_POWER_TABLE_SIZE]) -+{ -+ unsigned int idx[2] = { 0, 0 }; -+ s16 cur_pwr = 2 * pmin; -+ int i; -+ -+ if (intercepts < 2) -+ return; -+ -+ for(i = 0; i <= (pmax - pmin); i++) { -+ ath5k_get_table_index(pwr, intercepts, cur_pwr, idx); -+ -+ if (!idx[1]) -+ idx[1] = 1; -+ -+ if (idx[0] == intercepts - 1) -+ idx[0] = intercepts - 2; -+ -+ if (pwr[idx[0]] == pwr[idx[1]]) -+ vpdtable[i] = vpd[idx[0]]; -+ else -+ vpdtable[i] = (((cur_pwr - pwr[idx[0]]) * vpd[idx[1]] + -+ (pwr[idx[1]] - cur_pwr) * vpd[idx[0]]) / -+ (pwr[idx[1]] - pwr[idx[0]])); -+ -+ cur_pwr += 2; -+ } -+} -+ -+static inline s16 -+ath5k_interpolate_signed(u16 ref, u16 ref_l, u16 ref_r, s16 val_l, s16 val_r) -+{ -+ if (ref_l == ref_r) -+ return val_l; -+ -+ return ((ref - ref_l)*val_r + (ref_r - ref)*val_l) / (ref_r - ref_l); -+} -+ -+static inline s16 -+ath5k_get_min_power_2413(struct ath5k_chan_pcal_info *pcinfo) -+{ -+ struct ath5k_pdgain_info *pd; -+ int i; -+ -+ /* backwards - highest pdgain == lowest power */ -+ for (i = AR5K_EEPROM_N_PD_GAINS - 1; i >= 0; i--) { -+ pd = &pcinfo->rf2413_info.pdgains[i]; -+ if (!pd->n_vpd) -+ continue; -+ -+ return pd->pwr_t4[0]; -+ } -+ return 0; -+} -+ -+static inline s16 -+ath5k_get_max_power_2413(struct ath5k_chan_pcal_info *pcinfo) -+{ -+ struct ath5k_pdgain_info *pd; -+ int i; -+ -+ /* forwards: lowest pdgain == highest power */ -+ for (i = 0; i < AR5K_EEPROM_N_PD_GAINS; i++) { -+ pd = &pcinfo->rf2413_info.pdgains[i]; -+ if (!pd->n_vpd) -+ continue; -+ -+ return pd->pwr_t4[pd->n_vpd]; -+ } -+ return 0; -+} -+ -+ -+ -+static int -+ath5k_txpower_table_2413(struct ath5k_hw *ah, struct ieee80211_channel *ch, -+ struct ath5k_chan_pcal_info *pcinfo_l, -+ struct ath5k_chan_pcal_info *pcinfo_r) -+{ -+ struct ath5k_pdgain_info *pd_l, *pd_r; -+ u16 gain_boundaries[4]; -+ u16 *xpd = ah->ah_txpower.txp_xpd; -+ int n_xpd = 0; -+ s16 pmin_t2[AR5K_EEPROM_N_PD_GAINS]; -+ s16 pmax_t2[AR5K_EEPROM_N_PD_GAINS]; -+ u16 *pdadc_out = ah->ah_txpower.txp_pcdac; -+ unsigned int gain_overlap; -+ unsigned int vpd_size, target_idx, max_idx; -+ unsigned int n_pdadc = 0; -+ u16 vpd_step; -+ u16 *pcdacL; -+ u16 *pcdacR; -+ int i, j, s; -+ u32 reg; -+ s16 ch_pmin, ch_pmax; -+ -+ gain_overlap = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) & -+ AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP; -+ -+ /* loop backwards over pdgains (highest pdgain == lowest power) */ -+ for (i = AR5K_EEPROM_N_PD_GAINS - 1; i >= 0; i--) { -+ pd_l = &pcinfo_l->rf2413_info.pdgains[i]; -+ pd_r = &pcinfo_r->rf2413_info.pdgains[i]; -+ pcdacL = ah->ah_txpower.txp_rfdata.rf2413.pcdacL[n_xpd]; -+ pcdacR = ah->ah_txpower.txp_rfdata.rf2413.pcdacR[n_xpd]; -+ -+ if (!pd_l->n_vpd) -+ continue; -+ -+ xpd[n_xpd] = i; -+ -+ pmin_t2[n_xpd] = min(pd_l->pwr_t4[0], pd_r->pwr_t4[0]) / 2; -+ pmax_t2[n_xpd] = min(pd_l->pwr_t4[pd_l->n_vpd - 1], -+ pd_r->pwr_t4[pd_r->n_vpd - 1]) / 2; -+ -+ if ((u16) (pmax_t2[n_xpd] - pmin_t2[n_xpd]) > 64) -+ continue; -+ -+ /* fill vpd tables for left and right frequency info */ -+ ath5k_fill_vpdtable(pmin_t2[n_xpd], pmax_t2[n_xpd], -+ pd_l->pwr_t4, pd_l->vpd, pd_l->n_vpd, pcdacL); -+ -+ /* check if interpolation is necessary */ -+ if (pcinfo_l == pcinfo_r) -+ continue; -+ -+ ath5k_fill_vpdtable(pmin_t2[n_xpd], pmax_t2[n_xpd], -+ pd_r->pwr_t4, pd_r->vpd, pd_r->n_vpd, pcdacR); -+ -+ /* interpolate pcdac values, -+ * reuse pcdacL table for interpolation output */ -+ for (j = 0; j < (u16) (pmax_t2[n_xpd] - pmin_t2[n_xpd]); j++) { -+ pcdacL[j] = ath5k_interpolate_signed(ch->center_freq, -+ pcinfo_l->freq, pcinfo_r->freq, -+ (s16) pcdacL[j], (s16) pcdacR[j]); -+ } -+ n_xpd++; -+ } -+ -+ if (!n_xpd) -+ return 0; -+ -+ /* create final table */ -+ for (i = 0, n_pdadc = 0; i < n_xpd; i++) { -+ pcdacL = ah->ah_txpower.txp_rfdata.rf2413.pcdacL[i]; -+ -+ if (i == n_xpd - 1) { -+ /* 2 db boundary stretch */ -+ gain_boundaries[i] = pmax_t2[i] + 4; -+ } else { -+ gain_boundaries[i] = (pmax_t2[i] + pmin_t2[i + 1]) / 2; -+ } -+ -+ if (gain_boundaries[i] > AR5K_TUNE_MAX_TXPOWER) -+ gain_boundaries[i] = AR5K_TUNE_MAX_TXPOWER; -+ -+ /* find starting index */ -+ if (i == 0) -+ s = 0; -+ else -+ s = (gain_boundaries[i - 1] - pmin_t2[i]) - -+ gain_overlap; -+ -+ if (pcdacL[1] > pcdacL[0]) -+ vpd_step = pcdacL[1] - pcdacL[0]; -+ else -+ vpd_step = 1; -+ -+ /* if s is below 0, we need to extrapolate below this pdgain */ -+ while ((s < 0) && (n_pdadc < 128)) { -+ s16 tmp = pcdacL[0] + s * vpd_step; -+ pdadc_out[n_pdadc++] = (u16) ((tmp < 0) ? 0 : tmp); -+ s++; -+ } -+ -+ vpd_size = pmax_t2[i] - pmin_t2[i]; -+ target_idx = gain_boundaries[i] + gain_overlap - pmin_t2[i]; -+ max_idx = (target_idx < vpd_size) ? target_idx : vpd_size; -+ -+ while ((s < (s16) max_idx) && (n_pdadc < 128)) -+ pdadc_out[n_pdadc++] = pcdacL[s++]; -+ -+ /* need to extrapolate above this pdgain? */ -+ if (target_idx <= max_idx) -+ continue; - -- txpower = AR5K_TUNE_DEFAULT_TXPOWER * 2; -- if (max_power > txpower) -- txpower = max_power > AR5K_TUNE_MAX_TXPOWER ? -- AR5K_TUNE_MAX_TXPOWER : max_power; -+ if (pcdacL[vpd_size - 1] > pcdacL[vpd_size - 2]) -+ vpd_step = pcdacL[vpd_size - 1] - pcdacL[vpd_size - 2]; -+ else -+ vpd_step = 1; - -- for (i = 0; i < AR5K_MAX_RATES; i++) -- rates[i] = txpower; -+ while ((s < (s16) target_idx) && (n_pdadc < 128)) { -+ int tmp = pcdacL[vpd_size - 1] + -+ (s - max_idx) * vpd_step; -+ pdadc_out[n_pdadc++] = (tmp > 127) ? 127 : tmp; -+ s++; -+ } -+ } - -- /* XXX setup target powers by rate */ -+ while (i < AR5K_EEPROM_N_PD_GAINS) { -+ gain_boundaries[i] = gain_boundaries[i - 1]; -+ i++; -+ } -+ -+ while (n_pdadc < 128) { -+ pdadc_out[n_pdadc] = pdadc_out[n_pdadc - 1]; -+ n_pdadc++; -+ } -+ -+ /* select the right xpdgain curves */ -+ reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1); -+ reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 | -+ AR5K_PHY_TPC_RG1_PDGAIN_2 | -+ AR5K_PHY_TPC_RG1_PDGAIN_3 | -+ AR5K_PHY_TPC_RG1_NUM_PD_GAIN); -+ reg |= AR5K_REG_SM(n_xpd, AR5K_PHY_TPC_RG1_NUM_PD_GAIN); -+ switch(n_xpd) { -+ case 3: -+ reg |= AR5K_REG_SM(xpd[2], AR5K_PHY_TPC_RG1_PDGAIN_3); -+ /* fall through */ -+ case 2: -+ reg |= AR5K_REG_SM(xpd[1], AR5K_PHY_TPC_RG1_PDGAIN_2); -+ /* fall through */ -+ case 1: -+ reg |= AR5K_REG_SM(xpd[0], AR5K_PHY_TPC_RG1_PDGAIN_1); -+ break; -+ } -+ ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1); - -+ /* -+ * Write TX power values -+ */ -+ reg = AR5K_PHY_PDADC_TXPOWER_BASE; -+ for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { -+ ath5k_hw_reg_write(ah, -+ ((pdadc_out[4*i + 0] & 0xff) << 0) | -+ ((pdadc_out[4*i + 1] & 0xff) << 8) | -+ ((pdadc_out[4*i + 2] & 0xff) << 16) | -+ ((pdadc_out[4*i + 3] & 0xff) << 24), reg); -+ reg += 4; -+ } -+ -+ ath5k_hw_reg_write(ah, -+ AR5K_REG_SM(gain_overlap, -+ AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) | -+ AR5K_REG_SM(gain_boundaries[0], -+ AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) | -+ AR5K_REG_SM(gain_boundaries[1], -+ AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) | -+ AR5K_REG_SM(gain_boundaries[2], -+ AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) | -+ AR5K_REG_SM(gain_boundaries[3], -+ AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4), -+ AR5K_PHY_TPC_RG5); -+ -+ ah->ah_txpower.txp_offset = pmin_t2[0]; -+ -+ /* look up power boundaries for this channel */ -+ ch_pmin = ath5k_get_min_power_2413(pcinfo_l); -+ ch_pmax = ath5k_get_max_power_2413(pcinfo_l); -+ -+ if (pcinfo_l != pcinfo_r) { -+ s16 pwr_r; -+ -+ pwr_r = ath5k_get_min_power_2413(pcinfo_r); -+ ch_pmin = ath5k_interpolate_signed(ch->center_freq, -+ pcinfo_l->freq, pcinfo_r->freq, -+ ch_pmin, pwr_r); -+ -+ pwr_r = ath5k_get_max_power_2413(pcinfo_r); -+ ch_pmax = ath5k_interpolate_signed(ch->center_freq, -+ pcinfo_l->freq, pcinfo_r->freq, -+ ch_pmax, pwr_r); -+ } -+ ah->ah_txpower.txp_min = ch_pmin; -+ ah->ah_txpower.txp_max = ch_pmax; -+ -+ return 0; -+} -+ -+static void -+ath5k_setup_rate_table(struct ath5k_hw *ah, u16 max_pwr, -+ struct ath5k_rate_pcal_info *rate_info) -+{ -+ unsigned int i; -+ u16 *rates; -+ -+ max_pwr *= 2; -+ max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max); -+ -+ /* apply rate limits */ -+ rates = ah->ah_txpower.txp_rates; -+ for (i = 0; i < 5; i++) { -+ rates[i] = min(max_pwr, rate_info->target_power_6to24); -+ } -+ rates[5] = min(rates[0], rate_info->target_power_36); -+ rates[6] = min(rates[0], rate_info->target_power_48); -+ rates[7] = min(rates[0], rate_info->target_power_54); -+ rates[8] = min(rates[0], rate_info->target_power_6to24); -+ rates[9] = min(rates[0], rate_info->target_power_36); -+ rates[10] = min(rates[0], rate_info->target_power_36); -+ rates[11] = min(rates[0], rate_info->target_power_48); -+ rates[12] = min(rates[0], rate_info->target_power_48); -+ rates[13] = min(rates[0], rate_info->target_power_54); -+ rates[14] = min(rates[0], rate_info->target_power_54); -+ -+ ah->ah_txpower.txp_tpc = max_pwr; - ah->ah_txpower.txp_min = rates[7]; -- ah->ah_txpower.txp_max = rates[0]; -- ah->ah_txpower.txp_ofdm = rates[0]; -+ ah->ah_txpower.txp_max = min(ah->ah_txpower.txp_max, -+ (s16) rate_info->target_power_36); -+ ah->ah_txpower.txp_ofdm = ah->ah_txpower.txp_max; -+} -+ -+static int -+ath5k_txpower_table(struct ath5k_hw *ah, struct ieee80211_channel *ch, -+ struct ath5k_chan_pcal_info *pcinfo_l, -+ struct ath5k_chan_pcal_info *pcinfo_r, -+ u16 max_pwr) -+{ -+ unsigned int i, min, max, n; - -- /* Calculate the power table */ - n = ARRAY_SIZE(ah->ah_txpower.txp_pcdac); - min = AR5K_EEPROM_PCDAC_START; - max = AR5K_EEPROM_PCDAC_STOP; -@@ -1473,51 +1892,64 @@ static void ath5k_txpower_table(struct a - #else - min; - #endif -+ -+ /* -+ * Write TX power values -+ */ -+ for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { -+ ath5k_hw_reg_write(ah, -+ ((((ah->ah_txpower.txp_pcdac[(i << 1) + 1] << 8) | -+ 0xff) & 0xffff) << 16) | -+ (((ah->ah_txpower.txp_pcdac[(i << 1) ] << 8) | -+ 0xff) & 0xffff), -+ AR5K_PHY_PCDAC_TXPOWER(i)); -+ } -+ return 0; - } - -+ - /* - * Set transmition power - */ --int /*O.K. - txpower_table is unimplemented so this doesn't work*/ -+int - ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, - unsigned int txpower) - { -+ struct ath5k_chan_pcal_info *pcinfo_l, *pcinfo_r; -+ struct ath5k_rate_pcal_info rate_info; - bool tpc = ah->ah_txpower.txp_tpc; -- unsigned int i; - - ATH5K_TRACE(ah->ah_sc); - if (txpower > AR5K_TUNE_MAX_TXPOWER) { - ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); - return -EINVAL; - } -- -- /* -- * RF2413 for some reason can't -- * transmit anything if we call -- * this funtion, so we skip it -- * until we fix txpower. -- * -- * XXX: Assume same for RF2425 -- * to be safe. -- */ -- if ((ah->ah_radio == AR5K_RF2413) || (ah->ah_radio == AR5K_RF2425)) -- return 0; -+ if (txpower == 0) -+ txpower = AR5K_TUNE_MAX_TXPOWER; - - /* Reset TX power values */ - memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); - ah->ah_txpower.txp_tpc = tpc; -+ ah->ah_txpower.txp_min = 0; -+ ah->ah_txpower.txp_max = AR5K_TUNE_MAX_TXPOWER; - -- /* Initialize TX power table */ -- ath5k_txpower_table(ah, channel, txpower); -+ /* find matching frequency info */ -+ ath5k_get_freq_tables(ah, channel, &pcinfo_l, &pcinfo_r, &rate_info); -+ ath5k_setup_rate_table(ah, txpower, &rate_info); - -- /* -- * Write TX power values -- */ -- for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { -- ath5k_hw_reg_write(ah, -- ((((ah->ah_txpower.txp_pcdac[(i << 1) + 1] << 8) | 0xff) & 0xffff) << 16) | -- (((ah->ah_txpower.txp_pcdac[(i << 1) ] << 8) | 0xff) & 0xffff), -- AR5K_PHY_PCDAC_TXPOWER(i)); -+ /* Initialize TX power table */ -+ switch(ah->ah_radio) { -+ case AR5K_RF2413: -+ case AR5K_RF5413: -+ ath5k_txpower_table_2413(ah, channel, pcinfo_l, pcinfo_r); -+ break; -+ case AR5K_RF2425: -+ /* unimplemented */ -+ return 0; -+ default: -+ /* Default power table */ -+ ath5k_txpower_table(ah, channel, pcinfo_l, pcinfo_r, txpower); -+ break; - } - - ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) | -@@ -1536,12 +1968,19 @@ ath5k_hw_txpower(struct ath5k_hw *ah, st - AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | - AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); - -- if (ah->ah_txpower.txp_tpc) -+ if (ah->ah_txpower.txp_tpc) { - ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | - AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); -- else -+ -+ ath5k_hw_reg_write(ah, -+ AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) | -+ AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) | -+ AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP), -+ AR5K_TPC); -+ } else { - ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | - AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); -+ } - - return 0; - } ---- a/drivers/net/wireless/ath5k/ath5k.h -+++ b/drivers/net/wireless/ath5k/ath5k.h -@@ -204,7 +204,7 @@ - #define AR5K_TUNE_CWMAX_11B 1023 - #define AR5K_TUNE_CWMAX_XR 7 - #define AR5K_TUNE_NOISE_FLOOR -72 --#define AR5K_TUNE_MAX_TXPOWER 60 -+#define AR5K_TUNE_MAX_TXPOWER 63 - #define AR5K_TUNE_DEFAULT_TXPOWER 30 - #define AR5K_TUNE_TPC_TXPOWER true - #define AR5K_TUNE_ANT_DIVERSITY true -@@ -1085,11 +1085,23 @@ struct ath5k_hw { - struct ath5k_gain ah_gain; - u8 ah_offset[AR5K_MAX_RF_BANKS]; - -+ - struct { -- u16 txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE]; -+ union { -+ struct { -+ /* Temporary PCDAC tables for interpolation */ -+ u16 pcdacL[AR5K_EEPROM_N_PD_GAINS] -+ [AR5K_EEPROM_POWER_TABLE_SIZE]; -+ u16 pcdacR[AR5K_EEPROM_N_PD_GAINS] -+ [AR5K_EEPROM_POWER_TABLE_SIZE]; -+ } rf2413; -+ } txp_rfdata; -+ u16 txp_xpd[AR5K_EEPROM_N_XPD_PER_CHANNEL]; -+ u16 txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE * 2]; - u16 txp_rates[AR5K_MAX_RATES]; - s16 txp_min; - s16 txp_max; -+ s16 txp_offset; - bool txp_tpc; - s16 txp_ofdm; - } ah_txpower; ---- a/drivers/net/wireless/ath5k/reg.h -+++ b/drivers/net/wireless/ath5k/reg.h -@@ -1552,6 +1552,15 @@ - - - /*===5212 Specific PCU registers===*/ -+#define AR5K_TPC 0x80e8 -+#define AR5K_TPC_ACK 0x0000003f /* ack frames */ -+#define AR5K_TPC_ACK_S 0 -+#define AR5K_TPC_CTS 0x00003f00 /* cts frames */ -+#define AR5K_TPC_CTS_S 8 -+#define AR5K_TPC_CHIRP 0x003f0000 /* chirp frames */ -+#define AR5K_TPC_CHIRP_S 16 -+#define AR5K_TPC_DOPPLER 0x0f000000 /* doppler chirp span */ -+#define AR5K_TPC_DOPPLER_S 24 - - /* - * XR (eXtended Range) mode register -@@ -2550,6 +2559,12 @@ - #define AR5K_PHY_TPC_RG1 0xa258 - #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN 0x0000c000 - #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S 14 -+#define AR5K_PHY_TPC_RG1_PDGAIN_1 0x00030000 -+#define AR5K_PHY_TPC_RG1_PDGAIN_1_S 16 -+#define AR5K_PHY_TPC_RG1_PDGAIN_2 0x000c0000 -+#define AR5K_PHY_TPC_RG1_PDGAIN_2_S 18 -+#define AR5K_PHY_TPC_RG1_PDGAIN_3 0x00300000 -+#define AR5K_PHY_TPC_RG1_PDGAIN_3_S 20 - - #define AR5K_PHY_TPC_RG5 0xa26C - #define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP 0x0000000F ---- a/drivers/net/wireless/ath5k/desc.c -+++ b/drivers/net/wireless/ath5k/desc.c -@@ -194,6 +194,10 @@ static int ath5k_hw_setup_4word_tx_desc( - return -EINVAL; - } - -+ tx_power += ah->ah_txpower.txp_offset; -+ if (tx_power > AR5K_TUNE_MAX_TXPOWER) -+ tx_power = AR5K_TUNE_MAX_TXPOWER; -+ - /* Clear descriptor */ - memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); -