ath,ar9170: implemented conformance test limit calc. for tx power
PATCH 2/2 ath,ar9170: implemented conformance test limit calc. for tx power
apply the conformance test limits (CTL) stored in the eeprom upon the values calculated for the tx power (ar->power_*).
This is based on the implementation in the vendor driver (hal/hpmain.c, line 3700 ff.) with one difference:
If any ctl mode isn't found in the eeprom, we fall back to the "lower", legacy modes (5GHT20,11A or 2GHT20,11G,11B). Otus only did 5GHT20->11A.
Currently CTL are applied for the FCC group only.
Signed-off-by Joerg Albert <[email protected]>
---
The above diff is due to my AVM Fritz! USB stick having no *HT* CTL groups in the eeprom at all.
Furthermore I moved the "TODO: heavy clip ..." to an, IMHO, better place.
drivers/net/wireless/ath/ar9170/phy.c | 165 ++++++++++++++++++++++++++++++++- 1 files changed, 164 insertions(+), 1 deletions(-)
drivers/net/wireless/ath/ar9170/phy.c +164 -1
@@ -556,7 +556,6 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)if (err)return err; -/* TODO: (heavy clip) regulatory domain power level fine-tuning. */ err =ar9170_init_phy_from_eeprom (ar, is_2ghz, is_40mhz);if (err)return err;
@@ -1238,6 +1237,164 @@ static int ar9170_set_freq_cal_data(struct ar9170 *ar,return ar9170_regwrite_result (); } +static u8 ar9170_get_max_edge_power (struct ar9170 *ar, +struct ar9170_calctl_edges edges[], +u32 freq) +{ +/* TODO: move somewhere else */ +#define AR5416_MAX_RATE_POWER 63 + +int i; +u8 rc =AR5416_MAX_RATE_POWER ; +u8 f; +if (freq <3000 ) + f = freq -2300 ; +else + f = (freq -4800 ) /5 ; + +for (i =0 ; i <AR5416_NUM_BAND_EDGES ; i++) { +if (edges[i].channel ==0xff ) +break ; +if (f == edges[i].channel) { +/* exact freq match */ + rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS ; +break ; + } +if (i >0 && f < edges[i].channel) { +if (f > edges[i-1 ].channel && + edges[i-1 ].power_flags &AR9170_CALCTL_EDGE_FLAGS ) { +/* lower channel has the inband flag set */ + rc = edges[i-1 ].power_flags & + ~AR9170_CALCTL_EDGE_FLAGS ; + } +break ; + } + } + +if (i ==AR5416_NUM_BAND_EDGES ) { +if (f > edges[i-1 ].channel && + edges[i-1 ].power_flags &AR9170_CALCTL_EDGE_FLAGS ) { +/* lower channel has the inband flag set */ + rc = edges[i-1 ].power_flags & + ~AR9170_CALCTL_EDGE_FLAGS ; + } + } +return rc; +} + +/* calculate the conformance test limits and apply them to ar->power* +* (derived from otus hal/hpmain.c, line 3706 ff.) +*/ +static void ar9170_calc_ctl (struct ar9170 *ar,u32 freq,enum ar9170_bw bw) +{ +u8 ctl_grp;/* CTL group */ +u8 ctl_idx;/* CTL index */ +int i, j; +struct ctl_modes { +u8 ctl_mode; +u8 max_power; +u8 *pwr_cal_data; +int pwr_cal_len; + } *modes; + +/* order is relevant in the mode_list_*: we fall back to the +* lower indices if any mode is missed in the EEPROM. +*/ +struct ctl_modes mode_list_2ghz[] = { + {CTL_11B ,0 , ar->power_2G_cck,4 }, + {CTL_11G ,0 , ar->power_2G_ofdm,4 }, + {CTL_2GHT20 ,0 , ar->power_2G_ht20,8 }, + {CTL_2GHT40 ,0 , ar->power_2G_ht40,8 }, + }; +struct ctl_modes mode_list_5ghz[] = { + {CTL_11A ,0 , ar->power_5G_leg,4 }, + {CTL_5GHT20 ,0 , ar->power_5G_ht20,8 }, + {CTL_5GHT40 ,0 , ar->power_5G_ht40,8 }, + }; +int nr_modes; + +#define EDGES (c, n) (ar->eeprom.ctl_data[c].control_edges[n]) + +/* TODO: investigate the differences between OTUS' +* hpreg.c::zfHpGetRegulatoryDomain() and +* ath/regd.c::ath_regd_get_band_ctl() - +* e.g. for FCC3_WORLD the OTUS procedure +* always returns CTL_FCC, while the one in ath/ delivers +* CTL_ETSI for 2GHz and CTL_FCC for 5GHz. +*/ + ctl_grp =ath_regd_get_band_ctl (&ar->common.regulatory, + ar->hw->conf.channel->band); + +/* ctl group not found - either invalid band (NO_CTL) or ww roaming */ +if (ctl_grp ==NO_CTL || ctl_grp ==SD_NO_CTL ) + ctl_grp =CTL_FCC ; + +if (ctl_grp !=CTL_FCC ) +/* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */ +return ; + +if (ar->hw->conf.channel->band ==IEEE80211_BAND_2GHZ ) { + modes = mode_list_2ghz; + nr_modes =ARRAY_SIZE (mode_list_2ghz); + }else { + modes = mode_list_5ghz; + nr_modes =ARRAY_SIZE (mode_list_5ghz); + } + +for (i =0 ; i < nr_modes; i++) { +u8 c = ctl_grp | modes[i].ctl_mode; +for (ctl_idx =0 ; ctl_idx <AR5416_NUM_CTLS ; ctl_idx++) +if (c == ar->eeprom.ctl_index[ctl_idx]) +break ; +if (ctl_idx <AR5416_NUM_CTLS ) { +int f_off =0 ; + +/* adjust freq for 40MHz */ +if (modes[i].ctl_mode ==CTL_2GHT40 || + modes[i].ctl_mode ==CTL_5GHT40 ) { +if (bw ==AR9170_BW_40_BELOW ) + f_off =-10 ; +else + f_off =10 ; + } + + modes[i].max_power = +ar9170_get_max_edge_power (ar,EDGES (ctl_idx,1 ), + freq+f_off); + +/* TODO: check if the regulatory max. power is +* controlled by cfg80211 for DFS +* (hpmain applies it to max_power itself for DFS freq) +*/ + + }else { +/* Workaround in otus driver, hpmain.c, line 3906: +* if no data for 5GHT20 are found, take the +* legacy 5G value. +* We extend this here to fallback from any other *HT or +* 11G, too. +*/ +int k = i; + + modes[i].max_power =AR5416_MAX_RATE_POWER ; +while (k-- >0 ) { +if (modes[k].max_power != +AR5416_MAX_RATE_POWER ) { + modes[i].max_power = modes[k].max_power; +break ; + } + } + } + +/* apply max power to pwr_cal_data (ar->power_*) */ +for (j =0 ; j < modes[i].pwr_cal_len; j++) { + modes[i].pwr_cal_data[j] =min (modes[i].pwr_cal_data[j], + modes[i].max_power); + } + } +#undef EDGES +} +static int ar9170_set_power_cal (struct ar9170 *ar,u32 freq,enum ar9170_bw bw) {struct ar9170_calibration_target_power_legacy *ctpl;
@@ -1340,6 +1497,12 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) ctph[idx + 1].power[n]); } + +/* calc. conformance test limits and apply to ar->power*[] */ +ar9170_calc_ctl (ar, freq, bw); + +/* TODO: (heavy clip) regulatory domain power level fine-tuning. */ +/* set ACK/CTS TX power */ ar9170_regwrite_begin (ar);
Signature · 1 line
1.6.0.4